re PR c++/88449 (__builtin_is_constant_evaluated misbehaves due to constexpr call caching)
PR c++/88449 * constexpr.c (struct constexpr_call): Add pretend_const_required member. (constexpr_call_hasher::equal): Return false if pretend_const_required members differ. (cxx_eval_call_expression): Adjust new_call initialization. Hash in ctx->pretend_const_required. * g++.dg/cpp2a/is-constant-evaluated1.C: Change from dg-do compile to dg-do run. (e): Adjust comment with correct expected value. (main): Expect e == 1. * g++.dg/cpp2a/is-constant-evaluated2.C: New test. From-SVN: r267044
This commit is contained in:
parent
2f00fb3d0b
commit
cce3ae91f2
5 changed files with 105 additions and 6 deletions
|
@ -1,3 +1,13 @@
|
|||
2018-12-12 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/88449
|
||||
* constexpr.c (struct constexpr_call): Add pretend_const_required
|
||||
member.
|
||||
(constexpr_call_hasher::equal): Return false if pretend_const_required
|
||||
members differ.
|
||||
(cxx_eval_call_expression): Adjust new_call initialization. Hash in
|
||||
ctx->pretend_const_required.
|
||||
|
||||
2018-12-11 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/87861
|
||||
|
|
|
@ -976,6 +976,8 @@ struct GTY((for_user)) constexpr_call {
|
|||
/* The hash of this call; we remember it here to avoid having to
|
||||
recalculate it when expanding the hash table. */
|
||||
hashval_t hash;
|
||||
/* Whether __builtin_is_constant_evaluated() should evaluate to true. */
|
||||
bool pretend_const_required;
|
||||
};
|
||||
|
||||
struct constexpr_call_hasher : ggc_ptr_hash<constexpr_call>
|
||||
|
@ -1055,6 +1057,8 @@ constexpr_call_hasher::equal (constexpr_call *lhs, constexpr_call *rhs)
|
|||
return true;
|
||||
if (lhs->hash != rhs->hash)
|
||||
return false;
|
||||
if (lhs->pretend_const_required != rhs->pretend_const_required)
|
||||
return false;
|
||||
if (!constexpr_fundef_hasher::equal (lhs->fundef, rhs->fundef))
|
||||
return false;
|
||||
lhs_bindings = lhs->bindings;
|
||||
|
@ -1503,7 +1507,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
|
|||
{
|
||||
location_t loc = cp_expr_loc_or_loc (t, input_location);
|
||||
tree fun = get_function_named_in_call (t);
|
||||
constexpr_call new_call = { NULL, NULL, NULL, 0 };
|
||||
constexpr_call new_call
|
||||
= { NULL, NULL, NULL, 0, ctx->pretend_const_required };
|
||||
bool depth_ok;
|
||||
|
||||
if (fun == NULL_TREE)
|
||||
|
@ -1675,8 +1680,11 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
|
|||
constexpr_call *entry = NULL;
|
||||
if (depth_ok && !non_constant_args && ctx->strict)
|
||||
{
|
||||
new_call.hash = iterative_hash_template_arg
|
||||
(new_call.bindings, constexpr_fundef_hasher::hash (new_call.fundef));
|
||||
new_call.hash = constexpr_fundef_hasher::hash (new_call.fundef);
|
||||
new_call.hash
|
||||
= iterative_hash_template_arg (new_call.bindings, new_call.hash);
|
||||
new_call.hash
|
||||
= iterative_hash_object (ctx->pretend_const_required, new_call.hash);
|
||||
|
||||
/* If we have seen this call before, we are done. */
|
||||
maybe_initialize_constexpr_call_table ();
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
2018-12-12 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR c++/88449
|
||||
* g++.dg/cpp2a/is-constant-evaluated1.C: Change from dg-do compile
|
||||
to dg-do run.
|
||||
(e): Adjust comment with correct expected value.
|
||||
(main): Expect e == 1.
|
||||
* g++.dg/cpp2a/is-constant-evaluated2.C: New test.
|
||||
|
||||
2018-12-11 Steven G. Kargl <kargl@gcc.gnu.org>
|
||||
|
||||
PR fortran/88155
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// P0595R1
|
||||
// { dg-do compile { target c++14 } }
|
||||
// { dg-do run { target c++14 } }
|
||||
|
||||
template<int N> struct X { int v = N; };
|
||||
X<__builtin_is_constant_evaluated ()> x; // type X<true>
|
||||
|
@ -8,7 +8,7 @@ int a = __builtin_is_constant_evaluated () ? y : 1; // initializes a to 1
|
|||
int b = __builtin_is_constant_evaluated () ? 2 : y; // initializes b to 2
|
||||
int c = y + (__builtin_is_constant_evaluated () ? 2 : y); // initializes c to 2*y
|
||||
int d = __builtin_is_constant_evaluated (); // initializes d to 1
|
||||
int e = d + __builtin_is_constant_evaluated (); // initializes e to 0
|
||||
int e = d + __builtin_is_constant_evaluated (); // initializes e to 1 + 0
|
||||
|
||||
struct false_type { static constexpr bool value = false; };
|
||||
struct true_type { static constexpr bool value = true; };
|
||||
|
@ -50,7 +50,7 @@ static_assert (is_same<decltype (x), X<true> >::value, "x's type");
|
|||
int
|
||||
main ()
|
||||
{
|
||||
if (a != 1 || b != 2 || c != 8 || d != 1 || e != 0 || p != 26 || q != 56)
|
||||
if (a != 1 || b != 2 || c != 8 || d != 1 || e != 1 || p != 26 || q != 56)
|
||||
__builtin_abort ();
|
||||
if (s.a != 3 || s.b != 4 || t.a != 2 || t.b != 4)
|
||||
__builtin_abort ();
|
||||
|
|
72
gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated2.C
Normal file
72
gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated2.C
Normal file
|
@ -0,0 +1,72 @@
|
|||
// P0595R1
|
||||
// { dg-do run { target c++14 } }
|
||||
|
||||
constexpr inline bool
|
||||
is_constant_evaluated () noexcept
|
||||
{
|
||||
return __builtin_is_constant_evaluated ();
|
||||
}
|
||||
|
||||
template<int N> struct X { int v = N; };
|
||||
X<is_constant_evaluated ()> x; // type X<true>
|
||||
int y = 4;
|
||||
int a = is_constant_evaluated () ? y : 1; // initializes a to 1
|
||||
int b = is_constant_evaluated () ? 2 : y; // initializes b to 2
|
||||
int c = y + (is_constant_evaluated () ? 2 : y); // initializes c to 2*y
|
||||
int d = is_constant_evaluated (); // initializes d to 1
|
||||
int e = d + is_constant_evaluated (); // initializes e to 1 + 0
|
||||
|
||||
struct false_type { static constexpr bool value = false; };
|
||||
struct true_type { static constexpr bool value = true; };
|
||||
template<class T, class U>
|
||||
struct is_same : false_type {};
|
||||
template<class T>
|
||||
struct is_same<T, T> : true_type {};
|
||||
|
||||
constexpr int
|
||||
foo (int x)
|
||||
{
|
||||
const int n = is_constant_evaluated () ? 13 : 17; // n == 13
|
||||
int m = is_constant_evaluated () ? 13 : 17; // m might be 13 or 17 (see below)
|
||||
char arr[n] = {}; // char[13]
|
||||
return m + sizeof (arr) + x;
|
||||
}
|
||||
|
||||
constexpr int
|
||||
bar ()
|
||||
{
|
||||
const int n = is_constant_evaluated() ? 13 : 17;
|
||||
X<n> x1;
|
||||
X<is_constant_evaluated() ? 13 : 17> x2;
|
||||
static_assert (is_same<decltype (x1), decltype (x2)>::value, "x1/x2's type");
|
||||
return x1.v + x2.v;
|
||||
}
|
||||
|
||||
int p = foo (0); // m == 13; initialized to 26
|
||||
int q = p + foo (0); // m == 17 for this call; initialized to 56
|
||||
static_assert (bar () == 26, "bar");
|
||||
|
||||
struct S { int a, b; };
|
||||
|
||||
S s = { is_constant_evaluated () ? 2 : 3, y };
|
||||
S t = { is_constant_evaluated () ? 2 : 3, 4 };
|
||||
|
||||
static_assert (is_same<decltype (x), X<true> >::value, "x's type");
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
if (a != 1 || b != 2 || c != 8 || d != 1 || e != 1 || p != 26 || q != 56)
|
||||
__builtin_abort ();
|
||||
if (s.a != 3 || s.b != 4 || t.a != 2 || t.b != 4)
|
||||
__builtin_abort ();
|
||||
if (foo (y) != 34)
|
||||
__builtin_abort ();
|
||||
#if __cplusplus >= 201703L
|
||||
if constexpr (foo (0) != 26)
|
||||
__builtin_abort ();
|
||||
#endif
|
||||
constexpr int w = foo (0);
|
||||
if (w != 26)
|
||||
__builtin_abort ();
|
||||
}
|
Loading…
Add table
Reference in a new issue