PR c++/81525 - broken handling of auto in generic lambda.
authorJason Merrill <jason@redhat.com>
Wed, 4 Oct 2017 15:37:09 +0000 (11:37 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 4 Oct 2017 15:37:09 +0000 (11:37 -0400)
* pt.c (tsubst_decl) [VAR_DECL]: Use strip_innermost_template_args.

From-SVN: r253414

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

index 0d20ea5..b1eaaba 100644 (file)
@@ -1,3 +1,8 @@
+2017-10-04  Jason Merrill  <jason@redhat.com>
+
+       PR c++/81525 - broken handling of auto in generic lambda.
+       * pt.c (tsubst_decl) [VAR_DECL]: Use strip_innermost_template_args.
+
 2017-10-04  Nathan Sidwell  <nathan@acm.org>
 
        * call.c (convert_arg_to_ellipsis): Correct comment about passing
index c29c779..36c8c10 100644 (file)
@@ -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 (file)
index 0000000..b9e98c5
--- /dev/null
@@ -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>();
+}
index d56f379..1cf8551 100644 (file)
@@ -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 (file)
index 0000000..a6afb32
--- /dev/null
@@ -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); }