diff mbox

C++ PATCH for c++/50437 (ICE on auto with lambda in template)

Message ID 4E975529.90309@redhat.com
State New
Headers show

Commit Message

Jason Merrill Oct. 13, 2011, 9:16 p.m. UTC
The problem here was that auto deduced the closure type of the lambda in 
the template, and then instantiation tried to instantiate the closure 
outside of the context of the LAMBDA_EXPR, which doesn't work.  So I've 
changed LAMBDA_EXPR to always have a TREE_TYPE of NULL_TREE, and put the 
closure in a new field instead.

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

Patch

commit 1e940d8c7b567f7e0994ca99fe34b51309705d7f
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Oct 13 15:27:31 2011 -0400

    	PR c++/50437
    	* cp-tree.h (struct tree_lambda_expr): Add closure field.
    	(LAMBDA_EXPR_CLOSURE): New.
    	* pt.c (tsubst_copy_and_build) [LAMBDA_EXPR]: Likewise.
    	* semantics.c (build_lambda_object): Use it instead of TREE_TYPE.
    	(begin_lambda_type, lambda_function, add_capture): Likewise.
    	(add_default_capture, lambda_expr_this_capture): Likewise.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b53accf..e42cda1 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -671,6 +671,12 @@  enum cp_lambda_default_capture_mode_type {
 #define LAMBDA_EXPR_PENDING_PROXIES(NODE) \
   (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->pending_proxies)
 
+/* The closure type of the lambda.  Note that the TREE_TYPE of a
+   LAMBDA_EXPR is always NULL_TREE, because we need to instantiate the
+   LAMBDA_EXPR in order to instantiate the type.  */
+#define LAMBDA_EXPR_CLOSURE(NODE) \
+  (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->closure)
+
 struct GTY (()) tree_lambda_expr
 {
   struct tree_typed typed;
@@ -678,6 +684,7 @@  struct GTY (()) tree_lambda_expr
   tree this_capture;
   tree return_type;
   tree extra_scope;
+  tree closure;
   VEC(tree,gc)* pending_proxies;
   location_t locus;
   enum cp_lambda_default_capture_mode_type default_capture_mode;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index bfbd244..880f3d1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13937,8 +13937,8 @@  tsubst_copy_and_build (tree t,
       {
 	tree r = build_lambda_expr ();
 
-	tree type = tsubst (TREE_TYPE (t), args, complain, NULL_TREE);
-	TREE_TYPE (r) = type;
+	tree type = tsubst (LAMBDA_EXPR_CLOSURE (t), args, complain, NULL_TREE);
+	LAMBDA_EXPR_CLOSURE (r) = type;
 	CLASSTYPE_LAMBDA_EXPR (type) = r;
 
 	LAMBDA_EXPR_LOCATION (r)
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index eed38e6..7d37fa3 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -8324,7 +8324,7 @@  build_lambda_object (tree lambda_expr)
 
   /* N2927: "[The closure] class type is not an aggregate."
      But we briefly treat it as an aggregate to make this simpler.  */
-  type = TREE_TYPE (lambda_expr);
+  type = LAMBDA_EXPR_CLOSURE (lambda_expr);
   CLASSTYPE_NON_AGGREGATE (type) = 0;
   expr = finish_compound_literal (type, expr, tf_warning_or_error);
   CLASSTYPE_NON_AGGREGATE (type) = 1;
@@ -8365,7 +8365,7 @@  begin_lambda_type (tree lambda)
   type = begin_class_definition (type, /*attributes=*/NULL_TREE);
 
   /* Cross-reference the expression and the type.  */
-  TREE_TYPE (lambda) = type;
+  LAMBDA_EXPR_CLOSURE (lambda) = type;
   CLASSTYPE_LAMBDA_EXPR (type) = lambda;
 
   return type;
@@ -8399,7 +8399,7 @@  lambda_function (tree lambda)
 {
   tree type;
   if (TREE_CODE (lambda) == LAMBDA_EXPR)
-    type = TREE_TYPE (lambda);
+    type = LAMBDA_EXPR_CLOSURE (lambda);
   else
     type = lambda;
   gcc_assert (LAMBDA_TYPE_P (type));
@@ -8714,7 +8714,7 @@  add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
 
   /* If TREE_TYPE isn't set, we're still in the introducer, so check
      for duplicates.  */
-  if (!TREE_TYPE (lambda))
+  if (!LAMBDA_EXPR_CLOSURE (lambda))
     {
       if (IDENTIFIER_MARKED (name))
 	{
@@ -8740,13 +8740,14 @@  add_capture (tree lambda, tree id, tree initializer, bool by_reference_p,
     LAMBDA_EXPR_THIS_CAPTURE (lambda) = member;
 
   /* Add it to the appropriate closure class if we've started it.  */
-  if (current_class_type && current_class_type == TREE_TYPE (lambda))
+  if (current_class_type
+      && current_class_type == LAMBDA_EXPR_CLOSURE (lambda))
     finish_member_declaration (member);
 
   LAMBDA_EXPR_CAPTURE_LIST (lambda)
     = tree_cons (member, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
 
-  if (TREE_TYPE (lambda))
+  if (LAMBDA_EXPR_CLOSURE (lambda))
     return build_capture_proxy (member);
   /* For explicit captures we haven't started the function yet, so we wait
      and build the proxy from cp_parser_lambda_body.  */
@@ -8789,7 +8790,7 @@  add_default_capture (tree lambda_stack, tree id, tree initializer)
     {
       tree lambda = TREE_VALUE (node);
 
-      current_class_type = TREE_TYPE (lambda);
+      current_class_type = LAMBDA_EXPR_CLOSURE (lambda);
       var = add_capture (lambda,
                             id,
                             initializer,
@@ -8820,7 +8821,7 @@  lambda_expr_this_capture (tree lambda)
   if (!this_capture
       && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE)
     {
-      tree containing_function = TYPE_CONTEXT (TREE_TYPE (lambda));
+      tree containing_function = TYPE_CONTEXT (LAMBDA_EXPR_CLOSURE (lambda));
       tree lambda_stack = tree_cons (NULL_TREE, lambda, NULL_TREE);
       tree init = NULL_TREE;
 
@@ -8870,7 +8871,8 @@  lambda_expr_this_capture (tree lambda)
   else
     {
       /* To make sure that current_class_ref is for the lambda.  */
-      gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)) == TREE_TYPE (lambda));
+      gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref))
+		  == LAMBDA_EXPR_CLOSURE (lambda));
 
       result = this_capture;
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-auto1.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-auto1.C
new file mode 100644
index 0000000..b5ba066
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-auto1.C
@@ -0,0 +1,14 @@ 
+// PR c++/50437
+// { dg-options -std=c++0x }
+
+template <typename T>
+void f()
+{
+    auto g = [](T t){ return t == 0; };
+    g(T());
+}
+
+int main()
+{
+    f<int>();
+}