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;

}

Reply via email to