On Mon, 5 Aug 2024, Jason Merrill wrote:

> On 8/5/24 3:47 PM, Patrick Palka wrote:
> > 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?
> 
> Why not always flag it?  It doesn't seem harmful to give the "instatiating
> erroneous template" error later even if we gave a hard error during parsing.

Hmm, it just seems redundant to me I guess?  The reason we need the
"instantiating erroneous template" error is to ensure that _some_ error
was issued rendering the TU ill-formed when an erroneous template gets
instantiated.  If parse-time errors are hard errors then this is
guaranteed, but it's not if we're downgrading such errors.

On that note it just occurred to me that we don't need to abort
instantiation after the "instantiating erroneous template" error --
for sake of error recovery we can proceed to instantiate as if we
issued a hard error at parse time.

This version removes the early returns from instantiate_decl and
instantiate_class_template.

-- >8 --

Subject: [PATCH] c++: permit errors inside uninstantiated templates [PR116064]

        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                                  | 24 ++++++
 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, 253 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..f02f7d52e48 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 if we 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 get 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 its 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..5c66e464d86 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -12376,6 +12376,18 @@ 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");
+       relaxed_template_errors->remove (templ);
+      }
+
   int saved_unevaluated_operand = cp_unevaluated_operand;
   int saved_inhibit_evaluation_warnings = c_inhibit_evaluation_warnings;
 
@@ -27291,6 +27303,18 @@ 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");
+       relaxed_template_errors->remove (td);
+      }
+
   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..19910f105c2
--- /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 variable 'n' .-Wtemplate-body." }
+       // { dg-message "first error appeared here" "" { target *-*-* } .-1 }
+       // { dg-error "read-only variable 'n'\[\n\r\]" "" { target *-*-* } .-2 }
+}
+
+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" }
+  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..1ac49ce8be5
--- /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
+// diagnostics.
+
+template<class T>
+void f() {  // { dg-error "instantiating erroneous template" }
+  const int n = 42;
+  ++n; // { dg-message "first error appeared here" "" { target *-*-* } }
+       // { dg-error "read-only variable 'n'\[\n\r\]" "" { target *-*-* } .-1 }
+}
+
+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" }
+  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..e1e904b0828
--- /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 variable 'n' .-Wtemplate-body." }
+       // { dg-message "first error appeared here" "" { target *-*-* } .-1 }
+       // { dg-error "read-only variable 'n'\[\n\r\]" "" { target *-*-* } .-2 }
+}
+
+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" }
+  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

Reply via email to