diff options
author | Jason Merrill <jason@redhat.com> | 2017-10-10 14:04:02 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2017-10-10 14:04:02 -0400 |
commit | 84dd815ff8765c61376a352863d8482a72f79b37 (patch) | |
tree | a1d29341c64d9d46baace208102db49665b10367 /gcc/cp/lambda.c | |
parent | e1bea3412a75a300c3866dcf9559c2b796f5b430 (diff) | |
download | gcc-84dd815ff8765c61376a352863d8482a72f79b37.zip gcc-84dd815ff8765c61376a352863d8482a72f79b37.tar.gz gcc-84dd815ff8765c61376a352863d8482a72f79b37.tar.bz2 |
More delayed lambda capture fixes.
* call.c (add_function_candidate): Use build_address.
(build_op_call_1): Call mark_lvalue_use early.
(build_over_call): Handle error from build_this.
* constexpr.c (cxx_bind_parameters_in_call): Use build_address.
(cxx_eval_increment_expression): Don't use rvalue().
* cvt.c (convert_to_void): Use mark_discarded_use.
* expr.c (mark_use): Handle PARM_DECL, NON_DEPENDENT_EXPR. Fix
reference handling. Don't copy the expression.
(mark_discarded_use): New.
* lambda.c (insert_capture_proxy): Add some sanity checking.
(maybe_add_lambda_conv_op): Set cp_unevaluated_operand.
* pt.c (register_local_specialization): Add sanity check.
* semantics.c (process_outer_var_ref): Fix check for existing proxy.
* typeck.c (cp_build_addr_expr_1): Handle error from
mark_lvalue_use.
(cp_build_modify_expr): Call mark_lvalue_use_nonread, handle error
from rvalue.
Handle generic lambda capture in dependent expressions.
* lambda.c (need_generic_capture, dependent_capture_r)
(do_dependent_capture): New.
* pt.c (processing_nonlambda_template): Use need_generic_capture.
* semantics.c (maybe_cleanup_point_expr)
(maybe_cleanup_point_expr_void, finish_goto_stmt)
(maybe_convert_cond): Call do_dependent_capture.
* typeck.c (build_static_cast): Remove dependent capture handling.
From-SVN: r253601
Diffstat (limited to 'gcc/cp/lambda.c')
-rw-r--r-- | gcc/cp/lambda.c | 130 |
1 files changed, 129 insertions, 1 deletions
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 78bd897..76f2f29 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -297,7 +297,17 @@ void insert_capture_proxy (tree var) { if (is_normal_capture_proxy (var)) - register_local_specialization (var, DECL_CAPTURED_VARIABLE (var)); + { + tree cap = DECL_CAPTURED_VARIABLE (var); + if (CHECKING_P) + { + gcc_assert (!is_normal_capture_proxy (cap)); + tree old = retrieve_local_specialization (cap); + if (old) + gcc_assert (DECL_CONTEXT (old) != DECL_CONTEXT (var)); + } + register_local_specialization (var, cap); + } /* Put the capture proxy in the extra body block so that it won't clash with a later local variable. */ @@ -977,6 +987,121 @@ generic_lambda_fn_p (tree callop) && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (callop))); } +/* Returns true iff we need to consider default capture for an enclosing + generic lambda. */ + +bool +need_generic_capture (void) +{ + if (!processing_template_decl) + return false; + + tree outer_closure = NULL_TREE; + for (tree t = current_class_type; t; + t = decl_type_context (TYPE_MAIN_DECL (t))) + { + tree lam = CLASSTYPE_LAMBDA_EXPR (t); + if (!lam || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE) + /* No default capture. */ + break; + outer_closure = t; + } + + if (!outer_closure) + /* No lambda. */ + return false; + else if (dependent_type_p (outer_closure)) + /* The enclosing context isn't instantiated. */ + return false; + else + return true; +} + +/* A lambda-expression...is said to implicitly capture the entity...if the + compound-statement...names the entity in a potentially-evaluated + expression where the enclosing full-expression depends on a generic lambda + parameter declared within the reaching scope of the lambda-expression. */ + +static tree +dependent_capture_r (tree *tp, int *walk_subtrees, void *data) +{ + hash_set<tree> *pset = (hash_set<tree> *)data; + + if (TYPE_P (*tp)) + *walk_subtrees = 0; + + if (outer_automatic_var_p (*tp)) + { + tree t = process_outer_var_ref (*tp, tf_warning_or_error, /*force*/true); + if (t != *tp + && TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE + && TREE_CODE (TREE_TYPE (*tp)) != REFERENCE_TYPE) + t = convert_from_reference (t); + *tp = t; + } + + if (pset->add (*tp)) + *walk_subtrees = 0; + + switch (TREE_CODE (*tp)) + { + /* Don't walk into unevaluated context or another lambda. */ + case SIZEOF_EXPR: + case ALIGNOF_EXPR: + case TYPEID_EXPR: + case NOEXCEPT_EXPR: + case LAMBDA_EXPR: + *walk_subtrees = 0; + break; + + /* Don't walk into statements whose subexpressions we already + handled. */ + case TRY_BLOCK: + case EH_SPEC_BLOCK: + case HANDLER: + case IF_STMT: + case FOR_STMT: + case RANGE_FOR_STMT: + case WHILE_STMT: + case DO_STMT: + case SWITCH_STMT: + case STATEMENT_LIST: + case RETURN_EXPR: + *walk_subtrees = 0; + break; + + case DECL_EXPR: + { + tree decl = DECL_EXPR_DECL (*tp); + if (VAR_P (decl)) + { + /* walk_tree_1 won't step in here. */ + cp_walk_tree (&DECL_INITIAL (decl), + dependent_capture_r, &pset, NULL); + *walk_subtrees = 0; + } + } + break; + + default: + break; + } + + return NULL_TREE; +} + +tree +do_dependent_capture (tree expr, bool force) +{ + if (!need_generic_capture () + || (!force && !instantiation_dependent_expression_p (expr))) + return expr; + + hash_set<tree> pset; + cp_walk_tree (&expr, dependent_capture_r, &pset, NULL); + return expr; +} + /* If the closure TYPE has a static op(), also add a conversion to function pointer. */ @@ -1073,7 +1198,10 @@ maybe_add_lambda_conv_op (tree type) if (generic_lambda_p) { + /* Avoid capturing variables in this context. */ + ++cp_unevaluated_operand; tree a = forward_parm (tgt); + --cp_unevaluated_operand; CALL_EXPR_ARG (call, ix) = a; if (decltype_call) |