Hi! The C FE sadly passes through some really bad prototypes of builtin functions as "harmless": /* Accept "harmless" mismatches in function types such as missing qualifiers or pointer vs same size integer mismatches. This is for the ffs and fprintf builtins. However, with -Wextra in effect, diagnose return and argument types that are incompatible according to language rules. */ In the strlen pass, we'd better have pointers where we expect pointers and rightly sized integers where we expect integers. The following patch ensures that by calling gimple_builtin_call_types_compatible_p against the builtin_decl_explicit decl.
Furthermore, I've noticed that a bunch of later added builtins that the strlen pass now handles weren't added to valid_builtin_call, so the patch adds that too (that is to handle cases where e.g. somebody declares strncat as pure, or strcmp as const etc.). Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2019-03-13 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/89703 * tree-ssa-strlen.c (valid_builtin_call): Punt if stmt call types aren't compatible also with builtin_decl_explicit. Check pure or non-pure status of BUILT_IN_STR{{,N}CMP,N{LEN,{CAT,CPY}{,_CHK}}} and BUILT_IN_STPNCPY{,_CHK}. * gcc.c-torture/compile/pr89703-1.c: New test. * gcc.c-torture/compile/pr89703-2.c: New test. --- gcc/tree-ssa-strlen.c.jj 2019-02-26 21:33:38.992826180 +0100 +++ gcc/tree-ssa-strlen.c 2019-03-13 19:53:20.152551962 +0100 @@ -971,12 +971,21 @@ valid_builtin_call (gimple *stmt) return false; tree callee = gimple_call_fndecl (stmt); + tree decl = builtin_decl_explicit (DECL_FUNCTION_CODE (callee)); + if (decl + && decl != callee + && !gimple_builtin_call_types_compatible_p (stmt, decl)) + return false; + switch (DECL_FUNCTION_CODE (callee)) { case BUILT_IN_MEMCMP: case BUILT_IN_MEMCMP_EQ: + case BUILT_IN_STRCMP: + case BUILT_IN_STRNCMP: case BUILT_IN_STRCHR: case BUILT_IN_STRLEN: + case BUILT_IN_STRNLEN: /* The above functions should be pure. Punt if they aren't. */ if (gimple_vdef (stmt) || gimple_vuse (stmt) == NULL_TREE) return false; @@ -991,10 +1000,16 @@ valid_builtin_call (gimple *stmt) case BUILT_IN_MEMSET: case BUILT_IN_STPCPY: case BUILT_IN_STPCPY_CHK: + case BUILT_IN_STPNCPY: + case BUILT_IN_STPNCPY_CHK: case BUILT_IN_STRCAT: case BUILT_IN_STRCAT_CHK: case BUILT_IN_STRCPY: case BUILT_IN_STRCPY_CHK: + case BUILT_IN_STRNCAT: + case BUILT_IN_STRNCAT_CHK: + case BUILT_IN_STRNCPY: + case BUILT_IN_STRNCPY_CHK: /* The above functions should be neither const nor pure. Punt if they aren't. */ if (gimple_vdef (stmt) == NULL_TREE || gimple_vuse (stmt) == NULL_TREE) --- gcc/testsuite/gcc.c-torture/compile/pr89703-1.c.jj 2019-03-13 19:56:10.619785685 +0100 +++ gcc/testsuite/gcc.c-torture/compile/pr89703-1.c 2019-03-13 19:55:48.490146110 +0100 @@ -0,0 +1,13 @@ +/* PR tree-optimization/89703 */ + +typedef __SIZE_TYPE__ size_t; +extern char *strlen (const char *); +extern char *strnlen (const char *, size_t); +extern char c[2]; + +void +foo (char **q) +{ + q[0] = strlen (c); + q[1] = strnlen (c, 2); +} --- gcc/testsuite/gcc.c-torture/compile/pr89703-2.c.jj 2019-03-13 19:56:13.495738838 +0100 +++ gcc/testsuite/gcc.c-torture/compile/pr89703-2.c 2019-03-13 19:55:55.310035032 +0100 @@ -0,0 +1,13 @@ +/* PR tree-optimization/89703 */ + +typedef __SIZE_TYPE__ size_t; +extern void *memcpy (void *, const void *, size_t); +extern char *strlen (const char *); +extern char c[2]; + +void +foo (char **q) +{ + memcpy (c, "a", 2); + q[0] = strlen (c); +} Jakub