commit 67e2b85a7a28a739e25068f9e5eebabd827cd1af
Author: Jiri Palecek <jirka@debian>
Date:   Sat Aug 18 13:45:29 2012 +0200

    Fix capturing constants in lambda expressions in templates

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ad81bab..5008361 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14102,14 +14102,30 @@ tsubst_copy_and_build (tree t,
 
 	/* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set.  */
 	determine_visibility (TYPE_NAME (type));
+
+        /* This is a hack:
+
+           We absolutely need the capture list to be nonempty if the
+           template had it nonempty, otherwise, we will have the
+           conversion-to-function-pointer operator erroneously
+           added. We use a dummy list with a single element that we
+           can get rid of easily later
+        */
+	LAMBDA_EXPR_CAPTURE_LIST (r)
+          = LAMBDA_EXPR_CAPTURE_LIST (t) != NULL_TREE ? tree_cons(NULL_TREE, NULL_TREE, NULL_TREE) : NULL_TREE;
 	/* Now that we know visibility, instantiate the type so we have a
 	   declaration of the op() for later calls to lambda_function.  */
 	complete_type (type);
 
 	/* The capture list refers to closure members, so this needs to
 	   wait until after we finish instantiating the type.  */
+        /* The dummy element, if any, is now at the end of the capture
+           list. There might have been some default captures added, so
+           we reverse the list, remove the dummy element and append
+           the list to the capture list from the template */
+        tree reverse_list = LAMBDA_EXPR_CAPTURE_LIST(r)!= NULL_TREE ? nreverse(LAMBDA_EXPR_CAPTURE_LIST(r)) : NULL_TREE;
 	LAMBDA_EXPR_CAPTURE_LIST (r)
-	  = RECUR (LAMBDA_EXPR_CAPTURE_LIST (t));
+          = chainon(RECUR (LAMBDA_EXPR_CAPTURE_LIST (t)), (reverse_list!=NULL_TREE && TREE_PURPOSE(reverse_list) == NULL_TREE) ? TREE_CHAIN(reverse_list) : reverse_list);
 
 	return build_lambda_object (r);
       }
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index ebac960..d856f7a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2961,8 +2961,20 @@ finish_id_expression (tree id_expression,
 	     the complexity of the problem"
 
 	     FIXME update for final resolution of core issue 696.  */
-	  if (decl_constant_var_p (decl))
-	    return integral_constant_value (decl);
+          if (decl_constant_var_p (decl)) {
+	    tree const_value = integral_constant_value (decl);
+            if (TREE_CODE(const_value) != VAR_DECL)
+              return const_value;
+            /* If it didn't work out, it means we don't actually know
+               what will is the initializer (and if it is a constant
+               expression). We postpone the resolution to
+               instantiation time. This should be safe assuming we
+               find the same variable on instantiation time as here */
+            if (processing_template_decl)
+              return id_expression;
+            /* OK, I HOPE this can't happen */
+            gcc_unreachable();
+          }
 
 	  /* If we are in a lambda function, we can move out until we hit
 	     1. the context,
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const.C
new file mode 100644
index 0000000..92f98fa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const.C
@@ -0,0 +1,24 @@
+// { dg-do run }
+// { dg-options "-std=c++0x" }
+#include <cassert>
+
+template <class T>
+void f(T t, unsigned size)
+{
+  int i = 1, j = -1;
+  const int ci = sizeof(T);
+  [&] () { j = ci; } ();
+  assert(i == 1);
+  assert(j == size);
+  j = -1;
+  j = [=] (T) { return ci; } (T());
+  assert(j == size);
+  //[&ci] () -> void { ci = 0; } (); { dg-error: cannot assign to const int }
+}
+
+int main() {
+  f(1, sizeof(int));
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const2.C
new file mode 100644
index 0000000..0943280
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-const2.C
@@ -0,0 +1,20 @@
+// { dg-options "-std=c++0x" }
+
+struct A
+{
+  static int x;
+};
+
+int A::x;
+
+template <class T>
+void f()
+{
+  const int x = T::x;
+  [] { return x; }; // { dg-error "x.*not.*captured" }
+}
+
+int main()
+{
+  f<A>();
+}
