mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-08 15:42:07 +08:00
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:
parent
04757a2a49
commit
c1051bf7d8
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
115
gcc/cp/lambda.c
115
gcc/cp/lambda.c
@ -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. */
|
||||
|
||||
|
10
gcc/cp/pt.c
10
gcc/cp/pt.c
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user