diff options
author | Jason Merrill <jason@redhat.com> | 2022-10-07 20:34:53 -0400 |
---|---|---|
committer | Jason Merrill <jason@redhat.com> | 2022-10-12 11:38:05 -0400 |
commit | 9bf74082bc93226e1ceb66430706e957e460c841 (patch) | |
tree | 43df246d62d87945fb10948b4cdab83734adfe55 | |
parent | bfcd9f84531fa99e9d00efd8bcfd3c8ac16fa360 (diff) | |
download | gcc-9bf74082bc93226e1ceb66430706e957e460c841.zip gcc-9bf74082bc93226e1ceb66430706e957e460c841.tar.gz gcc-9bf74082bc93226e1ceb66430706e957e460c841.tar.bz2 |
c++: defer all consteval in default args [DR2631]
The proposed resolution of CWG2631 extends our current handling of
source_location::current to all consteval functions: default arguments
are not evaluated until they're used in a call, the same should apply to
evaluation of immediate invocations. And similarly for default member
initializers.
Previously we folded source_location::current in cp_fold_r; now we fold all
consteval calls in default arguments/member initializers in bot_replace.
DR 2631
gcc/cp/ChangeLog:
* cp-tree.h (source_location_current_p): Remove.
* name-lookup.h (struct cp_binding_level): Remove
immediate_fn_ctx_p.
* call.cc (in_immediate_context): All default args
and DMI are potentially immediate context.
(immediate_invocation_p): Don't treat source_location specially.
(struct in_consteval_if_p_temp_override): Move to cp-tree.h.
* constexpr.cc (get_nth_callarg): Move to cp-tree.h.
* cp-gimplify.cc (cp_fold_r): Don't fold consteval.
* name-lookup.cc (begin_scope): Don't set immediate_fn_ctx_p.
* parser.cc (cp_parser_lambda_declarator_opt): Likewise.
(cp_parser_direct_declarator): Likewise.
* pt.cc (tsubst_default_argument): Open sk_function_parms level.
* tree.cc (source_location_current_p): Remove.
(bot_replace): Fold consteval here.
(break_out_target_exprs): Handle errors.
gcc/testsuite/ChangeLog:
* g++.dg/cpp2a/consteval-defarg3.C: New test.
-rw-r--r-- | gcc/cp/call.cc | 38 | ||||
-rw-r--r-- | gcc/cp/constexpr.cc | 20 | ||||
-rw-r--r-- | gcc/cp/cp-gimplify.cc | 7 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 32 | ||||
-rw-r--r-- | gcc/cp/name-lookup.cc | 2 | ||||
-rw-r--r-- | gcc/cp/name-lookup.h | 5 | ||||
-rw-r--r-- | gcc/cp/parser.cc | 24 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 3 | ||||
-rw-r--r-- | gcc/cp/tree.cc | 52 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/consteval-defarg3.C | 23 |
10 files changed, 95 insertions, 111 deletions
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 70ec964..2fa33c5 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -9301,7 +9301,8 @@ build_trivial_dtor_call (tree instance, bool no_ptr_deref) } /* Return true if in an immediate function context, or an unevaluated operand, - or a subexpression of an immediate invocation. */ + or a default argument/member initializer, or a subexpression of an immediate + invocation. */ bool in_immediate_context () @@ -9309,8 +9310,11 @@ in_immediate_context () return (cp_unevaluated_operand != 0 || (current_function_decl != NULL_TREE && DECL_IMMEDIATE_FUNCTION_P (current_function_decl)) - || (current_binding_level->kind == sk_function_parms - && current_binding_level->immediate_fn_ctx_p) + /* DR 2631: default args and DMI aren't immediately evaluated. + Return true here so immediate_invocation_p returns false. */ + || current_binding_level->kind == sk_function_parms + || current_binding_level->kind == sk_template_parms + || parsing_nsdmi () || in_consteval_if_p); } @@ -9318,28 +9322,12 @@ in_immediate_context () is an immediate invocation. */ static bool -immediate_invocation_p (tree fn, int nargs) +immediate_invocation_p (tree fn) { return (TREE_CODE (fn) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (fn) - && !in_immediate_context () - /* As an exception, we defer std::source_location::current () - invocations until genericization because LWG3396 mandates - special behavior for it. */ - && (nargs > 1 || !source_location_current_p (fn))); -} - -/* temp_override for in_consteval_if_p, which can't use make_temp_override - because it is a bitfield. */ - -struct in_consteval_if_p_temp_override { - bool save_in_consteval_if_p; - in_consteval_if_p_temp_override () - : save_in_consteval_if_p (in_consteval_if_p) {} - void reset () { in_consteval_if_p = save_in_consteval_if_p; } - ~in_consteval_if_p_temp_override () - { reset (); } -}; + && !in_immediate_context ()); +} /* Subroutine of the various build_*_call functions. Overload resolution has chosen a winning candidate CAND; build up a CALL_EXPR accordingly. @@ -9398,7 +9386,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) SET_EXPR_LOCATION (expr, input_location); if (TREE_THIS_VOLATILE (fn) && cfun) current_function_returns_abnormally = 1; - if (immediate_invocation_p (fn, vec_safe_length (args))) + if (immediate_invocation_p (fn)) { tree obj_arg = NULL_TREE, exprimm = expr; if (DECL_CONSTRUCTOR_P (fn)) @@ -9543,7 +9531,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) in_consteval_if_p_temp_override icip; /* If the call is immediate function invocation, make sure taking address of immediate functions is allowed in its arguments. */ - if (immediate_invocation_p (STRIP_TEMPLATE (fn), nargs)) + if (immediate_invocation_p (STRIP_TEMPLATE (fn))) in_consteval_if_p = true; /* The implicit parameters to a constructor are not considered by overload @@ -10072,7 +10060,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) if (TREE_CODE (fn) == ADDR_EXPR) { tree fndecl = STRIP_TEMPLATE (TREE_OPERAND (fn, 0)); - if (immediate_invocation_p (fndecl, nargs)) + if (immediate_invocation_p (fndecl)) { tree obj_arg = NULL_TREE; /* Undo convert_from_reference called by build_cxx_call. */ diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 06dcd71..2038f43 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -1324,26 +1324,6 @@ save_fundef_copy (tree fun, tree copy) *slot = copy; } -/* We have an expression tree T that represents a call, either CALL_EXPR - or AGGR_INIT_EXPR. Return the Nth argument. */ - -static inline tree -get_nth_callarg (tree t, int n) -{ - switch (TREE_CODE (t)) - { - case CALL_EXPR: - return CALL_EXPR_ARG (t, n); - - case AGGR_INIT_EXPR: - return AGGR_INIT_EXPR_ARG (t, n); - - default: - gcc_unreachable (); - return NULL; - } -} - /* Whether our evaluation wants a prvalue (e.g. CONSTRUCTOR or _CST), a glvalue (e.g. VAR_DECL or _REF), or nothing. */ diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index d0e12c9..a937060 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -1010,13 +1010,6 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_) } break; - case CALL_EXPR: - if (tree fndecl = cp_get_callee_fndecl_nofold (stmt)) - if (DECL_IMMEDIATE_FUNCTION_P (fndecl) - && source_location_current_p (fndecl)) - *stmt_p = stmt = cxx_constant_value (stmt); - break; - default: break; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ab6f85a..80037fa 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -2030,6 +2030,18 @@ make_temp_override (T& var, type_identity_t<T> overrider) return { var, overrider }; } +/* temp_override for in_consteval_if_p, which can't use make_temp_override + because it is a bitfield. */ + +struct in_consteval_if_p_temp_override { + bool save_in_consteval_if_p; + in_consteval_if_p_temp_override () + : save_in_consteval_if_p (in_consteval_if_p) {} + void reset () { in_consteval_if_p = save_in_consteval_if_p; } + ~in_consteval_if_p_temp_override () + { reset (); } +}; + /* The cached class binding level, from the most recently exited class, or NULL if none. */ @@ -4201,6 +4213,25 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) for ((arg) = first_aggr_init_expr_arg ((call), &(iter)); (arg); \ (arg) = next_aggr_init_expr_arg (&(iter))) +/* We have an expression tree T that represents a call, either CALL_EXPR + or AGGR_INIT_EXPR. Return a reference to the Nth argument. */ + +static inline tree& +get_nth_callarg (tree t, int n) +{ + switch (TREE_CODE (t)) + { + case CALL_EXPR: + return CALL_EXPR_ARG (t, n); + + case AGGR_INIT_EXPR: + return AGGR_INIT_EXPR_ARG (t, n); + + default: + gcc_unreachable (); + } +} + /* VEC_INIT_EXPR accessors. */ #define VEC_INIT_EXPR_SLOT(NODE) TREE_OPERAND (VEC_INIT_EXPR_CHECK (NODE), 0) #define VEC_INIT_EXPR_INIT(NODE) TREE_OPERAND (VEC_INIT_EXPR_CHECK (NODE), 1) @@ -7880,7 +7911,6 @@ extern tree bind_template_template_parm (tree, tree); extern tree array_type_nelts_total (tree); extern tree array_type_nelts_top (tree); extern bool array_of_unknown_bound_p (const_tree); -extern bool source_location_current_p (tree); extern tree break_out_target_exprs (tree, bool = false); extern tree build_ctor_subob_ref (tree, tree, tree); extern tree replace_placeholders (tree, tree, bool * = NULL); diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index 25657cf..14e937d 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -4302,8 +4302,6 @@ begin_scope (scope_kind kind, tree entity) case sk_function_parms: scope->keep = keep_next_level_flag; - if (entity) - scope->immediate_fn_ctx_p = DECL_IMMEDIATE_FUNCTION_P (entity); break; case sk_namespace: diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h index 7201ae8..9e3b698 100644 --- a/gcc/cp/name-lookup.h +++ b/gcc/cp/name-lookup.h @@ -307,13 +307,10 @@ struct GTY(()) cp_binding_level { 'this_entity'. */ unsigned defining_class_p : 1; - /* true for SK_FUNCTION_PARMS of immediate functions. */ - unsigned immediate_fn_ctx_p : 1; - /* True for SK_FUNCTION_PARMS of a requires-expression. */ unsigned requires_expression: 1; - /* 21 bits left to fill a 32-bit word. */ + /* 22 bits left to fill a 32-bit word. */ }; /* The binding level currently in effect. */ diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index dc3d17c..4e3ed66 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -11519,31 +11519,11 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) opening parenthesis if present. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { - bool is_consteval = false; - /* For C++20, before parsing the parameter list check if there is - a consteval specifier in the corresponding decl-specifier-seq. */ - if (cxx_dialect >= cxx20) - { - for (size_t n = cp_parser_skip_balanced_tokens (parser, 1); - cp_lexer_nth_token_is (parser->lexer, n, CPP_KEYWORD); n++) - { - if (cp_lexer_peek_nth_token (parser->lexer, n)->keyword - == RID_CONSTEVAL) - { - is_consteval = true; - break; - } - } - } - matching_parens parens; parens.consume_open (parser); begin_scope (sk_function_parms, /*entity=*/NULL_TREE); - if (is_consteval) - current_binding_level->immediate_fn_ctx_p = true; - /* Parse parameters. */ param_list = cp_parser_parameter_declaration_clause @@ -23186,10 +23166,6 @@ cp_parser_direct_declarator (cp_parser* parser, begin_scope (sk_function_parms, NULL_TREE); - /* Signal we are in the immediate function context. */ - if (flags & CP_PARSER_FLAGS_CONSTEVAL) - current_binding_level->immediate_fn_ctx_p = true; - /* Parse the parameter-declaration-clause. */ params = cp_parser_parameter_declaration_clause (parser, flags); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index b80e7ff..ec337e2 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -13933,6 +13933,8 @@ tsubst_default_argument (tree fn, int parmnum, tree type, tree arg, push_to_top_level (); push_access_scope (fn); push_deferring_access_checks (dk_no_deferred); + /* So in_immediate_context knows this is a default argument. */ + begin_scope (sk_function_parms, fn); start_lambda_scope (parm); /* The default argument expression may cause implicitly defined @@ -13956,6 +13958,7 @@ tsubst_default_argument (tree fn, int parmnum, tree type, tree arg, inform (input_location, " when instantiating default argument for call to %qD", fn); + leave_scope (); pop_deferring_access_checks (); pop_access_scope (fn); pop_from_top_level (); diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc index 3532e44..45348c5 100644 --- a/gcc/cp/tree.cc +++ b/gcc/cp/tree.cc @@ -3125,32 +3125,6 @@ array_type_nelts_total (tree type) return sz; } -/* Return true if FNDECL is std::source_location::current () method. */ - -bool -source_location_current_p (tree fndecl) -{ - gcc_checking_assert (TREE_CODE (fndecl) == FUNCTION_DECL - && DECL_IMMEDIATE_FUNCTION_P (fndecl)); - if (DECL_NAME (fndecl) == NULL_TREE - || TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE - || TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != RECORD_TYPE - || DECL_CONTEXT (fndecl) != TREE_TYPE (TREE_TYPE (fndecl)) - || !id_equal (DECL_NAME (fndecl), "current")) - return false; - - tree source_location = DECL_CONTEXT (fndecl); - if (TYPE_NAME (source_location) == NULL_TREE - || TREE_CODE (TYPE_NAME (source_location)) != TYPE_DECL - || TYPE_IDENTIFIER (source_location) == NULL_TREE - || !id_equal (TYPE_IDENTIFIER (source_location), - "source_location") - || !decl_in_std_namespace_p (TYPE_NAME (source_location))) - return false; - - return true; -} - struct bot_data { splay_tree target_remap; @@ -3298,7 +3272,7 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_) variables. */ static tree -bot_replace (tree* t, int* /*walk_subtrees*/, void* data_) +bot_replace (tree* t, int* walk_subtrees, void* data_) { bot_data &data = *(bot_data*)data_; splay_tree target_remap = data.target_remap; @@ -3328,6 +3302,27 @@ bot_replace (tree* t, int* /*walk_subtrees*/, void* data_) /*check_access=*/false, /*nonnull=*/true, tf_warning_or_error); } + else if (cxx_dialect >= cxx20 + && (TREE_CODE (*t) == CALL_EXPR + || TREE_CODE (*t) == AGGR_INIT_EXPR) + && !in_immediate_context ()) + { + /* Expand immediate invocations. */ + if (tree fndecl = cp_get_callee_fndecl_nofold (*t)) + if (DECL_IMMEDIATE_FUNCTION_P (fndecl)) + { + /* Make in_immediate_context true within the args. */ + in_consteval_if_p_temp_override ito; + in_consteval_if_p = true; + int nargs = call_expr_nargs (*t); + for (int i = 0; i < nargs; ++i) + cp_walk_tree (&get_nth_callarg (*t, i), bot_replace, data_, NULL); + *t = cxx_constant_value (*t); + if (*t == error_mark_node) + return error_mark_node; + *walk_subtrees = 0; + } + } return NULL_TREE; } @@ -3353,7 +3348,8 @@ break_out_target_exprs (tree t, bool clear_location /* = false */) bot_data data = { target_remap, clear_location }; if (cp_walk_tree (&t, bot_manip, &data, NULL) == error_mark_node) t = error_mark_node; - cp_walk_tree (&t, bot_replace, &data, NULL); + if (cp_walk_tree (&t, bot_replace, &data, NULL) == error_mark_node) + t = error_mark_node; if (!--target_remap_count) { diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-defarg3.C b/gcc/testsuite/g++.dg/cpp2a/consteval-defarg3.C new file mode 100644 index 0000000..316219c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/consteval-defarg3.C @@ -0,0 +1,23 @@ +// DR 2631: default args and DMI aren't immediately evaluated +// { dg-do compile { target c++20 } } +// { dg-final { scan-assembler-not "foober" } } + +consteval int foober(); + +int g(int = foober()); +struct A { int i = foober(); }; +template <int i = foober()> struct B { }; +struct C +{ + consteval C(int = foober()) { } +}; +int h(C = C()); + +consteval int foober() { return 42; } + +int main() { + A a; + B<> b; + g(); + h(); +} |