]> granicus.if.org Git - clang/commitdiff
Properly propagate #pragma diagnostic mappings from PCH but not command-line warning...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Fri, 14 Jan 2011 20:54:07 +0000 (20:54 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Fri, 14 Jan 2011 20:54:07 +0000 (20:54 +0000)
Addresses rdar://8435969&8852495

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123462 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Diagnostic.h
include/clang/Serialization/ASTBitCodes.h
include/clang/Serialization/ASTReader.h
include/clang/Serialization/ASTWriter.h
lib/Basic/Diagnostic.cpp
lib/Basic/DiagnosticIDs.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/PCH/pragma-diag-section.cpp [new file with mode: 0644]
test/PCH/rdar8852495.c [new file with mode: 0644]

index bc835019c9aa0920119de252d92a89211ee8d991..fd34fdec1e35ff1ec24a1bbe87322e571af1cf58 100644 (file)
@@ -168,18 +168,26 @@ private:
   /// clear, then the low bits are set to the default value, and should be
   /// mapped with -pedantic, -Werror, etc.
   ///
-  /// 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.
+  /// 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;
+    llvm::DenseMap<unsigned, unsigned> DiagMap;
 
   public:
+    typedef llvm::DenseMap<unsigned, unsigned>::const_iterator iterator;
+
     void setMapping(diag::kind Diag, unsigned Map) { DiagMap[Diag] = Map; }
 
     diag::Mapping getMapping(diag::kind Diag) const {
-      return (diag::Mapping)DiagMap[Diag];
+      iterator I = DiagMap.find(Diag);
+      if (I != DiagMap.end())
+        return (diag::Mapping)I->second;
+      return diag::Mapping();
     }
+
+    iterator begin() const { return DiagMap.begin(); }
+    iterator end() const { return DiagMap.end(); }
   };
 
   /// \brief Keeps and automatically disposes all DiagStates that we create.
@@ -525,8 +533,10 @@ private:
   }
 
   void setDiagnosticMappingInternal(unsigned DiagId, unsigned Map,
-                                    DiagState *State, bool isUser) const {
+                                    DiagState *State,
+                                    bool isUser, bool isPragma) const {
     if (isUser) Map |= 8;  // Set the high bit for user mappings.
+    if (isPragma) Map |= 0x10;  // Set the bit for diagnostic pragma mappings.
     State->setMapping((diag::kind)DiagId, Map);
   }
 
index 0ea91329154c16cb187f7ee560e1439ff589a894..6ef4dbeb0cb650f783845527ee34c07c09879142 100644 (file)
@@ -343,8 +343,8 @@ namespace clang {
       /// sets.
       CXX_BASE_SPECIFIER_OFFSETS = 37,
 
-      /// \brief Record code for diagnostic mappings specified by the user.
-      DIAG_USER_MAPPINGS = 38
+      /// \brief Record code for #pragma diagnostic mappings.
+      DIAG_PRAGMA_MAPPINGS = 38
     };
 
     /// \brief Record types used within a source manager block.
index 845ca4b10f915190d78b02cc4d6048957242ecee..10c23c0834b33dc3cd02aa07cc6f8d87ff14d4e5 100644 (file)
@@ -569,7 +569,7 @@ private:
   //@}
 
   /// \brief Diagnostic IDs and their mappings that the user changed.
-  llvm::SmallVector<uint64_t, 8> UserDiagMappings;
+  llvm::SmallVector<uint64_t, 8> PragmaDiagMappings;
 
   /// \brief The original file name that was used to build the primary AST file,
   /// which may have been modified for relocatable-pch support.
@@ -851,7 +851,7 @@ public:
   /// \brief Read the preprocessed entity at the given offset.
   virtual PreprocessedEntity *ReadPreprocessedEntity(uint64_t Offset);
 
-  void ReadUserDiagnosticMappings(Diagnostic &Diag);
+  void ReadPragmaDiagnosticMappings(Diagnostic &Diag);
 
   /// \brief Returns the number of source locations found in the chain.
   unsigned getTotalNumSLocs() const {
index 86e241939ef76859d3d623bb4db5ce6d374c0fc8..0da5ecca4a5e1890fe62f934488db547e7a0a185 100644 (file)
@@ -311,7 +311,7 @@ private:
                                const Preprocessor &PP,
                                const char* isysroot);
   void WritePreprocessor(const Preprocessor &PP);
-  void WriteUserDiagnosticMappings(const Diagnostic &Diag);
+  void WritePragmaDiagnosticMappings(const Diagnostic &Diag);
   void WriteType(QualType T);
   uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
   uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC);
index 919ba8187ecf72a5f95962627eabf3740e42e427..9a263c1d0bc0a58f1f5254f814303a3fe7ff17ee 100644 (file)
@@ -147,12 +147,13 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
          "Cannot map errors into warnings!");
   assert(!DiagStatePoints.empty());
 
+  bool isPragma = L.isValid();
   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);
+    setDiagnosticMappingInternal(Diag, Map, GetCurDiagState(), true, isPragma);
     return;
   }
 
@@ -165,7 +166,7 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
     // the new state became active.
     DiagStates.push_back(*GetCurDiagState());
     PushDiagStatePoint(&DiagStates.back(), Loc);
-    setDiagnosticMappingInternal(Diag, Map, GetCurDiagState(), true);
+    setDiagnosticMappingInternal(Diag, Map, GetCurDiagState(), true, isPragma);
     return;
   }
 
@@ -178,12 +179,12 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
   // 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);
+    setDiagnosticMappingInternal(Diag, Map, I->State, true, isPragma);
   }
 
   // If the location corresponds to an existing point, just update its state.
   if (Pos->Loc == Loc) {
-    setDiagnosticMappingInternal(Diag, Map, Pos->State, true);
+    setDiagnosticMappingInternal(Diag, Map, Pos->State, true, isPragma);
     return;
   }
 
@@ -192,7 +193,7 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
   Pos->Loc.isBeforeInTranslationUnitThan(Loc);
   DiagStates.push_back(*Pos->State);
   DiagState *NewState = &DiagStates.back();
-  setDiagnosticMappingInternal(Diag, Map, NewState, true);
+  setDiagnosticMappingInternal(Diag, Map, NewState, true, isPragma);
   DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
                                                FullSourceLoc(Loc, *SourceMgr)));
 }
index df32c31ea9e72c2975f424b7808cfbb5891bcd2d..f4d7047a4b05e96d3fbfd9750d4e2f27aea2670b 100644 (file)
@@ -317,7 +317,7 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass,
                                                        State);
   if (MappingInfo == 0) {
     MappingInfo = GetDefaultDiagMapping(DiagID);
-    Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false);
+    Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false, false);
   }
 
   switch (MappingInfo & 7) {
index e7a3b0aebb0208dc33f2a3c09fa3e1996ef7e5bc..2c52f7f3a0c76e93e348988d8b14d9f7ca996056 100644 (file)
@@ -2128,15 +2128,15 @@ ASTReader::ReadASTBlock(PerFileData &F) {
       break;
     }
 
-    case DIAG_USER_MAPPINGS:
+    case DIAG_PRAGMA_MAPPINGS:
       if (Record.size() % 2 != 0) {
         Error("invalid DIAG_USER_MAPPINGS block in AST file");
         return Failure;
       }
-      if (UserDiagMappings.empty())
-        UserDiagMappings.swap(Record);
+      if (PragmaDiagMappings.empty())
+        PragmaDiagMappings.swap(Record);
       else
-        UserDiagMappings.insert(UserDiagMappings.end(),
+        PragmaDiagMappings.insert(PragmaDiagMappings.end(),
                                 Record.begin(), Record.end());
       break;
     }
@@ -2482,7 +2482,7 @@ void ASTReader::InitializeContext(ASTContext &Ctx) {
   if (SpecialTypes[SPECIAL_TYPE_INT128_INSTALLED])
     Context->setInt128Installed();
 
-  ReadUserDiagnosticMappings(Context->getDiagnostics());
+  ReadPragmaDiagnosticMappings(Context->getDiagnostics());
 }
 
 /// \brief Retrieve the name of the original source file name
@@ -2670,13 +2670,23 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(uint64_t Offset) {
   return ReadMacroRecord(*F, Offset);
 }
 
-void ASTReader::ReadUserDiagnosticMappings(Diagnostic &Diag) {
+void ASTReader::ReadPragmaDiagnosticMappings(Diagnostic &Diag) {
   unsigned Idx = 0;
-  while (Idx < UserDiagMappings.size()) {
-    unsigned DiagID = UserDiagMappings[Idx++];
-    unsigned Map = UserDiagMappings[Idx++];
-    Diag.setDiagnosticMappingInternal(DiagID, Map, Diag.GetCurDiagState(),
-                                      /*isUser=*/true);
+  while (Idx < PragmaDiagMappings.size()) {
+    SourceLocation
+      Loc = SourceLocation::getFromRawEncoding(PragmaDiagMappings[Idx++]);
+    while (1) {
+      assert(Idx < PragmaDiagMappings.size() &&
+             "Invalid data, didn't find '-1' marking end of diag/map pairs");
+      if (Idx >= PragmaDiagMappings.size())
+        break; // Something is messed up but at least avoid infinite loop in
+               // release build.
+      unsigned DiagID = PragmaDiagMappings[Idx++];
+      if (DiagID == (unsigned)-1)
+        break; // no more diag/map pairs for this location.
+      diag::Mapping Map = (diag::Mapping)PragmaDiagMappings[Idx++];
+      Diag.setDiagnosticMapping(DiagID, Map, Loc);
+    }
   }
 }
 
index 7582d1a4502fe2c6410a6569fe4cfd3f8eb9b5cc..00d46bc66030898dcabef2309d69ef1fbf3a481e 100644 (file)
@@ -1507,18 +1507,30 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP) {
   }
 }
 
-void ASTWriter::WriteUserDiagnosticMappings(const Diagnostic &Diag) {
+void ASTWriter::WritePragmaDiagnosticMappings(const Diagnostic &Diag) {
   RecordData Record;
-  for (unsigned i = 0; i != diag::DIAG_UPPER_LIMIT; ++i) {
-    diag::Mapping Map = Diag.getDiagnosticMappingInfo(i,Diag.GetCurDiagState());
-    if (Map & 0x8) { // user mapping.
-      Record.push_back(i);
-      Record.push_back(Map & 0x7);
+  for (Diagnostic::DiagStatePointsTy::const_iterator
+         I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end();
+         I != E; ++I) {
+    const Diagnostic::DiagStatePoint &point = *I; 
+    if (point.Loc.isInvalid())
+      continue;
+
+    Record.push_back(point.Loc.getRawEncoding());
+    for (Diagnostic::DiagState::iterator
+           I = point.State->begin(), E = point.State->end(); I != E; ++I) {
+      unsigned diag = I->first, map = I->second;
+      if (map & 0x10) { // mapping from a diagnostic pragma.
+        Record.push_back(diag);
+        Record.push_back(map & 0x7);
+      }
     }
+    Record.push_back(-1); // mark the end of the diag/map pairs for this
+                          // location.
   }
 
   if (!Record.empty())
-    Stream.EmitRecord(DIAG_USER_MAPPINGS, Record);
+    Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record);
 }
 
 //===----------------------------------------------------------------------===//
@@ -2483,7 +2495,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
   WriteIdentifierTable(PP);
 
   WriteTypeDeclOffsets();
-  WriteUserDiagnosticMappings(Context.getDiagnostics());
+  WritePragmaDiagnosticMappings(Context.getDiagnostics());
 
   // Write the C++ base-specifier set offsets.
   if (!CXXBaseSpecifiersOffsets.empty()) {
@@ -2719,7 +2731,7 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
   WriteTypeDeclOffsets();
   // FIXME: For chained PCH only write the new mappings (we currently
   // write all of them again).
-  WriteUserDiagnosticMappings(Context.getDiagnostics());
+  WritePragmaDiagnosticMappings(Context.getDiagnostics());
 
   /// Build a record containing first declarations from a chained PCH and the
   /// most recent declarations in this AST that they point to.
diff --git a/test/PCH/pragma-diag-section.cpp b/test/PCH/pragma-diag-section.cpp
new file mode 100644 (file)
index 0000000..312f720
--- /dev/null
@@ -0,0 +1,26 @@
+// Test this without pch.
+// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only
+
+// Test with pch.
+// RUN: %clang_cc1 %s -emit-pch -o %t
+// RUN: %clang_cc1 %s -include-pch %t -verify -fsyntax-only
+
+#ifndef HEADER
+#define HEADER
+
+#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
+
+#else
+
+void f() {
+    TS<int> ts;
+    ts.m();
+}
+
+#endif
diff --git a/test/PCH/rdar8852495.c b/test/PCH/rdar8852495.c
new file mode 100644 (file)
index 0000000..2d49e00
--- /dev/null
@@ -0,0 +1,25 @@
+// Test this without pch.
+// RUN: %clang_cc1 %s -include %s -verify -fsyntax-only -Wno-sign-compare -Wtautological-compare
+
+// Test with pch.
+// RUN: %clang_cc1 %s -emit-pch -o %t -Wsign-compare -Wtautological-compare
+// RUN: %clang_cc1 %s -include-pch %t -verify -fsyntax-only -Wno-sign-compare -Wtautological-compare
+
+// This tests that diagnostic mappings from PCH are propagated for #pragma
+// diagnostics but not for command-line flags.
+
+#ifndef HEADER
+#define HEADER
+
+#pragma clang diagnostic ignored "-Wtautological-compare"
+
+#else
+
+int f() {
+  int b = b==b;
+  unsigned x;
+  signed y;
+  return x == y;
+}
+
+#endif