From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 23EBC3858031; Wed, 5 Jan 2022 19:45:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 23EBC3858031 From: "jakub at gcc dot gnu.org" To: gcc-bugs@gcc.gnu.org Subject: [Bug c++/89074] valid pointer equality constexpr comparison rejected Date: Wed, 05 Jan 2022 19:45:20 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: c++ X-Bugzilla-Version: 9.0 X-Bugzilla-Keywords: rejects-valid X-Bugzilla-Severity: normal X-Bugzilla-Who: jakub at gcc dot gnu.org X-Bugzilla-Status: NEW X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-BeenThere: gcc-bugs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-bugs mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 05 Jan 2022 19:45:21 -0000 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D89074 --- Comment #10 from Jakub Jelinek --- So, for #c5, if (&a[1] =3D=3D &b[0]) instead of if (a+1 =3D=3D b+0) works right, that is handled by the match.pd (cmp (convert1?@2 addr@0) (convert2? addr@1)) address_compare simplification. And it also works for GIMPLE, where we have in gimple-fold.c the: /* Translate &x + CST into an invariant form suitable for further propagation. */ if (subcode =3D=3D POINTER_PLUS_EXPR) { tree op0 =3D (*valueize) (gimple_assign_rhs1 (stmt)); tree op1 =3D (*valueize) (gimple_assign_rhs2 (stmt)); if (TREE_CODE (op0) =3D=3D ADDR_EXPR && TREE_CODE (op1) =3D=3D INTEGER_CST) { tree off =3D fold_convert (ptr_type_node, op1); return build1_loc (loc, ADDR_EXPR, TREE_TYPE (op0), fold_build2 (MEM_REF, TREE_TYPE (TREE_TYPE (op0)), unshare_expr (op0), off)); } } I think we don't do this for GENERIC because that can seriously break the constant evaluation, the details on which exact field is accessed can be lo= st in there. But, if we take e.g. struct S { int s; }; struct T : public S {}; struct U : public T {}; constexpr bool test() { U a[] =3D { 1, 2, 3, 4 }; U b[] =3D { 5, 6, 7, 8 }; T *c =3D (T *) a + 1; S *d =3D (S *) c + 2; S *e =3D (S *) b + 1; if (a+0 =3D=3D b+0) // OK return false; if (d =3D=3D e) // ERROR return false; return true; } static_assert( test() ); then we can see the comparison is tried on =E2=80=98((((S*)((& a[0].U::) + 4)) + 8) =3D=3D ((& b[0].U::.T::) + 4))=E2=80=99 is not a constant expres= sion so the multiple pointer_plus aren't merged in there either. Hasving a GENERIC guarded variant of the address_compare with one pointer_p= lus in one or the other or both operands might be still doable, but the above s= hows that it wouldn't be sufficient. So, perhaps instead if simple comparison fails during constexpr evaluation, we could call some helper function that looks through cast and optimizes the POINTER_PLUS into MEM_REF that it folds and then we'd try to compare it aga= in (or call that helper function regardless on both comparison operands)? Another thing is that the following testcase isn't rejected: 2022-01-05 Jakub Jelinek 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[] =3D { 1, 2 }; + int b[] =3D { 3, 4 }; + + if (&a[0] =3D=3D &b[0]) + return false; + + if (&a[1] =3D=3D &b[0]) + return false; + + if (&a[1] =3D=3D &b[1]) + return false; + + if (&a[2] =3D=3D &b[1]) + return false; + + if (&a[2] =3D=3D &b[0]) // { dg-error "is not a constant expres= sion" } + return false; + + return true; +} + +constexpr bool a =3D foo ();=