From: Jakub Jelinek Date: Wed, 12 Dec 2018 08:28:43 +0000 (+0100) Subject: re PR c++/88449 (__builtin_is_constant_evaluated misbehaves due to constexpr call... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=cce3ae91f21f185756f604f529501810d8025f37;p=gcc.git 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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index db057d093f8..0347daa2bd3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2018-12-12 Jakub Jelinek + + 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 PR c++/87861 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 96326c3a698..81ce4cdbe75 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -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 @@ -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 (); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bfe527a7ad7..aa11d0ecb2d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2018-12-12 Jakub Jelinek + + 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 PR fortran/88155 diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated1.C b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated1.C index 3b988845e41..ead36c0efb1 100644 --- a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated1.C +++ b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated1.C @@ -1,5 +1,5 @@ // P0595R1 -// { dg-do compile { target c++14 } } +// { dg-do run { target c++14 } } template struct X { int v = N; }; X<__builtin_is_constant_evaluated ()> x; // type X @@ -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 >::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 (); diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated2.C b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated2.C new file mode 100644 index 00000000000..a3b377de053 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated2.C @@ -0,0 +1,72 @@ +// P0595R1 +// { dg-do run { target c++14 } } + +constexpr inline bool +is_constant_evaluated () noexcept +{ + return __builtin_is_constant_evaluated (); +} + +template struct X { int v = N; }; +X x; // type X +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 +struct is_same : false_type {}; +template +struct is_same : 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 x1; + X x2; + static_assert (is_same::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 >::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 (); +}