diff options
author | Jakub Jelinek <jakub@redhat.com> | 2021-06-11 15:50:34 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2021-06-11 15:52:23 +0200 |
commit | 117c64266405e244da4dae3ae7b60905af63b955 (patch) | |
tree | 54db8563f16d0bb55f7d4b90929984386071d3ef /gcc/cp/constexpr.c | |
parent | 9d20ec97475b1102d6ca005ad165056d34615a3d (diff) | |
download | gcc-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.c | 36 |
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) { |