PR c++/82029 - __PRETTY_FUNCTION__ in lambda in template
authorJason Merrill <jason@redhat.com>
Thu, 31 Aug 2017 15:39:04 +0000 (11:39 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 31 Aug 2017 15:39:04 +0000 (11:39 -0400)
* pt.c (enclosing_instantiation_of, lambda_fn_in_template_p)
(regenerated_lambda_fn_p): New.
(tsubst_decl) [VAR_DECL]: Use enclosing_instantiation_of.
(tsubst_copy) [VAR_DECL]: Likewise.

From-SVN: r251567

gcc/cp/ChangeLog
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C [new file with mode: 0644]

index a8c13672b5f3b0557188f454f67af9afafe200b0..4a791ddbbb4be60b29af5f713f1a85cbf630b823 100644 (file)
@@ -1,5 +1,11 @@
 2017-08-30  Jason Merrill  <jason@redhat.com>
 
+       PR c++/82029 - __PRETTY_FUNCTION__ in lambda in template
+       * pt.c (enclosing_instantiation_of, lambda_fn_in_template_p)
+       (regenerated_lambda_fn_p): New.
+       (tsubst_decl) [VAR_DECL]: Use enclosing_instantiation_of.
+       (tsubst_copy) [VAR_DECL]: Likewise.
+
        PR c++/82030 - ICE inheriting from multiple lambdas
        PR c++/80767
        * call.c (compare_ics): Handle null candidate.
index f4868abfda2623837542a8765265402c443e0acf..d5ab93985a3f0192c4749227c33b2f0adc48410a 100644 (file)
@@ -12587,6 +12587,63 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
   return r;
 }
 
+/* True if FN is the op() for a lambda in an uninstantiated template.  */
+
+bool
+lambda_fn_in_template_p (tree fn)
+{
+  if (!LAMBDA_FUNCTION_P (fn))
+    return false;
+  tree closure = DECL_CONTEXT (fn);
+  return CLASSTYPE_TEMPLATE_INFO (closure) != NULL_TREE;
+}
+
+/* True if FN is the op() for a lambda regenerated from a lambda in an
+   uninstantiated template.  */
+
+bool
+regenerated_lambda_fn_p (tree fn)
+{
+  return (LAMBDA_FUNCTION_P (fn)
+         && !DECL_TEMPLATE_INSTANTIATION (fn));
+}
+
+/* We're instantiating a variable from template function TCTX.  Return the
+   corresponding current enclosing scope.  This gets complicated because lambda
+   functions in templates are regenerated rather than instantiated, but generic
+   lambda functions are subsequently instantiated.  */
+
+static tree
+enclosing_instantiation_of (tree tctx)
+{
+  tree fn = current_function_decl;
+  int lambda_count = 0;
+
+  for (; tctx && lambda_fn_in_template_p (tctx);
+       tctx = decl_function_context (tctx))
+    ++lambda_count;
+  for (; fn; fn = decl_function_context (fn))
+    {
+      tree lambda = fn;
+      int flambda_count = 0;
+      for (; fn && regenerated_lambda_fn_p (fn);
+          fn = decl_function_context (fn))
+       ++flambda_count;
+      if (DECL_TEMPLATE_INFO (fn)
+         ? most_general_template (fn) != most_general_template (tctx)
+         : fn != tctx)
+       continue;
+      if (lambda_count)
+       {
+         fn = lambda;
+         while (flambda_count-- > lambda_count)
+           fn = decl_function_context (fn);
+       }
+      return fn;
+    }
+  gcc_unreachable ();
+}
+
 /* Substitute the ARGS into the T, which is a _DECL.  Return the
    result of the substitution.  Issue error and warning messages under
    control of COMPLAIN.  */
@@ -12955,7 +13012,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
               enclosing function, in which case we need to fill it in now.  */
            if (TREE_STATIC (t))
              {
-               tree fn = tsubst (DECL_CONTEXT (t), args, complain, in_decl);
+               tree fn = enclosing_instantiation_of (DECL_CONTEXT (t));
                if (fn != current_function_decl)
                  ctx = fn;
              }
@@ -14734,9 +14791,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
              if (r && !is_capture_proxy (r))
                {
                  /* Make sure that the one we found is the one we want.  */
-                 tree ctx = DECL_CONTEXT (t);
-                 if (DECL_LANG_SPECIFIC (ctx) && DECL_TEMPLATE_INFO (ctx))
-                   ctx = tsubst (ctx, args, complain, in_decl);
+                 tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t));
                  if (ctx != DECL_CONTEXT (r))
                    r = NULL_TREE;
                }
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-__func__2.C
new file mode 100644 (file)
index 0000000..bc0e3b2
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/82029
+// { dg-do compile { target c++11 } }
+
+template <typename> struct A {
+  void m_fn1() {
+    [] { return __func__; }();
+  }
+};
+struct B {
+  A<int> a;
+  void m_fn2();
+};
+void B::m_fn2() { a.m_fn1(); }