Patchwork C++ PATCH for c++/54276 (link error with lambda and static var)

login
register
mail settings
Submitter Jason Merrill
Date Feb. 15, 2013, 7:21 p.m.
Message ID <511E8AD5.8080405@redhat.com>
Download mbox | patch
Permalink /patch/220829/
State New
Headers show

Comments

Jason Merrill - Feb. 15, 2013, 7:21 p.m.
Like 52026, the problem here is that we have a reference to an outer 
variable in the lambda and can't instantiate it properly.  And like 
52026, the solution is to look up the variable again at instantiation time.

Tested x86_64-pc-linux-gnu, applying to trunk.

Patch

commit 43d4443096a0dbb9e9424370f010372ef79717e8
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Feb 15 13:52:14 2013 -0500

    	PR c++/54276
    	* semantics.c (finish_id_expression): Also return the identifier
    	for an outer local static.

diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 0e09d04..458ed26 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2876,18 +2876,26 @@  baselink_for_fns (tree fns)
   return build_baselink (cl, cl, fns, /*optype=*/NULL_TREE);
 }
 
-/* Returns true iff DECL is an automatic variable from a function outside
+/* Returns true iff DECL is a variable from a function outside
    the current one.  */
 
 static bool
-outer_automatic_var_p (tree decl)
+outer_var_p (tree decl)
 {
   return ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
 	  && DECL_FUNCTION_SCOPE_P (decl)
-	  && !TREE_STATIC (decl)
 	  && DECL_CONTEXT (decl) != current_function_decl);
 }
 
+/* As above, but also checks that DECL is automatic.  */
+
+static bool
+outer_automatic_var_p (tree decl)
+{
+  return (outer_var_p (decl)
+	  && !TREE_STATIC (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
@@ -2994,9 +3002,18 @@  finish_id_expression (tree id_expression,
 
       /* Disallow uses of local variables from containing functions, except
 	 within lambda-expressions.  */
-      if (outer_automatic_var_p (decl)
+      if (!outer_var_p (decl)
 	  /* It's not a use (3.2) if we're in an unevaluated context.  */
-	  && !cp_unevaluated_operand)
+	  || cp_unevaluated_operand)
+	/* OK.  */;
+      else if (TREE_STATIC (decl))
+	{
+	  if (processing_template_decl)
+	    /* For a use of an outer static var, return the identifier so
+	       that we'll look it up again in the instantiation.  */
+	    return id_expression;
+	}
+      else
 	{
 	  tree context = DECL_CONTEXT (decl);
 	  tree containing_function = current_function_decl;
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template9.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template9.C
new file mode 100644
index 0000000..c1d010b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-template9.C
@@ -0,0 +1,15 @@ 
+// PR c++/54276
+// { dg-do link { target c++11 } }
+
+template <typename T>
+void foo(T)
+{
+  static int x = 1;
+  auto f = [] { return x + 1; };
+  f();
+}
+
+int main()
+{
+  foo(4);
+}