On 8/22/19 3:55 PM, Martin Sebor wrote: >>> diff --git a/gcc/expr.c b/gcc/expr.c >>> index 92979289e83..d16e0982dcf 100644 >>> --- a/gcc/expr.c >>> +++ b/gcc/expr.c >>> @@ -11402,6 +11402,16 @@ is_aligning_offset (const_tree offset, >>> const_tree exp) >>> tree >>> string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree >>> *decl) >>> { >>> + tree dummy = NULL_TREE;; >>> + if (!mem_size) >>> + mem_size = &dummy; >>> + >>> + tree chartype = TREE_TYPE (arg); >>> + if (POINTER_TYPE_P (chartype)) >>> + chartype = TREE_TYPE (chartype); >>> + while (TREE_CODE (chartype) == ARRAY_TYPE) >>> + chartype = TREE_TYPE (chartype); >> I'm hesitant to ACK this bit. I can understand that if we're given an >> ADDR_EXPR, which should be a POINTER_TYPE_P, that we'll want to look at >> what it's pointing to. But shouldn't we verify that it's an ADDR_EXPR >> before just blindly stripping away the outer type? > > The character type is that of the expression, before any casts > are stripped. For example, given: > > struct S { char n, a[4]; } s[1] = { 0 }; > > and strlen (s->a), ARG is the POINTER_PLUS_EXPR > '(const char *) &s + 1' The type of the operand is a pointer to > the struct S. Given "chartype" is only used in the CONSTRUCTOR handling you're adding, couldn't we just use "char_type_node" in there instead and drop the bits noted above?
>>> + if (TREE_CODE (init) == CONSTRUCTOR && !CONSTRUCTOR_ELTS (init)) >> Would initializer_zerop be better here? That would catch >> zero-initialized constructors as well. > > I originally had initializer_zerop there and removed it at the last > minute it because none of my tests needed it. But my tests only > exercised the flexible array members (which have to be initialized > in constant objects) and not the case where initializer_zerop does > make a difference such as: > > struct A { char a[4]; }; > struct B { struct A a; }; > > const struct B b[2] = { 0 }; > > void f (void) > { > if (__builtin_strlen (b->a.a) == 3) > __builtin_abort (); > } > > Here, fold_ctor_reference returns a non-empty CONSTRUCTOR that > the code doesn't handle. Adding initializer_zerop lets it create > the empty string and the caller fold the call. But it's just > a special case of the more general problem where the CONSTRUCTOR > is both non-empty and non-zero for the parts of the object before > the array we're interested in, such as in > > const struct B b[1] = { 1 }; > > Here, strlen (b->a.a) again isn't folded. Ironically, the equivalent > strlen (b[0].a.a) is folded. The difference between the two is that > b[0].a.a is represented as itself (i.e., NOP (char*, ADDR (b.a.a)) > while b->a.a as (const char *) &b + 1. In the former case > fold_ctor_reference returns an empty CONSTRUCTOR for the char array. > In the latter, it returns the non-empty, non-zero CTOR for all of > b the we don't know how to extract the empty string from. > > Incidentally, it's only the C front-end that "bastardizes" > the expression like this. The C++ FE preserves the original form > of the expression and so it's able to fold the call. > > (Uncovering and trying to fix these problems, by the way, is what > I meant the other day when I said how patches in this area have > a tendency to snownball into "projects." Folding empty ctors of > constant objects probably isn't terribly important but the lack > of consistency is what makes writing tests that behave the same > way across different front-ends and back-ends challenging.) Yup. I understand. When presented with these kinds of snowballing issues, the best advice I can give is to break things down into logical units and make patches which are a series rather than a single unified patch to address multiple issues. git rebase can really help. > >> If not, then you want to make sure to check !TREE_CLOBBER_P (init) since >> that's something completely different than zero initialization. > > I went with the initializer_zerop since it improves things, if > negligibly, and added tests for it. If you or Richard have a test > case that I could add to the patch showing when TREE_CLOBBER_P is > set on a CTOR and that not checking would cause trouble. Note that initializer_zerop checks TREE_CLOBBER internally. So if you're using initializer_zerop, then you're good. So all that's left is the "chartype" stuff in string_constant. If we can use char_type_node instead of trying to extract a character type, then the problematical code would just go away. jeff