https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92765
--- Comment #11 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Untested patch to fix all these wrong-code issues would be something like: --- gcc/tree-ssa-strlen.c.jj 2019-11-28 09:35:32.443298424 +0100 +++ gcc/tree-ssa-strlen.c 2019-12-03 17:02:32.131658020 +0100 @@ -3473,54 +3473,30 @@ compute_string_length (int idx) static unsigned HOST_WIDE_INT determine_min_objsize (tree dest) { - unsigned HOST_WIDE_INT size = 0; + unsigned HOST_WIDE_INT size; init_object_sizes (); if (compute_builtin_object_size (dest, 2, &size)) return size; - /* Try to determine the size of the object through the RHS - of the assign statement. */ - if (TREE_CODE (dest) == SSA_NAME) - { - gimple *stmt = SSA_NAME_DEF_STMT (dest); - if (!is_gimple_assign (stmt)) - return HOST_WIDE_INT_M1U; - - if (!gimple_assign_single_p (stmt) - && !gimple_assign_unary_nop_p (stmt)) - return HOST_WIDE_INT_M1U; + return HOST_WIDE_INT_M1U; +} - dest = gimple_assign_rhs1 (stmt); - return determine_min_objsize (dest); - } +/* Similarly, but maximum instead of minimum, and return 0 when the + size cannot be determined. */ - /* Try to determine the size of the object from its type. */ - if (TREE_CODE (dest) != ADDR_EXPR) - return HOST_WIDE_INT_M1U; - - tree type = TREE_TYPE (dest); - if (TREE_CODE (type) == POINTER_TYPE) - type = TREE_TYPE (type); - - type = TYPE_MAIN_VARIANT (type); - - /* The size of a flexible array cannot be determined. Otherwise, - for arrays with more than one element, return the size of its - type. GCC itself misuses arrays of both zero and one elements - as flexible array members so they are excluded as well. */ - if (TREE_CODE (type) != ARRAY_TYPE - || !array_at_struct_end_p (dest)) - { - tree type_size = TYPE_SIZE_UNIT (type); - if (type_size && TREE_CODE (type_size) == INTEGER_CST - && !integer_onep (type_size) - && !integer_zerop (type_size)) - return tree_to_uhwi (type_size); - } +static unsigned HOST_WIDE_INT +determine_max_objsize (tree dest) +{ + unsigned HOST_WIDE_INT size; - return HOST_WIDE_INT_M1U; + init_object_sizes (); + + if (compute_builtin_object_size (dest, 0, &size)) + return size; + + return 0; } /* Given strinfo IDX for ARG, set LENRNG[] to the range of lengths @@ -3603,7 +3579,9 @@ get_len_or_size (tree arg, int idx, unsi /* Set *SIZE to the size of the smallest object referenced by ARG if ARG denotes a single object, or to HWI_M1U otherwise. */ - *size = determine_min_objsize (arg); + *size = determine_max_objsize (arg); + if (*size == 0) + *size = HOST_WIDE_INT_M1U; *nulterm = false; } } plus add testsuite coverage from the testcases in this PR and deal with testsuite regressions: FAIL: gcc.dg/Wstring-compare.c (test for warnings, line 123) FAIL: gcc.dg/strcmpopt_2.c scan-tree-dump-times strlen1 "cmp_eq \\(" 8 FAIL: gcc.dg/strcmpopt_4.c scan-tree-dump-times strlen1 "cmp_eq \\(" 1 FAIL: gcc.dg/strlenopt-69.c scan-tree-dump-not optimized "abort|strcmp|strncmp" where strcmpopt_2.c now matches just 4 times instead of 8. Or do we consider the #c10 testcase valid, but what strcmpopt_2.c does like: typedef struct { char s[8]; int x; } S; __attribute__ ((noinline)) int f1 (S *s) { return __builtin_strcmp (s->s, "abc") != 0; } ok (in that if there is a pointer to S, at least sizeof (s->s) bytes will be mapped? We could look through COMPONENT_REFs in the access path and if there is any UNION_TYPE in there, be conservative and consider the same addresses in all the union members and take conservative answer from all of them? Wouldn't that still be a problem if we have union somewhere earlier and just take address of a union member?