c++: wrong pretty printing of nested type [PR95303]

Message ID 20200707133327.1377955-2-ppalka@redhat.com
State New
Headers show
Series
  • c++: wrong pretty printing of nested type [PR95303]
Related show

Commit Message

Jason Merrill via Gcc-patches July 7, 2020, 1:33 p.m.
In the testcase below, we pretty print the nested type A<int>::B as
A<int>::B<int> because we don't check that B is itself a class template
before printing the innermost set of template arguments from B's
TEMPLATE_INFO (which in this case belongs to A).  This patch fixes this
by checking PRIMARY_TEMPLATE_P beforehand.

Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK to
commit to trunk and perhaps to the 10 branch?

gcc/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                    | 13 +++----
 gcc/testsuite/g++.dg/concepts/diagnostic14.C | 36 ++++++++++++++++++++
 2 files changed, 43 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic14.C

-- 
2.27.0.203.gf402ea6816

Comments

Jason Merrill via Gcc-patches July 7, 2020, 7:13 p.m. | #1
On 7/7/20 9:33 AM, Patrick Palka wrote:
> In the testcase below, we pretty print the nested type A<int>::B as

> A<int>::B<int> because we don't check that B is itself a class template

> before printing the innermost set of template arguments from B's

> TEMPLATE_INFO (which in this case belongs to A).  This patch fixes this

> by checking PRIMARY_TEMPLATE_P beforehand.

> 

> Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK to

> commit to trunk and perhaps to the 10 branch?


OK for trunk, this doesn't seem worth backporting.

> gcc/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                    | 13 +++----

>   gcc/testsuite/g++.dg/concepts/diagnostic14.C | 36 ++++++++++++++++++++

>   2 files changed, 43 insertions(+), 6 deletions(-)

>   create mode 100644 gcc/testsuite/g++.dg/concepts/diagnostic14.C

> 

> diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c

> index 188462a79e7..263f225a492 100644

> --- a/gcc/cp/cxx-pretty-print.c

> +++ b/gcc/cp/cxx-pretty-print.c

> @@ -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

> index 00000000000..ec2b68c4a3c

> --- /dev/null

> +++ b/gcc/testsuite/g++.dg/concepts/diagnostic14.C

> @@ -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" }

>

Patch

diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 188462a79e7..263f225a492 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -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
index 00000000000..ec2b68c4a3c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/diagnostic14.C
@@ -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" }