On 9 Jan 2025, at 18:05, Patrick Palka wrote: > On Wed, 8 Jan 2025, Jason Merrill wrote: > >> On 12/21/24 11:35 AM, Simon Martin wrote: >>> When erroring out due to an incomplete type, we add a contextual >>> note >>> about the type. However, when the error is suppressed by >>> -Wno-template-body, the note remains, making the compiler output >>> quite >>> puzzling. >>> >>> This patch makes sure the note is suppressed if we're processing a >>> template declaration body with -Wno-template-body. >>> >>> Successfully tested on x86_64-pc-linux-gnu. >>> >>> PR c++/118163 >>> >>> gcc/cp/ChangeLog: >>> >>> * cp-tree.h (get_current_template): Declare. >>> * error.cc (get_current_template): Make non static. >>> * typeck2.cc (cxx_incomplete_type_inform): Suppress note when >>> parsing a template declaration with -Wno-template-body. >> >> I think rather than adding this sort of thing in lots of places where >> an error >> is followed by an inform, we should change error to return bool like >> other >> diagnostic functions, and check its return value before calling >> cxx_incomplete_type_inform or plain inform. This likely involves the >> same >> number of changes, but they should be smaller. >> >> Patrick, what do you think? > > That makes sense to me, it's consistent with the 'warning' API and how > we handle issuing a warning followed by a note. But since the > -Wtemplate-body mechanism is really only useful for compiling legacy > code where you don't really care about any diagnostics anyway, and > the intended way to use it is -fpermissive / -Wno-error=template-body > rather than -Wno-template-body, I'd prefer a less invasive solution > that > doesn't change the API of 'error' if possible. What I like in Jason’s suggestion is that even though it’s a bit more invasive, you know exactly what you get when you call error.
Right now you know in >99% of the cases and it’s great. But when the diagnostics machinery does changes under you, the UX becomes weird for the end-user (this PR) or the GCC developer (see PR 118388 with seen_error and permerror). This PR is clearly not a burning issue, and it’s fine to only fix it in GCC 16 with a more robust fix. > > I wonder if we can work around this by taking advantage of the fact > that > notes that follow an error are expected to be linked via an active > auto_diagnostic_group? Roughly, if we issued a -Wtemplate-body > diagnostic from an active auto_diagnostic_group then all other > diagnostics from that auto_diagnostic_group should also be associated > with -Wtemplate-body, including notes. That way -Wno-template-body > will > effectively suppress subsequent notes followed by an eligible error, > and > no 'error' callers need to be changed (unless to use > auto_diagnostic_group). > > Another simpler approach, maybe for templates that have already been > deemed erroneous, and -Wno-template-body is active, we could suppress > all subsequent diagnostics, including warnings/notes. > >> >>> gcc/testsuite/ChangeLog: >>> >>> * g++.dg/diagnostic/incomplete-type-2.C: New test. >>> * g++.dg/diagnostic/incomplete-type-2a.C: New test. >>> >>> --- >>> gcc/cp/cp-tree.h | 1 + >>> gcc/cp/error.cc | 2 +- >>> gcc/cp/typeck2.cc | 6 ++++++ >>> gcc/testsuite/g++.dg/diagnostic/incomplete-type-2.C | 7 +++++++ >>> .../g++.dg/diagnostic/incomplete-type-2a.C | 13 >>> +++++++++++++ >>> 5 files changed, 28 insertions(+), 1 deletion(-) >>> create mode 100644 >>> gcc/testsuite/g++.dg/diagnostic/incomplete-type-2.C >>> create mode 100644 >>> gcc/testsuite/g++.dg/diagnostic/incomplete-type-2a.C >>> >>> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h >>> index 6de8f64b5ee..52f954b63d9 100644 >>> --- a/gcc/cp/cp-tree.h >>> +++ b/gcc/cp/cp-tree.h >>> @@ -7297,6 +7297,7 @@ struct decl_location_traits >>> typedef hash_map<tree, location_t, decl_location_traits> >>> erroneous_templates_t; >>> extern GTY((cache)) erroneous_templates_t *erroneous_templates; >>> +extern tree get_current_template (); >>> extern bool cp_seen_error (); >>> #define seen_error() cp_seen_error () >>> diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc >>> index 8c0644fba7e..7fd03dd6d12 100644 >>> --- a/gcc/cp/error.cc >>> +++ b/gcc/cp/error.cc >>> @@ -197,7 +197,7 @@ class cxx_format_postprocessor : public >>> format_postprocessor >>> /* Return the in-scope template that's currently being parsed, or >>> NULL_TREE otherwise. */ >>> -static tree >>> +tree >>> get_current_template () >>> { >>> if (scope_chain && in_template_context && !current_instantiation >>> ()) >>> diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc >>> index fce687e83b3..505c143dae7 100644 >>> --- a/gcc/cp/typeck2.cc >>> +++ b/gcc/cp/typeck2.cc >>> @@ -273,6 +273,12 @@ cxx_incomplete_type_inform (const_tree type) >>> if (!TYPE_MAIN_DECL (type)) >>> return; >>> + /* When processing a template declaration body, the error >>> generated by >>> the >>> + caller (if any) might have been suppressed by >>> -Wno-template-body. If >>> that >>> + is the case, suppress the inform as well. */ >>> + if (!warn_template_body && get_current_template ()) >>> + return; >>> + >>> location_t loc = DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)); >>> tree ptype = strip_top_quals (CONST_CAST_TREE (type)); >>> diff --git a/gcc/testsuite/g++.dg/diagnostic/incomplete-type-2.C >>> b/gcc/testsuite/g++.dg/diagnostic/incomplete-type-2.C >>> new file mode 100644 >>> index 00000000000..e2fb20a4ae8 >>> --- /dev/null >>> +++ b/gcc/testsuite/g++.dg/diagnostic/incomplete-type-2.C >>> @@ -0,0 +1,7 @@ >>> +// PR c++/118163 >>> +// { dg-do "compile" } >>> + >>> +template<class T> >>> +struct S { // { dg-note "until the closing brace" } >>> + S s; // { dg-error "has incomplete type" } >>> +}; >>> diff --git a/gcc/testsuite/g++.dg/diagnostic/incomplete-type-2a.C >>> b/gcc/testsuite/g++.dg/diagnostic/incomplete-type-2a.C >>> new file mode 100644 >>> index 00000000000..d13021d0b68 >>> --- /dev/null >>> +++ b/gcc/testsuite/g++.dg/diagnostic/incomplete-type-2a.C >>> @@ -0,0 +1,13 @@ >>> +// PR c++/118163 >>> +// { dg-do "compile" } >>> +// { dg-additional-options "-Wno-template-body" } >>> + >>> +template<class T> >>> +struct S { // { dg-bogus "until the closing brace" } >>> + S s; // { dg-bogus "has incomplete type" } >>> +}; >>> + >>> +// Check that we don't suppress errors outside of the body. >>> +struct forward_decl; // { dg-note "forward declaration" } >>> +template<class T> >>> +void foo (forward_decl) {} // { dg-error "has incomplete type" } >> >>