/// 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.
}
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);
}
/// 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.
//@}
/// \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.
/// \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 {
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);
"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;
}
// 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;
}
// 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;
}
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)));
}
State);
if (MappingInfo == 0) {
MappingInfo = GetDefaultDiagMapping(DiagID);
- Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false);
+ Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false, false);
}
switch (MappingInfo & 7) {
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;
}
if (SpecialTypes[SPECIAL_TYPE_INT128_INSTALLED])
Context->setInt128Installed();
- ReadUserDiagnosticMappings(Context->getDiagnostics());
+ ReadPragmaDiagnosticMappings(Context->getDiagnostics());
}
/// \brief Retrieve the name of the original source file name
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);
+ }
}
}
}
}
-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);
}
//===----------------------------------------------------------------------===//
WriteIdentifierTable(PP);
WriteTypeDeclOffsets();
- WriteUserDiagnosticMappings(Context.getDiagnostics());
+ WritePragmaDiagnosticMappings(Context.getDiagnostics());
// Write the C++ base-specifier set offsets.
if (!CXXBaseSpecifiersOffsets.empty()) {
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.
--- /dev/null
+// 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
--- /dev/null
+// 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