From 117c64266405e244da4dae3ae7b60905af63b955 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 11 Jun 2021 15:50:34 +0200 Subject: 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 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) : 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. --- gcc/cp/decl.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'gcc/cp/decl.c') diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index cbf647d..da254d8 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -222,6 +222,7 @@ struct GTY((for_user)) named_label_entry { bool in_omp_scope; bool in_transaction_scope; bool in_constexpr_if; + bool in_consteval_if; }; #define named_labels cp_function_chain->x_named_labels @@ -491,6 +492,16 @@ level_for_constexpr_if (cp_binding_level *b) && IF_STMT_CONSTEXPR_P (b->this_entity)); } +/* True if B is the level for the condition of a consteval if. */ + +static bool +level_for_consteval_if (cp_binding_level *b) +{ + return (b->kind == sk_cond && b->this_entity + && TREE_CODE (b->this_entity) == IF_STMT + && IF_STMT_CONSTEVAL_P (b->this_entity)); +} + /* Update data for defined and undefined labels when leaving a scope. */ int @@ -530,6 +541,8 @@ poplevel_named_label_1 (named_label_entry **slot, cp_binding_level *bl) case sk_block: if (level_for_constexpr_if (bl->level_chain)) ent->in_constexpr_if = true; + else if (level_for_consteval_if (bl->level_chain)) + ent->in_consteval_if = true; break; default: break; @@ -3391,6 +3404,7 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, bool complained = false; int identified = 0; bool saw_eh = false, saw_omp = false, saw_tm = false, saw_cxif = false; + bool saw_ceif = false; if (exited_omp) { @@ -3470,6 +3484,12 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names, loc = EXPR_LOCATION (b->level_chain->this_entity); saw_cxif = true; } + else if (!saw_ceif && level_for_consteval_if (b->level_chain)) + { + inf = G_(" enters % statement"); + loc = EXPR_LOCATION (b->level_chain->this_entity); + saw_ceif = true; + } break; default: @@ -3551,12 +3571,13 @@ check_goto (tree decl) unsigned ix; if (ent->in_try_scope || ent->in_catch_scope || ent->in_transaction_scope - || ent->in_constexpr_if + || ent->in_constexpr_if || ent->in_consteval_if || ent->in_omp_scope || !vec_safe_is_empty (ent->bad_decls)) { diagnostic_t diag_kind = DK_PERMERROR; if (ent->in_try_scope || ent->in_catch_scope || ent->in_constexpr_if - || ent->in_transaction_scope || ent->in_omp_scope) + || ent->in_consteval_if || ent->in_transaction_scope + || ent->in_omp_scope) diag_kind = DK_ERROR; complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl), &input_location, diag_kind); @@ -3602,6 +3623,8 @@ check_goto (tree decl) inform (input_location, " enters synchronized or atomic statement"); else if (ent->in_constexpr_if) inform (input_location, " enters % statement"); + else if (ent->in_consteval_if) + inform (input_location, " enters % statement"); } if (ent->in_omp_scope) -- cgit v1.1