On Mon, 5 Aug 2024, Jason Merrill wrote: > On 8/5/24 1:14 PM, Patrick Palka wrote: > > On Mon, 5 Aug 2024, Jason Merrill wrote: > > > > > On 8/2/24 4:18 PM, Patrick Palka wrote: > > > > On Fri, 2 Aug 2024, Patrick Palka wrote: > > > > > > > > > On Fri, 2 Aug 2024, Jason Merrill wrote: > > > > > > > > > > > On 8/1/24 2:52 PM, Patrick Palka wrote: > > > > > > > In recent versions of GCC we've been diagnosing more and more > > > > > > > kinds of > > > > > > > errors inside a template ahead of time. This is a largely good > > > > > > > thing > > > > > > > because it catches bugs, typos, dead code etc sooner. > > > > > > > > > > > > > > But if the template never gets instantiated then such errors are > > > > > > > harmless, and can be inconvenient to work around if say the code > > > > > > > in > > > > > > > question is third party and in maintenence mode. So it'd be > > > > > > > useful to > > > > > > > > > > > > "maintenance" > > > > > > > > > > Fixed > > > > > > > > > > > > > > > > > > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc > > > > > > > index d80bac822ba..0bb0a482e28 100644 > > > > > > > --- a/gcc/cp/error.cc > > > > > > > +++ b/gcc/cp/error.cc > > > > > > > @@ -165,6 +165,58 @@ class cxx_format_postprocessor : public > > > > > > > format_postprocessor > > > > > > > deferred_printed_type m_type_b; > > > > > > > }; > > > > > > > +/* A map from TEMPLATE_DECL to the location of the first > > > > > > > error (if > > > > > > > any) > > > > > > > + within the template that we permissivly downgraded to a > > > > > > > warning. > > > > > > > */ > > > > > > > > > > > > "permissively" > > > > > > > > > > Fixed > > > > > > > > > > > > > > > > > > +relaxed_template_errors_t *relaxed_template_errors; > > > > > > > + > > > > > > > +/* Callback function > > > > > > > diagnostic_context::m_adjust_diagnostic_info. > > > > > > > + > > > > > > > + In -fpermissive mode we downgrade errors within a template to > > > > > > > + warnings, and only issue an error if we later need to > > > > > > > instantiate > > > > > > > + the template. */ > > > > > > > + > > > > > > > +static void > > > > > > > +cp_adjust_diagnostic_info (diagnostic_context *context, > > > > > > > + diagnostic_info *diagnostic) > > > > > > > +{ > > > > > > > + tree ti; > > > > > > > + if (diagnostic->kind == DK_ERROR > > > > > > > + && context->m_permissive > > > > > > > + && !current_instantiation () > > > > > > > + && in_template_context > > > > > > > + && (ti = get_template_info (current_scope ()))) > > > > > > > + { > > > > > > > + if (!relaxed_template_errors) > > > > > > > + relaxed_template_errors = new relaxed_template_errors_t; > > > > > > > + > > > > > > > + tree tmpl = TI_TEMPLATE (ti); > > > > > > > + if (!relaxed_template_errors->get (tmpl)) > > > > > > > + relaxed_template_errors->put (tmpl, > > > > > > > diagnostic->richloc->get_loc ()); > > > > > > > + diagnostic->kind = DK_WARNING; > > > > > > > > > > > > Rather than check m_permissive directly and downgrade to DK_WARNING, > > > > > > how > > > > > > about > > > > > > downgrading to DK_PERMERROR? That way people will get the > > > > > > [-fpermissive] > > > > > > clue. > > > > > > > > > > > > ...though I suppose DK_PERMERROR doesn't work where you call this > > > > > > hook > > > > > > in > > > > > > report_diagnostic, at which point we've already reassigned it into > > > > > > DK_WARNING > > > > > > or DK_ERROR in diagnostic_impl. > > > > > > > > > > > > But we could still set diagnostic->option_index even for DK_ERROR, > > > > > > whether to > > > > > > context->m_opt_permissive or to its own warning flag, perhaps > > > > > > -Wno-template-body? > > > > > > > > > > Fixed by adding an enabled-by-default -Wtemplate-body flag and setting > > > > > option_index to it for each downgraded error. Thus -permissive > > > > > -Wno-template-body would suppress the downgraded warnings entirely, > > > > > and > > > > > only issue a generic error upon instantiation of the erroneous > > > > > template. > > > > > > > > ... or did you have in mind to set option_index even when not using > > > > -fpermissive so that eligible non-downgraded errors get the > > > > [-fpermissive] or [-Wtemplate-body] hint as well? > > > > > > Yes. > > > > > > > IMHO I'm not sure that'd be worth the extra noise since the vast > > > > majority of users appreciate and expect errors to get diagnosed inside > > > > templates. > > > > > > But people trying to build legacy code should appreciate the pointer for > > > how > > > to make it compile, as with other permerrors. > > > > > > > And on second thought I'm not sure what extra value a new warning flag > > > > adds either. I can't think of a good reason why one would use > > > > -fpermissive -Wno-template-body? > > > > > > One would use -Wno-template-body (or -Wno-error=template-body) without > > > -fpermissive, like with the various permerror_opt cases. > > > > Since compiling legacy/unmaintained code is the only plausible use case, > > why have a dedicated warning flag instead of just recommending -fpermissive > > when compiling legacy code? I don't quite understand the motivation for > > adding a new permerror_opt flag for this class of errors. > > It seems to me an interesting class of errors, but I don't mind leaving it > under just -fpermissive if you prefer. > > > -Wnarrowing is an existing permerror_opt flag, but I can imagine it's > > useful to pass -Wno-error=narrowing etc when incrementally migrating > > C / C++98 code to modern C++ where you don't want any conformance errors > > allowed by -fpermissive to sneak in. So being able to narrowly control > > this class of errors seems useful, so a dedicated flag makes sense. > > > > But there's no parallel for -Wtemplate-body here, since by assumption > > the code base is unmaintained / immutable. Otherwise the more proper > > fix would be to just fix and/or delete the uninstantiated erroneous > > template. If say you're #including a legacy header that has such > > errors, then doing #pragma GCC diagnostic "-fpermissive -w" around > > the #include should be totally fine too.
I just realized #pragma GCC diagnostic warning "-fpermissive" etc doesn't actually work since -fpermissive isn't a warning flag. So having a dedicated flag for the class of errors has at least one clear benefit -- we can use #pragmas to selectively disable the errors now. > > > > I just don't see the use case for being able to narrowly control this > > class of errors that justifies the extra implementation complexity > > (specifically for properly detecting -Wno-error=template-body in the > > callback hook)? > > The hook shouldn't need to do anything special; report_diagnostic handles > -Wno-error=whatever. The issue was that the callback has to know in advance whether -Wno-error=template-body is active so that it can flag the template as having a relaxed error. Checking !warning_enabled_at wasn't enough because it will return true even for -Wno-error=template-body. I think we just need to check diagnostic_enabled directly, like so? Bootstrap and regtest on x86_64-pc-linux-gnu in progress. -- >8 -- Subject: [PATCH] c++: permit errors inside uninstantiated templates [PR116064] As an example, permissive-error1a.C gives: gcc/testsuite/g++.dg/template/permissive-error1a.C: In function 'void f()': gcc/testsuite/g++.dg/template/permissive-error1a.C:7:5: warning: increment of read-only variable 'n' [-Wtemplate-body] 7 | ++n; | ^ ... gcc/testsuite/g++.dg/template/permissive-error1a.C: In instantiation of 'void f() [with T = int]': gcc/testsuite/g++.dg/template/permissive-error1a.C:26:9: required from here 26 | f<int>(); | ~~~~~~^~ gcc/testsuite/g++.dg/template/permissive-error1a.C:5:6: error: instantiating erroneous template pattern 5 | void f() { | ^ gcc/testsuite/g++.dg/template/permissive-error1a.C:7:5: note: first error appeared here 7 | ++n; // { | ^ ... PR c++/116064 gcc/c-family/ChangeLog: * c.opt (Wtemplate-body): New warning. gcc/cp/ChangeLog: * cp-tree.h (relaxed_template_errors_t): Declare. (related_template_errors): Declare. (cp_seen_error): Declare. (seen_error): #define to cp_seen_error. * error.cc (get_current_template): Define. (relaxed_template_errors): Define. (cp_adjust_diagnostic_info): Define. (cp_seen_error): Define. (cxx_initialize_diagnostics): Set diagnostic_context::m_adjust_diagnostic_info. * pt.cc (instantiate_class_template): Issue a hard error when trying to instantiate a template pattern containing a permissively downgraded error. (instantiate_decl): Likewise. gcc/ChangeLog: * diagnostic.cc (diagnostic_context::initialize): Set m_adjust_diagnostic_info. (diagnostic_context::report_diagnostic): Call m_adjust_diagnostic_info. * diagnostic.h (diagnostic_context::diagnostic_enabled): Make public. (diagnostic_context::m_adjust_diagnostic_info): New data member. * doc/invoke.texi (-Wno-template-body): Document. gcc/testsuite/ChangeLog: * g++.dg/ext/typedef-init.C: Downgrade error inside template to warning due to -fpermissive. * g++.dg/pr84492.C: Likewise. * g++.old-deja/g++.pt/crash51.C: Remove unneeded dg-options. * g++.dg/template/permissive-error1.C: New test. * g++.dg/template/permissive-error1a.C: New test. * g++.dg/template/permissive-error1b.C: New test. * g++.dg/template/permissive-error1c.C: New test. --- gcc/c-family/c.opt | 4 + gcc/cp/cp-tree.h | 5 ++ gcc/cp/error.cc | 81 +++++++++++++++++++ gcc/cp/pt.cc | 30 +++++++ gcc/diagnostic.cc | 4 + gcc/diagnostic.h | 8 +- gcc/doc/invoke.texi | 11 ++- gcc/testsuite/g++.dg/ext/typedef-init.C | 2 +- gcc/testsuite/g++.dg/pr84492.C | 4 +- .../g++.dg/template/permissive-error1.C | 20 +++++ .../g++.dg/template/permissive-error1a.C | 33 ++++++++ .../g++.dg/template/permissive-error1b.C | 30 +++++++ .../g++.dg/template/permissive-error1c.C | 33 ++++++++ gcc/testsuite/g++.old-deja/g++.pt/crash51.C | 1 - 14 files changed, 259 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/permissive-error1.C create mode 100644 gcc/testsuite/g++.dg/template/permissive-error1a.C create mode 100644 gcc/testsuite/g++.dg/template/permissive-error1b.C create mode 100644 gcc/testsuite/g++.dg/template/permissive-error1c.C diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index a52682d835c..44117ba713c 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1420,6 +1420,10 @@ Wtautological-compare C ObjC C++ ObjC++ Var(warn_tautological_compare) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) Warn if a comparison always evaluates to true or false. +Wtemplate-body +C++ ObjC++ Var(warn_template_body) Warning Init(1) +Diagnose errors when parsing a template. + Wtemplate-id-cdtor C++ ObjC++ Var(warn_template_id_cdtor) Warning Warn about simple-template-id in a constructor or destructor. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 238d786b067..ffdc0ba38ae 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7189,6 +7189,11 @@ extern bool pedwarn_cxx98 (location_t, int, const char *, extern location_t location_of (tree); extern void qualified_name_lookup_error (tree, tree, tree, location_t); +using relaxed_template_errors_t + = hash_map<tree, location_t, simple_hashmap_traits<tree_decl_hash, location_t>>; +extern relaxed_template_errors_t *relaxed_template_errors; +extern bool cp_seen_error (void); +#define seen_error cp_seen_error /* in except.cc */ extern void init_terminate_fn (void); diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc index d80bac822ba..56587170609 100644 --- a/gcc/cp/error.cc +++ b/gcc/cp/error.cc @@ -165,6 +165,86 @@ class cxx_format_postprocessor : public format_postprocessor deferred_printed_type m_type_b; }; +/* Return the in-scope template that's currently being parsed, or + NULL_TREE otherwise. */ + +static tree +get_current_template () +{ + if (in_template_context && !current_instantiation ()) + if (tree ti = get_template_info (current_scope ())) + return TI_TEMPLATE (ti); + + return NULL_TREE; +} + +/* A map from TEMPLATE_DECL to the location of the first error (if any) + within the template that we permissively downgraded to a warning. */ + +relaxed_template_errors_t *relaxed_template_errors; + +/* Callback function diagnostic_context::m_adjust_diagnostic_info. + + Errors issued when parsing a template are automatically treated like + permerrors associated with the -Wtemplate-body flag and can be + downgraded into warnings accordingly, in which case we'll still + issue an error later need to instantiate the template. */ + +static void +cp_adjust_diagnostic_info (diagnostic_context *context, + diagnostic_info *diagnostic) +{ + if (diagnostic->kind == DK_ERROR) + if (tree tmpl = get_current_template ()) + { + diagnostic->option_index = OPT_Wtemplate_body; + + if (context->m_permissive) + diagnostic->kind = DK_WARNING; + + /* Determine if this error should/will be downgraded to a warning, + or suppressed. */ + diagnostic_info diagnostic_copy = *diagnostic; + if (/* -fpermissive */ + context->m_permissive + /* -Wno-template-body */ + || !context->diagnostic_enabled (&diagnostic_copy) + /* -Wno-error=template-body */ + || diagnostic_copy.kind == DK_WARNING) + { + diagnostic->kind = DK_WARNING; + if (!relaxed_template_errors) + relaxed_template_errors = new relaxed_template_errors_t; + if (!relaxed_template_errors->get (tmpl)) + { + /* Remember that this template had a relaxed error + so that we'll issue a hard error upon instantiation. */ + location_t error_loc = diagnostic->richloc->get_loc (); + relaxed_template_errors->put (tmpl, error_loc); + } + } + } +} + +/* A generalization of seen_error which also returns true if we've + permissively downgraded an error to a warning inside a template. */ + +bool +cp_seen_error () +{ + /* cp-tree.h #defines seen_error to cp_seen_error. */ +#undef seen_error + if (seen_error ()) + return true; + + if (relaxed_template_errors) + if (tree tmpl = get_current_template ()) + if (relaxed_template_errors->get (tmpl)) + return true; + + return false; +} + /* CONTEXT->printer is a basic pretty printer that was constructed presumably by diagnostic_initialize(), called early in the compiler's initialization process (in general_init) Before the FE @@ -187,6 +267,7 @@ cxx_initialize_diagnostics (diagnostic_context *context) diagnostic_starter (context) = cp_diagnostic_starter; /* diagnostic_finalizer is already c_diagnostic_finalizer. */ diagnostic_format_decoder (context) = cp_printer; + context->m_adjust_diagnostic_info = cp_adjust_diagnostic_info; pp_format_postprocessor (pp) = new cxx_format_postprocessor (); } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 77fa5907c3d..3aa64b3d41c 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -12376,6 +12376,22 @@ instantiate_class_template (tree type) if (! push_tinst_level (type)) return type; + if (relaxed_template_errors) + if (location_t *error_loc = relaxed_template_errors->get (templ)) + { + /* We're trying to instantiate a template pattern containing + an error that we've permissively downgraded to a warning. + Issue a hard error now. */ + location_t decl_loc = location_of (templ); + error_at (decl_loc, "instantiating erroneous template"); + inform (*error_loc, "first error appeared here"); + + pop_tinst_level (); + TYPE_BEING_DEFINED (type) = false; + CLASSTYPE_ERRONEOUS (type) = true; + return type; + } + int saved_unevaluated_operand = cp_unevaluated_operand; int saved_inhibit_evaluation_warnings = c_inhibit_evaluation_warnings; @@ -27291,6 +27307,20 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p) } } + if (relaxed_template_errors) + if (location_t *error_loc = relaxed_template_errors->get (td)) + { + /* We're trying to instantiate a template pattern containing + an error that we've permissively downgraded to a warning. + Issue a hard error now. */ + location_t decl_loc = location_of (td); + error_at (decl_loc, "instantiating erroneous template"); + inform (*error_loc, "first error appeared here"); + + pop_tinst_level (); + return d; + } + code_pattern = DECL_TEMPLATE_RESULT (td); /* We should never be trying to instantiate a member of a class diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc index 71d2f44e40c..e90c121cb95 100644 --- a/gcc/diagnostic.cc +++ b/gcc/diagnostic.cc @@ -219,6 +219,7 @@ diagnostic_context::initialize (int n_opts) m_warn_system_headers = false; m_max_errors = 0; m_internal_error = nullptr; + m_adjust_diagnostic_info = nullptr; m_text_callbacks.m_begin_diagnostic = default_diagnostic_starter; m_text_callbacks.m_start_span = default_diagnostic_start_span_fn; m_text_callbacks.m_end_diagnostic = default_diagnostic_finalizer; @@ -1416,6 +1417,9 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic) if (was_warning && m_inhibit_warnings) return false; + if (m_adjust_diagnostic_info) + m_adjust_diagnostic_info (this, diagnostic); + if (diagnostic->kind == DK_PEDWARN) { diagnostic->kind = m_pedantic_errors ? DK_ERROR : DK_WARNING; diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index 79386ccbf85..426cdfb3a46 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -581,6 +581,8 @@ public: const char *, const char *, va_list *, diagnostic_t) ATTRIBUTE_GCC_DIAG(7,0); + bool diagnostic_enabled (diagnostic_info *diagnostic); + private: bool includes_seen_p (const line_map_ordinary *map); @@ -593,8 +595,6 @@ private: void error_recursion () ATTRIBUTE_NORETURN; - bool diagnostic_enabled (diagnostic_info *diagnostic); - void get_any_inlining_info (diagnostic_info *diagnostic); void show_locus (const rich_location &richloc, @@ -699,6 +699,10 @@ public: /* Client hook to report an internal error. */ void (*m_internal_error) (diagnostic_context *, const char *, va_list *); + /* Client hook to adjust properties of the given diagnostic that we're + about to issue, such as its kind. */ + void (*m_adjust_diagnostic_info)(diagnostic_context *, diagnostic_info *); + private: /* Client-supplied callbacks for working with options. */ struct { diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index ef2213b4e84..348da934cfc 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -270,7 +270,8 @@ in the following sections. -Wno-non-template-friend -Wold-style-cast -Woverloaded-virtual -Wno-pmf-conversions -Wself-move -Wsign-promo -Wsized-deallocation -Wsuggest-final-methods --Wsuggest-final-types -Wsuggest-override -Wno-template-id-cdtor +-Wsuggest-final-types -Wsuggest-override -Wno-template-body +-Wno-template-id-cdtor -Wno-terminate -Wno-vexing-parse -Wvirtual-inheritance -Wno-virtual-move-assign -Wvolatile -Wzero-as-null-pointer-constant} @@ -4634,6 +4635,14 @@ namespaces, and this may be used to enforce that rule. The warning is inactive inside a system header file, such as the STL, so one can still use the STL. One may also use using directives and qualified names. +@opindex Wtemplate-body +@opindex Wno-template-body +@item -Wno-template-body @r{(C++ and Objective-C++ only)} +Disable diagnosing errors when parsing a template, and instead issue an +error only upon instantiation of the template. This flag can also be +used to downgrade such errors into warnings with @option{Wno-error=} or +@option{-fpermissive}. + @opindex Wtemplate-id-cdtor @opindex Wno-template-id-cdtor @item -Wno-template-id-cdtor @r{(C++ and Objective-C++ only)} diff --git a/gcc/testsuite/g++.dg/ext/typedef-init.C b/gcc/testsuite/g++.dg/ext/typedef-init.C index 153303d217b..47a6642de51 100644 --- a/gcc/testsuite/g++.dg/ext/typedef-init.C +++ b/gcc/testsuite/g++.dg/ext/typedef-init.C @@ -32,5 +32,5 @@ struct S { template<int> void foo() { - typedef int i = 0; /* { dg-error "is initialized" } */ + typedef int i = 0; /* { dg-warning "is initialized" } */ } diff --git a/gcc/testsuite/g++.dg/pr84492.C b/gcc/testsuite/g++.dg/pr84492.C index 1a2922096d1..08f368ff29b 100644 --- a/gcc/testsuite/g++.dg/pr84492.C +++ b/gcc/testsuite/g++.dg/pr84492.C @@ -3,7 +3,7 @@ template<int> int foo() { - return ({ foo; }); // { dg-error "insufficient context" } + return ({ foo; }); // { dg-warning "insufficient context" } } int bar() @@ -35,6 +35,6 @@ class C } bool g(int) { - return ({ g; }); // { dg-error "insufficient context" } + return ({ g; }); // { dg-warning "insufficient context" } } }; diff --git a/gcc/testsuite/g++.dg/template/permissive-error1.C b/gcc/testsuite/g++.dg/template/permissive-error1.C new file mode 100644 index 00000000000..e4536a8b90e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/permissive-error1.C @@ -0,0 +1,20 @@ +// PR c++/116064 +// { dg-additional-options -fpermissive } + +template<class T> +void f() { + const int n = 42; + ++n; // { dg-warning "read-only" } +} + +template<class T> +struct A { + void f(typename A::type); // { dg-warning "does not name a type" } +}; + +template<class T> +struct B { + void f() { + this->g(); // { dg-warning "no member" } + } +}; diff --git a/gcc/testsuite/g++.dg/template/permissive-error1a.C b/gcc/testsuite/g++.dg/template/permissive-error1a.C new file mode 100644 index 00000000000..c4b5f760ff5 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/permissive-error1a.C @@ -0,0 +1,33 @@ +// PR c++/116064 +// { dg-additional-options -fpermissive } +// Like permissive-error1.C but verify instantiating the errorneous +// templates gives an error after all. + +template<class T> +void f() { // { dg-error "instantiating erroneous template" } + const int n = 42; + ++n; // { dg-warning "read-only" } + // { dg-message "first error appeared here" "" { target *-*-* } .-1 } +} + +template<class T> +struct A { // { dg-error "instantiating erroneous template" } + void f(typename A::type); // { dg-warning "does not name a type" } + // { dg-message "first error appeared here" "" { target *-*-* } .-1 } +}; + +template<class T> +struct B { + void f() { // { dg-error "instantiating erroneous template" } + this->g(); // { dg-warning "no member" } + // { dg-message "first error appeared here" "" { target *-*-* } .-1 } + } +}; + +int main() { + f<int>(); // { dg-message "required from here" } + A<int> a; // { dg-message "required from here" } + // { dg-error "incomplete type" "" { target *-*-* } .-1 } + B<int> b; // { dg-bogus "" } + b.f(); // { dg-message "required from here" } +} diff --git a/gcc/testsuite/g++.dg/template/permissive-error1b.C b/gcc/testsuite/g++.dg/template/permissive-error1b.C new file mode 100644 index 00000000000..7fb74300ddc --- /dev/null +++ b/gcc/testsuite/g++.dg/template/permissive-error1b.C @@ -0,0 +1,30 @@ +// PR c++/116064 +// { dg-additional-options -Wno-template-body } +// Like permissive-error1a.C but verify -Wno-template-body suppresses +// the diagnostics. + +template<class T> +void f() { // { dg-error "instantiating erroneous template" } + const int n = 42; + ++n; // { dg-message "first error appeared here" "" { target *-*-* } } +} + +template<class T> +struct A { // { dg-error "instantiating erroneous template" } + void f(typename A::type); // { dg-message "first error appeared here" "" { target *-*-* } } +}; + +template<class T> +struct B { + void f() { // { dg-error "instantiating erroneous template" } + this->g(); // { dg-message "first error appeared here" "" { target *-*-* } } + } +}; + +int main() { + f<int>(); // { dg-message "required from here" } + A<int> a; // { dg-message "required from here" } + // { dg-error "incomplete type" "" { target *-*-* } .-1 } + B<int> b; // { dg-bogus "" } + b.f(); // { dg-message "required from here" } +} diff --git a/gcc/testsuite/g++.dg/template/permissive-error1c.C b/gcc/testsuite/g++.dg/template/permissive-error1c.C new file mode 100644 index 00000000000..c3f79e0198c --- /dev/null +++ b/gcc/testsuite/g++.dg/template/permissive-error1c.C @@ -0,0 +1,33 @@ +// PR c++/116064 +// { dg-additional-options -Wno-error=template-body } +// Like permissive-error1a.C but verify the diagnostics can also +// be downgraded via Wno-error=template-body. + +template<class T> +void f() { // { dg-error "instantiating erroneous template" } + const int n = 42; + ++n; // { dg-warning "read-only" } + // { dg-message "first error appeared here" "" { target *-*-* } .-1 } +} + +template<class T> +struct A { // { dg-error "instantiating erroneous template" } + void f(typename A::type); // { dg-warning "does not name a type" } + // { dg-message "first error appeared here" "" { target *-*-* } .-1 } +}; + +template<class T> +struct B { + void f() { // { dg-error "instantiating erroneous template" } + this->g(); // { dg-warning "no member" } + // { dg-message "first error appeared here" "" { target *-*-* } .-1 } + } +}; + +int main() { + f<int>(); // { dg-message "required from here" } + A<int> a; // { dg-message "required from here" } + // { dg-error "incomplete type" "" { target *-*-* } .-1 } + B<int> b; // { dg-bogus "" } + b.f(); // { dg-message "required from here" } +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash51.C b/gcc/testsuite/g++.old-deja/g++.pt/crash51.C index a3fbc17f163..c5cbde521ad 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/crash51.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/crash51.C @@ -1,5 +1,4 @@ // { dg-do assemble } -// { dg-options "-fpermissive -w" } // Origin: Mark Mitchell <m...@codesourcery.com> char foo[26]; -- 2.46.0.39.g891ee3b9db