On Thu, Jan 6, 2022 at 10:25 AM Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > Hi! > > The following testcase used to be incorrectly accepted. The match.pd > optimization that uses address_compare punts on folding comparison > of start of one object and end of another one only when those addresses > are cast to integral types, when the comparison is done on pointer types > it assumes undefined behavior and decides to fold the comparison such > that the addresses don't compare equal even when they at runtime they > could be equal. > But C++ says it is undefined behavior and so during constant evaluation > we should reject those, so this patch adds !folding_initializer && > check to that spot. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > Note, address_compare has some special cases, e.g. it assumes that > static vars are never adjacent to automatic vars, which is the case > for the usual layout where automatic vars are on the stack and after > .rodata/.data sections there is heap: > /* Assume that automatic variables can't be adjacent to global > variables. */ > else if (is_global_var (base0) != is_global_var (base1)) > ; > Is it ok that during constant evaluation we don't treat those as undefined > behavior, or shall that be with !folding_initializer && too? > > Another special case is: > if ((DECL_P (base0) && TREE_CODE (base1) == STRING_CST) > || (TREE_CODE (base0) == STRING_CST && DECL_P (base1)) > || (TREE_CODE (base0) == STRING_CST > && TREE_CODE (base1) == STRING_CST > && ioff0 >= 0 && ioff1 >= 0 > && ioff0 < TREE_STRING_LENGTH (base0) > && ioff1 < TREE_STRING_LENGTH (base1) > /* This is a too conservative test that the STRING_CSTs > will not end up being string-merged. */ > && strncmp (TREE_STRING_POINTER (base0) + ioff0, > TREE_STRING_POINTER (base1) + ioff1, > MIN (TREE_STRING_LENGTH (base0) - ioff0, > TREE_STRING_LENGTH (base1) - ioff1)) != 0)) > ; > else if (!DECL_P (base0) || !DECL_P (base1)) > return 2; > Here we similarly assume that vars aren't adjacent to string literals > or vice versa. Do we need to stick !folding_initializer && to those > DECL_P vs. STRING_CST cases? Though, because of the return 2; for > non-DECL_P that would mean rejecting comparisons like &var == &"foobar"[3] > etc. which ought to be fine, no? So perhaps we need to watch for > decls. vs. STRING_CSTs like for DECLs whether the address is at the start > or at the end of the string literal or somewhere in between (at least > for folding_initializer)? > And yet another chapter but probably unsolvable is comparison of > string literal addresses. I think pedantically in C++ > &"foo"[0] == &"foo"[0] is undefined behavior, different occurences of > the same string literals might still not be merged in some implementations. > But constexpr const char *s = "foo"; &s[0] == &s[0] should be well defined, > and we aren't tracking anywhere whether the string literal was the same one > or different (and I think other compilers don't track that either).
On my TODO list is to make &"foo" invalid and instead require &CONST_DECL (and DECL_INITIAL of it then being "foo"), that would make it possible to track the "original" string literal and perform string merging in a more considerate way. Richard. > > 2022-01-06 Jakub Jelinek <ja...@redhat.com> > > PR c++/89074 > * fold-const.c (address_compare): Punt on comparison of address of > one object with address of end of another object if > folding_initializer. > > * g++.dg/cpp1y/constexpr-89074-1.C: New test. > > --- gcc/fold-const.c.jj 2022-01-05 20:30:08.731806756 +0100 > +++ gcc/fold-const.c 2022-01-05 20:34:52.277822349 +0100 > @@ -16627,7 +16627,7 @@ address_compare (tree_code code, tree ty > /* If this is a pointer comparison, ignore for now even > valid equalities where one pointer is the offset zero > of one object and the other to one past end of another one. */ > - else if (!INTEGRAL_TYPE_P (type)) > + else if (!folding_initializer && !INTEGRAL_TYPE_P (type)) > ; > /* Assume that automatic variables can't be adjacent to global > variables. */ > --- gcc/testsuite/g++.dg/cpp1y/constexpr-89074-1.C.jj 2022-01-05 > 20:43:03.696917484 +0100 > +++ gcc/testsuite/g++.dg/cpp1y/constexpr-89074-1.C 2022-01-05 > 20:42:12.676634044 +0100 > @@ -0,0 +1,28 @@ > +// PR c++/89074 > +// { dg-do compile { target c++14 } } > + > +constexpr bool > +foo () > +{ > + int a[] = { 1, 2 }; > + int b[] = { 3, 4 }; > + > + if (&a[0] == &b[0]) > + return false; > + > + if (&a[1] == &b[0]) > + return false; > + > + if (&a[1] == &b[1]) > + return false; > + > + if (&a[2] == &b[1]) > + return false; > + > + if (&a[2] == &b[0]) // { dg-error "is not a constant expression" } > + return false; > + > + return true; > +} > + > +constexpr bool a = foo (); > > Jakub >