diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index b0ed3e1a178c..bc835019c9aa 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/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) { - size_t Shift = (Diag & 1)*4; - Values[Diag/2] = (Values[Diag/2] & ~(15 << Shift)) | (Map << Shift); - } + void setMapping(diag::kind Diag, unsigned Map) { DiagMap[Diag] = Map; } diag::Mapping getMapping(diag::kind Diag) const { - return (diag::Mapping)((Values[Diag/2] >> (Diag & 1)*4) & 15); + return (diag::Mapping)DiagMap[Diag]; } }; - mutable std::vector DiagMappingsStack; + /// \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); + } + }; + + /// \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/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h index a84ebfaf9f60..eede94b2c5bd 100644 --- a/clang/include/clang/Basic/DiagnosticIDs.h +++ b/clang/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/clang/include/clang/Basic/SourceLocation.h b/clang/include/clang/Basic/SourceLocation.h index da2ec15e3fbc..74f762bd908d 100644 --- a/clang/include/clang/Basic/SourceLocation.h +++ b/clang/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/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index 90f95b7acee3..717c3008eca9 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/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/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index c2fcfe218e6d..1ced6a580040 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/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/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp index 5098c2e4f8fa..919ba8187ecf 100644 --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/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/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp index 5d5bf7b72a26..29a8d9270a90 100644 --- a/clang/lib/Basic/DiagnosticIDs.cpp +++ b/clang/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/clang/lib/Basic/SourceLocation.cpp b/clang/lib/Basic/SourceLocation.cpp index 1571e2205f8c..5062d43f58f2 100644 --- a/clang/lib/Basic/SourceLocation.cpp +++ b/clang/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/clang/lib/Lex/MacroInfo.cpp b/clang/lib/Lex/MacroInfo.cpp index c6d09349b5ef..c819011338e8 100644 --- a/clang/lib/Lex/MacroInfo.cpp +++ b/clang/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/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 3414c27bfc8b..467d48588837 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/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/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp index 79ed8677da7a..1451c5a1ef5f 100644 --- a/clang/lib/Lex/PPExpressions.cpp +++ b/clang/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/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index 4a4040599263..eef42b69d87f 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/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/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index d3f3db31daa4..333da11143b5 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/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/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 58625520a991..e6a53a104360 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/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/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index a9001c6e7691..f4fde40bfba8 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/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/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index b699f5a318cf..c75b27c3eccb 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 17a1a1badb57..6182e8663b42 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index eec80f0d5a4b..d53871591708 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index f29a01eb4540..38e91465d2cd 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 0d4eb7769801..dff9b458ba30 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 098f71a529a7..bbabf80486ea 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/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/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 7b405e9c8b31..26a54b1d55e3 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/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/clang/test/Preprocessor/pragma_diagnostic_sections.cpp b/clang/test/Preprocessor/pragma_diagnostic_sections.cpp new file mode 100644 index 000000000000..00163938cc52 --- /dev/null +++ b/clang/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 + {} +}; + +//------------------------------------------------------------------------------