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

Reply via email to