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.
{
/* 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);
&& 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;
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)
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,
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
{
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))
{
{
/* 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);
&& 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. */
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
{
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;
}
{
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;
}
= fold_build_cleanup_point_expr (TREE_TYPE (destination),
destination);
}
- else
- destination = do_dependent_capture (destination);
}
check_goto (destination);
/* 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);
}
/* 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. */
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. */
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);
}
}
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)
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: