aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2014-10-09 23:28:18 -0400
committerJason Merrill <jason@gcc.gnu.org>2014-10-09 23:28:18 -0400
commit548cb3d77c81104778f4cbc4d97410cb31a64971 (patch)
tree5e470a495fe25b3226b27b25383860487fe618cf /gcc
parent018e891a75501d357d3035d0e7ee6f98fd390887 (diff)
downloadgcc-548cb3d77c81104778f4cbc4d97410cb31a64971.zip
gcc-548cb3d77c81104778f4cbc4d97410cb31a64971.tar.gz
gcc-548cb3d77c81104778f4cbc4d97410cb31a64971.tar.bz2
re PR c++/63207 (ICE in expand_expr_real_l when instantiating a template with a lambda that captures a const variable with a dependent initializer)
PR c++/63207 * semantics.c (outer_var_p): Non-static. (process_outer_var_ref): Split out from finish_id_expression. * pt.c (tsubst_copy_and_build): Call them. * cp-tree.h: Declare them. From-SVN: r216056
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/cp-tree.h2
-rw-r--r--gcc/cp/pt.c3
-rw-r--r--gcc/cp/semantics.c180
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const4.C21
5 files changed, 129 insertions, 85 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 84996a4..7b2d09f 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2014-10-09 Jason Merrill <jason@redhat.com>
+
+ PR c++/63207
+ * semantics.c (outer_var_p): Non-static.
+ (process_outer_var_ref): Split out from finish_id_expression.
+ * pt.c (tsubst_copy_and_build): Call them.
+ * cp-tree.h: Declare them.
+
2014-10-09 Paolo Carlini <paolo.carlini@oracle.com>
* semantics.c (check_constexpr_ctor_body_1): New.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3787c4a..6d720c1 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5879,6 +5879,8 @@ extern void finish_template_decl (tree);
extern tree finish_template_type (tree, tree, int);
extern tree finish_base_specifier (tree, tree, bool);
extern void finish_member_declaration (tree);
+extern bool outer_automatic_var_p (tree);
+extern tree process_outer_var_ref (tree, tsubst_flags_t);
extern tree finish_id_expression (tree, tree, tree,
cp_id_kind *,
bool, bool, bool *,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 85af59d..f2c21ee 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15460,6 +15460,7 @@ tsubst_copy_and_build (tree t,
case PARM_DECL:
{
tree r = tsubst_copy (t, args, complain, in_decl);
+ /* ??? We're doing a subset of finish_id_expression here. */
if (VAR_P (r)
&& !processing_template_decl
&& !cp_unevaluated_operand
@@ -15471,6 +15472,8 @@ tsubst_copy_and_build (tree t,
a call to its wrapper. */
r = build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
}
+ else if (outer_automatic_var_p (r))
+ r = process_outer_var_ref (r, complain);
if (TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
/* If the original type was a reference, we'll be wrapped in
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 3ca91d8..ab8c82a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -3067,13 +3067,105 @@ outer_var_p (tree decl)
/* As above, but also checks that DECL is automatic. */
-static bool
+bool
outer_automatic_var_p (tree decl)
{
return (outer_var_p (decl)
&& !TREE_STATIC (decl));
}
+/* DECL satisfies outer_automatic_var_p. Possibly complain about it or
+ rewrite it for lambda capture. */
+
+tree
+process_outer_var_ref (tree decl, tsubst_flags_t complain)
+{
+ if (cp_unevaluated_operand)
+ /* It's not a use (3.2) if we're in an unevaluated context. */
+ return decl;
+
+ tree context = DECL_CONTEXT (decl);
+ tree containing_function = current_function_decl;
+ tree lambda_stack = NULL_TREE;
+ tree lambda_expr = NULL_TREE;
+ tree initializer = convert_from_reference (decl);
+
+ /* Mark it as used now even if the use is ill-formed. */
+ mark_used (decl);
+
+ /* Core issue 696: "[At the July 2009 meeting] the CWG expressed
+ support for an approach in which a reference to a local
+ [constant] automatic variable in a nested class or lambda body
+ would enter the expression as an rvalue, which would reduce
+ the complexity of the problem"
+
+ FIXME update for final resolution of core issue 696. */
+ if (decl_maybe_constant_var_p (decl))
+ {
+ if (processing_template_decl)
+ /* In a template, the constant value may not be in a usable
+ form, so wait until instantiation time. */
+ return decl;
+ else if (decl_constant_var_p (decl))
+ return integral_constant_value (decl);
+ }
+
+ if (parsing_nsdmi ())
+ containing_function = NULL_TREE;
+ else
+ /* If we are in a lambda function, we can move out until we hit
+ 1. the context,
+ 2. a non-lambda function, or
+ 3. a non-default capturing lambda function. */
+ while (context != containing_function
+ && LAMBDA_FUNCTION_P (containing_function))
+ {
+ lambda_expr = CLASSTYPE_LAMBDA_EXPR
+ (DECL_CONTEXT (containing_function));
+
+ if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr)
+ == CPLD_NONE)
+ break;
+
+ lambda_stack = tree_cons (NULL_TREE,
+ lambda_expr,
+ lambda_stack);
+
+ containing_function
+ = decl_function_context (containing_function);
+ }
+
+ if (lambda_expr && TREE_CODE (decl) == VAR_DECL
+ && DECL_ANON_UNION_VAR_P (decl))
+ {
+ if (complain & tf_error)
+ error ("cannot capture member %qD of anonymous union", decl);
+ return error_mark_node;
+ }
+ if (context == containing_function)
+ {
+ decl = add_default_capture (lambda_stack,
+ /*id=*/DECL_NAME (decl),
+ initializer);
+ }
+ else if (lambda_expr)
+ {
+ if (complain & tf_error)
+ error ("%qD is not captured", decl);
+ return error_mark_node;
+ }
+ else
+ {
+ if (complain & tf_error)
+ error (VAR_P (decl)
+ ? G_("use of local variable with automatic storage from containing function")
+ : G_("use of parameter from containing function"));
+ inform (input_location, "%q+#D declared here", decl);
+ return error_mark_node;
+ }
+ return decl;
+}
+
/* ID_EXPRESSION is a representation of parsed, but unprocessed,
id-expression. (See cp_parser_id_expression for details.) SCOPE,
if non-NULL, is the type or namespace used to explicitly qualify
@@ -3179,90 +3271,8 @@ finish_id_expression (tree id_expression,
/* Disallow uses of local variables from containing functions, except
within lambda-expressions. */
- if (!outer_var_p (decl))
- /* OK */;
- else if (TREE_STATIC (decl)
- /* It's not a use (3.2) if we're in an unevaluated context. */
- || cp_unevaluated_operand)
- /* OK */;
- else
- {
- tree context = DECL_CONTEXT (decl);
- tree containing_function = current_function_decl;
- tree lambda_stack = NULL_TREE;
- tree lambda_expr = NULL_TREE;
- tree initializer = convert_from_reference (decl);
-
- /* Mark it as used now even if the use is ill-formed. */
- mark_used (decl);
-
- /* Core issue 696: "[At the July 2009 meeting] the CWG expressed
- support for an approach in which a reference to a local
- [constant] automatic variable in a nested class or lambda body
- would enter the expression as an rvalue, which would reduce
- the complexity of the problem"
-
- FIXME update for final resolution of core issue 696. */
- if (decl_maybe_constant_var_p (decl))
- {
- if (processing_template_decl)
- /* In a template, the constant value may not be in a usable
- form, so wait until instantiation time. */
- return decl;
- else if (decl_constant_var_p (decl))
- return integral_constant_value (decl);
- }
-
- if (parsing_nsdmi ())
- containing_function = NULL_TREE;
- /* If we are in a lambda function, we can move out until we hit
- 1. the context,
- 2. a non-lambda function, or
- 3. a non-default capturing lambda function. */
- else while (context != containing_function
- && LAMBDA_FUNCTION_P (containing_function))
- {
- lambda_expr = CLASSTYPE_LAMBDA_EXPR
- (DECL_CONTEXT (containing_function));
-
- if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr)
- == CPLD_NONE)
- break;
-
- lambda_stack = tree_cons (NULL_TREE,
- lambda_expr,
- lambda_stack);
-
- containing_function
- = decl_function_context (containing_function);
- }
-
- if (lambda_expr && TREE_CODE (decl) == VAR_DECL
- && DECL_ANON_UNION_VAR_P (decl))
- {
- error ("cannot capture member %qD of anonymous union", decl);
- return error_mark_node;
- }
- if (context == containing_function)
- {
- decl = add_default_capture (lambda_stack,
- /*id=*/DECL_NAME (decl),
- initializer);
- }
- else if (lambda_expr)
- {
- error ("%qD is not captured", decl);
- return error_mark_node;
- }
- else
- {
- error (VAR_P (decl)
- ? G_("use of local variable with automatic storage from containing function")
- : G_("use of parameter from containing function"));
- inform (input_location, "%q+#D declared here", decl);
- return error_mark_node;
- }
- }
+ if (outer_automatic_var_p (decl))
+ decl = process_outer_var_ref (decl, tf_warning_or_error);
/* Also disallow uses of function parameters outside the function
body, except inside an unevaluated context (i.e. decltype). */
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const4.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const4.C
new file mode 100644
index 0000000..02ad602
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const4.C
@@ -0,0 +1,21 @@
+// PR c++/63207
+// { dg-do run { target c++11 } }
+
+template <typename T>
+struct Base {
+ T value;
+};
+
+template <typename T>
+struct Test : Base<T> {
+ T test() {
+ const int x = this->value;
+ return ([&]{ return x; })();
+ }
+};
+
+int main() {
+ Test<int> t;
+ t.value = 0;
+ return t.test();
+}