Capture adjustments for P0588R1.

* semantics.c (process_outer_var_ref): Capture variables when
	they are named; complain about non-capture uses when odr-used.
	* expr.c (mark_use): Rvalue use looks through capture proxy.
	* constexpr.c (potential_constant_expression_1): Improve error about
	use of captured variable.
	* lambda.c (need_generic_capture, dependent_capture_r)
	(do_dependent_capture, processing_nonlambda_template): Remove.
	* call.c (build_this): Remove uses of the above.
	* decl.c (cp_finish_decl): Likewise.
	* semantics.c (maybe_cleanup_point_expr)
	(maybe_cleanup_point_expr_void, finish_goto_stmt)
	(maybe_convert_cond): Likewise.
	* typeck.c (check_return_expr): Likewise.

From-SVN: r254713
This commit is contained in:
Jason Merrill 2017-11-13 17:34:38 -05:00 committed by Jason Merrill
parent 04757a2a49
commit c1051bf7d8
10 changed files with 68 additions and 150 deletions

View File

@ -1,5 +1,20 @@
2017-11-13 Jason Merrill <jason@redhat.com>
Capture adjustments for P0588R1.
* semantics.c (process_outer_var_ref): Capture variables when
they are named; complain about non-capture uses when odr-used.
* expr.c (mark_use): Rvalue use looks through capture proxy.
* constexpr.c (potential_constant_expression_1): Improve error about
use of captured variable.
* lambda.c (need_generic_capture, dependent_capture_r)
(do_dependent_capture, processing_nonlambda_template): Remove.
* call.c (build_this): Remove uses of the above.
* decl.c (cp_finish_decl): Likewise.
* semantics.c (maybe_cleanup_point_expr)
(maybe_cleanup_point_expr_void, finish_goto_stmt)
(maybe_convert_cond): Likewise.
* typeck.c (check_return_expr): Likewise.
Defer folding of *&.
* typeck.c (cp_build_fold_indirect_ref): New.
(cp_build_indirect_ref_1): Split out from cp_build_indirect_ref.

View File

@ -3365,7 +3365,7 @@ build_this (tree obj)
{
/* In a template, we are only concerned about the type of the
expression, so we can take a shortcut. */
if (processing_nonlambda_template ())
if (processing_template_decl)
return build_address (obj);
return cp_build_addr_expr (obj, tf_warning_or_error);

View File

@ -1286,8 +1286,6 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
&& is_dummy_object (x))
{
x = ctx->object;
/* We don't use cp_build_addr_expr here because we don't want to
capture the object argument during constexpr evaluation. */
x = build_address (x);
}
bool lval = false;
@ -5289,7 +5287,25 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
case VAR_DECL:
if (DECL_HAS_VALUE_EXPR_P (t))
return RECUR (DECL_VALUE_EXPR (t), rval);
{
if (now && is_normal_capture_proxy (t))
{
/* -- in a lambda-expression, a reference to this or to a
variable with automatic storage duration defined outside that
lambda-expression, where the reference would be an
odr-use. */
if (flags & tf_error)
{
tree cap = DECL_CAPTURED_VARIABLE (t);
error ("lambda capture of %qE is not a constant expression",
cap);
if (!want_rval && decl_constant_var_p (cap))
inform (input_location, "because it is used as a glvalue");
}
return false;
}
return RECUR (DECL_VALUE_EXPR (t), rval);
}
if (want_rval
&& !var_in_maybe_constexpr_fn (t)
&& !type_dependent_expression_p (t)

View File

@ -6462,7 +6462,6 @@ extern int uses_template_parms (tree);
extern bool uses_template_parms_level (tree, int);
extern bool in_template_function (void);
extern bool need_generic_capture (void);
extern bool processing_nonlambda_template (void);
extern tree instantiate_class_template (tree);
extern tree instantiate_template (tree, tree, tsubst_flags_t);
extern tree fn_type_unification (tree, tree, tree,

View File

@ -6844,8 +6844,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
DECL_INITIAL (decl) = NULL_TREE;
}
init = do_dependent_capture (init);
/* Generally, initializers in templates are expanded when the
template is instantiated. But, if DECL is a variable constant
then it can be used in future constant expressions, so its value

View File

@ -111,6 +111,14 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
{
case VAR_DECL:
case PARM_DECL:
if (rvalue_p && is_normal_capture_proxy (expr))
{
/* Look through capture by copy. */
tree cap = DECL_CAPTURED_VARIABLE (expr);
if (TREE_CODE (TREE_TYPE (cap)) == TREE_CODE (TREE_TYPE (expr))
&& decl_constant_var_p (cap))
return RECUR (cap);
}
if (outer_automatic_var_p (expr)
&& decl_constant_var_p (expr))
{
@ -146,6 +154,14 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
{
/* Try to look through the reference. */
tree ref = TREE_OPERAND (expr, 0);
if (rvalue_p && is_normal_capture_proxy (ref))
{
/* Look through capture by reference. */
tree cap = DECL_CAPTURED_VARIABLE (ref);
if (TREE_CODE (TREE_TYPE (cap)) != REFERENCE_TYPE
&& decl_constant_var_p (cap))
return RECUR (cap);
}
tree r = mark_rvalue_use (ref, loc, reject_builtin);
if (r != ref)
expr = convert_from_reference (r);

View File

@ -985,121 +985,6 @@ 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. */

View File

@ -9500,16 +9500,6 @@ in_template_function (void)
return ret;
}
/* Returns true iff we are currently within a template other than a
default-capturing generic lambda, so we don't need to worry about semantic
processing. */
bool
processing_nonlambda_template (void)
{
return processing_template_decl && !need_generic_capture ();
}
/* Returns true if T depends on any template parameter with level LEVEL. */
bool

View File

@ -410,8 +410,6 @@ maybe_cleanup_point_expr (tree expr)
{
if (!processing_template_decl && stmts_are_full_exprs_p ())
expr = fold_build_cleanup_point_expr (TREE_TYPE (expr), expr);
else
expr = do_dependent_capture (expr);
return expr;
}
@ -425,8 +423,6 @@ maybe_cleanup_point_expr_void (tree expr)
{
if (!processing_template_decl && stmts_are_full_exprs_p ())
expr = fold_build_cleanup_point_expr (void_type_node, expr);
else
expr = do_dependent_capture (expr);
return expr;
}
@ -633,8 +629,6 @@ finish_goto_stmt (tree destination)
= fold_build_cleanup_point_expr (TREE_TYPE (destination),
destination);
}
else
destination = do_dependent_capture (destination);
}
check_goto (destination);
@ -656,7 +650,7 @@ maybe_convert_cond (tree cond)
/* Wait until we instantiate templates before doing conversion. */
if (processing_template_decl)
return do_dependent_capture (cond);
return cond;
if (warn_sequence_point)
verify_sequence_points (cond);
@ -3291,10 +3285,14 @@ outer_automatic_var_p (tree decl)
}
/* DECL satisfies outer_automatic_var_p. Possibly complain about it or
rewrite it for lambda capture. */
rewrite it for lambda capture.
If ODR_USE is true, we're being called from mark_use, and we complain about
use of constant variables. If ODR_USE is false, we're being called for the
id-expression, and we do lambda capture. */
tree
process_outer_var_ref (tree decl, tsubst_flags_t complain, bool force_use)
process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)
{
if (cp_unevaluated_operand)
/* It's not a use (3.2) if we're in an unevaluated context. */
@ -3315,12 +3313,6 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool force_use)
if (parsing_nsdmi ())
containing_function = NULL_TREE;
/* Core issue 696: Only an odr-use of an outer automatic variable causes a
capture (or error), and a constant variable can decay to a prvalue
constant without odr-use. So don't capture yet. */
if (decl_constant_var_p (decl) && !force_use)
return decl;
if (containing_function && LAMBDA_FUNCTION_P (containing_function))
{
/* Check whether we've already built a proxy. */
@ -3336,7 +3328,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool force_use)
return d;
else
/* We need to capture an outer proxy. */
return process_outer_var_ref (d, complain, force_use);
return process_outer_var_ref (d, complain, odr_use);
}
}
@ -3382,12 +3374,19 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool force_use)
error ("cannot capture member %qD of anonymous union", decl);
return error_mark_node;
}
if (context == containing_function)
/* Do lambda capture when processing the id-expression, not when
odr-using a variable. */
if (!odr_use && context == containing_function)
{
decl = add_default_capture (lambda_stack,
/*id=*/DECL_NAME (decl),
initializer);
}
/* Only an odr-use of an outer automatic variable causes an
error, and a constant variable can decay to a prvalue
constant without odr-use. So don't complain yet. */
else if (!odr_use && decl_constant_var_p (decl))
return decl;
else if (lambda_expr)
{
if (complain & tf_error)

View File

@ -9158,7 +9158,7 @@ check_return_expr (tree retval, bool *no_warning)
dependent:
/* We should not have changed the return value. */
gcc_assert (retval == saved_retval);
return do_dependent_capture (retval, /*force*/true);
return retval;
}
/* The fabled Named Return Value optimization, as per [class.copy]/15: