From: Argyrios Kyrtzidis Date: Wed, 15 Dec 2010 18:44:22 +0000 (+0000) Subject: Fix diagnostic pragmas. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0827408865e32789e0ec4b8113a302ccdc531423;p=clang 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/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index b0ed3e1a17..bc835019c9 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -16,11 +16,13 @@ #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/type_traits.h" #include +#include namespace clang { class DiagnosticClient; @@ -158,30 +160,82 @@ private: DiagnosticClient *Client; bool OwnsDiagClient; SourceManager *SourceMgr; - - /// DiagMappings - Mapping information for diagnostics. Mapping info is + + /// \brief Mapping information for diagnostics. Mapping info is /// packed into four bits per diagnostic. The low three bits are the mapping /// (an instance of diag::Mapping), or zero if unset. The high bit is set /// when the mapping was established as a user mapping. If the high bit is /// clear, then the low bits are set to the default value, and should be /// mapped with -pedantic, -Werror, etc. - class DiagMappings { - unsigned char Values[diag::DIAG_UPPER_LIMIT/2]; + /// + /// Contrary to DiagMappings, a new DiagState is created and kept around when + /// diagnostic pragmas modify the state so that we know what is the diagnostic + /// state at any given source location. + class DiagState { + mutable llvm::DenseMap DiagMap; public: - DiagMappings() : Values() /*zero-initialization of array*/ { } + void setMapping(diag::kind Diag, unsigned Map) { DiagMap[Diag] = Map; } - void setMapping(diag::kind Diag, unsigned Map) { - size_t Shift = (Diag & 1)*4; - Values[Diag/2] = (Values[Diag/2] & ~(15 << Shift)) | (Map << Shift); + diag::Mapping getMapping(diag::kind Diag) const { + return (diag::Mapping)DiagMap[Diag]; } + }; - diag::Mapping getMapping(diag::kind Diag) const { - return (diag::Mapping)((Values[Diag/2] >> (Diag & 1)*4) & 15); + /// \brief Keeps and automatically disposes all DiagStates that we create. + std::list DiagStates; + + /// \brief Represents a point in source where the diagnostic state was + /// modified because of a pragma. 'Loc' can be null if the point represents + /// the diagnostic state modifications done through the command-line. + struct DiagStatePoint { + DiagState *State; + FullSourceLoc Loc; + DiagStatePoint(DiagState *State, FullSourceLoc Loc) + : State(State), Loc(Loc) { } + + bool operator<(const DiagStatePoint &RHS) const { + // If Loc is invalid it means it came from , in which case + // we regard it as coming before any valid source location. + if (RHS.Loc.isInvalid()) + return false; + if (Loc.isInvalid()) + return true; + return Loc.isBeforeInTranslationUnitThan(RHS.Loc); } }; - mutable std::vector DiagMappingsStack; + /// \brief A vector of all DiagStatePoints representing changes in diagnostic + /// state due to diagnostic pragmas. The vector is always sorted according to + /// the SourceLocation of the DiagStatePoint. + typedef std::vector DiagStatePointsTy; + mutable DiagStatePointsTy DiagStatePoints; + + /// \brief Keeps the DiagState that was active during each diagnostic 'push' + /// so we can get back at it when we 'pop'. + std::vector DiagStateOnPushStack; + + DiagState *GetCurDiagState() const { + assert(!DiagStatePoints.empty()); + return DiagStatePoints.back().State; + } + + void PushDiagStatePoint(DiagState *State, SourceLocation L) { + FullSourceLoc Loc(L, *SourceMgr); + // Make sure that DiagStatePoints is always sorted according to Loc. + assert((Loc.isValid() || DiagStatePoints.empty()) && + "Adding invalid loc point after another point"); + assert((Loc.isInvalid() || DiagStatePoints.empty() || + DiagStatePoints.back().Loc.isInvalid() || + DiagStatePoints.back().Loc.isBeforeInTranslationUnitThan(Loc)) && + "Previous point loc comes after or is the same as new one"); + DiagStatePoints.push_back(DiagStatePoint(State, + FullSourceLoc(Loc, *SourceMgr))); + } + + /// \brief Finds the DiagStatePoint that contains the diagnostic state of + /// the given source location. + DiagStatePointsTy::iterator GetDiagStatePointForLoc(SourceLocation Loc) const; /// ErrorOccurred / FatalErrorOccurred - This is set to true when an error or /// fatal error is emitted, and is sticky. @@ -261,13 +315,13 @@ public: /// pushMappings - Copies the current DiagMappings and pushes the new copy /// onto the top of the stack. - void pushMappings(); + void pushMappings(SourceLocation Loc); /// popMappings - Pops the current DiagMappings off the top of the stack /// causing the new top of the stack to be the active mappings. Returns /// true if the pop happens, false if there is only one DiagMapping on the /// stack. - bool popMappings(); + bool popMappings(SourceLocation Loc); /// \brief Set the diagnostic client associated with this diagnostic object. /// @@ -349,23 +403,24 @@ public: void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; } bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; } - /// setDiagnosticMapping - This allows the client to specify that certain + /// \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. - void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map) { - 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!"); - setDiagnosticMappingInternal(Diag, Map, true); - } + /// + /// \param Loc The source location that this change of diagnostic state should + /// take affect. It can be null if we are setting the latest state. + void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, + SourceLocation Loc); /// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g. /// "unknown-pragmas" to have the specified mapping. This returns true and /// ignores the request if "Group" was unknown, false otherwise. - bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map) { - return Diags->setDiagnosticGroupMapping(Group, Map, *this); + /// + /// 'Loc' is the source location that this change of diagnostic state should + /// take affect. It can be null if we are setting the state from command-line. + bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map, + SourceLocation Loc = SourceLocation()) { + return Diags->setDiagnosticGroupMapping(Group, Map, Loc, *this); } bool hasErrorOccurred() const { return ErrorOccurred; } @@ -408,11 +463,14 @@ public: // Diagnostic classification and reporting interfaces. // - /// 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. - Level getDiagnosticLevel(unsigned DiagID) const { - return (Level)Diags->getDiagnosticLevel(DiagID, *this); + /// + /// \param Loc The source location we are interested in finding out the + /// diagnostic state. Can be null in order to query the latest state. + Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const { + return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this); } /// Report - Issue the message to the client. @c DiagID is a member of the @@ -461,14 +519,15 @@ private: /// getDiagnosticMappingInfo - Return the mapping info currently set for the /// specified builtin diagnostic. This returns the high bit encoding, or zero /// if the field is completely uninitialized. - diag::Mapping getDiagnosticMappingInfo(diag::kind Diag) const { - return DiagMappingsStack.back().getMapping(Diag); + diag::Mapping getDiagnosticMappingInfo(diag::kind Diag, + DiagState *State) const { + return State->getMapping(Diag); } void setDiagnosticMappingInternal(unsigned DiagId, unsigned Map, - bool isUser) const { + DiagState *State, bool isUser) const { if (isUser) Map |= 8; // Set the high bit for user mappings. - DiagMappingsStack.back().setMapping((diag::kind)DiagId, Map); + State->setMapping((diag::kind)DiagId, Map); } // This is private state used by DiagnosticBuilder. We put it here instead of diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h index a84ebfaf9f..eede94b2c5 100644 --- a/include/clang/Basic/DiagnosticIDs.h +++ b/include/clang/Basic/DiagnosticIDs.h @@ -19,6 +19,7 @@ namespace clang { class Diagnostic; + class SourceLocation; // Import the diagnostic enums themselves. namespace diag { @@ -174,18 +175,22 @@ private: /// "unknown-pragmas" to have the specified mapping. This returns true and /// ignores the request if "Group" was unknown, false otherwise. bool setDiagnosticGroupMapping(const char *Group, diag::Mapping Map, - Diagnostic &Diag) const; + SourceLocation Loc, Diagnostic &Diag) const; - /// 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. - DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID, + /// + /// \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 getDiagnosticLevel(unsigned DiagID, SourceLocation Loc, const Diagnostic &Diag) const; /// getDiagnosticLevel - This is an internal implementation helper used when /// DiagClass is already known. DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID, unsigned DiagClass, + SourceLocation Loc, const Diagnostic &Diag) const; /// ProcessDiag - This is the method used to report a diagnostic that is diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h index da2ec15e3f..74f762bd90 100644 --- a/include/clang/Basic/SourceLocation.h +++ b/include/clang/Basic/SourceLocation.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_SOURCELOCATION_H #define LLVM_CLANG_SOURCELOCATION_H +#include "llvm/Support/PointerLikeTypeTraits.h" #include #include @@ -264,6 +265,20 @@ public: bool isInSystemHeader() const; + /// \brief Determines the order of 2 source locations in the translation unit. + /// + /// \returns true if this source location comes before 'Loc', false otherwise. + bool isBeforeInTranslationUnitThan(SourceLocation Loc) const; + + /// \brief Determines the order of 2 source locations in the translation unit. + /// + /// \returns true if this source location comes before 'Loc', false otherwise. + bool isBeforeInTranslationUnitThan(FullSourceLoc Loc) const { + assert(Loc.isValid()); + assert(SrcMgr == Loc.SrcMgr && "Loc comes from another SourceManager!"); + return isBeforeInTranslationUnitThan((SourceLocation)Loc); + } + /// Prints information about this FullSourceLoc to stderr. Useful for /// debugging. void dump() const { SourceLocation::dump(*SrcMgr); } @@ -349,6 +364,19 @@ namespace llvm { template <> struct isPodLike { static const bool value = true; }; + // Teach SmallPtrSet how to handle SourceLocation. + template<> + class PointerLikeTypeTraits { + public: + static inline void *getAsVoidPointer(clang::SourceLocation L) { + return (void*)L.getRawEncoding(); + } + static inline clang::SourceLocation getFromVoidPointer(void *P) { + return clang::SourceLocation::getFromRawEncoding((unsigned)(uintptr_t)P); + } + enum { NumLowBitsAvailable = 0 }; + }; + } // end namespace llvm #endif diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h index 90f95b7ace..717c3008ec 100644 --- a/include/clang/Lex/MacroInfo.h +++ b/include/clang/Lex/MacroInfo.h @@ -82,6 +82,9 @@ private: /// AllowRedefinitionsWithoutWarning - True if this macro can be redefined /// without emitting a warning. bool IsAllowRedefinitionsWithoutWarning : 1; + + /// \brief Must warn if the macro is unused at the end of translation unit. + bool IsWarnIfUnused : 1; ~MacroInfo() { assert(ArgumentList == 0 && "Didn't call destroy before dtor!"); @@ -138,6 +141,11 @@ public: IsAllowRedefinitionsWithoutWarning = Val; } + /// \brief Set the value of the IsWarnIfUnused flag. + void setIsWarnIfUnused(bool val) { + IsWarnIfUnused = val; + } + /// setArgumentList - Set the specified list of identifiers as the argument /// list for this macro. void setArgumentList(IdentifierInfo* const *List, unsigned NumArgs, @@ -201,6 +209,11 @@ public: return IsAllowRedefinitionsWithoutWarning; } + /// \brief Return true if we should emit a warning if the macro is unused. + bool isWarnIfUnused() const { + return IsWarnIfUnused; + } + /// getNumTokens - Return the number of tokens that this macro expands to. /// unsigned getNumTokens() const { diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index c2fcfe218e..1ced6a5800 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -25,6 +25,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Allocator.h" @@ -196,6 +197,16 @@ class Preprocessor { /// to the actual definition of the macro. llvm::DenseMap Macros; + /// \brief Macros that we want to warn because they are not used at the end + /// of the translation unit; we store just their SourceLocations instead + /// something like MacroInfo*. The benefit of this is that when we are + /// deserializing from PCH, we don't need to deserialize identifier & macros + /// just so that we can report that they are unused, we just warn using + /// the SourceLocations of this set (that will be filled by the ASTReader). + /// We are using SmallPtrSet instead of a vector for faster removal. + typedef llvm::SmallPtrSet WarnUnusedMacroLocsTy; + WarnUnusedMacroLocsTy WarnUnusedMacroLocs; + /// MacroArgCache - This is a "freelist" of MacroArg objects that can be /// reused for quick allocation. MacroArgs *MacroArgCache; @@ -1013,6 +1024,10 @@ public: // Return true and store the first token only if any CommentHandler // has inserted some tokens and getCommentRetentionState() is false. bool HandleComment(Token &Token, SourceRange Comment); + + /// \brief A macro is used, update information about macros that need unused + /// warnings. + void markMacroAsUsed(MacroInfo *MI); }; /// \brief Abstract base class that describes a handler that will receive diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 5098c2e4f8..919ba8187e 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -49,9 +49,10 @@ Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr &diags, 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 @@ Diagnostic::~Diagnostic() { } -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 @@ void Diagnostic::ReportDelayed() { 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 5d5bf7b72a..29a8d9270a 100644 --- a/lib/Basic/DiagnosticIDs.cpp +++ b/lib/Basic/DiagnosticIDs.cpp @@ -282,32 +282,42 @@ const char *DiagnosticIDs::getDescription(unsigned DiagID) const { /// 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 bool WarningOptionCompare(const WarningOption &LHS, } 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 @@ static void MapGroupMembers(const WarningOption *Group, diag::Mapping Mapping, /// 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 @@ bool DiagnosticIDs::setDiagnosticGroupMapping(const char *Group, 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 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { // *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 1571e2205f..5062d43f58 100644 --- a/lib/Basic/SourceLocation.cpp +++ b/lib/Basic/SourceLocation.cpp @@ -110,6 +110,11 @@ bool FullSourceLoc::isInSystemHeader() const { 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 c6d09349b5..c819011338 100644 --- a/lib/Lex/MacroInfo.cpp +++ b/lib/Lex/MacroInfo.cpp @@ -22,8 +22,9 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) { 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 3414c27bfc..467d485888 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -1504,11 +1504,6 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { } } - // 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 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { 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 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) { 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 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, // 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 79ed8677da..1451c5a1ef 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -112,7 +112,7 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT, // 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 4a40405992..eef42b69d8 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -250,15 +250,11 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { 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 d3f3db31da..333da11143 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -223,7 +223,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, } // 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 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { } 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 58625520a9..e6a53a1043 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -646,7 +646,11 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) { 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 @@ public: 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 @@ public: 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 @@ public: } 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 a9001c6e76..f4fde40bfb 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -216,9 +216,11 @@ struct CheckFallThroughDiagnostics { 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 @@ struct CheckFallThroughDiagnostics { 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::Policy::Policy() { 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 b699f5a318..c75b27c3ec 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -2863,11 +2863,12 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E, QualType T) { 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 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd, 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 17a1a1badb..6182e8663b 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -809,7 +809,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, << 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 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, /// 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 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { /// \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 @@ ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC, 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 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, << 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 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { 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 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // 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 eec80f0d5a..d538715917 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1991,8 +1991,19 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef, 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 f29a01eb45..38e91465d2 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -969,7 +969,8 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, 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 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, !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 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, 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 0d4eb77698..dff9b458ba 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8336,17 +8336,13 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { 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 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){ 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 098f71a529..bbabf80486 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -2670,7 +2670,8 @@ void ASTReader::ReadUserDiagnosticMappings(Diagnostic &Diag) { 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 7b405e9c8b..26a54b1d55 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1460,7 +1460,7 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) { 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); diff --git a/test/Preprocessor/pragma_diagnostic_sections.cpp b/test/Preprocessor/pragma_diagnostic_sections.cpp new file mode 100644 index 0000000000..00163938cc --- /dev/null +++ b/test/Preprocessor/pragma_diagnostic_sections.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -fsyntax-only -Wall -Wunused-macros -Wunused-parameter -verify %s + +// rdar://8365684 +struct S { + void m1() { int b = b==b; } // expected-warning {{always evaluates to true}} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wtautological-compare" + void m2() { int b = b==b; } +#pragma clang diagnostic pop + + void m3() { int b = b==b; } // expected-warning {{always evaluates to true}} +}; + +//------------------------------------------------------------------------------ + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wtautological-compare" +template +struct TS { + void m() { T b = b==b; } +}; +#pragma clang diagnostic pop + +void f() { + TS ts; + ts.m(); +} + +//------------------------------------------------------------------------------ + +#define UNUSED_MACRO1 // expected-warning {{macro is not used}} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-macros" +#define UNUSED_MACRO2 +#pragma clang diagnostic pop + +//------------------------------------------------------------------------------ + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type" +int g() { } +#pragma clang diagnostic pop + +//------------------------------------------------------------------------------ + +void ww( +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" + int x, +#pragma clang diagnostic pop + int y) // expected-warning {{unused}} +{ +} + +//------------------------------------------------------------------------------ + +struct S2 { + int x, y; + S2() : +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreorder" + y(), + x() +#pragma clang diagnostic pop + {} +}; + +//------------------------------------------------------------------------------