}
/* 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 ()
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);
}
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.
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))
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
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. */
*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. */
}
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;
}
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. */
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)
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);
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:
'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. */
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
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);
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
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 ();
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;
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;
/*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;
}
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)
{
--- /dev/null
+// 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();
+}