On Wed, Aug 9, 2017 at 3:20 PM, Jason Merrill <ja...@redhat.com> wrote:
> In this testcase, when building up an extra version of N to refer to
> when instantiating the generic lambda, we were mistakenly replacing
> the 'auto' with a template argument for the generic lambda.
>
> Tested x86_64-pc-linux-gnu, applying to trunk and 7.

Recent testing found a bug in this patch, whereby we would mistakenly
clobber the TREE_VEC_LENGTH of a single-level argument set, or
increase the length rather than decreasing it.  Fixed by using
strip_innermost_template_args and calculating how many levels we
actually want to remove.  On the trunk I've also added an assert that
we shouldn't get into this situation anymore.

Tested x86_64-pc-linux-gnu, applying to trunk and 7.
commit 2e694fe9477fefb4d746943c6996785109f61aa6
Author: Jason Merrill <ja...@redhat.com>
Date:   Thu Sep 28 16:07:34 2017 -0400

            PR c++/81525 - broken handling of auto in generic lambda.
    
            * pt.c (tsubst_decl) [VAR_DECL]: Use strip_innermost_template_args.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f3ad6083190..38d7b45eb9b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12896,15 +12896,17 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
                && VAR_HAD_UNKNOWN_BOUND (t)
                && type != error_mark_node)
              type = strip_array_domain (type);
-           tree auto_node = type_uses_auto (type);
-           int len = TREE_VEC_LENGTH (args);
-           if (auto_node)
-             /* Mask off any template args past the variable's context so we
-                don't replace the auto with an unrelated argument.  */
-             TREE_VEC_LENGTH (args) = TEMPLATE_TYPE_LEVEL (auto_node) - 1;
-           type = tsubst (type, args, complain, in_decl);
-           if (auto_node)
-             TREE_VEC_LENGTH (args) = len;
+           tree sub_args = args;
+           if (tree auto_node = type_uses_auto (type))
+             {
+               /* Mask off any template args past the variable's context so we
+                  don't replace the auto with an unrelated argument.  */
+               int nouter = TEMPLATE_TYPE_LEVEL (auto_node) - 1;
+               int extra = TMPL_ARGS_DEPTH (args) - nouter;
+               if (extra > 0)
+                 sub_args = strip_innermost_template_args (args, extra);
+             }
+           type = tsubst (type, sub_args, complain, in_decl);
          }
        if (VAR_P (r))
          {
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C 
b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C
new file mode 100644
index 00000000000..b9e98c551c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C
@@ -0,0 +1,19 @@
+// Related to c++/81525
+// { dg-do compile { target c++14 } }
+
+template <class X>
+struct A
+{
+  template <class T>
+  static void f()
+  {
+    [](auto b) {
+      auto c = +b;
+    }(42);
+  }
+};
+
+int main()
+{
+  A<int>::f<int>();
+}
commit c6c77e3c274bc8a1bdd33be58895e1ae08a453a7
Author: Jason Merrill <ja...@redhat.com>
Date:   Thu Sep 28 16:07:34 2017 -0400

            PR c++/81525 - broken handling of auto in generic lambda.
    
            * pt.c (tsubst_decl) [VAR_DECL]: Use strip_innermost_template_args.

diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index c29c779a147..36c8c106439 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -13042,15 +13042,20 @@ tsubst_decl (tree t, tree args, tsubst_flags_t 
complain)
                && VAR_HAD_UNKNOWN_BOUND (t)
                && type != error_mark_node)
              type = strip_array_domain (type);
-           tree auto_node = type_uses_auto (type);
-           int len = TREE_VEC_LENGTH (args);
-           if (auto_node)
-             /* Mask off any template args past the variable's context so we
-                don't replace the auto with an unrelated argument.  */
-             TREE_VEC_LENGTH (args) = TEMPLATE_TYPE_LEVEL (auto_node) - 1;
-           type = tsubst (type, args, complain, in_decl);
-           if (auto_node)
-             TREE_VEC_LENGTH (args) = len;
+           tree sub_args = args;
+           if (tree auto_node = type_uses_auto (type))
+             {
+               /* Mask off any template args past the variable's context so we
+                  don't replace the auto with an unrelated argument.  */
+               int nouter = TEMPLATE_TYPE_LEVEL (auto_node) - 1;
+               int extra = TMPL_ARGS_DEPTH (args) - nouter;
+               if (extra > 0)
+                 /* This should never happen with the new lambda instantiation
+                    model, but keep the handling just in case.  */
+                 gcc_assert (!CHECKING_P),
+                 sub_args = strip_innermost_template_args (args, extra);
+             }
+           type = tsubst (type, sub_args, complain, in_decl);
          }
        if (VAR_P (r))
          {
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C 
b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C
new file mode 100644
index 00000000000..b9e98c551c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C
@@ -0,0 +1,19 @@
+// Related to c++/81525
+// { dg-do compile { target c++14 } }
+
+template <class X>
+struct A
+{
+  template <class T>
+  static void f()
+  {
+    [](auto b) {
+      auto c = +b;
+    }(42);
+  }
+};
+
+int main()
+{
+  A<int>::f<int>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4.C 
b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4.C
index d56f379c680..1cf85518813 100644
--- a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4.C
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4.C
@@ -1,5 +1,5 @@
 // PR c++/81525
-// { dg-do compile { target c++14 } }
+// { dg-do run { target c++14 } }
 
 template <int i> struct A {
   constexpr operator int () const { return i; }
@@ -13,7 +13,7 @@ template <typename T>
 void bar (T) {
   constexpr auto N = a<1>;
   auto f = [&] (auto i) {
-    return static_cast<int>(N) == 1;
+    if (static_cast<int>(N) != 1) __builtin_abort();
   };
   foo (f);
 }
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4a.C 
b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4a.C
new file mode 100644
index 00000000000..a6afb32584f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4a.C
@@ -0,0 +1,20 @@
+// PR c++/81525
+// { dg-do run { target c++14 } }
+
+template <int i> struct A {
+  constexpr operator int () const { return i; }
+};
+template <int i> constexpr A<i> a = {};
+
+template <typename F> void foo (F f) {
+  f (42);
+}
+template <typename T>
+void bar (T) {
+  constexpr auto N = a<1>;
+  auto f = [&] (auto i) {
+    if (static_cast<decltype(i)>(N) != 1) __builtin_abort();
+  };
+  foo (f);
+}
+int main () { bar (0); }

Reply via email to