re PR c++/63207 (ICE in expand_expr_real_l when instantiating a template with a lambd...
authorJason Merrill <jason@redhat.com>
Fri, 10 Oct 2014 03:28:18 +0000 (23:28 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 10 Oct 2014 03:28:18 +0000 (23:28 -0400)
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

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const4.C [new file with mode: 0644]

index 84996a45cba69c900cfda5a75289997d85be88e3..7b2d09f14026a0a65cab8cbd79f7ce20cd6bef2c 100644 (file)
@@ -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.
index 3787c4a3f250d7ab322bdd67a808b1783b1da2a1..6d720c152a624324d70b112b53ed18092982ab8a 100644 (file)
@@ -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 *,
index 85af59d7a5c4982f443c4a3fc108642a5bc1a372..f2c21eec322e446a1492b0c9159d0090d51b4ede 100644 (file)
@@ -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
index 3ca91d88bfef44911692adafeed2c6aed4f28527..ab8c82ae5f6603a52674c972b156a64000097e95 100644 (file)
@@ -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 (file)
index 0000000..02ad602
--- /dev/null
@@ -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();
+}