c++: wrong pretty printing of nested type [PR95303]
authorPatrick Palka <ppalka@redhat.com>
Tue, 7 Jul 2020 20:33:12 +0000 (16:33 -0400)
committerPatrick Palka <ppalka@redhat.com>
Tue, 7 Jul 2020 20:33:12 +0000 (16:33 -0400)
In the testcase below, we pretty print the nested type A<int>::B as
A<int>::B<int> because we don't check whether B is itself a class
template before printing the innermost set of template arguments from
B's TEMPLATE_INFO (which in this case belong to A).  This patch fixes
this by checking PRIMARY_TEMPLATE_P beforehand.

gcc/cp/ChangeLog:

PR c++/95303
* cxx-pretty-print.c (pp_cxx_unqualified_id): Check
PRIMARY_TEMPLATE_P before printing the innermost template
arguments.

gcc/testsuite/ChangeLog:

PR c++/95303
* g++.dg/concepts/diagnostic14.C: New test.

gcc/cp/cxx-pretty-print.c
gcc/testsuite/g++.dg/concepts/diagnostic14.C [new file with mode: 0644]

index 188462a79e7179e49a741500f1d21939e292ad23..263f225a492e27a5b103430f675c2b9499d98b2d 100644 (file)
@@ -173,12 +173,13 @@ pp_cxx_unqualified_id (cxx_pretty_printer *pp, tree t)
     case UNBOUND_CLASS_TEMPLATE:
       pp_cxx_unqualified_id (pp, TYPE_NAME (t));
       if (tree ti = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (t))
-       {
-         pp_cxx_begin_template_argument_list (pp);
-         tree args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti));
-         pp_cxx_template_argument_list (pp, args);
-         pp_cxx_end_template_argument_list (pp);
-       }
+       if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (ti)))
+         {
+           pp_cxx_begin_template_argument_list (pp);
+           tree args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti));
+           pp_cxx_template_argument_list (pp, args);
+           pp_cxx_end_template_argument_list (pp);
+         }
       break;
 
     case BIT_NOT_EXPR:
diff --git a/gcc/testsuite/g++.dg/concepts/diagnostic14.C b/gcc/testsuite/g++.dg/concepts/diagnostic14.C
new file mode 100644 (file)
index 0000000..ec2b68c
--- /dev/null
@@ -0,0 +1,36 @@
+// PR c++/95303
+// { dg-do compile { target c++20 } }
+
+template<class>
+struct A {
+    struct B {};
+};
+
+template<class T>
+  requires __is_same(T, char)
+struct A<T> {
+    struct B {};
+};
+
+template<>
+  struct A<bool> {
+    struct B {};
+  };
+
+template<class T>
+concept C = requires (T&& t) { // { dg-message "\\\[with T = A<int>::B\\\]" }
+    t.a;
+};
+static_assert(C<A<int>::B>); // { dg-error "failed" }
+
+template<class T>
+concept D = requires (T&& t) { // { dg-message "\\\[with T = A<char>::B\\\]" }
+    t.a;
+};
+static_assert(D<A<char>::B>); // { dg-error "failed" }
+
+template<class T>
+concept E = requires (T&& t) { // { dg-message "\\\[with T = A<bool>::B\\\]" }
+    t.a;
+};
+static_assert(E<A<bool>::B>); // { dg-error "failed" }