Fix diagnostic pragmas.
Diagnostic pragmas are broken because we don't keep track of the diagnostic state changes and we only check the current/latest state.
Problems manifest if a diagnostic is emitted for a source line that has different diagnostic state than the current state; this can affect
a lot of places, like C++ inline methods, template instantiations, the lexer, etc.
Fix the issue by having the Diagnostic object keep track of the source location of the pragmas so that it is able to know what is the diagnostic state at any given source location.
Fixes rdar://8365684.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121873 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 5098c2e..919ba81 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -49,9 +49,10 @@
ErrorLimit = 0;
TemplateBacktraceLimit = 0;
- // Set all mappings to 'unset'.
- DiagMappingsStack.clear();
- DiagMappingsStack.push_back(DiagMappings());
+ // Create a DiagState and DiagStatePoint representing diagnostic changes
+ // through command-line.
+ DiagStates.push_back(DiagState());
+ PushDiagStatePoint(&DiagStates.back(), SourceLocation());
Reset();
}
@@ -62,17 +63,19 @@
}
-void Diagnostic::pushMappings() {
- // Avoids undefined behavior when the stack has to resize.
- DiagMappingsStack.reserve(DiagMappingsStack.size() + 1);
- DiagMappingsStack.push_back(DiagMappingsStack.back());
+void Diagnostic::pushMappings(SourceLocation Loc) {
+ DiagStateOnPushStack.push_back(GetCurDiagState());
}
-bool Diagnostic::popMappings() {
- if (DiagMappingsStack.size() == 1)
+bool Diagnostic::popMappings(SourceLocation Loc) {
+ if (DiagStateOnPushStack.empty())
return false;
- DiagMappingsStack.pop_back();
+ if (DiagStateOnPushStack.back() != GetCurDiagState()) {
+ // State changed at some point between push/pop.
+ PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
+ }
+ DiagStateOnPushStack.pop_back();
return true;
}
@@ -109,6 +112,91 @@
DelayedDiagArg2.clear();
}
+Diagnostic::DiagStatePointsTy::iterator
+Diagnostic::GetDiagStatePointForLoc(SourceLocation L) const {
+ assert(!DiagStatePoints.empty());
+ assert(DiagStatePoints.front().Loc.isInvalid() &&
+ "Should have created a DiagStatePoint for command-line");
+
+ FullSourceLoc Loc(L, *SourceMgr);
+ if (Loc.isInvalid())
+ return DiagStatePoints.end() - 1;
+
+ DiagStatePointsTy::iterator Pos = DiagStatePoints.end();
+ FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
+ if (LastStateChangePos.isValid() &&
+ Loc.isBeforeInTranslationUnitThan(LastStateChangePos))
+ Pos = std::upper_bound(DiagStatePoints.begin(), DiagStatePoints.end(),
+ DiagStatePoint(0, Loc));
+ --Pos;
+ return Pos;
+}
+
+/// \brief This allows the client to specify that certain
+/// warnings are ignored. Notes can never be mapped, errors can only be
+/// mapped to fatal, and WARNINGs and EXTENSIONs can be mapped arbitrarily.
+///
+/// \param The source location that this change of diagnostic state should
+/// take affect. It can be null if we are setting the latest state.
+void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
+ SourceLocation L) {
+ assert(Diag < diag::DIAG_UPPER_LIMIT &&
+ "Can only map builtin diagnostics");
+ assert((Diags->isBuiltinWarningOrExtension(Diag) ||
+ (Map == diag::MAP_FATAL || Map == diag::MAP_ERROR)) &&
+ "Cannot map errors into warnings!");
+ assert(!DiagStatePoints.empty());
+
+ FullSourceLoc Loc(L, *SourceMgr);
+ FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
+
+ // Common case; setting all the diagnostics of a group in one place.
+ if (Loc.isInvalid() || Loc == LastStateChangePos) {
+ setDiagnosticMappingInternal(Diag, Map, GetCurDiagState(), true);
+ return;
+ }
+
+ // Another common case; modifying diagnostic state in a source location
+ // after the previous one.
+ if ((Loc.isValid() && LastStateChangePos.isInvalid()) ||
+ LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) {
+ // A diagnostic pragma occured, create a new DiagState initialized with
+ // the current one and a new DiagStatePoint to record at which location
+ // the new state became active.
+ DiagStates.push_back(*GetCurDiagState());
+ PushDiagStatePoint(&DiagStates.back(), Loc);
+ setDiagnosticMappingInternal(Diag, Map, GetCurDiagState(), true);
+ return;
+ }
+
+ // We allow setting the diagnostic state in random source order for
+ // completeness but it should not be actually happening in normal practice.
+
+ DiagStatePointsTy::iterator Pos = GetDiagStatePointForLoc(Loc);
+ assert(Pos != DiagStatePoints.end());
+
+ // Update all diagnostic states that are active after the given location.
+ for (DiagStatePointsTy::iterator
+ I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) {
+ setDiagnosticMappingInternal(Diag, Map, I->State, true);
+ }
+
+ // If the location corresponds to an existing point, just update its state.
+ if (Pos->Loc == Loc) {
+ setDiagnosticMappingInternal(Diag, Map, Pos->State, true);
+ return;
+ }
+
+ // Create a new state/point and fit it into the vector of DiagStatePoints
+ // so that the vector is always ordered according to location.
+ Pos->Loc.isBeforeInTranslationUnitThan(Loc);
+ DiagStates.push_back(*Pos->State);
+ DiagState *NewState = &DiagStates.back();
+ setDiagnosticMappingInternal(Diag, Map, NewState, true);
+ DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
+ FullSourceLoc(Loc, *SourceMgr)));
+}
+
void DiagnosticBuilder::FlushCounts() {
DiagObj->NumDiagArgs = NumArgs;
DiagObj->NumDiagRanges = NumRanges;
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index 5d5bf7b..29a8d92 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -282,32 +282,42 @@
/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
/// object, classify the specified diagnostic ID into a Level, consumable by
/// the DiagnosticClient.
-DiagnosticIDs::Level DiagnosticIDs::getDiagnosticLevel(unsigned DiagID,
- const Diagnostic &Diag) const {
+DiagnosticIDs::Level
+DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc,
+ const Diagnostic &Diag) const {
// Handle custom diagnostics, which cannot be mapped.
if (DiagID >= diag::DIAG_UPPER_LIMIT)
return CustomDiagInfo->getLevel(DiagID);
unsigned DiagClass = getBuiltinDiagClass(DiagID);
assert(DiagClass != CLASS_NOTE && "Cannot get diagnostic level of a note!");
- return getDiagnosticLevel(DiagID, DiagClass, Diag);
+ return getDiagnosticLevel(DiagID, DiagClass, Loc, Diag);
}
-/// getDiagnosticLevel - Based on the way the client configured the Diagnostic
+/// \brief Based on the way the client configured the Diagnostic
/// object, classify the specified diagnostic ID into a Level, consumable by
/// the DiagnosticClient.
+///
+/// \param Loc The source location we are interested in finding out the
+/// diagnostic state. Can be null in order to query the latest state.
DiagnosticIDs::Level
DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
- const Diagnostic &Diag) const {
+ SourceLocation Loc,
+ const Diagnostic &Diag) const {
// Specific non-error diagnostics may be mapped to various levels from ignored
// to error. Errors can only be mapped to fatal.
DiagnosticIDs::Level Result = DiagnosticIDs::Fatal;
+ Diagnostic::DiagStatePointsTy::iterator
+ Pos = Diag.GetDiagStatePointForLoc(Loc);
+ Diagnostic::DiagState *State = Pos->State;
+
// Get the mapping information, if unset, compute it lazily.
- unsigned MappingInfo = Diag.getDiagnosticMappingInfo((diag::kind)DiagID);
+ unsigned MappingInfo = Diag.getDiagnosticMappingInfo((diag::kind)DiagID,
+ State);
if (MappingInfo == 0) {
MappingInfo = GetDefaultDiagMapping(DiagID);
- Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, false);
+ Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false);
}
switch (MappingInfo & 7) {
@@ -404,17 +414,17 @@
}
static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping,
- Diagnostic &Diag) {
+ SourceLocation Loc, Diagnostic &Diag) {
// Option exists, poke all the members of its diagnostic set.
if (const short *Member = Group->Members) {
for (; *Member != -1; ++Member)
- Diag.setDiagnosticMapping(*Member, Mapping);
+ Diag.setDiagnosticMapping(*Member, Mapping, Loc);
}
// Enable/disable all subgroups along with this one.
if (const short *SubGroups = Group->SubGroups) {
for (; *SubGroups != (short)-1; ++SubGroups)
- MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Diag);
+ MapGroupMembers(&OptionTable[(short)*SubGroups], Mapping, Loc, Diag);
}
}
@@ -423,7 +433,18 @@
/// ignores the request if "Group" was unknown, false otherwise.
bool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group,
diag::Mapping Map,
+ SourceLocation Loc,
Diagnostic &Diag) const {
+ assert((Loc.isValid() ||
+ Diag.DiagStatePoints.empty() ||
+ Diag.DiagStatePoints.back().Loc.isInvalid()) &&
+ "Loc should be invalid only when the mapping comes from command-line");
+ assert((Loc.isInvalid() || Diag.DiagStatePoints.empty() ||
+ Diag.DiagStatePoints.back().Loc.isInvalid() ||
+ !Diag.SourceMgr->isBeforeInTranslationUnit(Loc,
+ Diag.DiagStatePoints.back().Loc)) &&
+ "Source location of new mapping is before the previous one!");
+
WarningOption Key = { Group, 0, 0 };
const WarningOption *Found =
std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
@@ -432,7 +453,7 @@
strcmp(Found->Name, Group) != 0)
return true; // Option not found.
- MapGroupMembers(Found, Map, Diag);
+ MapGroupMembers(Found, Map, Loc, Diag);
return false;
}
@@ -475,7 +496,8 @@
// *map* warnings/extensions to errors.
ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR;
- DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Diag);
+ DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Info.getLocation(),
+ Diag);
}
}
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index 1571e22..5062d43 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -110,6 +110,11 @@
return SrcMgr->isInSystemHeader(*this);
}
+bool FullSourceLoc::isBeforeInTranslationUnitThan(SourceLocation Loc) const {
+ assert(isValid());
+ return SrcMgr->isBeforeInTranslationUnit(*this, Loc);
+}
+
const char *FullSourceLoc::getCharacterData(bool *Invalid) const {
assert(isValid());
return SrcMgr->getCharacterData(*this, Invalid);
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index c6d0934..c819011 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -22,8 +22,9 @@
IsBuiltinMacro = false;
IsFromAST = false;
IsDisabled = false;
- IsUsed = true;
+ IsUsed = false;
IsAllowRedefinitionsWithoutWarning = false;
+ IsWarnIfUnused = false;
ArgumentList = 0;
NumArguments = 0;
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index 3414c27..467d485 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -1504,11 +1504,6 @@
}
}
- // If this is the primary source file, remember that this macro hasn't been
- // used yet.
- if (isInPrimaryFile())
- MI->setIsUsed(false);
-
MI->setDefinitionEndLoc(LastTok.getLocation());
// Finally, if this identifier already had a macro defined for it, verify that
@@ -1536,6 +1531,16 @@
setMacroInfo(MacroNameTok.getIdentifierInfo(), MI);
+ assert(!MI->isUsed());
+ // If we need warning for not using the macro, add its location in the
+ // warn-because-unused-macro set. If it gets used it will be removed from set.
+ if (isInPrimaryFile() && // don't warn for include'd macros.
+ Diags->getDiagnosticLevel(diag::pp_macro_not_used,
+ MI->getDefinitionLoc()) != Diagnostic::Ignored) {
+ MI->setIsWarnIfUnused(true);
+ WarnUnusedMacroLocs.insert(MI->getDefinitionLoc());
+ }
+
// If the callbacks want to know, tell them about the macro definition.
if (Callbacks)
Callbacks->MacroDefined(MacroNameTok, MI);
@@ -1569,6 +1574,9 @@
if (Callbacks)
Callbacks->MacroUndefined(MacroNameTok, MI);
+ if (MI->isWarnIfUnused())
+ WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
+
// Free macro definition.
ReleaseMacroInfo(MI);
setMacroInfo(MacroNameTok.getIdentifierInfo(), 0);
@@ -1621,7 +1629,7 @@
// If there is a macro, process it.
if (MI) // Mark it used.
- MI->setIsUsed(true);
+ markMacroAsUsed(MI);
// Should we include the stuff contained by this directive?
if (!MI == isIfndef) {
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index 79ed867..1451c5a 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -112,7 +112,7 @@
// If there is a macro, mark it used.
if (Result.Val != 0 && ValueLive) {
MacroInfo *Macro = PP.getMacroInfo(II);
- Macro->setIsUsed(true);
+ PP.markMacroAsUsed(Macro);
}
// Consume identifier.
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index 4a40405..eef42b6 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -250,15 +250,11 @@
CurPPLexer = 0;
- // This is the end of the top-level file. If the diag::pp_macro_not_used
- // diagnostic is enabled, look for macros that have not been used.
- if (getDiagnostics().getDiagnosticLevel(diag::pp_macro_not_used) !=
- Diagnostic::Ignored) {
- for (macro_iterator I = macro_begin(false), E = macro_end(false);
- I != E; ++I)
- if (!I->second->isUsed())
- Diag(I->second->getDefinitionLoc(), diag::pp_macro_not_used);
- }
+ // This is the end of the top-level file. 'WarnUnusedMacroLocs' has collected
+ // all macro locations that we need to warn because they are not used.
+ for (WarnUnusedMacroLocsTy::iterator
+ I=WarnUnusedMacroLocs.begin(), E=WarnUnusedMacroLocs.end(); I!=E; ++I)
+ Diag(*I, diag::pp_macro_not_used);
return true;
}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index d3f3db3..333da11 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -223,7 +223,7 @@
}
// Notice that this macro has been used.
- MI->setIsUsed(true);
+ markMacroAsUsed(MI);
// If we started lexing a macro, enter the macro expansion body.
@@ -869,3 +869,11 @@
}
CreateString(OS.str().data(), OS.str().size(), Tok, Tok.getLocation());
}
+
+void Preprocessor::markMacroAsUsed(MacroInfo *MI) {
+ // If the 'used' status changed, and the macro requires 'unused' warning,
+ // remove its SourceLocation from the warn-for-unused-macro locations.
+ if (MI->isWarnIfUnused() && !MI->isUsed())
+ WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
+ MI->setIsUsed(true);
+}
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 5862552..e6a53a1 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -646,7 +646,11 @@
if (iter != PragmaPushMacroInfo.end()) {
// Release the MacroInfo currently associated with IdentInfo.
MacroInfo *CurrentMI = getMacroInfo(IdentInfo);
- if (CurrentMI) ReleaseMacroInfo(CurrentMI);
+ if (CurrentMI) {
+ if (CurrentMI->isWarnIfUnused())
+ WarnUnusedMacroLocs.erase(CurrentMI->getDefinitionLoc());
+ ReleaseMacroInfo(CurrentMI);
+ }
// Get the MacroInfo we want to reinstall.
MacroInfo *MacroToReInstall = iter->second.back();
@@ -810,6 +814,7 @@
explicit PragmaDiagnosticHandler() : PragmaHandler("diagnostic") {}
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &DiagToken) {
+ SourceLocation DiagLoc = DiagToken.getLocation();
Token Tok;
PP.LexUnexpandedToken(Tok);
if (Tok.isNot(tok::identifier)) {
@@ -828,12 +833,12 @@
else if (II->isStr("fatal"))
Map = diag::MAP_FATAL;
else if (II->isStr("pop")) {
- if (!PP.getDiagnostics().popMappings())
+ if (!PP.getDiagnostics().popMappings(DiagLoc))
PP.Diag(Tok, diag::warn_pragma_diagnostic_cannot_pop);
return;
} else if (II->isStr("push")) {
- PP.getDiagnostics().pushMappings();
+ PP.getDiagnostics().pushMappings(DiagLoc);
return;
} else {
PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
@@ -883,7 +888,7 @@
}
if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.c_str()+2,
- Map))
+ Map, DiagLoc))
PP.Diag(StrToks[0].getLocation(),
diag::warn_pragma_diagnostic_unknown_warning) << WarningName;
}
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index a9001c6..f4fde40 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -216,9 +216,11 @@
unsigned diag_AlwaysFallThrough_ReturnsNonVoid;
unsigned diag_NeverFallThroughOrReturn;
bool funMode;
+ SourceLocation FuncLoc;
static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) {
CheckFallThroughDiagnostics D;
+ D.FuncLoc = Func->getLocation();
D.diag_MaybeFallThrough_HasNoReturn =
diag::warn_falloff_noreturn_function;
D.diag_MaybeFallThrough_ReturnsNonVoid =
@@ -263,18 +265,22 @@
bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid,
bool HasNoReturn) const {
if (funMode) {
- return (D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
- == Diagnostic::Ignored || ReturnsVoid)
- && (D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
- == Diagnostic::Ignored || !HasNoReturn)
- && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
- == Diagnostic::Ignored || !ReturnsVoid);
+ return (ReturnsVoid ||
+ D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function,
+ FuncLoc) == Diagnostic::Ignored)
+ && (!HasNoReturn ||
+ D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr,
+ FuncLoc) == Diagnostic::Ignored)
+ && (!ReturnsVoid ||
+ D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc)
+ == Diagnostic::Ignored);
}
// For blocks.
return ReturnsVoid && !HasNoReturn
- && (D.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
- == Diagnostic::Ignored || !ReturnsVoid);
+ && (!ReturnsVoid ||
+ D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc)
+ == Diagnostic::Ignored);
}
};
@@ -363,7 +369,8 @@
clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) : S(s) {
Diagnostic &D = S.getDiagnostics();
DefaultPolicy.enableCheckUnreachable = (unsigned)
- (D.getDiagnosticLevel(diag::warn_unreachable) != Diagnostic::Ignored);
+ (D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) !=
+ Diagnostic::Ignored);
}
void clang::sema::
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index b699f5a..c75b27c 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -2863,11 +2863,12 @@
if (!Suspicious) return;
// ...but it's currently ignored...
- if (S.Diags.getDiagnosticLevel(diag::warn_impcast_integer_sign_conditional))
+ if (S.Diags.getDiagnosticLevel(diag::warn_impcast_integer_sign_conditional,
+ CC))
return;
// ...and -Wsign-compare isn't...
- if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional))
+ if (!S.Diags.getDiagnosticLevel(diag::warn_mixed_sign_conditional, CC))
return;
// ...then check whether it would have warned about either of the
@@ -3028,7 +3029,8 @@
void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
// This is actually a lot of work to potentially be doing on every
// cast; don't do it if we're ignoring -Wcast_align (as is the default).
- if (getDiagnostics().getDiagnosticLevel(diag::warn_cast_align)
+ if (getDiagnostics().getDiagnosticLevel(diag::warn_cast_align,
+ TRange.getBegin())
== Diagnostic::Ignored)
return;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 17a1a1b..6182e86 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -809,7 +809,7 @@
<< Context.BuiltinInfo.GetName(BID)
<< R;
if (Context.BuiltinInfo.getHeaderName(BID) &&
- Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl)
+ Diags.getDiagnosticLevel(diag::ext_implicit_lib_function_decl, Loc)
!= Diagnostic::Ignored)
Diag(Loc, diag::note_please_include_header)
<< Context.BuiltinInfo.getHeaderName(BID)
@@ -3081,7 +3081,8 @@
///
void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
// Return if warning is ignored.
- if (Diags.getDiagnosticLevel(diag::warn_decl_shadow) == Diagnostic::Ignored)
+ if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, R.getNameLoc()) ==
+ Diagnostic::Ignored)
return;
// Don't diagnose declarations at file scope. The scope might not
@@ -3135,6 +3136,10 @@
/// \brief Check -Wshadow without the advantage of a previous lookup.
void Sema::CheckShadow(Scope *S, VarDecl *D) {
+ if (Diags.getDiagnosticLevel(diag::warn_decl_shadow, D->getLocation()) ==
+ Diagnostic::Ignored)
+ return;
+
LookupResult R(*this, D->getDeclName(), D->getLocation(),
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
LookupName(R, S);
@@ -5014,10 +5019,6 @@
void Sema::DiagnoseUnusedParameters(ParmVarDecl * const *Param,
ParmVarDecl * const *ParamEnd) {
- if (Diags.getDiagnosticLevel(diag::warn_unused_parameter) ==
- Diagnostic::Ignored)
- return;
-
// Don't diagnose unused-parameter errors in template instantiations; we
// will already have done so in the template itself.
if (!ActiveTemplateInstantiations.empty())
@@ -5048,9 +5049,6 @@
<< D->getDeclName() << Size;
}
- if (Diags.getDiagnosticLevel(diag::warn_parameter_size)==Diagnostic::Ignored)
- return;
-
// Warn if any parameter is pass-by-value and larger than the specified
// threshold.
for (; Param != ParamEnd; ++Param) {
@@ -5255,9 +5253,6 @@
CheckParmsForFunctionDef(FD->param_begin(), FD->param_end(),
/*CheckParameterNames=*/true);
- bool ShouldCheckShadow =
- Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored;
-
// Introduce our parameters into the function scope
for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
@@ -5265,8 +5260,7 @@
// If this has an identifier, add it to the scope stack.
if (Param->getIdentifier() && FnBodyScope) {
- if (ShouldCheckShadow)
- CheckShadow(FnBodyScope, Param);
+ CheckShadow(FnBodyScope, Param);
PushOnScopeChains(Param, FnBodyScope);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index eec80f0..d538715 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1991,8 +1991,19 @@
if (Constructor->getDeclContext()->isDependentContext())
return;
- if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order)
- == Diagnostic::Ignored)
+ // Don't check initializers order unless the warning is enabled at the
+ // location of at least one initializer.
+ bool ShouldCheckOrder = false;
+ for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) {
+ CXXBaseOrMemberInitializer *Init = Inits[InitIndex];
+ if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order,
+ Init->getSourceLocation())
+ != Diagnostic::Ignored) {
+ ShouldCheckOrder = true;
+ break;
+ }
+ }
+ if (!ShouldCheckOrder)
return;
// Build the list of bases and members in the order that they'll
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index f29a01e..38e9146 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -969,7 +969,8 @@
IDecl->lookupInstanceMethod(method->getSelector());
if (!MethodInClass || !MethodInClass->isSynthesized()) {
unsigned DIAG = diag::warn_unimplemented_protocol_method;
- if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) {
+ if (Diags.getDiagnosticLevel(DIAG, ImpLoc)
+ != Diagnostic::Ignored) {
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
Diag(method->getLocation(), diag::note_method_declared_at);
Diag(CDecl->getLocation(), diag::note_required_for_protocol_at)
@@ -987,7 +988,7 @@
!ClsMap.count(method->getSelector()) &&
(!Super || !Super->lookupClassMethod(method->getSelector()))) {
unsigned DIAG = diag::warn_unimplemented_protocol_method;
- if (Diags.getDiagnosticLevel(DIAG) != Diagnostic::Ignored) {
+ if (Diags.getDiagnosticLevel(DIAG, ImpLoc) != Diagnostic::Ignored) {
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
Diag(method->getLocation(), diag::note_method_declared_at);
Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) <<
@@ -1325,7 +1326,8 @@
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
bool strictSelectorMatch = receiverIdOrClass && warn &&
- (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl) !=
+ (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
+ R.getBegin()) !=
Diagnostic::Ignored);
if (warn && MethList.Method && MethList.Next) {
bool issueWarning = false;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 0d4eb77..dff9b45 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -8336,17 +8336,13 @@
if (Params.empty())
return;
- bool ShouldCheckShadow =
- Diags.getDiagnosticLevel(diag::warn_decl_shadow) != Diagnostic::Ignored;
-
for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
E = CurBlock->TheDecl->param_end(); AI != E; ++AI) {
(*AI)->setOwningFunction(CurBlock->TheDecl);
// If this has an identifier, add it to the scope stack.
if ((*AI)->getIdentifier()) {
- if (ShouldCheckShadow)
- CheckShadow(CurBlock->TheScope, *AI);
+ CheckShadow(CurBlock->TheScope, *AI);
PushOnScopeChains(*AI, CurBlock->TheScope);
}
@@ -8670,7 +8666,8 @@
E->getSourceRange();
if (EvalResult.Diag &&
- Diags.getDiagnosticLevel(diag::ext_expr_not_ice) != Diagnostic::Ignored)
+ Diags.getDiagnosticLevel(diag::ext_expr_not_ice, EvalResult.DiagLoc)
+ != Diagnostic::Ignored)
Diag(EvalResult.DiagLoc, EvalResult.Diag);
if (Result)
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 098f71a..bbabf80 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -2670,7 +2670,8 @@
while (Idx < UserDiagMappings.size()) {
unsigned DiagID = UserDiagMappings[Idx++];
unsigned Map = UserDiagMappings[Idx++];
- Diag.setDiagnosticMappingInternal(DiagID, Map, /*isUser=*/true);
+ Diag.setDiagnosticMappingInternal(DiagID, Map, Diag.GetCurDiagState(),
+ /*isUser=*/true);
}
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 7b405e9..26a54b1 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -1460,7 +1460,7 @@
void ASTWriter::WriteUserDiagnosticMappings(const Diagnostic &Diag) {
RecordData Record;
for (unsigned i = 0; i != diag::DIAG_UPPER_LIMIT; ++i) {
- diag::Mapping Map = Diag.getDiagnosticMappingInfo(i);
+ diag::Mapping Map = Diag.getDiagnosticMappingInfo(i,Diag.GetCurDiagState());
if (Map & 0x8) { // user mapping.
Record.push_back(i);
Record.push_back(Map & 0x7);