From 4cd3e7df0b7dc202d10ed7935918f1194adfc514 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 21 Dec 2018 20:58:36 +0100 Subject: [PATCH] re PR c++/86524 (std::less with pointer arguments not usable in static_assert in constexpr function) PR c++/86524 PR c++/88446 * cp-tree.h (cp_fold_maybe_rvalue, cp_fold_rvalue): Declare. (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. Don't reuse dummy{1,2} vars between different arguments. Use cp_fold_rvalue instead of cp_fully_fold. 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. * cp-gimplify.c (cp_fold_maybe_rvalue, cp_fold_rvalue): No longer static. * 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. From-SVN: r267341 --- gcc/cp/ChangeLog | 18 ++++++++ gcc/cp/constexpr.c | 24 +++++++---- gcc/cp/cp-gimplify.c | 4 +- gcc/cp/cp-tree.h | 6 ++- gcc/cp/semantics.c | 3 +- gcc/testsuite/ChangeLog | 7 ++++ gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C | 41 +++++++++++++++++++ .../g++.dg/cpp2a/is-constant-evaluated4.C | 19 +++++++++ .../g++.dg/cpp2a/is-constant-evaluated5.C | 41 +++++++++++++++++++ .../g++.dg/cpp2a/is-constant-evaluated6.C | 29 +++++++++++++ 10 files changed, 179 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C create mode 100644 gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f4295f33d5e..2201a472d53 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2018-12-21 Jakub Jelinek + + PR c++/86524 + PR c++/88446 + * cp-tree.h (cp_fold_maybe_rvalue, cp_fold_rvalue): Declare. + (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. Don't reuse dummy{1,2} vars between different arguments. + Use cp_fold_rvalue instead of cp_fully_fold. 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. + * cp-gimplify.c (cp_fold_maybe_rvalue, cp_fold_rvalue): No longer + static. + * semantics.c (finish_static_assert): Call fold_non_dependent_expr + with true as manifestly_const_eval. + 2018-12-20 Marek Polacek PR c++/88196 - ICE with class non-type template parameter. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 15a30fdcdd0..cea414d33de 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1197,7 +1197,7 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, /* 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 constexpr_ctx *ctx, tree t, tree fun, 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,12 +1230,16 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun, 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 dummy1 = false, dummy2 = false; + args[i] = cxx_eval_constant_expression (&new_ctx, args[i], false, + &dummy1, &dummy2); + } + 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]); + args[i] = cp_fold_rvalue (args[i]); } bool save_ffbcp = force_folding_builtin_constant_p; @@ -5340,6 +5343,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 +5354,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 +5385,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 +5404,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 diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 9d848eaaef0..76bd8f6dcb7 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -2118,7 +2118,7 @@ cxx_omp_disregard_value_expr (tree decl, bool shared) /* Fold expression X which is used as an rvalue if RVAL is true. */ -static tree +tree cp_fold_maybe_rvalue (tree x, bool rval) { while (true) @@ -2141,7 +2141,7 @@ cp_fold_maybe_rvalue (tree x, bool rval) /* Fold expression X which is used as an rvalue. */ -static tree +tree cp_fold_rvalue (tree x) { return cp_fold_maybe_rvalue (x, true); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f6b7c6e516b..604e615721f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7543,6 +7543,8 @@ extern void cxx_omp_finish_clause (tree, gimple_seq *); extern bool cxx_omp_privatize_by_reference (const_tree); extern bool cxx_omp_disregard_value_expr (tree, bool); extern void cp_fold_function (tree); +extern tree cp_fold_maybe_rvalue (tree, bool); +extern tree cp_fold_rvalue (tree); extern tree cp_fully_fold (tree); extern tree cp_fully_fold_init (tree); extern void clear_fold_cache (void); @@ -7668,7 +7670,9 @@ extern tree cxx_constant_value (tree, tree = NULL_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); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 0865076493d..e201c3db9a2 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -9225,7 +9225,8 @@ finish_static_assert (tree condition, tree message, location_t location, /* 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. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e5928ecec61..eaabddfff23 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,12 @@ 2018-12-21 Jakub Jelinek + PR c++/86524 + PR c++/88446 + * 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. + PR middle-end/85594 PR middle-end/88553 * gcc.dg/gomp/pr85594.c: New test. diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C new file mode 100644 index 00000000000..59e6b8059d1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-86524.C @@ -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 (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C new file mode 100644 index 00000000000..809e3d2e687 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated4.C @@ -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, ""); diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C new file mode 100644 index 00000000000..22b762db4f3 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated5.C @@ -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 (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C new file mode 100644 index 00000000000..842e4467115 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/is-constant-evaluated6.C @@ -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, ""); -- 2.30.2