On Tue, 2024-08-06 at 17:52 -0400, Jason Merrill wrote:
> On 8/6/24 5:47 PM, Patrick Palka wrote:
> > On Tue, 6 Aug 2024, Jason Merrill wrote:
> > 
> > > On 8/6/24 2:00 PM, Patrick Palka wrote:
> > > > On Tue, 6 Aug 2024, Jason Merrill wrote:
> > > > 
> > > > > On 8/5/24 6:09 PM, Patrick Palka wrote:
> > > > > > 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_i
> > > > > > > > > > > > > > > nfo.
> > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > +   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.
> > > > > 
> > > > > Yes, it's redundant, but avoiding it doesn't seem worth
> > > > > duplicating all
> > > > > the
> > > > > logic to determine whether it will be an error or not.
> > > > > 
> > > > > Simpler might be to skip the "instantiating" error if
> > > > > seen_error()?
> > > > 
> > > > Sure.  This makes the expected diagnostics in the -Wno-
> > > > template-body
> > > > testcase a bit lacking since there's three instantiated
> > > > templates with
> > > > one logical error each, but only the first error is diagnosed. 
> > > > But I
> > > > don't particularly mind that.
> > > > 
> > > > > 
> > > > > > 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.
> > > > > 
> > > > > Agreed.
> > > > > 
> > > > > Jason
> > > > > 
> > > > > 
> > > > 
> > > > -- >8 --
> > > > 
> > > > Subject: [PATCH] c++: permit errors inside uninstantiated
> > > > templates
> > > > [PR116064]
> > > > 
> > > > 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 maintenance mode.  So it'd be handy to be
> > > > able to
> > > > prevent these template errors from rendering the entire TU
> > > > uncompilable.
> > > > (Note that such code is "ill-formed no diagnostic required"
> > > > according
> > > > the standard.)
> > > > 
> > > > To that end this patch turns any errors issued within a
> > > > template into
> > > > premerrors associated with a new -Wtemplate-body flag so that
> > > > they can
> > > 
> > > perm
> > > 
> > > > be downgraded via e.g. -fpermissive or -Wno-template=template-
> > > > body.  If
> > > > the template containing a downgraded error later needs to be
> > > > instantiated,
> > > > we'll issue an error then.  But if the template never gets
> > > > instantiated
> > > > then the downgraded error won't affect validity of the rest of
> > > > the TU.
> > > > 
> > > > This is implemented via a diagnostic hook that gets called for
> > > > each
> > > > diagnostic, and which adjusts an error diagnostic if we detect
> > > > it's
> > > > occurring from a template context and additionally flags this
> > > > template
> > > > context as erroneous.
> > > > 
> > > > 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
> > > 
> > > Drop "pattern" here too.
> > 
> > Fixed
> > 
> > > 
> > > >       5 | void f() {
> > > >         |      ^
> > > > gcc/testsuite/g++.dg/template/permissive-error1a.C:7:5: note:
> > > > first error
> > > > appeared here
> > > >       7 |   ++n; // {
> > > >         |     ^
> > > > ...
> > > 
> > > What happens if we compile an interface/header unit with an
> > > erroneous
> > > uninstantiated template?  I'd probably reject such a module
> > > rather than write
> > > out the erroneity.  Possibly just if the template isn't
> > > discarded, not sure if
> > > that distinction is too much trouble to bother with.
> > 
> > I think it's good enough to uniformly reject the module given how
> > small
> > the intersection -fpermissive and modules users is, I imagine.
> > 
> > > 
> > > >         PR c++/116064
> > > > 
> > > > gcc/c-family/ChangeLog:
> > > > 
> > > >         * c.opt (Wtemplate-body): New warning.
> > > > 
> > > > gcc/cp/ChangeLog:
> > > > 
> > > >         * cp-tree.h (erroneous_templates_t): Declare.
> > > >         (erroneous_templates): Declare.
> > > >         (cp_seen_error): Declare.
> > > >         (basic_seen_error): Define as alias to existing
> > > > seen_error.
> > > 
> > > Or we could use (seen_error)() where we mean the basic one?
> > 
> > Sure, changed.
> > 
> > > 
> > > >         (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.
> > > 
> > > You shouldn't need this change now?
> > 
> > Oops, removed.
> > 
> > > 
> > > > +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;
> > > > +
> > > > +       if (!erroneous_templates)
> > > > +         erroneous_templates = new erroneous_templates_t;
> > > > +       if (!erroneous_templates->get (tmpl))
> > > > +         {
> > > > +           /* Remember that this template had a parse-time
> > > > error so
> > > > +              that we'll ensure a hard error has been issued
> > > > upon
> > > > +              its instantiation.  */
> > > > +           location_t error_loc = diagnostic->richloc->get_loc
> > > > ();
> > > > +           erroneous_templates->put (tmpl, error_loc);
> > > 
> > > Instead of get+put you could use the get return value to store
> > > error_loc?
> > 
> > We need to use get_or_insert if we want to combine the two lookups.
> > I went ahead and used hash_map_safe_get_or_insert here to get rid
> > of the construction boilerplate as well.
> > 
> > > 
> > > > +@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}.
> > > 
> > > Please also refer to this flag in the -fpermissive documentation.
> > 
> > Done.
> > 
> > -- >8 --
> > 
> > Subject: [PATCH] c++: permit errors inside uninstantiated templates
> > [PR116064]
> > 
> > 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 maintenance mode.  So it'd be handy to be able
> > to
> > prevent these template errors from rendering the entire TU
> > uncompilable.
> > (Note that such code is "ill-formed no diagnostic required"
> > according
> > the standard.)
> > 
> > To that end this patch turns any errors issued within a template
> > into
> > permerrors associated with a new -Wtemplate-body flag so that they
> > can
> > be downgraded via e.g. -fpermissive or -Wno-template=template-
> > body.  If
> > the template containing a downgraded error later needs to be
> > instantiated,
> > we'll issue an error then.  But if the template never gets
> > instantiated
> > then the downgraded error won't affect validity of the rest of the
> > TU.
> > 
> > This is implemented via a diagnostic hook that gets called for each
> > diagnostic, and which adjusts an error diagnostic if we detect it's
> > occurring from a template context and additionally flags this
> > template
> > context as erroneous.
> > 
> > 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
> >      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 (erroneous_templates_t): Declare.
> >         (erroneous_templates): 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.
> >         * module.cc (finish_module_processing): Don't write the
> >         module if it contains an erroneous template.
> >         * pt.cc (instantiate_class_template): Issue a hard error
> >         when trying to instantiate a template 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::m_adjust_diagnostic_info):
> >         New data member.
> >         * doc/invoke.texi (-Wno-template-body): Document.
> >         (-fpermissive): Mention -Wtemplate-body.
> > 
> > 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                              |  7 ++
> >   gcc/cp/error.cc                               | 67
> > +++++++++++++++++++
> >   gcc/cp/module.cc                              |  5 +-
> >   gcc/cp/pt.cc                                  | 24 +++++++
> >   gcc/diagnostic.cc                             |  4 ++
> >   gcc/diagnostic.h                              |  4 ++
> >   gcc/doc/invoke.texi                           | 12 +++-
> >   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      | 31 +++++++++
> >   .../g++.dg/template/permissive-error1b.C      | 30 +++++++++
> >   .../g++.dg/template/permissive-error1c.C      | 31 +++++++++
> >   gcc/testsuite/g++.old-deja/g++.pt/crash51.C   |  1 -
> >   15 files changed, 240 insertions(+), 6 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..08ee5895c6a 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -7190,6 +7190,13 @@ extern location_t
> > location_of                   (tree);
> >   extern void qualified_name_lookup_error               (tree,
> > tree, tree,
> >                                                  location_t);
> >   
> > +using erroneous_templates_t
> > +  = hash_map<tree, location_t,
> > simple_hashmap_traits<tree_decl_hash, location_t>>;
> > +extern erroneous_templates_t *erroneous_templates;
> > +
> > +extern bool cp_seen_error ();
> > +#define seen_error() cp_seen_error()
> > +
> >   /* in except.cc */
> >   extern void init_terminate_fn                 (void);
> >   extern void init_exception_processing         (void);
> > diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
> > index d80bac822ba..7eab0bf76b4 100644
> > --- a/gcc/cp/error.cc
> > +++ b/gcc/cp/error.cc
> > @@ -165,6 +165,72 @@ 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 (scope_chain && in_template_context && !current_instantiation
> > ())
> > +    if (tree ti = get_template_info (current_scope ()))
> > +      return TI_TEMPLATE (ti);
> > +
> > +  return NULL_TREE;
> > +}
> > +
> > +/* A map from TEMPLATE_DECLs that we've determined to be erroneous
> > +   at parse time to the location of the first error within.  */
> > +
> > +erroneous_templates_t *erroneous_templates;
> > +
> > +/* 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;
> > +
> > +       bool existed;
> > +       location_t &error_loc
> > +         = hash_map_safe_get_or_insert<false>
> > (erroneous_templates,
> > +                                               tmpl, &existed);
> > +       if (!existed)
> > +         /* Remember that this template had a parse-time error so
> > +            that we'll ensure a hard error has been issued upon
> > +            its instantiation.  */
> > +         error_loc = diagnostic->richloc->get_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 ()
> > +{
> > +  if ((seen_error) ())
> > +    return true;
> > +
> > +  if (erroneous_templates)
> > +    if (tree tmpl = get_current_template ())
> > +      if (erroneous_templates->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 +253,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/module.cc b/gcc/cp/module.cc
> > index d1607a06757..7130faf26f5 100644
> > --- a/gcc/cp/module.cc
> > +++ b/gcc/cp/module.cc
> > @@ -20768,7 +20768,10 @@ finish_module_processing (cpp_reader
> > *reader)
> >   
> >         cookie = new module_processing_cookie (cmi_name, tmp_name,
> > fd, e);
> >   
> > -      if (errorcount)
> > +      if (errorcount
> > +         /* Don't write the module if it contains an erroneous
> > template.  */
> > +         || (erroneous_templates
> > +             && !erroneous_templates->is_empty ()))
> >         warning_at (state->loc, 0, "not writing module %qs due to
> > errors",
> >                     state->get_flatname ());
> >         else if (cookie->out.begin ())
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 77fa5907c3d..b83922a530d 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 (erroneous_templates && !(seen_error) ())
> > +    if (location_t *error_loc = erroneous_templates->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 to ensure the TU is considered
> > +          ill-formed.  */
> > +       location_t decl_loc = location_of (templ);
> > +       error_at (decl_loc, "instantiating erroneous template");
> > +       inform (*error_loc, "first error appeared here");
> > +      }

I confess I haven't been paying proper attention to this thread -
sorry, but please can you add an
   auto_diagnostic_group d;
before the "error_at", so that the "inform" is assocated with it.

Thanks
Dave


> 
> Let's factor this out instead of repeating it.  OK with that change.
> 
> Jason
> 

Reply via email to