From 3efd52cf8f4e57c5571bd8cc3168264c3bc46a1e Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Fri, 14 Jan 2011 20:54:07 +0000 Subject: [PATCH] Properly propagate #pragma diagnostic mappings from PCH but not command-line warning flags. 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 | 22 +++++++++++----- include/clang/Serialization/ASTBitCodes.h | 4 +-- include/clang/Serialization/ASTReader.h | 4 +-- include/clang/Serialization/ASTWriter.h | 2 +- lib/Basic/Diagnostic.cpp | 11 ++++---- lib/Basic/DiagnosticIDs.cpp | 2 +- lib/Serialization/ASTReader.cpp | 32 +++++++++++++++-------- lib/Serialization/ASTWriter.cpp | 30 ++++++++++++++------- test/PCH/pragma-diag-section.cpp | 26 ++++++++++++++++++ test/PCH/rdar8852495.c | 25 ++++++++++++++++++ 10 files changed, 121 insertions(+), 37 deletions(-) create mode 100644 test/PCH/pragma-diag-section.cpp create mode 100644 test/PCH/rdar8852495.c diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index bc835019c9..fd34fdec1e 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -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 DiagMap; + llvm::DenseMap DiagMap; public: + typedef llvm::DenseMap::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); } diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 0ea9132915..6ef4dbeb0c 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -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. diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 845ca4b10f..10c23c0834 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -569,7 +569,7 @@ private: //@} /// \brief Diagnostic IDs and their mappings that the user changed. - llvm::SmallVector UserDiagMappings; + llvm::SmallVector 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 { diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 86e241939e..0da5ecca4a 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -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); diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 919ba8187e..9a263c1d0b 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -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))); } diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp index df32c31ea9..f4d7047a4b 100644 --- a/lib/Basic/DiagnosticIDs.cpp +++ b/lib/Basic/DiagnosticIDs.cpp @@ -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) { diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index e7a3b0aebb..2c52f7f3a0 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -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); + } } } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 7582d1a450..00d46bc660 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -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 index 0000000000..312f720ebd --- /dev/null +++ b/test/PCH/pragma-diag-section.cpp @@ -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 +struct TS { + void m() { T b = b==b; } +}; +#pragma clang diagnostic pop + +#else + +void f() { + TS ts; + ts.m(); +} + +#endif diff --git a/test/PCH/rdar8852495.c b/test/PCH/rdar8852495.c new file mode 100644 index 0000000000..2d49e001b0 --- /dev/null +++ b/test/PCH/rdar8852495.c @@ -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 -- 2.40.0