[cfe-dev] EXTENSION for some diags
Chris Lattner
clattner at apple.com
Wed Sep 5 18:43:22 PDT 2007
>> You're right, we do. What do you suggest? GCC has a class of
>> extension warnings that are emitted by default. Is this what you
>> mean? That would give us:
>>
>> 1. Error.
>> 2. Warning always (eventually enabled or disabled by other -W
>> options)
>> 3. Extension, defaults to a warning
>> 4. Extension, defaults to silent
>>
>> -pedantic would then map #4 to a warning. -pedantic-errors would
>> make #3/#4 to error.
>>
>> Sound reasonable?
>
> I implemented something like the following myself; I'm quite fond
> of this approach and it's flexible:
Sorry for dropping the ball on this, it got buried in some other mail
when I was playing with filtering rules. :(
> a) Each diagnostic tag has a default severity suitable for normal
> compiles. Severities are, in order, suppress, remark, warning,
> soft error, hard error, fatal and maybe ice.
> b) User can change the severity of any diagnostic with default
> severity <= soft error to any severity <= soft error, either
> via #pragma or on the command line.
> c) In C90 and C99 pedantic mode, a table of tags that must
> be diagnosed according to the standard is scanned and the
> severity of said tag "upgraded" to warning (-pedantic or
> equivalent) or error (-pedantic-errors or equivalent) if it
> isn't already.
> d) Some severities need to be different depending on compile-
> time context anyway (e.g. integer division by zero is a
> run-time error, compile-time warning except in constant
> expressions where it is compile-time error). So when
> raising a diagnostic it should be possible for the front
> end to specify a severity override anyway.
> You probably feel something slightly different is appropriate
> for LLVM, but there may be ideas worth using here. It avoids
> the need for duplicate tags too, which is good from a user-
> interface point of view if they are exposed to the user (they
> probably should be for the fine-grained control of b)).
I think this makes sense. You basically have a table mapping
diagnostics to severity, which can be manipulated based on a variety
of things.
clang currently has two distinct notions: we distinguish between what
class a particular diagnostic falls into from how it is reported.
These two categorizations are used by different pieces of the
diagnostic handling machinery.
The first part of the diagnostics machinery is the piece that is
generating the diagnostics: the parser, lexer, sema, checking system,
etc. Each diagnostic itself is tagged (in DiagnosticKinds.def) with
a class, which is a member of the set
{NOTE,WARNING,EXTENSION,ERROR}. The important part of the
classification at this level is that it is completely independent of
how the diagnostic is reported and they have obvious meanings:
1. NOTEs (which aren't used and may be removed in the future) are
informational messages. For example, perhaps the optimizer could
emit information about which loops are vectorized etc.
2. WARNINGs are emitted for legal code that is questionable somehow.
3. EXTENSIONs are emitted for illegal code that is accepted anyway as
an extension to the language.
4. ERRORs flag a malformed program where error recovery techniques
must be used to continue parsing.
I believe that each of these categories is well described and
simple. It is easy to determine which class any particular
diagnostic falls into.
> a) Each diagnostic tag has a default severity suitable for normal
> compiles. Severities are, in order, suppress, remark, warning,
> soft error, hard error, fatal and maybe ice.
In contrast to your system, we don't specify a "default mapping":
that is completely client-specific. Because the library generating
the diagnostic doesn't know/care about how these diagnostics are
emitted, we don't need to talk about suppressed diagnostics. I'm not
sure the distinction between soft/hard error in your scheme. Fatal/
ICE are also interesting: we don't emit a diagnostic for these cases:
these are presumably internal consistency failures, where we prefer
to have the library assert/abort and die.
When diagnostics are reported by the parser (etc), they get routed
through the Diagnostic class. This class is designed to do various
types of mapping, which turns the class above into a concrete
diagnostic level. The level is completely different from the class,
but they have similar names (and are thus somewhat confusing). The
Diagnostic class maps each diagnostic onto the level set, which is
{ Ignored, Note, Warning, Error, Fatal }.
These levels are what we expect the tool to report to the user. As
you might expect, the {note,warning,extension} classes can be mapped
onto any of these levels, and the {error} class can only be mapped
onto {error,fatal}. Most of these are self-explanatory, but here are
some interesting pieces:
1. The warning class can be mapped onto the note level if desired (or
completely ignored) at the discretion of the client.
2. Fatal errors aren't property of the diagnostic, they are a level
that can be mapped onto: we expect all errors to be recovered from
when the diagnostic generator produces them. The Fatal level is
useful for clients that want the parser to stop as soon as possible
after some set of diagnostics are emitted (for example an error).
I believe that this system is fully general: any interesting policy
the client wants can be implemented with this scheme
(Diagnostic::setDiagnosticMapping can be used to specify a level on a
per-diagnostic basis), and higher level policies (e.g. -Werror, -
pedantic, -pedantic-errors etc) can be easily handled by mapping
entire classes to levels.
> Something I've not implemented yet is diagnostic groups, so
> you could give groups of tags a name and manipulate them
> en-masse, e.g. portability warnings, unused warnings, etc.
This is also something that clang is missing. In particular, the
client would like to be able to manipulate groups at a coarse grain
to implement controls such as the GCC options -Wextra, -Wall, -W,
etc. These are basically controls that modify a whole set of
diagnostics. However, it is important to note that the groupings are
client specific, so this should be implemented in the driver, not in
the libraries.
The original topic of discussion was what "extensions" should be
warned about even when -pedantic is not specified. In contrast to my
original proposal, I now don't think this should be another class of
warning, I think this should be controlled with the (currently
missing) diagnostic grouping mechanism in the driver.
Is this design reasonable?
-Chris
More information about the cfe-dev
mailing list