Skip to content

Commit e37391c

Browse files
committed
[modules] Round-trip -Werror flag through explicit module build.
The intent for an explicit module build is that the diagnostics produced within the module are those that were configured when the module was built, not those that are enabled within a user of the module. This includes diagnostics that don't actually show up until the module is used (for instance, diagnostics produced during template instantiation and weird cases like -Wpadded). We serialized and restored the diagnostic state for individual warning groups, but previously did not track the state for flags like -Werror and -Weverything, which are implemented as separate bits rather than as part of the diagnostics mapping information. llvm-svn: 301992
1 parent e95901c commit e37391c

File tree

10 files changed

+178
-108
lines changed

10 files changed

+178
-108
lines changed

clang/include/clang/Basic/Diagnostic.h

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,7 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
178178

179179
private:
180180
unsigned char AllExtensionsSilenced; // Used by __extension__
181-
bool IgnoreAllWarnings; // Ignore all warnings: -w
182-
bool WarningsAsErrors; // Treat warnings like errors.
183-
bool EnableAllWarnings; // Enable all warnings.
184-
bool ErrorsAsFatal; // Treat errors like fatal errors.
185-
bool FatalsAsError; // Treat fatal errors like errors.
186-
bool SuppressSystemWarnings; // Suppress warnings in system headers.
181+
bool SuppressAfterFatalError; // Suppress diagnostics after a fatal error?
187182
bool SuppressAllDiagnostics; // Suppress all diagnostics.
188183
bool ElideType; // Elide common types of templates.
189184
bool PrintTemplateTree; // Print a tree when comparing templates.
@@ -194,7 +189,6 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
194189
// 0 -> no limit.
195190
unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation
196191
// backtrace stack, 0 -> no limit.
197-
diag::Severity ExtBehavior; // Map extensions to warnings or errors?
198192
IntrusiveRefCntPtr<DiagnosticIDs> Diags;
199193
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
200194
DiagnosticConsumer *Client;
@@ -216,6 +210,19 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
216210
llvm::DenseMap<unsigned, DiagnosticMapping> DiagMap;
217211

218212
public:
213+
// "Global" configuration state that can actually vary between modules.
214+
unsigned IgnoreAllWarnings : 1; // Ignore all warnings: -w
215+
unsigned EnableAllWarnings : 1; // Enable all warnings.
216+
unsigned WarningsAsErrors : 1; // Treat warnings like errors.
217+
unsigned ErrorsAsFatal : 1; // Treat errors like fatal errors.
218+
unsigned SuppressSystemWarnings : 1; // Suppress warnings in system headers.
219+
diag::Severity ExtBehavior : 4; // Map extensions to warnings or errors?
220+
221+
DiagState()
222+
: IgnoreAllWarnings(false), EnableAllWarnings(false),
223+
WarningsAsErrors(false), ErrorsAsFatal(false),
224+
SuppressSystemWarnings(false), ExtBehavior(diag::Severity::Ignored) {}
225+
219226
typedef llvm::DenseMap<unsigned, DiagnosticMapping>::iterator iterator;
220227
typedef llvm::DenseMap<unsigned, DiagnosticMapping>::const_iterator
221228
const_iterator;
@@ -493,33 +500,47 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
493500
/// \brief When set to true, any unmapped warnings are ignored.
494501
///
495502
/// If this and WarningsAsErrors are both set, then this one wins.
496-
void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; }
497-
bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; }
503+
void setIgnoreAllWarnings(bool Val) {
504+
GetCurDiagState()->IgnoreAllWarnings = Val;
505+
}
506+
bool getIgnoreAllWarnings() const {
507+
return GetCurDiagState()->IgnoreAllWarnings;
508+
}
498509

499510
/// \brief When set to true, any unmapped ignored warnings are no longer
500511
/// ignored.
501512
///
502513
/// If this and IgnoreAllWarnings are both set, then that one wins.
503-
void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; }
504-
bool getEnableAllWarnings() const { return EnableAllWarnings; }
514+
void setEnableAllWarnings(bool Val) {
515+
GetCurDiagState()->EnableAllWarnings = Val;
516+
}
517+
bool getEnableAllWarnings() const {
518+
return GetCurDiagState()->EnableAllWarnings;
519+
}
505520

506521
/// \brief When set to true, any warnings reported are issued as errors.
507-
void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
508-
bool getWarningsAsErrors() const { return WarningsAsErrors; }
522+
void setWarningsAsErrors(bool Val) {
523+
GetCurDiagState()->WarningsAsErrors = Val;
524+
}
525+
bool getWarningsAsErrors() const {
526+
return GetCurDiagState()->WarningsAsErrors;
527+
}
509528

510529
/// \brief When set to true, any error reported is made a fatal error.
511-
void setErrorsAsFatal(bool Val) { ErrorsAsFatal = Val; }
512-
bool getErrorsAsFatal() const { return ErrorsAsFatal; }
530+
void setErrorsAsFatal(bool Val) { GetCurDiagState()->ErrorsAsFatal = Val; }
531+
bool getErrorsAsFatal() const { return GetCurDiagState()->ErrorsAsFatal; }
513532

514-
/// \brief When set to true, any fatal error reported is made an error.
515-
///
516-
/// This setting takes precedence over the setErrorsAsFatal setting above.
517-
void setFatalsAsError(bool Val) { FatalsAsError = Val; }
518-
bool getFatalsAsError() const { return FatalsAsError; }
533+
/// \brief When set to true (the default), suppress further diagnostics after
534+
/// a fatal error.
535+
void setSuppressAfterFatalError(bool Val) { SuppressAfterFatalError = Val; }
519536

520537
/// \brief When set to true mask warnings that come from system headers.
521-
void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; }
522-
bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; }
538+
void setSuppressSystemWarnings(bool Val) {
539+
GetCurDiagState()->SuppressSystemWarnings = Val;
540+
}
541+
bool getSuppressSystemWarnings() const {
542+
return GetCurDiagState()->SuppressSystemWarnings;
543+
}
523544

524545
/// \brief Suppress all diagnostics, to silence the front end when we
525546
/// know that we don't want any more diagnostics to be passed along to the
@@ -571,11 +592,15 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
571592
}
572593

573594
/// \brief Controls whether otherwise-unmapped extension diagnostics are
574-
/// mapped onto ignore/warning/error.
595+
/// mapped onto ignore/warning/error.
575596
///
576597
/// This corresponds to the GCC -pedantic and -pedantic-errors option.
577-
void setExtensionHandlingBehavior(diag::Severity H) { ExtBehavior = H; }
578-
diag::Severity getExtensionHandlingBehavior() const { return ExtBehavior; }
598+
void setExtensionHandlingBehavior(diag::Severity H) {
599+
GetCurDiagState()->ExtBehavior = H;
600+
}
601+
diag::Severity getExtensionHandlingBehavior() const {
602+
return GetCurDiagState()->ExtBehavior;
603+
}
579604

580605
/// \brief Counter bumped when an __extension__ block is/ encountered.
581606
///

clang/include/clang/Basic/DiagnosticIDs.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,21 @@ class DiagnosticMapping {
122122
bool wasUpgradedFromWarning() const { return WasUpgradedFromWarning; }
123123
void setUpgradedFromWarning(bool Value) { WasUpgradedFromWarning = Value; }
124124

125-
/// Serialize the bits that aren't based on context.
126-
unsigned serializeBits() const {
127-
return (WasUpgradedFromWarning << 3) | Severity;
125+
/// Serialize this mapping as a raw integer.
126+
unsigned serialize() const {
127+
return (IsUser << 7) | (IsPragma << 6) | (HasNoWarningAsError << 5) |
128+
(HasNoErrorAsFatal << 4) | (WasUpgradedFromWarning << 3) | Severity;
128129
}
129-
static diag::Severity deserializeSeverity(unsigned Bits) {
130-
return (diag::Severity)(Bits & 0x7);
131-
}
132-
static bool deserializeUpgradedFromWarning(unsigned Bits) {
133-
return Bits >> 3;
130+
/// Deserialize a mapping.
131+
static DiagnosticMapping deserialize(unsigned Bits) {
132+
DiagnosticMapping Result;
133+
Result.IsUser = (Bits >> 7) & 1;
134+
Result.IsPragma = (Bits >> 6) & 1;
135+
Result.HasNoWarningAsError = (Bits >> 5) & 1;
136+
Result.HasNoErrorAsFatal = (Bits >> 4) & 1;
137+
Result.WasUpgradedFromWarning = (Bits >> 3) & 1;
138+
Result.Severity = Bits & 0x7;
139+
return Result;
134140
}
135141
};
136142

clang/lib/Basic/Diagnostic.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,12 @@ DiagnosticsEngine::DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> diags,
6767
ArgToStringCookie = nullptr;
6868

6969
AllExtensionsSilenced = 0;
70-
IgnoreAllWarnings = false;
71-
WarningsAsErrors = false;
72-
EnableAllWarnings = false;
73-
ErrorsAsFatal = false;
74-
FatalsAsError = false;
75-
SuppressSystemWarnings = false;
70+
SuppressAfterFatalError = true;
7671
SuppressAllDiagnostics = false;
7772
ElideType = true;
7873
PrintTemplateTree = false;
7974
ShowColors = false;
8075
ShowOverloads = Ovl_All;
81-
ExtBehavior = diag::Severity::Ignored;
8276

8377
ErrorLimit = 0;
8478
TemplateBacktraceLimit = 0;
@@ -343,8 +337,8 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
343337
return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
344338
diag::Severity::Fatal);
345339

346-
// Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
347-
// potentially downgrade anything already mapped to be an error.
340+
// Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
341+
// and potentially downgrade anything already mapped to be a fatal error.
348342

349343
// Get the diagnostics in this group.
350344
SmallVector<diag::kind, 8> GroupDiags;

clang/lib/Basic/DiagnosticIDs.cpp

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
420420
Result = Mapping.getSeverity();
421421

422422
// Upgrade ignored diagnostics if -Weverything is enabled.
423-
if (Diag.EnableAllWarnings && Result == diag::Severity::Ignored &&
423+
if (State->EnableAllWarnings && Result == diag::Severity::Ignored &&
424424
!Mapping.isUser() && getBuiltinDiagClass(DiagID) != CLASS_REMARK)
425425
Result = diag::Severity::Warning;
426426

@@ -435,44 +435,40 @@ DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc,
435435
// For extension diagnostics that haven't been explicitly mapped, check if we
436436
// should upgrade the diagnostic.
437437
if (IsExtensionDiag && !Mapping.isUser())
438-
Result = std::max(Result, Diag.ExtBehavior);
438+
Result = std::max(Result, State->ExtBehavior);
439439

440440
// At this point, ignored errors can no longer be upgraded.
441441
if (Result == diag::Severity::Ignored)
442442
return Result;
443443

444444
// Honor -w, which is lower in priority than pedantic-errors, but higher than
445445
// -Werror.
446-
if (Result == diag::Severity::Warning && Diag.IgnoreAllWarnings)
446+
// FIXME: Under GCC, this also suppresses warnings that have been mapped to
447+
// errors by -W flags and #pragma diagnostic.
448+
if (Result == diag::Severity::Warning && State->IgnoreAllWarnings)
447449
return diag::Severity::Ignored;
448450

449451
// If -Werror is enabled, map warnings to errors unless explicitly disabled.
450452
if (Result == diag::Severity::Warning) {
451-
if (Diag.WarningsAsErrors && !Mapping.hasNoWarningAsError())
453+
if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError())
452454
Result = diag::Severity::Error;
453455
}
454456

455457
// If -Wfatal-errors is enabled, map errors to fatal unless explicity
456458
// disabled.
457459
if (Result == diag::Severity::Error) {
458-
if (Diag.ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
460+
if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal())
459461
Result = diag::Severity::Fatal;
460462
}
461463

462-
// If explicitly requested, map fatal errors to errors.
463-
if (Result == diag::Severity::Fatal) {
464-
if (Diag.FatalsAsError)
465-
Result = diag::Severity::Error;
466-
}
467-
468464
// Custom diagnostics always are emitted in system headers.
469465
bool ShowInSystemHeader =
470466
!GetDiagInfo(DiagID) || GetDiagInfo(DiagID)->WarnShowInSystemHeader;
471467

472468
// If we are in a system header, we ignore it. We look at the diagnostic class
473469
// because we also want to ignore extensions and warnings in -Werror and
474470
// -pedantic-errors modes, which *map* warnings/extensions to errors.
475-
if (Diag.SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
471+
if (State->SuppressSystemWarnings && !ShowInSystemHeader && Loc.isValid() &&
476472
Diag.getSourceManager().isInSystemHeader(
477473
Diag.getSourceManager().getExpansionLoc(Loc)))
478474
return diag::Severity::Ignored;
@@ -632,7 +628,7 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
632628

633629
// If a fatal error has already been emitted, silence all subsequent
634630
// diagnostics.
635-
if (Diag.FatalErrorOccurred) {
631+
if (Diag.FatalErrorOccurred && Diag.SuppressAfterFatalError) {
636632
if (DiagLevel >= DiagnosticIDs::Error &&
637633
Diag.Client->IncludeInDiagnosticCounts()) {
638634
++Diag.NumErrors;

clang/lib/Serialization/ASTReader.cpp

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5531,14 +5531,8 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
55315531
"Invalid data, not enough diag/map pairs");
55325532
while (Size--) {
55335533
unsigned DiagID = Record[Idx++];
5534-
unsigned SeverityAndUpgradedFromWarning = Record[Idx++];
5535-
bool WasUpgradedFromWarning =
5536-
DiagnosticMapping::deserializeUpgradedFromWarning(
5537-
SeverityAndUpgradedFromWarning);
55385534
DiagnosticMapping NewMapping =
5539-
Diag.makeUserMapping(DiagnosticMapping::deserializeSeverity(
5540-
SeverityAndUpgradedFromWarning),
5541-
Loc);
5535+
DiagnosticMapping::deserialize(Record[Idx++]);
55425536
if (!NewMapping.isPragma() && !IncludeNonPragmaStates)
55435537
continue;
55445538

@@ -5547,14 +5541,12 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
55475541
// If this mapping was specified as a warning but the severity was
55485542
// upgraded due to diagnostic settings, simulate the current diagnostic
55495543
// settings (and use a warning).
5550-
if (WasUpgradedFromWarning && !Mapping.isErrorOrFatal()) {
5551-
Mapping = Diag.makeUserMapping(diag::Severity::Warning, Loc);
5552-
continue;
5544+
if (NewMapping.wasUpgradedFromWarning() && !Mapping.isErrorOrFatal()) {
5545+
NewMapping.setSeverity(diag::Severity::Warning);
5546+
NewMapping.setUpgradedFromWarning(false);
55535547
}
55545548

5555-
// Use the deserialized mapping verbatim.
55565549
Mapping = NewMapping;
5557-
Mapping.setUpgradedFromWarning(WasUpgradedFromWarning);
55585550
}
55595551
return NewState;
55605552
};
@@ -5569,22 +5561,36 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
55695561
DiagStates.push_back(FirstState);
55705562

55715563
// Skip the initial diagnostic state from the serialized module.
5572-
assert(Record[0] == 0 &&
5564+
assert(Record[1] == 0 &&
55735565
"Invalid data, unexpected backref in initial state");
5574-
Idx = 2 + Record[1] * 2;
5566+
Idx = 3 + Record[2] * 2;
55755567
assert(Idx < Record.size() &&
55765568
"Invalid data, not enough state change pairs in initial state");
5569+
} else if (F.isModule()) {
5570+
// For an explicit module, preserve the flags from the module build
5571+
// command line (-w, -Weverything, -Werror, ...) along with any explicit
5572+
// -Wblah flags.
5573+
unsigned Flags = Record[Idx++];
5574+
DiagState Initial;
5575+
Initial.SuppressSystemWarnings = Flags & 1; Flags >>= 1;
5576+
Initial.ErrorsAsFatal = Flags & 1; Flags >>= 1;
5577+
Initial.WarningsAsErrors = Flags & 1; Flags >>= 1;
5578+
Initial.EnableAllWarnings = Flags & 1; Flags >>= 1;
5579+
Initial.IgnoreAllWarnings = Flags & 1; Flags >>= 1;
5580+
Initial.ExtBehavior = (diag::Severity)Flags;
5581+
FirstState = ReadDiagState(Initial, SourceLocation(), true);
5582+
5583+
// Set up the root buffer of the module to start with the initial
5584+
// diagnostic state of the module itself, to cover files that contain no
5585+
// explicit transitions (for which we did not serialize anything).
5586+
Diag.DiagStatesByLoc.Files[F.OriginalSourceFileID]
5587+
.StateTransitions.push_back({FirstState, 0});
55775588
} else {
5578-
FirstState = ReadDiagState(
5579-
F.isModule() ? DiagState() : *Diag.DiagStatesByLoc.CurDiagState,
5580-
SourceLocation(), F.isModule());
5581-
5582-
// For an explicit module, set up the root buffer of the module to start
5583-
// with the initial diagnostic state of the module itself, to cover files
5584-
// that contain no explicit transitions.
5585-
if (F.isModule())
5586-
Diag.DiagStatesByLoc.Files[F.OriginalSourceFileID]
5587-
.StateTransitions.push_back({FirstState, 0});
5589+
// For prefix ASTs, start with whatever the user configured on the
5590+
// command line.
5591+
Idx++; // Skip flags.
5592+
FirstState = ReadDiagState(*Diag.DiagStatesByLoc.CurDiagState,
5593+
SourceLocation(), false);
55885594
}
55895595

55905596
// Read the state transitions.

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2868,8 +2868,26 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
28682868
unsigned CurrID = 0;
28692869
RecordData Record;
28702870

2871+
auto EncodeDiagStateFlags =
2872+
[](const DiagnosticsEngine::DiagState *DS) -> unsigned {
2873+
unsigned Result = (unsigned)DS->ExtBehavior;
2874+
for (unsigned Val :
2875+
{DS->IgnoreAllWarnings, DS->EnableAllWarnings, DS->WarningsAsErrors,
2876+
DS->ErrorsAsFatal, DS->SuppressSystemWarnings})
2877+
Result = (Result << 1) | Val;
2878+
return Result;
2879+
};
2880+
2881+
unsigned Flags = EncodeDiagStateFlags(Diag.DiagStatesByLoc.FirstDiagState);
2882+
Record.push_back(Flags);
2883+
28712884
auto AddDiagState = [&](const DiagnosticsEngine::DiagState *State,
28722885
bool IncludeNonPragmaStates) {
2886+
// Ensure that the diagnostic state wasn't modified since it was created.
2887+
// We will not correctly round-trip this information otherwise.
2888+
assert(Flags == EncodeDiagStateFlags(State) &&
2889+
"diag state flags vary in single AST file");
2890+
28732891
unsigned &DiagStateID = DiagStateIDMap[State];
28742892
Record.push_back(DiagStateID);
28752893

@@ -2882,7 +2900,7 @@ void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
28822900
for (const auto &I : *State) {
28832901
if (I.second.isPragma() || IncludeNonPragmaStates) {
28842902
Record.push_back(I.first);
2885-
Record.push_back(I.second.serializeBits());
2903+
Record.push_back(I.second.serialize());
28862904
}
28872905
}
28882906
// Update the placeholder.

clang/test/Index/keep-going.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ class C : public A<float> { };
2525
// CHECK: C++ base class specifier=A<float>:4:7 [access=public isVirtual=false] [type=A<float>] [typekind=Unexposed] [templateargs/1= [type=float] [typekind=Float]] [canonicaltype=A<float>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=float] [typekind=Float]] [isPOD=0] [nbFields=1]
2626
// CHECK: TemplateRef=A:4:7 [type=] [typekind=Invalid] [isPOD=0]
2727

28-
// CHECK-DIAG: keep-going.cpp:1:10: error: 'missing1.h' file not found
29-
// CHECK-DIAG: keep-going.cpp:8:10: error: 'missing2.h' file not found
28+
// CHECK-DIAG: keep-going.cpp:1:10: fatal error: 'missing1.h' file not found
29+
// CHECK-DIAG: keep-going.cpp:8:10: fatal error: 'missing2.h' file not found

0 commit comments

Comments
 (0)