[PATCH] c++, v2: Improve printing of null pointer to data member constants [PR126599]

Jakub Jelinek <[email protected]> Thu, 6 Aug 2026 19:45:56 +0200
Newsgroups gmane.comp.gcc.patches
Message-ID <anTIVLkI3omtbXxB@tucnak>
On Tue, Aug 04, 2026 at 12:28:06PM -0400, Jason Merrill wrote:
> It looks like you don't test the C++98 case.

Here is an updated patch with another testcase for C++98 to 29.

2026-08-06  Jakub Jelinek  <[email protected]>

	PR c++/126599
	* error.cc (dump_expr): Print OFFSET_TYPE -1 differently.

	* g++.dg/diagnostic/ptrtomem5.C: New test.
	* g++.dg/diagnostic/ptrtomem6.C: New test.
	* g++.dg/reflect/display_string_of1.C: Add 2 new tests.
	* g++.dg/reflect/u8display_string_of1.C: Likewise.

--- gcc/cp/error.cc.jj	2026-08-03 18:00:32.060597726 +0200
+++ gcc/cp/error.cc	2026-08-06 19:36:49.614253622 +0200
@@ -2474,8 +2474,23 @@ dump_expr (cxx_pretty_printer *pp, tree
 	pp_cxx_ws_string (pp, M_("<unknown>"));
       break;
 
-    case VOID_CST:
     case INTEGER_CST:
+      if (TYPE_PTRDATAMEM_P (TREE_TYPE (t)) && integer_all_onesp (t))
+	{
+	  /* OFFSET_TYPE -1 is a null pointer to member.  */
+	  if (flags & TFF_EXPR_IN_PARENS)
+	    pp_cxx_left_paren (pp);
+	  pp_cxx_left_paren (pp);
+	  dump_type (pp, TREE_TYPE (t), flags);
+	  pp_cxx_right_paren (pp);
+	  pp->constant (cxx_dialect < cxx11 ? null_pointer_node : nullptr_node);
+	  if (flags & TFF_EXPR_IN_PARENS)
+	    pp_cxx_right_paren (pp);
+	  break;
+	}
+      /* FALLTHRU */
+
+    case VOID_CST:
     case REAL_CST:
     case STRING_CST:
     case COMPLEX_CST:
--- gcc/testsuite/g++.dg/diagnostic/ptrtomem5.C.jj	2026-08-06 19:36:49.614816419 +0200
+++ gcc/testsuite/g++.dg/diagnostic/ptrtomem5.C	2026-08-06 19:36:49.614816419 +0200
@@ -0,0 +1,15 @@
+// PR c++/126599
+// { dg-do compile { target c++17 } }
+
+struct S { int s, t, u[3][3]; };
+using A = int[3][3];
+template <auto M>
+void foo (int);
+void
+bar ()
+{
+  foo <(int S::*)nullptr> ();	// { dg-error "no matching function for call to 'foo<\\\(\\\(int S::\\\*\\\)nullptr\\\)>\\\(\\\)'" }
+  foo <&S::s> ();		// { dg-error "no matching function for call to 'foo<\\\&S::s>\\\(\\\)'" }
+  foo <&S::t> ();		// { dg-error "no matching function for call to 'foo<\\\&S::t>\\\(\\\)'" }
+  foo <(A S::*)nullptr> ();	// { dg-error "no matching function for call to 'foo<\\\(\\\(int \\\(S::\\\*\\\)\\\[3\\\]\\\[3\\\]\\\)nullptr\\\)>\\\(\\\)'" }
+}
--- gcc/testsuite/g++.dg/diagnostic/ptrtomem6.C.jj	2026-08-06 19:37:11.867986696 +0200
+++ gcc/testsuite/g++.dg/diagnostic/ptrtomem6.C	2026-08-06 19:44:09.941972013 +0200
@@ -0,0 +1,7 @@
+// PR c++/126599
+// { dg-do compile }
+
+struct A { int a; };
+__attribute__((assume_aligned ((int A::*) 0))) int *foo ();
+// { dg-warning "'assume_aligned' attribute argument \\\(int A::\\\*\\\)0 is not positive" "" { target c++98_only } .-1 }
+// { dg-warning "'assume_aligned' attribute argument \\\(int A::\\\*\\\)nullptr is not positive" "" { target c++11 } .-2 }
--- gcc/testsuite/g++.dg/reflect/display_string_of1.C.jj	2026-08-03 18:00:32.061597713 +0200
+++ gcc/testsuite/g++.dg/reflect/display_string_of1.C	2026-08-06 19:36:49.615028703 +0200
@@ -135,6 +135,8 @@ foo (int a, const long b, T c, int d[4],
   static_assert (display_string_of (members_of (^^V4, ctx)[0]) == "V4& V4::operator+=(const V4&)");
   static_assert (display_string_of (members_of (^^V5, ctx)[0]) == "V5::operator int()");
   static_assert (display_string_of (^^operator""_a) == "int operator\"\"_a(const char*)");
+  static_assert (display_string_of (reflect_constant ((int U::*)nullptr)) == "(int U::*)nullptr");
+  static_assert (display_string_of (reflect_constant (&U::u)) == "&U::u");
 }
 
 namespace NS5 {
--- gcc/testsuite/g++.dg/reflect/u8display_string_of1.C.jj	2026-08-03 18:00:32.061597713 +0200
+++ gcc/testsuite/g++.dg/reflect/u8display_string_of1.C	2026-08-06 19:36:49.615212176 +0200
@@ -135,6 +135,8 @@ foo (int a, const long b, T c, int d[4],
   static_assert (u8display_string_of (members_of (^^V4, ctx)[0]) == u8"V4& V4::operator+=(const V4&)");
   static_assert (u8display_string_of (members_of (^^V5, ctx)[0]) == u8"V5::operator int()");
   static_assert (u8display_string_of (^^operator""_a) == u8"int operator\"\"_a(const char*)");
+  static_assert (u8display_string_of (reflect_constant ((int U::*)nullptr)) == u8"(int U::*)nullptr");
+  static_assert (u8display_string_of (reflect_constant (&U::u)) == u8"&U::u");
 }
 
 namespace NS5 {


	Jakub