Re: [PATCH] c++: Improve printing of null pointer to data member constants [PR126599]
Jason Merrill <[email protected]> Tue, 4 Aug 2026 12:28:06 -0400
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
On 8/4/26 3:46 AM, Jakub Jelinek wrote: > Hi! > > For null pointer to data member we use INTEGER_CST with OFFSET_TYPE > and -1 value. When that is printed in diagnostics or in > display_string_of, it is printed as -1, which is confusing to users > and an implementation detail (well, part of ABI > https://itanium-cxx-abi.github.io/cxx-abi/abi.html#data-member-pointers > A null data member pointer is represented as an offset of -1. > ). > Now, as the first testcase shows, if we have a non-null pointer to data > member constant, it is actually PTRMEM_CST and is printed in a user-friendly > way, the following patch just arranges to print the OFFSET_TYPE -1 > INTEGER_CST similarly. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2026-08-04 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/reflect/display_string_of1.C: Add 2 new tests. > * g++.dg/reflect/u8display_string_of1.C: Likewise. > > --- gcc/cp/error.cc.jj 2026-07-31 08:37:07.905871693 +0200 > +++ gcc/cp/error.cc 2026-08-03 17:33:12.517674249 +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); It looks like you don't test the C++98 case. > + 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-03 17:16:01.549113408 +0200 > +++ gcc/testsuite/g++.dg/diagnostic/ptrtomem5.C 2026-08-03 17:15:09.305755762 +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/reflect/display_string_of1.C.jj 2026-04-01 00:03:32.626089610 +0200 > +++ gcc/testsuite/g++.dg/reflect/display_string_of1.C 2026-08-03 17:22:28.415414943 +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-04-01 00:03:32.626244353 +0200 > +++ gcc/testsuite/g++.dg/reflect/u8display_string_of1.C 2026-08-03 17:24:08.416213148 +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 >