aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2022-10-07 20:34:53 -0400
committerJason Merrill <jason@redhat.com>2022-10-12 11:38:05 -0400
commit9bf74082bc93226e1ceb66430706e957e460c841 (patch)
tree43df246d62d87945fb10948b4cdab83734adfe55
parentbfcd9f84531fa99e9d00efd8bcfd3c8ac16fa360 (diff)
downloadgcc-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.cc38
-rw-r--r--gcc/cp/constexpr.cc20
-rw-r--r--gcc/cp/cp-gimplify.cc7
-rw-r--r--gcc/cp/cp-tree.h32
-rw-r--r--gcc/cp/name-lookup.cc2
-rw-r--r--gcc/cp/name-lookup.h5
-rw-r--r--gcc/cp/parser.cc24
-rw-r--r--gcc/cp/pt.cc3
-rw-r--r--gcc/cp/tree.cc52
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/consteval-defarg3.C23
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();
+}