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 <[email protected]>
char foo[26];
--
2.46.0.39.g891ee3b9db