Re: [PATCH] c++: Improve printing of pointers-to-members [PR97406, PR85901]

2020-10-15 Thread Jason Merrill via Gcc-patches

On 10/14/20 3:52 PM, Marek Polacek wrote:

This PR points out that when printing the parameter mapping for a
pointer-to-member-function, the output was truncated:

   [with T = void (X::*]

Fixed by printing the abstract declarator for pointers-to-members in
cxx_pretty_printer::type_id.  So now we print:

   [with T = void (X::*)()]

But when I tried a pointer-to-data-member, I got

   [with T = ‘offset_type’ not supported by simple_type_specifier)‘offset_type’ 
not supported by direct_abstract_declarator]

so had to fix that too so that we now print:

   [with T = int X::*]

or

   [with T = int (X::*)[5]]

when the type is an array type.  Which is what PR85901 was about.

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


OK.


gcc/cp/ChangeLog:

PR c++/97406
PR c++/85901
* cxx-pretty-print.c (pp_cxx_type_specifier_seq): Handle OFFSET_TYPE.
(cxx_pretty_printer::abstract_declarator): Fix the printing of ')'.
(cxx_pretty_printer::direct_abstract_declarator): Handle OFFSET_TYPE.
(cxx_pretty_printer::type_id): Likewise.  Print the abstract declarator
for pointers-to-members.

gcc/testsuite/ChangeLog:

PR c++/97406
PR c++/85901
* g++.dg/diagnostic/ptrtomem1.C: New test.
* g++.dg/diagnostic/ptrtomem2.C: New test.
---
  gcc/cp/cxx-pretty-print.c   | 33 -
  gcc/testsuite/g++.dg/diagnostic/ptrtomem1.C | 31 +++
  gcc/testsuite/g++.dg/diagnostic/ptrtomem2.C | 14 +
  3 files changed, 77 insertions(+), 1 deletion(-)
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/ptrtomem1.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/ptrtomem2.C

diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 8bea79b93a2..058b9c2f4fc 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -1420,6 +1420,16 @@ pp_cxx_type_specifier_seq (cxx_pretty_printer *pp, tree 
t)
}
/* fall through */
  
+case OFFSET_TYPE:

+  if (TYPE_PTRDATAMEM_P (t))
+   {
+ pp_cxx_type_specifier_seq (pp, TREE_TYPE (t));
+ pp_cxx_whitespace (pp);
+ pp_cxx_ptr_operator (pp, t);
+ break;
+   }
+  /* fall through */
+
  default:
if (!(TREE_CODE (t) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (t)))
pp_c_specifier_qualifier_list (pp, t);
@@ -1753,7 +1763,20 @@ pp_cxx_function_definition (cxx_pretty_printer *pp, tree 
t)
  void
  cxx_pretty_printer::abstract_declarator (tree t)
  {
-  if (TYPE_PTRMEM_P (t))
+  /* pp_cxx_ptr_operator prints '(' for a pointer-to-member function,
+ or a pointer-to-data-member of array type:
+
+   void (X::*)()
+   int (X::*)[5]
+
+ but not for a pointer-to-data-member of non-array type:
+
+   int X::*
+
+ so be mindful of that.  */
+  if (TYPE_PTRMEMFUNC_P (t)
+  || (TYPE_PTRDATAMEM_P (t)
+ && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE))
  pp_cxx_right_paren (this);
else if (INDIRECT_TYPE_P (t))
  {
@@ -1785,6 +1808,11 @@ cxx_pretty_printer::direct_abstract_declarator (tree t)
direct_abstract_declarator (TYPE_PTRMEMFUNC_FN_TYPE (t));
break;
  
+case OFFSET_TYPE:

+  if (TYPE_PTRDATAMEM_P (t))
+   direct_abstract_declarator (TREE_TYPE (t));
+  break;
+
  case METHOD_TYPE:
  case FUNCTION_TYPE:
pp_cxx_parameter_declaration_clause (this, t);
@@ -1837,7 +1865,10 @@ cxx_pretty_printer::type_id (tree t)
  case UNDERLYING_TYPE:
  case DECLTYPE_TYPE:
  case TEMPLATE_ID_EXPR:
+case OFFSET_TYPE:
pp_cxx_type_specifier_seq (this, t);
+  if (TYPE_PTRMEM_P (t))
+   abstract_declarator (t);
break;
  
  case TYPE_PACK_EXPANSION:

diff --git a/gcc/testsuite/g++.dg/diagnostic/ptrtomem1.C 
b/gcc/testsuite/g++.dg/diagnostic/ptrtomem1.C
new file mode 100644
index 000..bb1327f7af1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/ptrtomem1.C
@@ -0,0 +1,31 @@
+// PR c++/97406
+// { dg-do compile { target c++20 } }
+
+struct X {
+  void f() { }
+  int a;
+  int arr[5];
+};
+
+// Duplicated so that I can check dg-message.
+template
+requires (sizeof(T)==1) // { dg-message {\[with T = void \(X::\*\)\(\)\]} }
+void f1(T)
+{ }
+
+template
+requires (sizeof(T)==1) // { dg-message {\[with T = int X::\*\]} }
+void f2(T)
+{ }
+
+template
+requires (sizeof(T)==1) // dg-message {\[with T = int \(X::\*\)\[5\]\]} }
+void f3(T)
+{ }
+
+int main()
+{
+  f1(::f); // { dg-error "no matching function for call" }
+  f2(::a); // { dg-error "no matching function for call" }
+  f3(::arr); // { dg-error "no matching function for call" }
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/ptrtomem2.C 
b/gcc/testsuite/g++.dg/diagnostic/ptrtomem2.C
new file mode 100644
index 000..f3b29a07a99
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/ptrtomem2.C
@@ -0,0 +1,14 @@
+// PR c++/85901
+// { dg-do compile { target c++11 } }
+
+template struct A;
+

[PATCH] c++: Improve printing of pointers-to-members [PR97406, PR85901]

2020-10-14 Thread Marek Polacek via Gcc-patches
This PR points out that when printing the parameter mapping for a
pointer-to-member-function, the output was truncated:

  [with T = void (X::*]

Fixed by printing the abstract declarator for pointers-to-members in
cxx_pretty_printer::type_id.  So now we print:

  [with T = void (X::*)()]

But when I tried a pointer-to-data-member, I got

  [with T = ‘offset_type’ not supported by simple_type_specifier)‘offset_type’ 
not supported by direct_abstract_declarator]

so had to fix that too so that we now print:

  [with T = int X::*]

or

  [with T = int (X::*)[5]]

when the type is an array type.  Which is what PR85901 was about.

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

gcc/cp/ChangeLog:

PR c++/97406
PR c++/85901
* cxx-pretty-print.c (pp_cxx_type_specifier_seq): Handle OFFSET_TYPE.
(cxx_pretty_printer::abstract_declarator): Fix the printing of ')'.
(cxx_pretty_printer::direct_abstract_declarator): Handle OFFSET_TYPE.
(cxx_pretty_printer::type_id): Likewise.  Print the abstract declarator
for pointers-to-members.

gcc/testsuite/ChangeLog:

PR c++/97406
PR c++/85901
* g++.dg/diagnostic/ptrtomem1.C: New test.
* g++.dg/diagnostic/ptrtomem2.C: New test.
---
 gcc/cp/cxx-pretty-print.c   | 33 -
 gcc/testsuite/g++.dg/diagnostic/ptrtomem1.C | 31 +++
 gcc/testsuite/g++.dg/diagnostic/ptrtomem2.C | 14 +
 3 files changed, 77 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/ptrtomem1.C
 create mode 100644 gcc/testsuite/g++.dg/diagnostic/ptrtomem2.C

diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 8bea79b93a2..058b9c2f4fc 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -1420,6 +1420,16 @@ pp_cxx_type_specifier_seq (cxx_pretty_printer *pp, tree 
t)
}
   /* fall through */
 
+case OFFSET_TYPE:
+  if (TYPE_PTRDATAMEM_P (t))
+   {
+ pp_cxx_type_specifier_seq (pp, TREE_TYPE (t));
+ pp_cxx_whitespace (pp);
+ pp_cxx_ptr_operator (pp, t);
+ break;
+   }
+  /* fall through */
+
 default:
   if (!(TREE_CODE (t) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (t)))
pp_c_specifier_qualifier_list (pp, t);
@@ -1753,7 +1763,20 @@ pp_cxx_function_definition (cxx_pretty_printer *pp, tree 
t)
 void
 cxx_pretty_printer::abstract_declarator (tree t)
 {
-  if (TYPE_PTRMEM_P (t))
+  /* pp_cxx_ptr_operator prints '(' for a pointer-to-member function,
+ or a pointer-to-data-member of array type:
+
+   void (X::*)()
+   int (X::*)[5]
+
+ but not for a pointer-to-data-member of non-array type:
+
+   int X::*
+
+ so be mindful of that.  */
+  if (TYPE_PTRMEMFUNC_P (t)
+  || (TYPE_PTRDATAMEM_P (t)
+ && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE))
 pp_cxx_right_paren (this);
   else if (INDIRECT_TYPE_P (t))
 {
@@ -1785,6 +1808,11 @@ cxx_pretty_printer::direct_abstract_declarator (tree t)
direct_abstract_declarator (TYPE_PTRMEMFUNC_FN_TYPE (t));
   break;
 
+case OFFSET_TYPE:
+  if (TYPE_PTRDATAMEM_P (t))
+   direct_abstract_declarator (TREE_TYPE (t));
+  break;
+
 case METHOD_TYPE:
 case FUNCTION_TYPE:
   pp_cxx_parameter_declaration_clause (this, t);
@@ -1837,7 +1865,10 @@ cxx_pretty_printer::type_id (tree t)
 case UNDERLYING_TYPE:
 case DECLTYPE_TYPE:
 case TEMPLATE_ID_EXPR:
+case OFFSET_TYPE:
   pp_cxx_type_specifier_seq (this, t);
+  if (TYPE_PTRMEM_P (t))
+   abstract_declarator (t);
   break;
 
 case TYPE_PACK_EXPANSION:
diff --git a/gcc/testsuite/g++.dg/diagnostic/ptrtomem1.C 
b/gcc/testsuite/g++.dg/diagnostic/ptrtomem1.C
new file mode 100644
index 000..bb1327f7af1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/ptrtomem1.C
@@ -0,0 +1,31 @@
+// PR c++/97406
+// { dg-do compile { target c++20 } }
+
+struct X {
+  void f() { }
+  int a;
+  int arr[5];
+};
+
+// Duplicated so that I can check dg-message.
+template
+requires (sizeof(T)==1) // { dg-message {\[with T = void \(X::\*\)\(\)\]} }
+void f1(T)
+{ }
+
+template
+requires (sizeof(T)==1) // { dg-message {\[with T = int X::\*\]} }
+void f2(T)
+{ }
+
+template
+requires (sizeof(T)==1) // dg-message {\[with T = int \(X::\*\)\[5\]\]} }
+void f3(T)
+{ }
+
+int main()
+{
+  f1(::f); // { dg-error "no matching function for call" }
+  f2(::a); // { dg-error "no matching function for call" }
+  f3(::arr); // { dg-error "no matching function for call" }
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/ptrtomem2.C 
b/gcc/testsuite/g++.dg/diagnostic/ptrtomem2.C
new file mode 100644
index 000..f3b29a07a99
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/ptrtomem2.C
@@ -0,0 +1,14 @@
+// PR c++/85901
+// { dg-do compile { target c++11 } }
+
+template struct A;
+
+template
+struct A {
+template
+static auto c(int U::*p, TT o) -> decltype(o.*p);