c++: Reject in constant evaluation address comparisons of start of one var and end of another [PR89074]
Message ID | 20220106092416.GX2646553@tucnak |
---|---|
State | New |
Headers |
Return-Path: <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 023D53857406 for <patchwork@sourceware.org>; Thu, 6 Jan 2022 09:25:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 023D53857406 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1641461128; bh=jyftRQAJJq6nvuv4HD0ZYVdhayr5lmuhqBaU8XW6mEs=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=Iz8HggAWPqxgYimzbXMdDpJxMhFknKK2fpt6O/PV1ii7EC06RpC0WgPW8Q7AGC9rn 8Dn14Im6U8SRvZolHYAznSl/uGHfOL9pX1veOPIW2Za/LpKeXhxWdsE56hOmnWWfhP pB2DfaysBxW+FO06HhYvYfWPKvZ066FuFP7ksup4= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id CD1D4385AC27 for <gcc-patches@gcc.gnu.org>; Thu, 6 Jan 2022 09:24:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org CD1D4385AC27 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-647-JQ90JxLKPLyNBCqSHdR5Sg-1; Thu, 06 Jan 2022 04:24:27 -0500 X-MC-Unique: JQ90JxLKPLyNBCqSHdR5Sg-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id EA7261083F64 for <gcc-patches@gcc.gnu.org>; Thu, 6 Jan 2022 09:24:25 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.2.16.169]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 88AFD60C3F; Thu, 6 Jan 2022 09:24:19 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.16.1/8.16.1) with ESMTPS id 2069OHWx128220 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Thu, 6 Jan 2022 10:24:17 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.16.1/8.16.1/Submit) id 2069OGT4128219; Thu, 6 Jan 2022 10:24:16 +0100 Date: Thu, 6 Jan 2022 10:24:16 +0100 To: Jason Merrill <jason@redhat.com> Subject: [PATCH] c++: Reject in constant evaluation address comparisons of start of one var and end of another [PR89074] Message-ID: <20220106092416.GX2646553@tucnak> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=us-ascii Content-Disposition: inline X-Spam-Status: No, score=-5.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list <gcc-patches.gcc.gnu.org> List-Unsubscribe: <https://gcc.gnu.org/mailman/options/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe> List-Archive: <https://gcc.gnu.org/pipermail/gcc-patches/> List-Post: <mailto:gcc-patches@gcc.gnu.org> List-Help: <mailto:gcc-patches-request@gcc.gnu.org?subject=help> List-Subscribe: <https://gcc.gnu.org/mailman/listinfo/gcc-patches>, <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe> From: Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> Reply-To: Jakub Jelinek <jakub@redhat.com> Cc: gcc-patches@gcc.gnu.org Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" <gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org> |
Series |
c++: Reject in constant evaluation address comparisons of start of one var and end of another [PR89074]
|
|
Commit Message
Jakub Jelinek
Jan. 6, 2022, 9:24 a.m. UTC
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). 2022-01-06 Jakub Jelinek <jakub@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. Jakub
Comments
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 <jakub@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 >
On Mon, Jan 10, 2022 at 6:11 AM Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > 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. Interesting because I wrote this would be one way to fix PR88925. Thanks, Andrew Pinski > > Richard. > > > > > 2022-01-06 Jakub Jelinek <jakub@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 > >
Hi! I'd like to ping this patch: > 2022-01-06 Jakub Jelinek <jakub@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. Thanks. Jakub
On 1/6/22 04:24, Jakub Jelinek wrote: > > 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? OK. > 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? I guess that's undefined as well. > 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? Seems so. > 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)? Agreed. > 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. I disagree; it's unspecified whether string literals are merged, but I think the comparison result is well specified depending on that implementation behavior. > 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). > > 2022-01-06 Jakub Jelinek <jakub@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 ();
--- 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 ();