aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/lambda.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/lambda.cc')
-rw-r--r--gcc/cp/lambda.cc186
1 files changed, 125 insertions, 61 deletions
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index b2e0ecd..c2655a9 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -150,7 +150,7 @@ begin_lambda_type (tree lambda)
/* Cross-reference the expression and the type. */
LAMBDA_EXPR_CLOSURE (lambda) = type;
- CLASSTYPE_LAMBDA_EXPR (type) = lambda;
+ SET_CLASSTYPE_LAMBDA_EXPR (type, lambda);
/* In C++17, assume the closure is literal; we'll clear the flag later if
necessary. */
@@ -218,22 +218,25 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
tree type;
bool is_this = is_this_parameter (tree_strip_nop_conversions (expr));
- if (is_this)
- type = TREE_TYPE (expr);
- else if (explicit_init_p)
+ if (explicit_init_p)
{
- tree auto_node = make_auto ();
-
- type = auto_node;
- if (by_reference_p)
- /* Add the reference now, so deduction doesn't lose
- outermost CV qualifiers of EXPR. */
- type = build_reference_type (type);
if (uses_parameter_packs (expr))
- /* Stick with 'auto' even if the type could be deduced. */
- TEMPLATE_TYPE_PARAMETER_PACK (auto_node) = true;
+ {
+ /* Stick with 'auto...' even if the type could be deduced. */
+ type = make_auto_pack ();
+ if (by_reference_p)
+ type = build_reference_type (type);
+ }
else
- type = do_auto_deduction (type, expr, auto_node);
+ {
+ tree auto_node = make_auto ();
+ type = auto_node;
+ if (by_reference_p)
+ /* Add the reference now, so deduction doesn't lose
+ outermost CV qualifiers of EXPR. */
+ type = build_reference_type (type);
+ type = do_auto_deduction (type, expr, auto_node);
+ }
}
else if (!type_deducible_expression_p (expr))
{
@@ -259,7 +262,7 @@ lambda_capture_field_type (tree expr, bool explicit_init_p,
type = non_reference (unlowered_expr_type (expr));
- if (by_reference_p || TREE_CODE (type) == FUNCTION_TYPE)
+ if ((by_reference_p && !is_this) || TREE_CODE (type) == FUNCTION_TYPE)
type = build_reference_type (type);
}
@@ -348,7 +351,11 @@ insert_capture_proxy (tree var)
/* And put a DECL_EXPR in the STATEMENT_LIST for the same block. */
var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var);
- tree stmt_list = (*stmt_list_stack)[1];
+ /* The first stmt_list is from start_preparsed_function. Then there's a
+ possible stmt_list from begin_eh_spec_block, then the one from the
+ lambda's outer {}. */
+ unsigned index = 1 + use_eh_spec_block (current_function_decl);
+ tree stmt_list = (*stmt_list_stack)[index];
gcc_assert (stmt_list);
append_to_statement_list_force (var, &stmt_list);
}
@@ -407,10 +414,11 @@ lambda_proxy_type (tree ref)
/* MEMBER is a capture field in a lambda closure class. Now that we're
inside the operator(), build a placeholder var for future lookups and
- debugging. */
+ debugging. But if EARLY_P is true, we do not have the real operator()
+ yet and we have to proceed differently. */
-static tree
-build_capture_proxy (tree member, tree init)
+tree
+build_capture_proxy (tree member, tree init, bool early_p)
{
tree var, object, fn, closure, name, lam, type;
@@ -436,13 +444,21 @@ build_capture_proxy (tree member, tree init)
else
name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2);
- type = lambda_proxy_type (object);
-
- if (name == this_identifier && !INDIRECT_TYPE_P (type))
+ if (name == this_identifier && TYPE_PTR_P (TREE_TYPE (member)))
+ /* Avoid DECLTYPE_TYPE for by-ref 'this' capture in an xobj lambda; the
+ constness of the closure doesn't matter just like it doesn't matter to
+ other by-ref capture. It's simpler to handle this special case here
+ than in lambda_proxy_type. */
+ type = TREE_TYPE (member);
+ else
{
- type = build_pointer_type (type);
- type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
- object = build_fold_addr_expr_with_type (object, type);
+ type = lambda_proxy_type (object);
+ if (name == this_identifier)
+ {
+ type = build_pointer_type (type);
+ type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
+ object = build_fold_addr_expr_with_type (object, type);
+ }
}
if (DECL_VLA_CAPTURE_P (member))
@@ -493,11 +509,19 @@ build_capture_proxy (tree member, tree init)
if (name == this_identifier)
{
+ if (early_p)
+ return var;
gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (lam) == member);
LAMBDA_EXPR_THIS_CAPTURE (lam) = var;
}
- if (fn == current_function_decl)
+ if (early_p)
+ {
+ gcc_checking_assert (current_binding_level->kind == sk_lambda);
+ /* insert_capture_proxy below wouldn't push into the lambda scope. */
+ pushdecl (var);
+ }
+ else if (fn == current_function_decl)
insert_capture_proxy (var);
else
vec_safe_push (LAMBDA_EXPR_PENDING_PROXIES (lam), var);
@@ -717,7 +741,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
= tree_cons (listmem, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
if (LAMBDA_EXPR_CLOSURE (lambda))
- return build_capture_proxy (member, initializer);
+ return build_capture_proxy (member, initializer, /*early_p=*/false);
/* For explicit captures we haven't started the function yet, so we wait
and build the proxy from cp_parser_lambda_body. */
LAMBDA_CAPTURE_EXPLICIT_P (LAMBDA_EXPR_CAPTURE_LIST (lambda)) = true;
@@ -813,6 +837,14 @@ lambda_expr_this_capture (tree lambda, int add_capture_p)
if (cp_unevaluated_operand)
add_capture_p = false;
+ /* If we captured 'this' but don't have a capture proxy yet, look up the
+ captured 'this' again. */
+ if (this_capture && TREE_CODE (this_capture) == FIELD_DECL)
+ {
+ gcc_assert (!add_capture_p);
+ this_capture = NULL_TREE;
+ }
+
/* Try to default capture 'this' if we can. */
if (!this_capture)
{
@@ -917,8 +949,9 @@ lambda_expr_this_capture (tree lambda, int add_capture_p)
else
{
/* To make sure that current_class_ref is for the lambda. */
- gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref))
- == LAMBDA_EXPR_CLOSURE (lambda));
+ gcc_assert (!current_class_ref
+ || (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref))
+ == LAMBDA_EXPR_CLOSURE (lambda)));
result = this_capture;
@@ -929,6 +962,9 @@ lambda_expr_this_capture (tree lambda, int add_capture_p)
result = rvalue (result);
}
+ gcc_checking_assert (!result || result == error_mark_node
+ || TYPE_PTR_P (TREE_TYPE (result)));
+
return result;
}
@@ -958,10 +994,14 @@ resolvable_dummy_lambda (tree object)
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (object));
gcc_assert (!TYPE_PTR_P (type));
+ tree fn;
if (type != current_class_type
&& current_class_type
&& LAMBDA_TYPE_P (current_class_type)
- && lambda_function (current_class_type)
+ && (fn = lambda_function (current_class_type))
+ /* Even dummy lambdas have an operator() since P2036, but the
+ dummy operator() doesn't have this set. */
+ && DECL_LAMBDA_FUNCTION_P (fn)
&& DERIVED_FROM_P (type, nonlambda_method_basetype()))
return CLASSTYPE_LAMBDA_EXPR (current_class_type);
@@ -1016,13 +1056,19 @@ maybe_generic_this_capture (tree object, tree fns)
}
}
-/* Returns the innermost non-lambda function. */
+/* Returns the innermost non-lambda function. If ONLY_SKIP_CONSTEVAL_BLOCK_P,
+ we only skip lambda functions that represent consteval blocks. */
tree
-current_nonlambda_function (void)
+current_nonlambda_function (bool only_skip_consteval_block_p/*=false*/)
{
tree fn = current_function_decl;
- while (fn && LAMBDA_FUNCTION_P (fn))
+ tree lam;
+ while (fn && LAMBDA_FUNCTION_P (fn)
+ && (!only_skip_consteval_block_p
+ /* Only keep going if FN represents a consteval block. */
+ || ((lam = CLASSTYPE_LAMBDA_EXPR (CP_DECL_CONTEXT (fn)))
+ && LAMBDA_EXPR_CONSTEVAL_BLOCK_P (lam))))
fn = decl_function_context (fn);
return fn;
}
@@ -1033,12 +1079,9 @@ current_nonlambda_function (void)
tree
nonlambda_method_basetype (void)
{
- if (!current_class_ref)
- return NULL_TREE;
-
tree type = current_class_type;
if (!type || !LAMBDA_TYPE_P (type))
- return type;
+ return current_class_ref ? type : NULL_TREE;
while (true)
{
@@ -1050,7 +1093,7 @@ nonlambda_method_basetype (void)
tree fn = TYPE_CONTEXT (type);
if (!fn || TREE_CODE (fn) != FUNCTION_DECL
- || !DECL_IOBJ_MEMBER_FUNCTION_P (fn))
+ || !DECL_OBJECT_MEMBER_FUNCTION_P (fn))
/* No enclosing non-lambda method. */
return NULL_TREE;
if (!LAMBDA_FUNCTION_P (fn))
@@ -1124,7 +1167,9 @@ maybe_add_lambda_conv_op (tree type)
tree lam = CLASSTYPE_LAMBDA_EXPR (type);
if (LAMBDA_EXPR_CAPTURE_LIST (lam) != NULL_TREE
- || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) != CPLD_NONE)
+ || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) != CPLD_NONE
+ /* CWG2561 ...and no explicit object parameter. */
+ || DECL_XOBJ_MEMBER_FUNCTION_P (callop))
return;
if (processing_template_decl)
@@ -1284,9 +1329,10 @@ maybe_add_lambda_conv_op (tree type)
}
tree stattype
- = build_function_type (fn_result, FUNCTION_FIRST_USER_PARMTYPE (callop));
- stattype = (cp_build_type_attribute_variant
- (stattype, TYPE_ATTRIBUTES (optype)));
+ = cp_build_function_type (fn_result,
+ FUNCTION_FIRST_USER_PARMTYPE (callop));
+ stattype = cp_build_type_attribute_variant (stattype,
+ TYPE_ATTRIBUTES (optype));
if (flag_noexcept_type
&& TYPE_NOTHROW_P (TREE_TYPE (callop)))
stattype = build_exception_variant (stattype, noexcept_true_spec);
@@ -1702,8 +1748,8 @@ compare_lambda_sig (tree fn_a, tree fn_b)
|| fn_b == error_mark_node)
return false;
- for (tree args_a = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn_a))),
- args_b = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fn_b)));
+ for (tree args_a = FUNCTION_FIRST_USER_PARMTYPE (fn_a),
+ args_b = FUNCTION_FIRST_USER_PARMTYPE (fn_b);
args_a || args_b;
args_a = TREE_CHAIN (args_a), args_b = TREE_CHAIN (args_b))
{
@@ -1757,6 +1803,17 @@ record_lambda_scope_sig_discriminator (tree lambda, tree fn)
LAMBDA_EXPR_SCOPE_SIG_DISCRIMINATOR (lambda) = sig->count++;
}
+/* Push the proxies for any explicit captures in LAMBDA_EXPR.
+ If EARLY_P, we do not have the real operator() yet. */
+
+void
+push_capture_proxies (tree lambda_expr, bool early_p)
+{
+ for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;
+ cap = TREE_CHAIN (cap))
+ build_capture_proxy (TREE_PURPOSE (cap), TREE_VALUE (cap), early_p);
+}
+
tree
start_lambda_function (tree fco, tree lambda_expr)
{
@@ -1769,9 +1826,7 @@ start_lambda_function (tree fco, tree lambda_expr)
tree body = begin_function_body ();
/* Push the proxies for any explicit captures. */
- for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;
- cap = TREE_CHAIN (cap))
- build_capture_proxy (TREE_PURPOSE (cap), TREE_VALUE (cap));
+ push_capture_proxies (lambda_expr);
return body;
}
@@ -1859,11 +1914,10 @@ prune_lambda_captures (tree body)
cp_walk_tree_without_duplicates (&body, mark_const_cap_r, &const_vars);
tree bind_expr = expr_single (DECL_SAVED_TREE (lambda_function (lam)));
- if (bind_expr && TREE_CODE (bind_expr) == MUST_NOT_THROW_EXPR)
+ bool noexcept_p = (bind_expr
+ && TREE_CODE (bind_expr) == MUST_NOT_THROW_EXPR);
+ if (noexcept_p)
bind_expr = expr_single (TREE_OPERAND (bind_expr, 0));
- /* FIXME: We don't currently handle noexcept lambda captures correctly,
- so bind_expr may not be set; see PR c++/119764. */
- gcc_assert (!bind_expr || TREE_CODE (bind_expr) == BIND_EXPR);
tree *fieldp = &TYPE_FIELDS (LAMBDA_EXPR_CLOSURE (lam));
for (tree *capp = &LAMBDA_EXPR_CAPTURE_LIST (lam); *capp; )
@@ -1872,11 +1926,23 @@ prune_lambda_captures (tree body)
if (tree var = var_to_maybe_prune (cap))
{
tree **use = const_vars.get (var);
- if (use && TREE_CODE (**use) == DECL_EXPR)
+ if (TREE_CODE (**use) == DECL_EXPR)
{
/* All uses of this capture were folded away, leaving only the
proxy declaration. */
+ if (noexcept_p)
+ {
+ /* We didn't handle noexcept lambda captures correctly before
+ the fix for PR c++/119764. */
+ if (abi_version_crosses (21))
+ warning_at (location_of (lam), OPT_Wabi, "%qD is no longer"
+ " captured in noexcept lambda in ABI v21 "
+ "(GCC 16)", var);
+ if (!abi_version_at_least (21))
+ goto next;
+ }
+
/* Splice the capture out of LAMBDA_EXPR_CAPTURE_LIST. */
*capp = TREE_CHAIN (cap);
@@ -1894,14 +1960,11 @@ prune_lambda_captures (tree body)
/* And maybe out of the vars declared in the containing
BIND_EXPR, if it's listed there. */
- if (bind_expr)
- {
- tree *bindp = &BIND_EXPR_VARS (bind_expr);
- while (*bindp && *bindp != DECL_EXPR_DECL (**use))
- bindp = &DECL_CHAIN (*bindp);
- if (*bindp)
- *bindp = DECL_CHAIN (*bindp);
- }
+ tree *bindp = &BIND_EXPR_VARS (bind_expr);
+ while (*bindp && *bindp != DECL_EXPR_DECL (**use))
+ bindp = &DECL_CHAIN (*bindp);
+ if (*bindp)
+ *bindp = DECL_CHAIN (*bindp);
/* And remove the capture proxy declaration. */
**use = void_node;
@@ -1909,6 +1972,7 @@ prune_lambda_captures (tree body)
}
}
+ next:
capp = &TREE_CHAIN (cap);
}
}
@@ -1922,7 +1986,7 @@ finish_lambda_function (tree body)
{
finish_function_body (body);
- prune_lambda_captures (body);
+ prune_lambda_captures (cur_stmt_list);
/* Finish the function and generate code for it if necessary. */
tree fn = finish_function (/*inline_p=*/true);