https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82429
Bug ID: 82429 Summary: strcpy to stpcpy transformation disabled in strict mode Product: gcc Version: 8.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: msebor at gcc dot gnu.org Target Milestone: --- In https://gcc.gnu.org/ml/gcc/2017-10/msg00010.html Jakub explains that the strcpy to stpcpy optimizing transformation that is normally disabled in strict conformance modes (e.g., with -std=c11 rather than -std=gnu11) is meant to be enabled by defining _GNU_SOURCE, or _POSIX_C_SOURCE=200809, or _XOPEN_SOURCE=700, or various other feature test macros that cause stpcpy to be declared in system headers. However, as the test case below shows (from https://gcc.gnu.org/ml/gcc/2017-10/msg00015.html in the same thread), this is not what actually happens. What appears to be necessary in addition to defining one of the feature test macros above is also explicitly declaring the stpcpy function in the program. A declaration alone in one of the system headers is not sufficient. This seems like a bug. Explicitly declaring a standard function that's already declared in a system header shouldn't have an impact on the quality of emitted code. $ cat z.c && gcc -O2 -S -Wall -Wextra -fdump-tree-optimized=/dev/stdout -std=c11 -D_GNU_SOURCE z.c #include <string.h> #if STPCPY extern char* stpcpy (char*, const char*); #endif void __attribute__ ((noclone)) f (char *d, const char *s) { strcpy (d, s); // with -D_GNU_SOURCE strcpy is expected to be transformed to stpcpy if (__builtin_strlen (d) != __builtin_strlen (s)) __builtin_abort (); } ;; Function f (f, funcdef_no=4, decl_uid=1972, cgraph_uid=4, symbol_order=4) __attribute__((noclone)) f (char * d, const char * s) { long unsigned int _1; long unsigned int _2; <bb 2> [100.00%] [count: INV]: strcpy (d_4(D), s_5(D)); // strcpy not transformed to stpcpy _1 = __builtin_strlen (d_4(D)); _2 = __builtin_strlen (s_5(D)); if (_1 != _2) goto <bb 3>; [0.04%] [count: 0] else goto <bb 4>; [99.96%] [count: INV] <bb 3> [0.04%] [count: 0]: __builtin_abort (); <bb 4> [99.96%] [count: INV]: return; } $ gcc -O2 -S -Wall -Wextra -fdump-tree-optimized=/dev/stdout -std=c11 -D_GNU_SOURCE -DSTPCPY z.c ;; Function f (f, funcdef_no=4, decl_uid=1975, cgraph_uid=4, symbol_order=4) __attribute__((noclone)) f (char * d, const char * s) { long unsigned int _1; long unsigned int _2; char * _8; long unsigned int _9; long unsigned int _10; <bb 2> [100.00%] [count: INV]: _8 = __builtin_stpcpy (d_4(D), s_5(D)); // strcpy transformed to stpcpy _9 = (long unsigned int) _8; _10 = (long unsigned int) d_4(D); _1 = _9 - _10; _2 = __builtin_strlen (s_5(D)); if (_1 != _2) goto <bb 3>; [0.04%] [count: 0] else goto <bb 4>; [99.96%] [count: INV] <bb 3> [0.04%] [count: 0]: __builtin_abort (); <bb 4> [99.96%] [count: INV]: return; }