symtab: Fold &a == &b to 0 if folding_initializer [PR94716]

On Thu, Dec 09, 2021 at 06:09:12PM -0500, Jason Merrill wrote:
> For the more general comparison of decls like your a != b example above I
> think clang is in the right; in manifestly constant-evaluated context
> (folding_initializer) we should return that they are unequal and prevent a
> later alias declaration, like we do for comparison to 0 in
> maybe_nonzero_address.  It's possible that this gives a wrong answer based
> on something in another translation unit, but that's unlikely, and taking
> that chance seems better than rejecting code that needs a constant answer.

I agree.  This is an incremental patch to do that.

2022-01-03  Jakub Jelinek  <jakub@redhat.com>

	PR c++/94716
gcc/
	* symtab.c: Include fold-const.h.
	(symtab_node::equal_address_to): If folding_initializer is true,
	handle it like memory_accessed.  Simplify.
gcc/testsuite/
	* gcc.dg/init-compare-1.c: New test.
	* g++.dg/cpp0x/constexpr-compare1.C: New test.
	* g++.dg/cpp1y/constexpr-94716.C: New test.
	* g++.dg/cpp1z/constexpr-compare1.C: New test.
This commit is contained in:
Jakub Jelinek 2022-01-03 13:47:53 +01:00
parent 814c221c9e
commit 91031bffa4
5 changed files with 39 additions and 3 deletions

View File

@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h" #include "stringpool.h"
#include "attribs.h" #include "attribs.h"
#include "builtins.h" #include "builtins.h"
#include "fold-const.h"
static const char *ipa_ref_use_name[] = {"read","write","addr","alias"}; static const char *ipa_ref_use_name[] = {"read","write","addr","alias"};
@ -2276,10 +2277,12 @@ symtab_node::equal_address_to (symtab_node *s2, bool memory_accessed)
return 0; return 0;
} }
if (rs1 == rs2)
return -1;
/* If the FE tells us at least one of the decls will never be aliased nor /* If the FE tells us at least one of the decls will never be aliased nor
overlapping with other vars in some other way, return 0. */ overlapping with other vars in some other way, return 0. */
if (VAR_P (decl) if (VAR_P (decl)
&& rs1 != rs2
&& (lookup_attribute ("non overlapping", DECL_ATTRIBUTES (decl)) && (lookup_attribute ("non overlapping", DECL_ATTRIBUTES (decl))
|| lookup_attribute ("non overlapping", DECL_ATTRIBUTES (s2->decl)))) || lookup_attribute ("non overlapping", DECL_ATTRIBUTES (s2->decl))))
return 0; return 0;
@ -2288,9 +2291,14 @@ symtab_node::equal_address_to (symtab_node *s2, bool memory_accessed)
are different unless they are declared as alias of one to another while are different unless they are declared as alias of one to another while
the code folding comparisons doesn't. the code folding comparisons doesn't.
We probably should be consistent and use this fact here, too, but for We probably should be consistent and use this fact here, too, but for
the moment return false only when we are called from the alias oracle. */ the moment return false only when we are called from the alias oracle.
Return 0 in C constant initializers and C++ manifestly constant
expressions, the likelyhood that different vars will be aliases is
small and returning -1 lets us reject too many initializers. */
if (memory_accessed || folding_initializer)
return 0;
return memory_accessed && rs1 != rs2 ? 0 : -1; return -1;
} }
/* Worker for call_for_symbol_and_aliases. */ /* Worker for call_for_symbol_and_aliases. */

View File

@ -0,0 +1,7 @@
// { dg-do compile { target c++11 } }
extern int a, b;
static_assert (&a == &a, "");
static_assert (&a != &b, "");
constexpr bool c = &a == &a;
constexpr bool d = &a != &b;

View File

@ -0,0 +1,8 @@
// PR c++/94716
// { dg-do compile { target c++14 } }
template <int> char v = 0;
static_assert (&v<2> == &v<2>, "");
static_assert (&v<0> != &v<1>, "");
constexpr bool a = &v<2> == &v<2>;
constexpr bool b = &v<0> != &v<1>;

View File

@ -0,0 +1,8 @@
// { dg-do compile { target c++17 } }
inline int a = 0;
inline int b = 0;
static_assert (&a == &a);
static_assert (&a != &b);
constexpr bool c = &a == &a;
constexpr bool d = &a != &b;

View File

@ -0,0 +1,5 @@
/* { dg-do compile } */
extern int a, b;
int c = &a == &a;
int d = &a != &b;