PR c++/85764 - bogus 'this' not captured error.
authorJason Merrill <jason@redhat.com>
Sat, 2 Jun 2018 03:14:44 +0000 (23:14 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Sat, 2 Jun 2018 03:14:44 +0000 (23:14 -0400)
* lambda.c (resolvable_dummy_lambda): Use nonlambda_method_basetype.
(nonlambda_method_basetype): Handle NSDMI.

From-SVN: r261101

gcc/cp/ChangeLog
gcc/cp/lambda.c
gcc/testsuite/g++.dg/cpp1y/lambda-generic-this2.C [new file with mode: 0644]

index 5446278..bbf76ea 100644 (file)
@@ -1,5 +1,9 @@
 2018-06-01  Jason Merrill  <jason@redhat.com>
 
+       PR c++/85764 - bogus 'this' not captured error.
+       * lambda.c (resolvable_dummy_lambda): Use nonlambda_method_basetype.
+       (nonlambda_method_basetype): Handle NSDMI.
+
        CWG 1581: When are constexpr member functions defined?
        * constexpr.c (instantiate_cx_fn_r, instantiate_constexpr_fns): New.
        (cxx_eval_outermost_constant_expr): Call instantiate_constexpr_fns.
index 9c1b49b..231490f 100644 (file)
@@ -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));
-
-  if (!fn || !DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
-    return NULL_TREE;
-
-  return TYPE_METHOD_BASETYPE (TREE_TYPE (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);
+
+      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 (file)
index 0000000..d27ed71
--- /dev/null
@@ -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 {
+    }
+};