diff mbox

C++ PATCH for c++/65727 (ICE with lambda in decltype)

Message ID 552ED3EA.7050907@redhat.com
State New
Headers show

Commit Message

Jason Merrill April 15, 2015, 9:11 p.m. UTC
Here we were getting confused because we push into type_e when parsing 
the initializer for type_e::b, but then don't find any 'this' for 
resolving the reference to type_e::d.  We should allow that in decltype 
context, but the code wasn't handling it.

Marek suggested just handling null return from lambda_expr_this_capture, 
and that's what I'll apply for GCC 5.2, but on the trunk I'm also going 
to tidy up that function a bit, to avoid multiple code paths giving 
different results.

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

Patch

commit dc2b99c84e2b929fe777b44aab1be2228445bc27
Author: Jason Merrill <jason@redhat.com>
Date:   Mon Apr 13 16:54:12 2015 -0400

    	PR c++/65727
    	* lambda.c (lambda_expr_this_capture): In unevaluated context go
    	through the normal loop, just don't capture.
    	(maybe_resolve_dummy): Handle null return.

diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index dd1c2d4..174700f 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -646,7 +646,7 @@  add_default_capture (tree lambda_stack, tree id, tree initializer)
 
 /* Return the capture pertaining to a use of 'this' in LAMBDA, in the
    form of an INDIRECT_REF, possibly adding it through default
-   capturing, if ADD_CAPTURE_P is false.  */
+   capturing, if ADD_CAPTURE_P is true.  */
 
 tree
 lambda_expr_this_capture (tree lambda, bool add_capture_p)
@@ -655,17 +655,9 @@  lambda_expr_this_capture (tree lambda, bool add_capture_p)
 
   tree this_capture = LAMBDA_EXPR_THIS_CAPTURE (lambda);
 
-  /* In unevaluated context this isn't an odr-use, so just return the
-     nearest 'this'.  */
+  /* In unevaluated context this isn't an odr-use, so don't capture.  */
   if (cp_unevaluated_operand)
-    {
-      /* In an NSDMI the fake 'this' pointer that we're using for
-	 parsing is in scope_chain.  */
-      if (LAMBDA_EXPR_EXTRA_SCOPE (lambda)
-	  && TREE_CODE (LAMBDA_EXPR_EXTRA_SCOPE (lambda)) == FIELD_DECL)
-	return scope_chain->x_current_class_ptr;
-      return lookup_name (this_identifier);
-    }
+    add_capture_p = false;
 
   /* Try to default capture 'this' if we can.  */
   if (!this_capture
@@ -740,11 +732,17 @@  lambda_expr_this_capture (tree lambda, bool add_capture_p)
         }
     }
 
-  if (!this_capture)
+  if (cp_unevaluated_operand)
+    result = this_capture;
+  else if (!this_capture)
     {
       if (add_capture_p)
-	error ("%<this%> was not captured for this lambda function");
-      result = error_mark_node;
+	{
+	  error ("%<this%> was not captured for this lambda function");
+	  result = error_mark_node;
+	}
+      else
+	result = NULL_TREE;
     }
   else
     {
@@ -787,7 +785,7 @@  maybe_resolve_dummy (tree object, bool add_capture_p)
       /* In a lambda, need to go through 'this' capture.  */
       tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type);
       tree cap = lambda_expr_this_capture (lam, add_capture_p);
-      if (cap != error_mark_node)
+      if (cap && cap != error_mark_node)
 	object = build_x_indirect_ref (EXPR_LOCATION (object), cap,
 				       RO_NULL, tf_warning_or_error);
     }
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype2.C
new file mode 100644
index 0000000..51bf0ec
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-decltype2.C
@@ -0,0 +1,25 @@ 
+// PR c++/65727
+// { dg-do compile { target c++11 } }
+
+struct type_a { void(*cb)(); };
+
+struct type_b
+{
+    type_b(type_a p);
+    void dummy();
+};
+
+template<class T>
+constexpr T function_c(T**t) {return **t;}
+
+class type_d {
+    public:
+        static void dummy();
+};
+class type_e {
+    public:
+        static type_b b;
+        type_d *d[1];
+};
+
+type_b type_e::b = {{[](){decltype(function_c(type_e::d))::dummy();}}};