aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2017-11-13 17:34:38 -0500
committerJason Merrill <jason@gcc.gnu.org>2017-11-13 17:34:38 -0500
commitc1051bf7d8c99d056c6ae3353eb2b61751293d2f (patch)
treefd734eba6bb7c4373c5a32b46fdb8e5256e42335
parent04757a2a49bd21c71af386a64591f77c165a0d93 (diff)
downloadgcc-c1051bf7d8c99d056c6ae3353eb2b61751293d2f.zip
gcc-c1051bf7d8c99d056c6ae3353eb2b61751293d2f.tar.gz
gcc-c1051bf7d8c99d056c6ae3353eb2b61751293d2f.tar.bz2
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
-rw-r--r--gcc/cp/ChangeLog15
-rw-r--r--gcc/cp/call.c2
-rw-r--r--gcc/cp/constexpr.c22
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl.c2
-rw-r--r--gcc/cp/expr.c16
-rw-r--r--gcc/cp/lambda.c115
-rw-r--r--gcc/cp/pt.c10
-rw-r--r--gcc/cp/semantics.c33
-rw-r--r--gcc/cp/typeck.c2
10 files changed, 68 insertions, 150 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index f71506b..ce0c874 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index e18f077..e09cf97 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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);
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 670aae2..d6b6843 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -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)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ea61e87..b994206 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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,
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 54077d5..2e356a0 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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
diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c
index 23e30cf..81b9a5b 100644
--- a/gcc/cp/expr.c
+++ b/gcc/cp/expr.c
@@ -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);
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 7c8b640..2cbad87 100644
--- a/gcc/cp/lambda.c
+++ b/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. */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 710333d..4ca5974 100644
--- a/gcc/cp/pt.c
+++ b/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
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 664952e..51489d1 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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)
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index f9a5f85..cb93cc3 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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: