diff options
| author | Ben Langmuir <blangmuir@apple.com> | 2014-04-29 00:36:53 +0000 | 
|---|---|---|
| committer | Ben Langmuir <blangmuir@apple.com> | 2014-04-29 00:36:53 +0000 | 
| commit | be84adbf1b7d2c7d30c524392151f7e14a82daff (patch) | |
| tree | bba2a35725a23b1201a06381a091d88ab1bf5243 /clang/lib/Serialization | |
| parent | 72d57ab32e3ec8d59c40ee13344e3692139ca737 (diff) | |
| download | bcm5719-llvm-be84adbf1b7d2c7d30c524392151f7e14a82daff.tar.gz bcm5719-llvm-be84adbf1b7d2c7d30c524392151f7e14a82daff.zip | |
Check -Werror options during module validation
This patch checks whether the diagnostic options that could lead to
errors (principally -Werror) are consistent between when a module was
built and when it is loaded.  If there are new -Werror flags, then the
module is rebuilt.  In order to canonicalize the options we do this
check at the level of the constructed DiagnosticsEngine, which contains
the final set of diag to diagnostic level mappings.  Currently we only
rebuild with the new diagnostic options, but we intend to refine this in
the future to include the union of the new and old flags, since we know
the old ones did not cause errors.  System modules are only rebuilt when
-Wsystem-headers is enabled.
One oddity is that unlike checking language options, we don’t perform
this diagnostic option checking when loading from a precompiled header.
The reason for this is that the compiler cannot rebuild the PCH, so
anything that requires it to be rebuilt effectively leaks into the build
system.  And in this case, that would mean the build system
understanding the complex relationship between diagnostic options and
the underlying diagnostic mappings, which is unreasonable.  Skipping the
check is safe, because these options do not affect the generated AST.
You simply won’t get new build errors due to changed -Werror options
automatically, which is also true for non-module cases.
llvm-svn: 207477
Diffstat (limited to 'clang/lib/Serialization')
| -rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 131 | 
1 files changed, 123 insertions, 8 deletions
| diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 834917de1d4..c6aec4592ba 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -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); | 

