On Thu, Dec 20, 2018 at 04:26:21PM -0500, Jason Merrill wrote: > Right, but they either are or they aren't. Doing this isn't likely to help > anything, and can lead to paradoxical results in contrived testcases. > > > But if you think this is a bad idea, I can remove it, I haven't been > > successful in constructing a testcase where this would matter. > > Please. OK with those changes.
Actually, the main reason for any changes in that block was mainly that I thought it is a bad idea to fold the argument with __builtin_is_const_evaluated () folded into true if that argument isn't a constant expression. So are you ok with what is in the patch below, i.e. { bool non_cst_p = false, ovf_p = false; tree a = cxx_eval_constant_expression (&new_ctx, args[i], false, &non_cst_p, &ovf_p); if ((!non_cst_p && !ovf_p) || !ctx->manifestly_const_eval) args[i] = a; } , or perhaps without the || !ctx->manifestly_const_eval? So, if the argument is a constant expression, fold to that, if it is not, just do cp_fully_fold on it if it is __builtin_constant_p, otherwise nothing? 2018-12-20 Jakub Jelinek <ja...@redhat.com> PR c++/86524 PR c++/88446 * cp-tree.h (fold_non_dependent_expr): Add manifestly_const_eval argument. * constexpr.c (cxx_eval_builtin_function_call): Evaluate __builtin_constant_p if ctx->manifestly_const_eval even in constexpr functions. For arguments to builtins, if ctx->manifestly_const_eval and argument is not a constant expression, use original argument. Fix comment typo. (fold_non_dependent_expr): Add manifestly_const_eval argument, pass it through to cxx_eval_outermost_constant_expr and maybe_constant_value. * semantics.c (finish_static_assert): Call fold_non_dependent_expr with true as manifestly_const_eval. * g++.dg/cpp1y/constexpr-86524.C: New test. * g++.dg/cpp2a/is-constant-evaluated4.C: New test. * g++.dg/cpp2a/is-constant-evaluated5.C: New test. * g++.dg/cpp2a/is-constant-evaluated6.C: New test. --- gcc/cp/cp-tree.h.jj 2018-12-20 18:29:24.069715207 +0100 +++ gcc/cp/cp-tree.h 2018-12-20 22:10:46.686521475 +0100 @@ -7668,7 +7668,9 @@ extern tree cxx_constant_value (tree, extern tree cxx_constant_init (tree, tree = NULL_TREE); extern tree maybe_constant_value (tree, tree = NULL_TREE, bool = false); extern tree maybe_constant_init (tree, tree = NULL_TREE, bool = false); -extern tree fold_non_dependent_expr (tree, tsubst_flags_t = tf_warning_or_error); +extern tree fold_non_dependent_expr (tree, + tsubst_flags_t = tf_warning_or_error, + bool = false); extern tree fold_simple (tree); extern bool is_sub_constant_expr (tree); extern bool reduced_constant_expression_p (tree); --- gcc/cp/constexpr.c.jj 2018-12-20 08:50:29.695444227 +0100 +++ gcc/cp/constexpr.c 2018-12-20 22:12:43.754615737 +0100 @@ -1197,7 +1197,7 @@ cxx_eval_builtin_function_call (const co /* If we aren't requiring a constant expression, defer __builtin_constant_p in a constexpr function until we have values for the parameters. */ if (bi_const_p - && ctx->quiet + && !ctx->manifestly_const_eval && current_function_decl && DECL_DECLARED_CONSTEXPR_P (current_function_decl)) { @@ -1222,7 +1222,6 @@ cxx_eval_builtin_function_call (const co return constant false for a non-constant argument. */ constexpr_ctx new_ctx = *ctx; new_ctx.quiet = true; - bool dummy1 = false, dummy2 = false; for (i = 0; i < nargs; ++i) { args[i] = CALL_EXPR_ARG (t, i); @@ -1231,10 +1230,16 @@ cxx_eval_builtin_function_call (const co of the builtin, verify it here. */ if (!builtin_valid_in_constant_expr_p (fun) || potential_constant_expression (args[i])) - args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false, - &dummy1, &dummy2); + { + bool non_cst_p = false, ovf_p = false; + tree a = cxx_eval_constant_expression (&new_ctx, args[i], false, + &non_cst_p, &ovf_p); + if ((!non_cst_p && !ovf_p) || !ctx->manifestly_const_eval) + args[i] = a; + } + if (bi_const_p) - /* For __built_in_constant_p, fold all expressions with constant values + /* For __builtin_constant_p, fold all expressions with constant values even if they aren't C++ constant-expressions. */ args[i] = cp_fully_fold (args[i]); } @@ -5340,6 +5345,7 @@ clear_cv_and_fold_caches (void) (t, complain) followed by maybe_constant_value but is more efficient, because it calls instantiation_dependent_expression_p and potential_constant_expression at most once. + The manifestly_const_eval argument is passed to maybe_constant_value. Callers should generally pass their active complain, or if they are in a non-template, diagnosing context, they can use the default of @@ -5350,7 +5356,8 @@ clear_cv_and_fold_caches (void) tree fold_non_dependent_expr (tree t, - tsubst_flags_t complain /* = tf_warning_or_error */) + tsubst_flags_t complain /* = tf_warning_or_error */, + bool manifestly_const_eval /* = false */) { if (t == NULL_TREE) return NULL_TREE; @@ -5380,7 +5387,8 @@ fold_non_dependent_expr (tree t, return t; } - tree r = cxx_eval_outermost_constant_expr (t, true, true, false, + tree r = cxx_eval_outermost_constant_expr (t, true, true, + manifestly_const_eval, NULL_TREE); /* cp_tree_equal looks through NOPs, so allow them. */ gcc_checking_assert (r == t @@ -5398,7 +5406,7 @@ fold_non_dependent_expr (tree t, return t; } - return maybe_constant_value (t); + return maybe_constant_value (t, NULL_TREE, manifestly_const_eval); } /* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather --- gcc/cp/semantics.c.jj 2018-12-20 08:50:29.712443949 +0100 +++ gcc/cp/semantics.c 2018-12-20 22:10:46.690521410 +0100 @@ -9225,7 +9225,8 @@ finish_static_assert (tree condition, tr /* Fold the expression and convert it to a boolean value. */ condition = perform_implicit_conversion_flags (boolean_type_node, condition, complain, LOOKUP_NORMAL); - condition = fold_non_dependent_expr (condition, complain); + condition = fold_non_dependent_expr (condition, complain, + /*manifestly_const_eval=*/true); if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition)) /* Do nothing; the condition is satisfied. */ --- gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C.jj 2018-12-20 22:10:46.690521410 +0100 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C 2018-12-20 22:10:46.690521410 +0100 @@ -0,0 +1,41 @@ +// PR c++/86524 +// { dg-do run { target c++14 } } +// { dg-options "-O2" } + +extern "C" void abort (); +typedef __UINTPTR_TYPE__ uintptr_t; + +constexpr bool +foo (const int *x, const int *y) +{ + if (__builtin_constant_p (x < y)) + return x < y; + return (uintptr_t) x < (uintptr_t) y; +} + +void +bar () +{ + constexpr int x = 0; + static_assert (!(&x < &x)); + static_assert (!foo (&x, &x)); +} + +constexpr void +baz () +{ + constexpr int x = 0; + static_assert (!(&x < &x)); + static_assert (!foo (&x, &x)); +} + +int i, j; + +int +main () +{ + bar (); + baz (); + if (!(foo (&i, &j) ^ foo (&j, &i))) + abort (); +} --- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C.jj 2018-12-20 22:10:46.691521394 +0100 +++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C 2018-12-20 22:10:46.691521394 +0100 @@ -0,0 +1,19 @@ +// P0595R2 +// { dg-do compile { target c++14 } } + +namespace std { + constexpr inline bool + is_constant_evaluated () noexcept + { + return __builtin_is_constant_evaluated (); + } +} + +constexpr int +foo () noexcept +{ + return std::is_constant_evaluated () ? 5 : 12; +} + +static_assert (std::is_constant_evaluated (), ""); +static_assert (foo () == 5, ""); --- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C.jj 2018-12-20 22:10:46.691521394 +0100 +++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C 2018-12-20 22:10:46.691521394 +0100 @@ -0,0 +1,41 @@ +// PR c++/86524 +// { dg-do run { target c++14 } } +// { dg-options "-O2" } + +extern "C" void abort (); +typedef __UINTPTR_TYPE__ uintptr_t; + +constexpr bool +foo (const int *x, const int *y) +{ + if (__builtin_is_constant_evaluated ()) + return x < y; + return (uintptr_t) x < (uintptr_t) y; +} + +void +bar () +{ + constexpr int x = 0; + static_assert (!(&x < &x)); + static_assert (!foo (&x, &x)); +} + +constexpr void +baz () +{ + constexpr int x = 0; + static_assert (!(&x < &x)); + static_assert (!foo (&x, &x)); +} + +int i, j; + +int +main () +{ + bar (); + baz (); + if (!(foo (&i, &j) ^ foo (&j, &i))) + abort (); +} --- gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C.jj 2018-12-20 22:10:46.691521394 +0100 +++ gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C 2018-12-20 22:10:46.691521394 +0100 @@ -0,0 +1,29 @@ +// P0595R2 +// { dg-do compile { target c++14 } } + +namespace std { + constexpr inline bool + is_constant_evaluated () noexcept + { + return __builtin_is_constant_evaluated (); + } +} + +int a; + +constexpr bool +foo (int x) +{ + return __builtin_constant_p (x); +} + +constexpr bool +bar (int x) +{ + return __builtin_constant_p (x + a); +} + +static_assert (__builtin_constant_p (0) + 2 * std::is_constant_evaluated () == 3, ""); +static_assert (__builtin_constant_p (a) + 2 * std::is_constant_evaluated () == 2, ""); +static_assert (foo (0) + 2 * std::is_constant_evaluated () == 3, ""); +static_assert (bar (0) + 2 * std::is_constant_evaluated () == 2, ""); Jakub