Re: [PATCH] c++, v2: Improve diagnostics for nullptr_t/info [PR126343]
Jason Merrill <[email protected]>
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <[email protected]> |
On 7/27/26 4:40 PM, Jakub Jelinek wrote: > On Fri, Jul 24, 2026 at 03:06:14PM -0400, Jason Merrill wrote: >> On 7/22/26 4:44 AM, Jakub Jelinek wrote: >>> We currently print std::nullptr_t or std::meta::info in diagnostics >>> when seeing a NULLPTR_TYPE or META_TYPE, when they aren't type aliases >>> (or when they are exactly those type aliases). >>> I think that isn't a bad idea, the aliases is what users usually >>> use for those. There are 2 problems with this though. >>> We print >>> decltype(nullptr) >>> and >>> decltype(nullptr) const volatile >>> exactly the same, both as std::nullptr_t, so the qualifiers are lost. >>> And, e.g. in case of a static assertion failure when people want to find >>> out why some reflections aren't equal we can print >>> note: the comparison reduces to '(^^std::meta::info == ^^std::meta:info)' >>> and the user then has no idea what is going on. Is it because one of >>> those is a type alias (which one), or because of cv-qual differences, >>> or both? >>> The following patch prints the aliases in normal %qT etc. printing >>> only if unqualified, when qualified prints decltype(^^int) or >>> decltype(nullptr) with the qualifications. >>> And, when printing a reflection expression, it differentiates even >>> between the type alias case and non-alias. >>> >>> So far lightly tested, ok for trunk if it passes full bootstrap/regtest? >>> >>> Or do you prefer always printing decltype? >> >> In the non-reflection case, we could continue to always print nullptr_t and >> info, just add the cv-quals? > > Ok, here is an updated version which does it that way. > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? OK. > 2026-07-27 Jakub Jelinek <[email protected]> > > PR c++/126343 > * error.cc (dump_type) <case NULLPTR_TYPE>: Call > pp_c_type_qualifier_list. > (dump_type) <case META_TYPE>: Likewise. > (dump_expr) <case REFLECT_EXPR>: For REFLECT_EXPR on > non-typedef META_TYPE or NULLPTR_TYPE print > decltype(^^int) or decltype(nullptr). > > * g++.dg/reflect/pr126343.C: New test. > * g++.dg/reflect/diag6.C: Adjust expected diagnostic wording. > * g++.dg/reflect/init2.C: Likewise. > * g++.dg/cpp0x/pr124489.C: Likewise. > > --- gcc/cp/error.cc.jj 2026-07-22 11:41:35.683252926 +0200 > +++ gcc/cp/error.cc 2026-07-26 15:40:27.586800726 +0200 > @@ -876,10 +876,12 @@ dump_type (cxx_pretty_printer *pp, tree > > case NULLPTR_TYPE: > pp_cxx_ws_string (pp, "std::nullptr_t"); > + pp_c_type_qualifier_list (pp, t); > break; > > case META_TYPE: > pp_cxx_ws_string (pp, "std::meta::info"); > + pp_c_type_qualifier_list (pp, t); > break; > > case SPLICE_SCOPE: > @@ -3481,7 +3483,24 @@ dump_expr (cxx_pretty_printer *pp, tree > if (DECL_P (h)) > dump_decl (pp, h, flags); > else if (TYPE_P (h)) > - dump_type (pp, h, flags); > + { > + /* For reflection we care about the difference > + between std::meta::info/std::nullptr_t and > + decltype(^^int)/decltype(nullptr). */ > + if (TREE_CODE (h) == META_TYPE && !typedef_variant_p (h)) > + { > + pp_cxx_ws_string (pp, "decltype(^^int)"); > + pp_c_type_qualifier_list (pp, h); > + } > + else if (TREE_CODE (h) == NULLPTR_TYPE > + && !typedef_variant_p (h)) > + { > + pp_cxx_ws_string (pp, "decltype(nullptr)"); > + pp_c_type_qualifier_list (pp, h); > + } > + else > + dump_type (pp, h, flags); > + } > else > dump_expr (pp, h, flags); > break; > --- gcc/testsuite/g++.dg/cpp0x/pr124489.C.jj 2026-03-27 10:17:15.510308285 +0100 > +++ gcc/testsuite/g++.dg/cpp0x/pr124489.C 2026-07-26 16:08:22.216399495 +0200 > @@ -4,6 +4,6 @@ > void > g () > { > - constexpr decltype(nullptr) dm = nullptr; // { dg-message ".constexpr std::nullptr_t dm. previously declared here" } > - constexpr decltype(nullptr) dm = nullptr; // { dg-error "redeclaration of .constexpr std::nullptr_t dm." } > + constexpr decltype(nullptr) dm = nullptr; // { dg-message ".constexpr std::nullptr_t const dm. previously declared here" } > + constexpr decltype(nullptr) dm = nullptr; // { dg-error "redeclaration of .constexpr std::nullptr_t const dm." } > } > --- gcc/testsuite/g++.dg/reflect/pr126343.C.jj 2026-07-26 15:38:12.536398557 +0200 > +++ gcc/testsuite/g++.dg/reflect/pr126343.C 2026-07-26 15:38:12.536398557 +0200 > @@ -0,0 +1,43 @@ > +// PR c++/126343 > +// { dg-do compile { target c++26 } } > +// { dg-additional-options "-freflection" } > +namespace std { > + namespace meta { > + using info = decltype (^^::); > + } > + using nullptr_t = decltype (nullptr); > +} > +namespace my { > + using info = decltype (^^::) const; > + using nullptr_t = volatile decltype (nullptr); > +} > +constexpr auto a = ^^decltype (^^int); > +constexpr auto b = ^^decltype (nullptr); > +constexpr auto c = ^^const decltype (^^int); > +constexpr auto d = ^^const decltype (nullptr); > +constexpr auto e = ^^decltype (^^int) const volatile; > +constexpr auto f = ^^decltype (nullptr) volatile; > +constexpr auto g = ^^std::meta::info; > +constexpr auto h = ^^std::nullptr_t; > +constexpr auto i = ^^my::info; > +constexpr auto j = ^^my::nullptr_t; > +static_assert (a == ^^char); // { dg-error "static assertion " } > + // { dg-message "note: the comparison reduces to '\\\(\\\^\\\^decltype\\\(\\\^\\\^int\\\) == \\\^\\\^char\\\)'" "" { target *-*-* } .-1 } > +static_assert (b == ^^short); // { dg-error "static assertion " } > + // { dg-message "note: the comparison reduces to '\\\(\\\^\\\^decltype\\\(nullptr\\\) == \\\^\\\^short int\\\)'" "" { target *-*-* } .-1 } > +static_assert (c == ^^int); // { dg-error "static assertion " } > + // { dg-message "note: the comparison reduces to '\\\(\\\^\\\^decltype\\\(\\\^\\\^int\\\) const == \\\^\\\^int\\\)'" "" { target *-*-* } .-1 } > +static_assert (d == ^^long); // { dg-error "static assertion " } > + // { dg-message "note: the comparison reduces to '\\\(\\\^\\\^decltype\\\(nullptr\\\) const == \\\^\\\^long int\\\)'" "" { target *-*-* } .-1 } > +static_assert (e == ^^long long); // { dg-error "static assertion " } > + // { dg-message "note: the comparison reduces to '\\\(\\\^\\\^decltype\\\(\\\^\\\^int\\\) const volatile == \\\^\\\^long long int\\\)'" "" { target *-*-* } .-1 } > +static_assert (f == ^^unsigned char); // { dg-error "static assertion " } > + // { dg-message "note: the comparison reduces to '\\\(\\\^\\\^decltype\\\(nullptr\\\) volatile == \\\^\\\^unsigned char\\\)'" "" { target *-*-* } .-1 } > +static_assert (g == ^^unsigned short); // { dg-error "static assertion " } > + // { dg-message "note: the comparison reduces to '\\\(\\\^\\\^std::meta::info == \\\^\\\^short unsigned int\\\)'" "" { target *-*-* } .-1 } > +static_assert (h == ^^unsigned int); // { dg-error "static assertion " } > + // { dg-message "note: the comparison reduces to '\\\(\\\^\\\^std::nullptr_t == \\\^\\\^unsigned int\\\)'" "" { target *-*-* } .-1 } > +static_assert (i == ^^unsigned long); // { dg-error "static assertion " } > + // { dg-message "note: the comparison reduces to '\\\(\\\^\\\^my::info == \\\^\\\^long unsigned int\\\)'" "" { target *-*-* } .-1 } > +static_assert (j == ^^unsigned long long);// { dg-error "static assertion " } > + // { dg-message "note: the comparison reduces to '\\\(\\\^\\\^my::nullptr_t == \\\^\\\^long long unsigned int\\\)'" "" { target *-*-* } .-1 } > --- gcc/testsuite/g++.dg/reflect/diag6.C.jj 2026-07-22 11:41:35.685252899 +0200 > +++ gcc/testsuite/g++.dg/reflect/diag6.C 2026-07-26 16:09:48.561296031 +0200 > @@ -5,6 +5,6 @@ > void > g () > { > - constexpr decltype(^^::) dm = ^^int; // { dg-message ".constexpr std::meta::info dm. previously declared here" } > - constexpr decltype(^^::) dm = ^^int; // { dg-error "redeclaration of .constexpr std::meta::info dm." } > + constexpr decltype(^^::) dm = ^^int; // { dg-message ".constexpr std::meta::info const dm. previously declared here" } > + constexpr decltype(^^::) dm = ^^int; // { dg-error "redeclaration of .constexpr std::meta::info const dm." } > } > --- gcc/testsuite/g++.dg/reflect/init2.C.jj 2026-07-22 11:41:35.685252899 +0200 > +++ gcc/testsuite/g++.dg/reflect/init2.C 2026-07-26 16:10:21.208878807 +0200 > @@ -8,7 +8,7 @@ f () > constexpr static auto srefl = ^^int; > constexpr auto *p = &srefl; > constexpr auto **q = &p; // { dg-error "unable to deduce" } > - // { dg-message "types .auto\\*. and .std::meta::info\\* const." "" { target *-*-* } .-1 } > + // { dg-message "types .auto\\*. and .std::meta::info const\\* const." "" { target *-*-* } .-1 } > } > > void > > > Jakub >