aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/constexpr.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2021-06-11 15:50:34 +0200
committerJakub Jelinek <jakub@redhat.com>2021-06-11 15:52:23 +0200
commit117c64266405e244da4dae3ae7b60905af63b955 (patch)
tree54db8563f16d0bb55f7d4b90929984386071d3ef /gcc/cp/constexpr.c
parent9d20ec97475b1102d6ca005ad165056d34615a3d (diff)
downloadgcc-117c64266405e244da4dae3ae7b60905af63b955.zip
gcc-117c64266405e244da4dae3ae7b60905af63b955.tar.gz
gcc-117c64266405e244da4dae3ae7b60905af63b955.tar.bz2
c++: Add C++23 consteval if support - P1938R3 [PR100974]
The following patch implements consteval if support. There is a new IF_STMT_CONSTEVAL_P flag on IF_STMT and IF_COND is boolean_false_node to match the non-manifestly constant evaluation behavior, while constexpr evaluation special-cases it. Perhaps cleaner would be to set the condition to __builtin_is_constant_evaluated () call but we need the IF_STMT_CONSTEVAL_P flag anyway and the IL would be larger. And I'm not changing the libstdc++ side, where perhaps we could change std::is_constant_evaluated definition for #ifdef __cpp_if_consteval case to if consteval { return true; } else { return false; } but we need to keep it defined to __builtin_is_constant_evaluated () for C++20 or older. 2021-06-11 Jakub Jelinek <jakub@redhat.com> PR c++/100974 gcc/c-family/ * c-cppbuiltin.c (c_cpp_builtins): Predefine __cpp_if_consteval for -std=c++2b for P1938R3 consteval if support. gcc/cp/ * cp-tree.h (struct saved_scope): Add consteval_if_p member. Formatting fix for the discarded_stmt comment. (in_consteval_if_p, IF_STMT_CONSTEVAL_P): Define. * parser.c (cp_parser_lambda_expression): Temporarily disable in_consteval_if_p when parsing lambda body. (cp_parser_selection_statement): Parse consteval if. * decl.c (struct named_label_entry): Add in_consteval_if member. (level_for_consteval_if): New function. (poplevel_named_label_1, check_previous_goto_1, check_goto): Handle consteval if. * constexpr.c (cxx_eval_builtin_function_call): Clarify in comment why CP_BUILT_IN_IS_CONSTANT_EVALUATED needs to *non_constant_p for !ctx->manifestly_const_eval. (cxx_eval_conditional_expression): For IF_STMT_CONSTEVAL_P evaluate condition as if it was __builtin_is_constant_evaluated call. (potential_constant_expression_1): For IF_STMT_CONSTEVAL_P always recurse on both branches. * cp-gimplify.c (genericize_if_stmt): Genericize IF_STMT_CONSTEVAL_P as the else branch. * pt.c (tsubst_expr) <case IF_STMT>: Copy IF_STMT_CONSTEVAL_P. Temporarily set in_consteval_if_p when recursing on IF_STMT_CONSTEVAL_P then branch. (tsubst_lambda_expr): Temporarily disable in_consteval_if_p when instantiating lambda body. * call.c (immediate_invocation_p): Return false when in_consteval_if_p. gcc/testsuite/ * g++.dg/cpp23/consteval-if1.C: New test. * g++.dg/cpp23/consteval-if2.C: New test. * g++.dg/cpp23/consteval-if3.C: New test. * g++.dg/cpp23/consteval-if4.C: New test. * g++.dg/cpp23/consteval-if5.C: New test. * g++.dg/cpp23/consteval-if6.C: New test. * g++.dg/cpp23/consteval-if7.C: New test. * g++.dg/cpp23/consteval-if8.C: New test. * g++.dg/cpp23/consteval-if9.C: New test. * g++.dg/cpp23/consteval-if10.C: New test. * g++.dg/cpp23/feat-cxx2b.C: Add __cpp_if_consteval tests.
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r--gcc/cp/constexpr.c36
1 files changed, 31 insertions, 5 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 01b0c42..4f1c3d6 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1315,7 +1315,10 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
}
/* For __builtin_is_constant_evaluated, defer it if not
- ctx->manifestly_const_eval, otherwise fold it to true. */
+ ctx->manifestly_const_eval (as sometimes we try to constant evaluate
+ without manifestly_const_eval even expressions or parts thereof which
+ will later be manifestly const_eval evaluated), otherwise fold it to
+ true. */
if (fndecl_built_in_p (fun, CP_BUILT_IN_IS_CONSTANT_EVALUATED,
BUILT_IN_FRONTEND))
{
@@ -3298,6 +3301,22 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
/*lval*/false,
non_constant_p, overflow_p);
VERIFY_CONSTANT (val);
+ if (TREE_CODE (t) == IF_STMT && IF_STMT_CONSTEVAL_P (t))
+ {
+ /* Evaluate the condition as if it was
+ if (__builtin_is_constant_evaluated ()), i.e. defer it if not
+ ctx->manifestly_const_eval (as sometimes we try to constant evaluate
+ without manifestly_const_eval even expressions or parts thereof which
+ will later be manifestly const_eval evaluated), otherwise fold it to
+ true. */
+ if (ctx->manifestly_const_eval)
+ val = boolean_true_node;
+ else
+ {
+ *non_constant_p = true;
+ return t;
+ }
+ }
/* Don't VERIFY_CONSTANT the other operands. */
if (integer_zerop (val))
val = TREE_OPERAND (t, 2);
@@ -8809,10 +8828,17 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
return false;
if (!processing_template_decl)
tmp = cxx_eval_outermost_constant_expr (tmp, true);
- if (integer_zerop (tmp))
- return RECUR (TREE_OPERAND (t, 2), want_rval);
- else if (TREE_CODE (tmp) == INTEGER_CST)
- return RECUR (TREE_OPERAND (t, 1), want_rval);
+ /* potential_constant_expression* isn't told if it is called for
+ manifestly_const_eval or not, so for consteval if always
+ process both branches as if the condition is not a known
+ constant. */
+ if (TREE_CODE (t) != IF_STMT || !IF_STMT_CONSTEVAL_P (t))
+ {
+ if (integer_zerop (tmp))
+ return RECUR (TREE_OPERAND (t, 2), want_rval);
+ else if (TREE_CODE (tmp) == INTEGER_CST)
+ return RECUR (TREE_OPERAND (t, 1), want_rval);
+ }
tmp = *jump_target;
for (i = 1; i < 3; ++i)
{