|
@@ -29,6 +29,7 @@
|
|
|
#include "clang/Basic/TargetOptions.h"
|
|
|
#include "clang/Basic/Version.h"
|
|
|
#include "clang/Basic/VersionTuple.h"
|
|
|
+#include "clang/Frontend/Utils.h"
|
|
|
#include "clang/Lex/HeaderSearch.h"
|
|
|
#include "clang/Lex/HeaderSearchOptions.h"
|
|
|
#include "clang/Lex/MacroInfo.h"
|
|
@@ -90,7 +91,7 @@ ChainedASTReaderListener::ReadTargetOptions(const TargetOptions &TargetOpts,
|
|
|
Second->ReadTargetOptions(TargetOpts, Complain);
|
|
|
}
|
|
|
bool ChainedASTReaderListener::ReadDiagnosticOptions(
|
|
|
- const DiagnosticOptions &DiagOpts, bool Complain) {
|
|
|
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) {
|
|
|
return First->ReadDiagnosticOptions(DiagOpts, Complain) ||
|
|
|
Second->ReadDiagnosticOptions(DiagOpts, Complain);
|
|
|
}
|
|
@@ -291,6 +292,120 @@ namespace {
|
|
|
DeclsMap;
|
|
|
}
|
|
|
|
|
|
+static bool checkDiagnosticGroupMappings(DiagnosticsEngine &StoredDiags,
|
|
|
+ DiagnosticsEngine &Diags,
|
|
|
+ bool Complain) {
|
|
|
+ typedef DiagnosticsEngine::Level Level;
|
|
|
+
|
|
|
+ // Check current mappings for new -Werror mappings, and the stored mappings
|
|
|
+ // for cases that were explicitly mapped to *not* be errors that are now
|
|
|
+ // errors because of options like -Werror.
|
|
|
+ DiagnosticsEngine *MappingSources[] = { &Diags, &StoredDiags };
|
|
|
+
|
|
|
+ for (DiagnosticsEngine *MappingSource : MappingSources) {
|
|
|
+ for (auto DiagIDMappingPair : MappingSource->getDiagnosticMappings()) {
|
|
|
+ diag::kind DiagID = DiagIDMappingPair.first;
|
|
|
+ Level CurLevel = Diags.getDiagnosticLevel(DiagID, SourceLocation());
|
|
|
+ if (CurLevel < DiagnosticsEngine::Error)
|
|
|
+ continue; // not significant
|
|
|
+ Level StoredLevel =
|
|
|
+ StoredDiags.getDiagnosticLevel(DiagID, SourceLocation());
|
|
|
+ if (StoredLevel < DiagnosticsEngine::Error) {
|
|
|
+ if (Complain)
|
|
|
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror=" +
|
|
|
+ Diags.getDiagnosticIDs()->getWarningOptionForDiag(DiagID).str();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static DiagnosticsEngine::ExtensionHandling
|
|
|
+isExtHandlingFromDiagsError(DiagnosticsEngine &Diags) {
|
|
|
+ DiagnosticsEngine::ExtensionHandling Ext =
|
|
|
+ Diags.getExtensionHandlingBehavior();
|
|
|
+ if (Ext == DiagnosticsEngine::Ext_Warn && Diags.getWarningsAsErrors())
|
|
|
+ Ext = DiagnosticsEngine::Ext_Error;
|
|
|
+ return Ext;
|
|
|
+}
|
|
|
+
|
|
|
+static bool checkDiagnosticMappings(DiagnosticsEngine &StoredDiags,
|
|
|
+ DiagnosticsEngine &Diags,
|
|
|
+ bool IsSystem, bool Complain) {
|
|
|
+ // Top-level options
|
|
|
+ if (IsSystem) {
|
|
|
+ if (Diags.getSuppressSystemWarnings())
|
|
|
+ return false;
|
|
|
+ // If -Wsystem-headers was not enabled before, be conservative
|
|
|
+ if (StoredDiags.getSuppressSystemWarnings()) {
|
|
|
+ if (Complain)
|
|
|
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Wsystem-headers";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Diags.getWarningsAsErrors() && !StoredDiags.getWarningsAsErrors()) {
|
|
|
+ if (Complain)
|
|
|
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (Diags.getWarningsAsErrors() && Diags.getEnableAllWarnings() &&
|
|
|
+ !StoredDiags.getEnableAllWarnings()) {
|
|
|
+ if (Complain)
|
|
|
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-Weverything -Werror";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isExtHandlingFromDiagsError(Diags) &&
|
|
|
+ !isExtHandlingFromDiagsError(StoredDiags)) {
|
|
|
+ if (Complain)
|
|
|
+ Diags.Report(diag::err_pch_diagopt_mismatch) << "-pedantic-errors";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return checkDiagnosticGroupMappings(StoredDiags, Diags, Complain);
|
|
|
+}
|
|
|
+
|
|
|
+bool PCHValidator::ReadDiagnosticOptions(
|
|
|
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, bool Complain) {
|
|
|
+ DiagnosticsEngine &ExistingDiags = PP.getDiagnostics();
|
|
|
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(ExistingDiags.getDiagnosticIDs());
|
|
|
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
|
|
|
+ new DiagnosticsEngine(DiagIDs, DiagOpts.getPtr()));
|
|
|
+ // This should never fail, because we would have processed these options
|
|
|
+ // before writing them to an ASTFile.
|
|
|
+ ProcessWarningOptions(*Diags, *DiagOpts, /*Report*/false);
|
|
|
+
|
|
|
+ ModuleManager &ModuleMgr = Reader.getModuleManager();
|
|
|
+ assert(ModuleMgr.size() >= 1 && "what ASTFile is this then");
|
|
|
+
|
|
|
+ // If the original import came from a file explicitly generated by the user,
|
|
|
+ // don't check the diagnostic mappings.
|
|
|
+ // FIXME: currently this is approximated by checking whether this is not a
|
|
|
+ // module import.
|
|
|
+ // Note: ModuleMgr.rbegin() may not be the current module, but it must be in
|
|
|
+ // the transitive closure of its imports, since unrelated modules cannot be
|
|
|
+ // imported until after this module finishes validation.
|
|
|
+ ModuleFile *TopImport = *ModuleMgr.rbegin();
|
|
|
+ while (!TopImport->ImportedBy.empty())
|
|
|
+ TopImport = TopImport->ImportedBy[0];
|
|
|
+ if (TopImport->Kind != MK_Module)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ StringRef ModuleName = TopImport->ModuleName;
|
|
|
+ assert(!ModuleName.empty() && "diagnostic options read before module name");
|
|
|
+
|
|
|
+ Module *M = PP.getHeaderSearchInfo().lookupModule(ModuleName);
|
|
|
+ assert(M && "missing module");
|
|
|
+
|
|
|
+ // FIXME: if the diagnostics are incompatible, save a DiagnosticOptions that
|
|
|
+ // contains the union of their flags.
|
|
|
+ return checkDiagnosticMappings(*Diags, ExistingDiags, M->IsSystem, Complain);
|
|
|
+}
|
|
|
+
|
|
|
/// \brief Collect the macro definitions provided by the given preprocessor
|
|
|
/// options.
|
|
|
static void collectMacroDefinitions(const PreprocessorOptions &PPOpts,
|
|
@@ -2268,11 +2383,11 @@ ASTReader::ReadControlBlock(ModuleFile &F,
|
|
|
}
|
|
|
|
|
|
case DIAGNOSTIC_OPTIONS: {
|
|
|
- bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
|
|
|
+ bool Complain = (ClientLoadCapabilities & ARR_OutOfDate)==0;
|
|
|
if (Listener && &F == *ModuleMgr.begin() &&
|
|
|
ParseDiagnosticOptions(Record, Complain, *Listener) &&
|
|
|
- !DisableValidation && !AllowConfigurationMismatch)
|
|
|
- return ConfigurationMismatch;
|
|
|
+ !DisableValidation)
|
|
|
+ return OutOfDate;
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -4481,15 +4596,15 @@ bool ASTReader::ParseTargetOptions(const RecordData &Record,
|
|
|
|
|
|
bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain,
|
|
|
ASTReaderListener &Listener) {
|
|
|
- DiagnosticOptions DiagOpts;
|
|
|
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
|
|
|
unsigned Idx = 0;
|
|
|
-#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++];
|
|
|
+#define DIAGOPT(Name, Bits, Default) DiagOpts->Name = Record[Idx++];
|
|
|
#define ENUM_DIAGOPT(Name, Type, Bits, Default) \
|
|
|
- DiagOpts.set##Name(static_cast<Type>(Record[Idx++]));
|
|
|
+ DiagOpts->set##Name(static_cast<Type>(Record[Idx++]));
|
|
|
#include "clang/Basic/DiagnosticOptions.def"
|
|
|
|
|
|
for (unsigned N = Record[Idx++]; N; --N) {
|
|
|
- DiagOpts.Warnings.push_back(ReadString(Record, Idx));
|
|
|
+ DiagOpts->Warnings.push_back(ReadString(Record, Idx));
|
|
|
}
|
|
|
|
|
|
return Listener.ReadDiagnosticOptions(DiagOpts, Complain);
|