diff mbox series

C++ PATCH for c++/85764, bogus 'this' not captured error

Message ID CADzB+2=xRJ-wO8khvDsJb8UbejaYnzWFuLuPEuZMnOnjStOccg@mail.gmail.com
State New
Headers show
Series C++ PATCH for c++/85764, bogus 'this' not captured error | expand

Commit Message

Jason Merrill June 2, 2018, 3:13 a.m. UTC
Here, because we're inside a member function, resolvable_dummy_lambda
thought we could resolve a reference to 'this'.  But because it's a
static member function, we can't.  Using nonlambda_method_basetype
instead of current_nonlambda_class_type fixes that, but then I needed
to improve n_m_b to handle NSDMI context.

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

Patch

commit 100e3e46cc5e8000ebe27640beb34d027b414beb
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jun 1 19:10:39 2018 -0400

            PR c++/85764 - bogus 'this' not captured error.
    
            * lambda.c (resolvable_dummy_lambda): Use nonlambda_method_basetype.
            (nonlambda_method_basetype): Handle NSDMI.

diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index 9c1b49b4d8e..231490fbe4e 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -884,7 +884,7 @@  resolvable_dummy_lambda (tree object)
       && current_class_type
       && LAMBDA_TYPE_P (current_class_type)
       && lambda_function (current_class_type)
-      && DERIVED_FROM_P (type, current_nonlambda_class_type ()))
+      && DERIVED_FROM_P (type, nonlambda_method_basetype()))
     return CLASSTYPE_LAMBDA_EXPR (current_class_type);
 
   return NULL_TREE;
@@ -949,30 +949,37 @@  current_nonlambda_function (void)
   return fn;
 }
 
-/* Returns the method basetype of the innermost non-lambda function, or
-   NULL_TREE if none.  */
+/* Returns the method basetype of the innermost non-lambda function, including
+   a hypothetical constructor if inside an NSDMI, or NULL_TREE if none.  */
 
 tree
 nonlambda_method_basetype (void)
 {
-  tree fn, type;
   if (!current_class_ref)
     return NULL_TREE;
 
-  type = current_class_type;
+  tree type = current_class_type;
   if (!type || !LAMBDA_TYPE_P (type))
     return type;
 
-  /* Find the nearest enclosing non-lambda function.  */
-  fn = TYPE_NAME (type);
-  do
-    fn = decl_function_context (fn);
-  while (fn && LAMBDA_FUNCTION_P (fn));
+  while (true)
+    {
+      tree lam = CLASSTYPE_LAMBDA_EXPR (type);
+      tree ex = LAMBDA_EXPR_EXTRA_SCOPE (lam);
+      if (ex && TREE_CODE (ex) == FIELD_DECL)
+	/* Lambda in an NSDMI.  */
+	return DECL_CONTEXT (ex);
 
-  if (!fn || !DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
-    return NULL_TREE;
-
-  return TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
+      tree fn = TYPE_CONTEXT (type);
+      if (!fn || TREE_CODE (fn) != FUNCTION_DECL
+	  || !DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
+	/* No enclosing non-lambda method.  */
+	return NULL_TREE;
+      if (!LAMBDA_FUNCTION_P (fn))
+	/* Found an enclosing non-lambda method.  */
+	return TYPE_METHOD_BASETYPE (TREE_TYPE (fn));
+      type = DECL_CONTEXT (fn);
+    }
 }
 
 /* Like current_scope, but looking through lambdas.  */
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this2.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this2.C
new file mode 100644
index 00000000000..d27ed713fff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-this2.C
@@ -0,0 +1,13 @@ 
+// PR c++/85764
+// { dg-do compile { target c++14 } }
+
+template<typename Key>
+class trie {
+    static void for_each(int & f, trie const & n, Key & prefix) {
+        [&](trie const & c) {
+          for_each(f, c, prefix);
+        };
+    }
+    void for_each(int & f) const {
+    }
+};