Here we ICE on

  template<typename T, T = T{}> // #1
  struct A {};

  template<typename T> void foo(A<T>) {}

  void bar() { foo(A<char>()); }

when deducing T in the non-type template parameter, because unify didn't
expect a CONSTRUCTOR:

    default:
      /* An unresolved overload is a nondeduced context.  */
      if (is_overloaded_fn (parm) || type_unknown_p (parm))
        return unify_success (explain_p);
      gcc_assert (EXPR_P (parm) || TREE_CODE (parm) == TRAIT_EXPR);

This works if T{} is replaced with T() in #1 -- then unify gets a CAST_EXPR,
which is EXPR_P.

Since here we're in a non-deduced context, I think we should simply accept
the CONSTRUCTOR and return unify_success.

I've also updated a comment that has gotten obsolete now.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2019-06-18  Marek Polacek  <pola...@redhat.com>

        PR c++/60223 - ICE with T{} in non-deduced context.
        * pt.c (unify): Allow COMPOUND_LITERAL_P in a non-deduced context.
        Update a comment.

        * g++.dg/cpp0x/nondeduced1.C: New test.
        * g++.dg/cpp0x/nondeduced2.C: New test.
        * g++.dg/cpp0x/nondeduced3.C: New test.
        * g++.dg/cpp0x/nondeduced4.C: New test.

diff --git gcc/cp/pt.c gcc/cp/pt.c
index 2a626526c6f..69de55369dd 100644
--- gcc/cp/pt.c
+++ gcc/cp/pt.c
@@ -22786,7 +22786,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
       /* An unresolved overload is a nondeduced context.  */
       if (is_overloaded_fn (parm) || type_unknown_p (parm))
        return unify_success (explain_p);
-      gcc_assert (EXPR_P (parm) || TREE_CODE (parm) == TRAIT_EXPR);
+      gcc_assert (EXPR_P (parm)
+                 || COMPOUND_LITERAL_P (parm)
+                 || TREE_CODE (parm) == TRAIT_EXPR);
     expr:
       /* We must be looking at an expression.  This can happen with
         something like:
@@ -22794,15 +22796,19 @@ unify (tree tparms, tree targs, tree parm, tree arg, 
int strict,
           template <int I>
           void foo(S<I>, S<I + 2>);
 
-        This is a "nondeduced context":
+        or
+
+          template<typename T>
+          void foo(A<T, T{}>);
+
+        This is a "non-deduced context":
 
           [deduct.type]
 
-          The nondeduced contexts are:
+          The non-deduced contexts are:
 
-          --A type that is a template-id in which one or more of
-            the template-arguments is an expression that references
-            a template-parameter.
+          --A non-type template argument or an array bound in which
+            a subexpression references a template parameter.
 
         In these cases, we assume deduction succeeded, but don't
         actually infer any unifications.  */
diff --git gcc/testsuite/g++.dg/cpp0x/nondeduced1.C 
gcc/testsuite/g++.dg/cpp0x/nondeduced1.C
new file mode 100644
index 00000000000..067079e50df
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/nondeduced1.C
@@ -0,0 +1,16 @@
+// PR c++/60223
+// { dg-do compile { target c++11 } }
+
+template<typename T, T = T{}>
+struct A { };
+
+template<typename T>
+void foo(A<T> a);
+
+void bar()
+{
+  foo(A<char, char{}>());
+  foo(A<char>());
+  foo<>(A<char>());
+  foo<>(A<char, char{}>());
+}
diff --git gcc/testsuite/g++.dg/cpp0x/nondeduced2.C 
gcc/testsuite/g++.dg/cpp0x/nondeduced2.C
new file mode 100644
index 00000000000..3f96fe4e858
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/nondeduced2.C
@@ -0,0 +1,14 @@
+// PR c++/60223
+// { dg-do compile { target c++11 } }
+
+template<typename T, T>
+struct A { };
+
+template<typename T>
+void foo(A<T, T{}>);
+
+void bar()
+{
+  foo(A<char, char{}>());
+  foo<>(A<char, char{}>());
+}
diff --git gcc/testsuite/g++.dg/cpp0x/nondeduced3.C 
gcc/testsuite/g++.dg/cpp0x/nondeduced3.C
new file mode 100644
index 00000000000..d943dceea4b
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/nondeduced3.C
@@ -0,0 +1,16 @@
+// PR c++/60223
+// { dg-do compile { target c++11 } }
+
+template<typename T, T = T{1}>
+struct A { };
+
+template<typename T>
+void foo(A<T> a);
+
+void bar()
+{
+  foo(A<char>());
+  foo(A<char, char{1}>());
+  foo<>(A<char>());
+  foo<>(A<char, char{1}>());
+}
diff --git gcc/testsuite/g++.dg/cpp0x/nondeduced4.C 
gcc/testsuite/g++.dg/cpp0x/nondeduced4.C
new file mode 100644
index 00000000000..818034c857c
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/nondeduced4.C
@@ -0,0 +1,13 @@
+// PR c++/60223
+// { dg-do compile { target c++11 } }
+
+template<typename T>
+struct A { };
+
+template<typename T>
+void foo(A<T>, T = T{});
+
+void bar()
+{
+  foo(A<int>());
+}

Reply via email to