[cfe-commits] r121873 - in /cfe/trunk: include/clang/Basic/ include/clang/Lex/ lib/Basic/ lib/Lex/ lib/Sema/ lib/Serialization/ test/Preprocessor/

Argyrios Kyrtzidis akyrtzi at gmail.com
Wed Dec 15 10:44:23 PST 2010


Author: akirtzidis
Date: Wed Dec 15 12:44:22 2010
New Revision: 121873

URL: http://llvm.org/viewvc/llvm-project?rev=121873&view=rev
Log:
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.

Added:
    cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp
Modified:
    cfe/trunk/include/clang/Basic/Diagnostic.h
    cfe/trunk/include/clang/Basic/DiagnosticIDs.h
    cfe/trunk/include/clang/Basic/SourceLocation.h
    cfe/trunk/include/clang/Lex/MacroInfo.h
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/lib/Basic/Diagnostic.cpp
    cfe/trunk/lib/Basic/DiagnosticIDs.cpp
    cfe/trunk/lib/Basic/SourceLocation.cpp
    cfe/trunk/lib/Lex/MacroInfo.cpp
    cfe/trunk/lib/Lex/PPDirectives.cpp
    cfe/trunk/lib/Lex/PPExpressions.cpp
    cfe/trunk/lib/Lex/PPLexerChange.cpp
    cfe/trunk/lib/Lex/PPMacroExpansion.cpp
    cfe/trunk/lib/Lex/Pragma.cpp
    cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp

Modified: cfe/trunk/include/clang/Basic/Diagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.h?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Diagnostic.h (original)
+++ cfe/trunk/include/clang/Basic/Diagnostic.h Wed Dec 15 12:44:22 2010
@@ -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 <vector>
+#include <list>
 
 namespace clang {
   class DiagnosticClient;
@@ -158,30 +160,82 @@
   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<unsigned, unsigned> 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<DiagState> 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 <command-line>, 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<DiagMappings> 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<DiagStatePoint> 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<DiagState *> 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 @@
 
   /// 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 @@
   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 @@
   // 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 @@
   /// 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

Modified: cfe/trunk/include/clang/Basic/DiagnosticIDs.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticIDs.h?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticIDs.h (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticIDs.h Wed Dec 15 12:44:22 2010
@@ -19,6 +19,7 @@
 
 namespace clang {
   class Diagnostic;
+  class SourceLocation;
 
   // Import the diagnostic enums themselves.
   namespace diag {
@@ -174,18 +175,22 @@
   /// "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

Modified: cfe/trunk/include/clang/Basic/SourceLocation.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/SourceLocation.h?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/SourceLocation.h (original)
+++ cfe/trunk/include/clang/Basic/SourceLocation.h Wed Dec 15 12:44:22 2010
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_SOURCELOCATION_H
 #define LLVM_CLANG_SOURCELOCATION_H
 
+#include "llvm/Support/PointerLikeTypeTraits.h"
 #include <utility>
 #include <cassert>
 
@@ -264,6 +265,20 @@
 
   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 @@
   template <>
   struct isPodLike<clang::FileID> { static const bool value = true; };
 
+  // Teach SmallPtrSet how to handle SourceLocation.
+  template<>
+  class PointerLikeTypeTraits<clang::SourceLocation> {
+  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

Modified: cfe/trunk/include/clang/Lex/MacroInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/MacroInfo.h?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/MacroInfo.h (original)
+++ cfe/trunk/include/clang/Lex/MacroInfo.h Wed Dec 15 12:44:22 2010
@@ -82,6 +82,9 @@
   /// 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 @@
     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 @@
     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 {

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Wed Dec 15 12:44:22 2010
@@ -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 @@
   /// to the actual definition of the macro.
   llvm::DenseMap<IdentifierInfo*, MacroInfo*> 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<SourceLocation, 32> WarnUnusedMacroLocsTy;
+  WarnUnusedMacroLocsTy WarnUnusedMacroLocs;
+
   /// MacroArgCache - This is a "freelist" of MacroArg objects that can be
   /// reused for quick allocation.
   MacroArgs *MacroArgCache;
@@ -1013,6 +1024,10 @@
   // 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

Modified: cfe/trunk/lib/Basic/Diagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Diagnostic.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Diagnostic.cpp (original)
+++ cfe/trunk/lib/Basic/Diagnostic.cpp Wed Dec 15 12:44:22 2010
@@ -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;

Modified: cfe/trunk/lib/Basic/DiagnosticIDs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/DiagnosticIDs.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/DiagnosticIDs.cpp (original)
+++ cfe/trunk/lib/Basic/DiagnosticIDs.cpp Wed Dec 15 12:44:22 2010
@@ -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);
     }
   }
 

Modified: cfe/trunk/lib/Basic/SourceLocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/SourceLocation.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/SourceLocation.cpp (original)
+++ cfe/trunk/lib/Basic/SourceLocation.cpp Wed Dec 15 12:44:22 2010
@@ -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);

Modified: cfe/trunk/lib/Lex/MacroInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/MacroInfo.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/MacroInfo.cpp (original)
+++ cfe/trunk/lib/Lex/MacroInfo.cpp Wed Dec 15 12:44:22 2010
@@ -22,8 +22,9 @@
   IsBuiltinMacro = false;
   IsFromAST = false;
   IsDisabled = false;
-  IsUsed = true;
+  IsUsed = false;
   IsAllowRedefinitionsWithoutWarning = false;
+  IsWarnIfUnused = false;
 
   ArgumentList = 0;
   NumArguments = 0;

Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Wed Dec 15 12:44:22 2010
@@ -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) {

Modified: cfe/trunk/lib/Lex/PPExpressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPExpressions.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPExpressions.cpp (original)
+++ cfe/trunk/lib/Lex/PPExpressions.cpp Wed Dec 15 12:44:22 2010
@@ -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.

Modified: cfe/trunk/lib/Lex/PPLexerChange.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPLexerChange.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPLexerChange.cpp (original)
+++ cfe/trunk/lib/Lex/PPLexerChange.cpp Wed Dec 15 12:44:22 2010
@@ -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;
 }

Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Wed Dec 15 12:44:22 2010
@@ -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);
+}

Modified: cfe/trunk/lib/Lex/Pragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Pragma.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Pragma.cpp (original)
+++ cfe/trunk/lib/Lex/Pragma.cpp Wed Dec 15 12:44:22 2010
@@ -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;
   }

Modified: cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp (original)
+++ cfe/trunk/lib/Sema/AnalysisBasedWarnings.cpp Wed Dec 15 12:44:22 2010
@@ -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::

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Dec 15 12:44:22 2010
@@ -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;
 

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Dec 15 12:44:22 2010
@@ -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);
     }

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Dec 15 12:44:22 2010
@@ -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

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Wed Dec 15 12:44:22 2010
@@ -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;

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Dec 15 12:44:22 2010
@@ -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)

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Wed Dec 15 12:44:22 2010
@@ -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);
   }
 }
 

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=121873&r1=121872&r2=121873&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Dec 15 12:44:22 2010
@@ -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);

Added: cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp?rev=121873&view=auto
==============================================================================
--- cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp (added)
+++ cfe/trunk/test/Preprocessor/pragma_diagnostic_sections.cpp Wed Dec 15 12:44:22 2010
@@ -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 <typename T>
+struct TS {
+    void m() { T b = b==b; }
+};
+#pragma clang diagnostic pop
+
+void f() {
+    TS<int> 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
+    {}
+};
+
+//------------------------------------------------------------------------------





More information about the cfe-commits mailing list