]> granicus.if.org Git - clang/commitdiff
Allow clients of the AST reader to specify what kinds of AST load
authorDouglas Gregor <dgregor@apple.com>
Mon, 22 Oct 2012 23:51:00 +0000 (23:51 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 22 Oct 2012 23:51:00 +0000 (23:51 +0000)
failures they know how to tolerate, e.g., out-of-date input files or
configuration/version mismatches. Suppress the corresponding
diagnostics if the client can handle it.

No clients actually use this functionality, yet.

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

include/clang/Serialization/ASTReader.h
lib/Frontend/ASTUnit.cpp
lib/Frontend/ChainedIncludesSource.cpp
lib/Frontend/CompilerInstance.cpp
lib/Serialization/ASTReader.cpp

index 3b623dfe4fad095d7a37412ac05aafab36e65fa1..e72e451749e70366bf46e65cfbbd34a5d6d9b211 100644 (file)
@@ -107,7 +107,8 @@ public:
   ///
   /// \returns true to indicate the options are invalid or false otherwise.
   virtual bool ReadLanguageOptions(const serialization::ModuleFile &M,
-                                   const LangOptions &LangOpts) {
+                                   const LangOptions &LangOpts,
+                                   bool Complain) {
     return false;
   }
 
@@ -116,7 +117,8 @@ public:
   /// \returns true to indicate the target options are invalid, or false
   /// otherwise.
   virtual bool ReadTargetOptions(const serialization::ModuleFile &M,
-                                 const TargetOptions &TargetOpts) {
+                                 const TargetOptions &TargetOpts,
+                                 bool Complain) {
     return false;
   }
 
@@ -130,11 +132,14 @@ public:
   /// \param SuggestedPredefines If necessary, additional definitions are added
   /// here.
   ///
+  /// \param Complain Whether to complain about non-matching predefines buffers.
+  ///
   /// \returns true to indicate the predefines are invalid or false otherwise.
   virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
                                     StringRef OriginalFileName,
                                     std::string &SuggestedPredefines,
-                                    FileManager &FileMgr) {
+                                    FileManager &FileMgr,
+                                    bool Complain) {
     return false;
   }
 
@@ -159,13 +164,16 @@ public:
     : PP(PP), Reader(Reader), NumHeaderInfos(0) {}
 
   virtual bool ReadLanguageOptions(const serialization::ModuleFile &M,
-                                   const LangOptions &LangOpts);
+                                   const LangOptions &LangOpts,
+                                   bool Complain);
   virtual bool ReadTargetOptions(const serialization::ModuleFile &M,
-                                 const TargetOptions &TargetOpts);
+                                 const TargetOptions &TargetOpts,
+                                 bool Complain);
   virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
                                     StringRef OriginalFileName,
                                     std::string &SuggestedPredefines,
-                                    FileManager &FileMgr);
+                                    FileManager &FileMgr,
+                                    bool Complain);
   virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID);
   virtual void ReadCounter(const serialization::ModuleFile &M, unsigned Value);
 
@@ -883,7 +891,7 @@ private:
 
   /// \brief Retrieve the file entry and 'overridden' bit for an input
   /// file in the given module file.
-  InputFile getInputFile(ModuleFile &F, unsigned ID);
+  InputFile getInputFile(ModuleFile &F, unsigned ID, bool Complain = true);
 
   /// \brief Get a FileEntry out of stored-in-PCH filename, making sure we take
   /// into account all the necessary relocations.
@@ -893,17 +901,20 @@ private:
 
   ASTReadResult ReadASTCore(StringRef FileName, ModuleKind Type,
                             ModuleFile *ImportedBy,
-                            llvm::SmallVectorImpl<ModuleFile *> &Loaded);
+                            llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+                            unsigned ClientLoadCapabilities);
   ASTReadResult ReadControlBlock(ModuleFile &F,
-                                 llvm::SmallVectorImpl<ModuleFile *> &Loaded);
+                                 llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+                                 unsigned ClientLoadCapabilities);
   bool ReadASTBlock(ModuleFile &F);
-  bool CheckPredefinesBuffers();
+  bool CheckPredefinesBuffers(bool Complain);
   bool ParseLineTable(ModuleFile &F, SmallVectorImpl<uint64_t> &Record);
   bool ReadSourceManagerBlock(ModuleFile &F);
   llvm::BitstreamCursor &SLocCursorForID(int ID);
   SourceLocation getImportLocation(ModuleFile *F);
   bool ReadSubmoduleBlock(ModuleFile &F);
-  bool ParseLanguageOptions(const ModuleFile &M, const RecordData &Record);
+  bool ParseLanguageOptions(const ModuleFile &M, const RecordData &Record,
+                            bool Complain);
   
   struct RecordLocation {
     RecordLocation(ModuleFile *M, uint64_t O)
@@ -1062,8 +1073,38 @@ public:
 
   SourceManager &getSourceManager() const { return SourceMgr; }
 
+  /// \brief Flags that indicate what kind of AST loading failures the client
+  /// of the AST reader can directly handle.
+  ///
+  /// When a client states that it can handle a particular kind of failure,
+  /// the AST reader will not emit errors when producing that kind of failure.
+  enum LoadFailureCapabilities {
+    /// \brief The client can't handle any AST loading failures.
+    ARR_None = 0,
+    /// \brief The client can handle an AST file that cannot load because it
+    /// is out-of-date relative to its input files.
+    ARR_OutOfDate = 0x1,
+    /// \brief The client can handle an AST file that cannot load because it
+    /// was built with a different version of Clang.
+    ARR_VersionMismatch = 0x2,
+    /// \brief The client can handle an AST file that cannot load because it's
+    /// compiled configuration doesn't match that of the context it was
+    /// loaded into.
+    ARR_ConfigurationMismatch = 0x4
+  };
+
   /// \brief Load the AST file designated by the given file name.
-  ASTReadResult ReadAST(const std::string &FileName, ModuleKind Type);
+  ///
+  /// \param FileName The name of the AST file to load.
+  ///
+  /// \param Type The kind of AST being loaded, e.g., PCH, module, main file,
+  /// or preamble.
+  ///
+  /// \param ClientLoadCapabilities The set of client load-failure
+  /// capabilities, represented as a bitset of the enumerators of
+  /// LoadFailureCapabilities.
+  ASTReadResult ReadAST(const std::string &FileName, ModuleKind Type,
+                        unsigned ClientLoadCapabilities);
 
   /// \brief Make the entities in the given module and any of its (non-explicit)
   /// submodules visible to name lookup.
index 11bd33ec418b0cb90e4331a05345cc74b83c5d53..a340d7db33eada0fb858ea3366f88b03b939d659 100644 (file)
@@ -524,7 +524,8 @@ public:
       InitializedLanguage(false) {}
 
   virtual bool ReadLanguageOptions(const serialization::ModuleFile &M,
-                                   const LangOptions &LangOpts) {
+                                   const LangOptions &LangOpts,
+                                   bool Complain) {
     if (InitializedLanguage)
       return false;
     
@@ -538,7 +539,8 @@ public:
   }
 
   virtual bool ReadTargetOptions(const serialization::ModuleFile &M,
-                                 const TargetOptions &TargetOpts) {
+                                 const TargetOptions &TargetOpts,
+                                 bool Complain) {
     // If we've already initialized the target, don't do it again.
     if (Target)
       return false;
@@ -557,7 +559,8 @@ public:
   virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
                                     StringRef OriginalFileName,
                                     std::string &SuggestedPredefines,
-                                    FileManager &FileMgr) {
+                                    FileManager &FileMgr,
+                                    bool Complain) {
     Predefines = Buffers[0].Data;
     for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
       Predefines += Buffers[I].Data;
@@ -809,7 +812,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
                                            AST->TargetOpts, AST->Target, 
                                            Predefines, Counter));
 
-  switch (Reader->ReadAST(Filename, serialization::MK_MainFile)) {
+  switch (Reader->ReadAST(Filename, serialization::MK_MainFile,
+                          ASTReader::ARR_None)) {
   case ASTReader::Success:
     break;
 
index bfe0693ad4cdb55446875423fb00d16aba1ffd09..205cb51cb0b4d329c18faa188aaef910f5faea43 100644 (file)
@@ -39,7 +39,8 @@ static ASTReader *createASTReader(CompilerInstance &CI,
     Reader->addInMemoryBuffer(sr, memBufs[ti]);
   }
   Reader->setDeserializationListener(deserialListener);
-  switch (Reader->ReadAST(pchFile, serialization::MK_PCH)) {
+  switch (Reader->ReadAST(pchFile, serialization::MK_PCH,
+                          ASTReader::ARR_None)) {
   case ASTReader::Success:
     // Set the predefines buffer as suggested by the PCH reader.
     PP.setPredefines(Reader->getSuggestedPredefines());
index 225bc137fb3d280e3cb933544b6b363797c00ba6..3806f57c9478a1c30fe7fe51d7cad62911a6125a 100644 (file)
@@ -343,7 +343,8 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
             static_cast<ASTDeserializationListener *>(DeserializationListener));
   switch (Reader->ReadAST(Path,
                           Preamble ? serialization::MK_Preamble
-                                   : serialization::MK_PCH)) {
+                                   : serialization::MK_PCH,
+                          ASTReader::ARR_None)) {
   case ASTReader::Success:
     // Set the predefines buffer as suggested by the PCH reader. Typically, the
     // predefines buffer will be empty.
@@ -965,7 +966,8 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
 
     // Try to load the module we found.
     switch (ModuleManager->ReadAST(ModuleFile->getName(),
-                                   serialization::MK_Module)) {
+                                   serialization::MK_Module,
+                                   ASTReader::ARR_None)) {
     case ASTReader::Success:
       break;
 
index 5a9eeceb46b71331ec275b93c25a680ce00961d1..a541e241417ad1fc92fb64bc2f1f948061b2b22d 100644 (file)
@@ -65,27 +65,31 @@ ASTReaderListener::~ASTReaderListener() {}
 
 bool
 PCHValidator::ReadLanguageOptions(const ModuleFile &M,
-                                  const LangOptions &LangOpts) {
+                                  const LangOptions &LangOpts,
+                                  bool Complain) {
   const LangOptions &PPLangOpts = PP.getLangOpts();
   
-#define LANGOPT(Name, Bits, Default, Description)         \
-  if (PPLangOpts.Name != LangOpts.Name) {                 \
-    Reader.Diag(diag::err_pch_langopt_mismatch)           \
-      << Description << LangOpts.Name << PPLangOpts.Name; \
-    return true;                                          \
+#define LANGOPT(Name, Bits, Default, Description)           \
+  if (PPLangOpts.Name != LangOpts.Name) {                   \
+    if (Complain)                                           \
+      Reader.Diag(diag::err_pch_langopt_mismatch)           \
+        << Description << LangOpts.Name << PPLangOpts.Name; \
+    return true;                                            \
   }
 
 #define VALUE_LANGOPT(Name, Bits, Default, Description) \
   if (PPLangOpts.Name != LangOpts.Name) {               \
-    Reader.Diag(diag::err_pch_langopt_value_mismatch)   \
-      << Description;                                   \
-  return true;                                          \
-}
+    if (Complain)                                       \
+      Reader.Diag(diag::err_pch_langopt_value_mismatch) \
+        << Description;                                 \
+    return true;                                        \
+  }
 
 #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
   if (PPLangOpts.get##Name() != LangOpts.get##Name()) {      \
-    Reader.Diag(diag::err_pch_langopt_value_mismatch)        \
-      << Description;                                        \
+    if (Complain)                                            \
+      Reader.Diag(diag::err_pch_langopt_value_mismatch)      \
+        << Description;                                      \
     return true;                                             \
   }
 
@@ -94,8 +98,9 @@ PCHValidator::ReadLanguageOptions(const ModuleFile &M,
 #include "clang/Basic/LangOptions.def"
 
   if (PPLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) {
-    Reader.Diag(diag::err_pch_langopt_value_mismatch)
-      << "target Objective-C runtime";
+    if (Complain)
+      Reader.Diag(diag::err_pch_langopt_value_mismatch)
+        << "target Objective-C runtime";
     return true;
   }
   
@@ -103,14 +108,16 @@ PCHValidator::ReadLanguageOptions(const ModuleFile &M,
 }
 
 bool PCHValidator::ReadTargetOptions(const ModuleFile &M, 
-                                     const TargetOptions &TargetOpts) {
+                                     const TargetOptions &TargetOpts,
+                                     bool Complain) {
   const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
 
-#define CHECK_TARGET_OPT(Field, Name)                           \
-  if (TargetOpts.Field != ExistingTargetOpts.Field) {           \
-    Reader.Diag(diag::err_pch_targetopt_mismatch)               \
-      << Name << TargetOpts.Field << ExistingTargetOpts.Field;  \
-    return true;                                                \
+#define CHECK_TARGET_OPT(Field, Name)                             \
+  if (TargetOpts.Field != ExistingTargetOpts.Field) {             \
+    if (Complain)                                                 \
+      Reader.Diag(diag::err_pch_targetopt_mismatch)               \
+        << Name << TargetOpts.Field << ExistingTargetOpts.Field;  \
+    return true;                                                  \
   }
 
   CHECK_TARGET_OPT(Triple, "target");
@@ -139,25 +146,29 @@ bool PCHValidator::ReadTargetOptions(const ModuleFile &M,
     }
 
     if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) {
-      Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
-        << false << ReadFeatures[ReadIdx];
+      if (Complain)
+        Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
+          << false << ReadFeatures[ReadIdx];
       return true;
     }
 
-    Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
-      << true << ExistingFeatures[ExistingIdx];
+    if (Complain)
+      Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
+        << true << ExistingFeatures[ExistingIdx];
     return true;
   }
 
   if (ExistingIdx < ExistingN) {
-    Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
-      << true << ExistingFeatures[ExistingIdx];
+    if (Complain)
+      Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
+        << true << ExistingFeatures[ExistingIdx];
     return true;
   }
 
   if (ReadIdx < ReadN) {
-    Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
-      << false << ReadFeatures[ReadIdx];
+    if (Complain)
+      Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
+        << false << ReadFeatures[ReadIdx];
     return true;
   }
 
@@ -249,7 +260,8 @@ FindMacro(const PCHPredefinesBlocks &Buffers, StringRef MacroDef) {
 bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
                                         StringRef OriginalFileName,
                                         std::string &SuggestedPredefines,
-                                        FileManager &FileMgr) {
+                                        FileManager &FileMgr,
+                                        bool Complain) {
   // We are in the context of an implicit include, so the predefines buffer will
   // have a #include entry for the PCH file itself (as normalized by the
   // preprocessor initialization). Find it and skip over it in the checking
@@ -263,7 +275,8 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
     StringRef(PP.getPredefines()).split(PCHInclude.str());
   StringRef Left =  Split.first, Right = Split.second;
   if (Left == PP.getPredefines()) {
-    Error("Missing PCH include entry!");
+    if (Complain)
+      Error("Missing PCH include entry!");
     return true;
   }
 
@@ -338,7 +351,8 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
       continue;
     }
     if (!Missing.startswith("#define ")) {
-      Reader.Diag(diag::warn_pch_compiler_options_mismatch);
+      if (Complain)
+        Reader.Diag(diag::warn_pch_compiler_options_mismatch);
       return true;
     }
 
@@ -376,6 +390,9 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
     }
 
     if (ConflictPos != CmdLineLines.end()) {
+      if (!Complain)
+        return true;
+      
       Reader.Diag(diag::warn_cmdline_conflicting_macro_def)
           << MacroName;
 
@@ -398,10 +415,16 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
       continue; // Don't complain if there are already conflicting defs
 
     if (!MissingDefines) {
+      if (!Complain)
+        return true;
+      
       Reader.Diag(diag::warn_cmdline_missing_macro_defs);
       MissingDefines = true;
     }
 
+    if (!Complain)
+      return true;
+    
     // Show the definition of this macro within the PCH file.
     std::pair<FileID, StringRef::size_type> MacroLoc =
         FindMacro(Buffers, Missing);
@@ -426,7 +449,8 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
   for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) {
     StringRef &Extra = ExtraPredefines[I];
     if (!Extra.startswith("#define ")) {
-      Reader.Diag(diag::warn_pch_compiler_options_mismatch);
+      if (Complain)
+        Reader.Diag(diag::warn_pch_compiler_options_mismatch);
       return true;
     }
 
@@ -443,7 +467,8 @@ bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
     // so, defining it as a macro could change behavior, so we reject
     // the PCH file.
     if (IdentifierInfo *II = Reader.get(MacroName)) {
-      Reader.Diag(diag::warn_macro_name_used_in_pch) << II;
+      if (Complain)
+        Reader.Diag(diag::warn_macro_name_used_in_pch) << II;
       return true;
     }
 
@@ -818,14 +843,15 @@ void ASTReader::Error(unsigned DiagID,
 }
 
 /// \brief Tell the AST listener about the predefines buffers in the chain.
-bool ASTReader::CheckPredefinesBuffers() {
+bool ASTReader::CheckPredefinesBuffers(bool Complain) {
   if (Listener) {
     // We only care about the primary module.
     ModuleFile &M = ModuleMgr.getPrimaryModule();
     return Listener->ReadPredefinesBuffer(PCHPredefinesBuffers,
                                           M.ActualOriginalSourceFileName,
                                           SuggestedPredefines,
-                                          FileMgr);
+                                          FileMgr,
+                                          Complain);
   }
   return false;
 }
@@ -1665,7 +1691,7 @@ void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
 }
 
 llvm::PointerIntPair<const FileEntry *, 1, bool> 
-ASTReader::getInputFile(ModuleFile &F, unsigned ID) {
+ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
   // If this ID is bogus, just return an empty input file.
   if (ID == 0 || ID > F.InputFilesLoaded.size())
     return InputFile();
@@ -1719,10 +1745,12 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID) {
     }
     
     if (File == 0) {
-      std::string ErrorStr = "could not find file '";
-      ErrorStr += Filename;
-      ErrorStr += "' referenced by AST file";
-      Error(ErrorStr.c_str());
+      if (Complain) {
+        std::string ErrorStr = "could not find file '";
+        ErrorStr += Filename;
+        ErrorStr += "' referenced by AST file";
+        Error(ErrorStr.c_str());
+      }
       return InputFile();
     }
     
@@ -1766,7 +1794,9 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID) {
          || StoredTime != StatBuf.st_mtime
 #endif
          )) {
-      Error(diag::err_fe_pch_file_modified, Filename);
+      if (Complain)
+        Error(diag::err_fe_pch_file_modified, Filename);
+      
       return InputFile();
     }
 
@@ -1820,8 +1850,10 @@ StringRef ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
   return Filename;
 }
 
-ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F,
-                           llvm::SmallVectorImpl<ModuleFile *> &Loaded) {
+ASTReader::ASTReadResult
+ASTReader::ReadControlBlock(ModuleFile &F,
+                            llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+                            unsigned ClientLoadCapabilities) {
   llvm::BitstreamCursor &Stream = F.Stream;
 
   if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
@@ -1841,8 +1873,9 @@ ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F,
 
       // Validate all of the input files.
       if (!DisableValidation) {
+        bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
         for (unsigned I = 0, N = Record[0]; I < N; ++I)
-          if (!getInputFile(F, I+1).getPointer())
+          if (!getInputFile(F, I+1, Complain).getPointer())
             return OutOfDate;
       }
 
@@ -1884,8 +1917,9 @@ ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F,
                                                   &BlobStart, &BlobLen)) {
     case METADATA: {
       if (Record[0] != VERSION_MAJOR && !DisableValidation) {
-        Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old
-                                      : diag::warn_pch_version_too_new);
+        if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+          Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old
+                                        : diag::warn_pch_version_too_new);
         return VersionMismatch;
       }
 
@@ -1900,7 +1934,8 @@ ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F,
       const std::string &CurBranch = getClangFullRepositoryVersion();
       StringRef ASTBranch(BlobStart, BlobLen);
       if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
-        Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
+        if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+          Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
         return VersionMismatch;
       }
       break;
@@ -1918,7 +1953,8 @@ ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F,
         Idx += Length;
 
         // Load the AST file.
-        switch(ReadASTCore(ImportedFile, ImportedKind, &F, Loaded)) {
+        switch(ReadASTCore(ImportedFile, ImportedKind, &F, Loaded,
+                           ClientLoadCapabilities)) {
         case Failure: return Failure;
           // If we have to ignore the dependency, we'll have to ignore this too.
         case OutOfDate: return OutOfDate;
@@ -1931,11 +1967,13 @@ ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F,
       break;
     }
 
-    case LANGUAGE_OPTIONS:
-      if (Listener && &F == *ModuleMgr.begin() && 
-          ParseLanguageOptions(F, Record) && !DisableValidation)
+    case LANGUAGE_OPTIONS: {
+      bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
+      if (Listener && &F == *ModuleMgr.begin() &&
+          ParseLanguageOptions(F, Record, Complain) && !DisableValidation)
         return ConfigurationMismatch;
       break;
+    }
 
     case TARGET_OPTIONS: {
       if (Listener && &F == *ModuleMgr.begin()) {
@@ -1953,7 +1991,9 @@ ASTReader::ASTReadResult ASTReader::ReadControlBlock(ModuleFile &F,
           TargetOpts.Features.push_back(ReadString(Record, Idx));
         }
 
-        if (Listener->ReadTargetOptions(F, TargetOpts) && !DisableValidation)
+        bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+        if (Listener->ReadTargetOptions(F, TargetOpts, Complain) &&
+            !DisableValidation)
           return ConfigurationMismatch;
       }
       break;
@@ -2869,13 +2909,15 @@ void ASTReader::makeModuleVisible(Module *Mod,
 }
 
 ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
-                                            ModuleKind Type) {
+                                            ModuleKind Type,
+                                            unsigned ClientLoadCapabilities) {
   // Bump the generation number.
   unsigned PreviousGeneration = CurrentGeneration++;
 
   // Load the core of the AST files.
   llvm::SmallVector<ModuleFile *, 4> Loaded;
-  switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0, Loaded)) {
+  switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0, Loaded,
+                     ClientLoadCapabilities)) {
   case Failure: return Failure;
   case OutOfDate: return OutOfDate;
   case VersionMismatch: return VersionMismatch;
@@ -2914,11 +2956,12 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
   }
 
   // Check the predefines buffers.
+  bool ConfigComplain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
   if (!DisableValidation && Type == MK_PCH &&
       // FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines;
       // if DisableValidation is true, defines that were set on command-line
       // but not in the PCH file will not be added to SuggestedPredefines.
-      CheckPredefinesBuffers())
+      CheckPredefinesBuffers(ConfigComplain))
     return ConfigurationMismatch;
 
   // Mark all of the identifiers in the identifier table as being out of date,
@@ -2979,10 +3022,12 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
   return Success;
 }
 
-ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
-                                                ModuleKind Type,
-                                                ModuleFile *ImportedBy,
-                           llvm::SmallVectorImpl<ModuleFile *> &Loaded) {
+ASTReader::ASTReadResult
+ASTReader::ReadASTCore(StringRef FileName,
+                       ModuleKind Type,
+                       ModuleFile *ImportedBy,
+                       llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+                       unsigned ClientLoadCapabilities) {
   ModuleFile *M;
   bool NewModule;
   std::string ErrorStr;
@@ -3042,7 +3087,7 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName,
       }
       break;
     case CONTROL_BLOCK_ID:
-      switch (ReadControlBlock(F, Loaded)) {
+      switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) {
       case Success:
         break;
 
@@ -3584,7 +3629,8 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
 ///
 /// \returns true if the listener deems the file unacceptable, false otherwise.
 bool ASTReader::ParseLanguageOptions(const ModuleFile &M,
-                                     const RecordData &Record) {
+                                     const RecordData &Record,
+                                     bool Complain) {
   if (Listener) {
     LangOptions LangOpts;
     unsigned Idx = 0;
@@ -3601,7 +3647,7 @@ bool ASTReader::ParseLanguageOptions(const ModuleFile &M,
     unsigned Length = Record[Idx++];
     LangOpts.CurrentModule.assign(Record.begin() + Idx, 
                                   Record.begin() + Idx + Length);
-    return Listener->ReadLanguageOptions(M, LangOpts);
+    return Listener->ReadLanguageOptions(M, LangOpts, Complain);
   }
 
   return false;