]> granicus.if.org Git - clang/commitdiff
If the precompiled header named by "-include" is actually a directory,
authorDouglas Gregor <dgregor@apple.com>
Tue, 23 Oct 2012 06:18:24 +0000 (06:18 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 23 Oct 2012 06:18:24 +0000 (06:18 +0000)
check each of the files within that directory to determine if any of
them is an AST file that matches the language and target options. If
so, the first matching AST file is loaded. This fixes a longstanding
discrepency with GCC's precompiled header implementation.

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

include/clang/Basic/DiagnosticFrontendKinds.td
include/clang/Serialization/ASTReader.h
lib/Frontend/ASTUnit.cpp
lib/Frontend/FrontendAction.cpp
lib/Serialization/ASTReader.cpp
test/PCH/badpch.c
test/PCH/pch-dir.c [new file with mode: 0644]
test/PCH/pch-dir.h [new file with mode: 0644]

index c0099310cbace0d5ff95017beb9edca9c899d95a..b7a84764391b6ce993d92b00cd718e60192d9495 100644 (file)
@@ -58,6 +58,8 @@ def warn_fe_cc_print_header_failure : Warning<
     "unable to open CC_PRINT_HEADERS file: %0 (using stderr)">;
 def warn_fe_cc_log_diagnostics_failure : Warning<
     "unable to open CC_LOG_DIAGNOSTICS file: %0 (using stderr)">;
+def err_fe_no_pch_in_dir : Error<
+    "no suitable precompiled header file found in directory '%0'">;
 
 def warn_fe_serialized_diag_failure : Warning<
     "unable to open file %0 for serializing diagnostics (%1)">,
index e72e451749e70366bf46e65cfbbd34a5d6d9b211..e9920efaa88e708bce80bed9d96b42802d3d8c94 100644 (file)
@@ -106,8 +106,7 @@ public:
   /// \brief Receives the language options.
   ///
   /// \returns true to indicate the options are invalid or false otherwise.
-  virtual bool ReadLanguageOptions(const serialization::ModuleFile &M,
-                                   const LangOptions &LangOpts,
+  virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
                                    bool Complain) {
     return false;
   }
@@ -116,8 +115,7 @@ public:
   ///
   /// \returns true to indicate the target options are invalid, or false
   /// otherwise.
-  virtual bool ReadTargetOptions(const serialization::ModuleFile &M,
-                                 const TargetOptions &TargetOpts,
+  virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
                                  bool Complain) {
     return false;
   }
@@ -163,11 +161,9 @@ public:
   PCHValidator(Preprocessor &PP, ASTReader &Reader)
     : PP(PP), Reader(Reader), NumHeaderInfos(0) {}
 
-  virtual bool ReadLanguageOptions(const serialization::ModuleFile &M,
-                                   const LangOptions &LangOpts,
+  virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
                                    bool Complain);
-  virtual bool ReadTargetOptions(const serialization::ModuleFile &M,
-                                 const TargetOptions &TargetOpts,
+  virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
                                  bool Complain);
   virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
                                     StringRef OriginalFileName,
@@ -913,9 +909,11 @@ private:
   llvm::BitstreamCursor &SLocCursorForID(int ID);
   SourceLocation getImportLocation(ModuleFile *F);
   bool ReadSubmoduleBlock(ModuleFile &F);
-  bool ParseLanguageOptions(const ModuleFile &M, const RecordData &Record,
-                            bool Complain);
-  
+  static bool ParseLanguageOptions(const RecordData &Record, bool Complain,
+                                   ASTReaderListener &Listener);
+  static bool ParseTargetOptions(const RecordData &Record, bool Complain,
+                                 ASTReaderListener &Listener);
+
   struct RecordLocation {
     RecordLocation(ModuleFile *M, uint64_t O)
       : F(M), Offset(O) {}
@@ -1160,6 +1158,13 @@ public:
                                            FileManager &FileMgr,
                                            DiagnosticsEngine &Diags);
 
+  /// \brief Determine whether the given AST file is acceptable to load into a
+  /// translation unit with the given language and target options.
+  static bool isAcceptableASTFile(StringRef Filename,
+                                  FileManager &FileMgr,
+                                  const LangOptions &LangOpts,
+                                  const TargetOptions &TargetOpts);
+
   /// \brief Returns the suggested contents of the predefines buffer,
   /// which contains a (typically-empty) subset of the predefines
   /// build prior to including the precompiled header.
@@ -1623,10 +1628,10 @@ public:
   llvm::APFloat ReadAPFloat(const RecordData &Record, unsigned &Idx);
 
   // \brief Read a string
-  std::string ReadString(const RecordData &Record, unsigned &Idx);
+  static std::string ReadString(const RecordData &Record, unsigned &Idx);
 
   /// \brief Read a version tuple.
-  VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx);
+  static VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx);
 
   CXXTemporary *ReadCXXTemporary(ModuleFile &F, const RecordData &Record,
                                  unsigned &Idx);
index a340d7db33eada0fb858ea3366f88b03b939d659..11cddc788690a433115da32df7ce848ccbc24c04 100644 (file)
@@ -523,14 +523,11 @@ public:
       Predefines(Predefines), Counter(Counter), NumHeaderInfos(0),
       InitializedLanguage(false) {}
 
-  virtual bool ReadLanguageOptions(const serialization::ModuleFile &M,
-                                   const LangOptions &LangOpts,
+  virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
                                    bool Complain) {
     if (InitializedLanguage)
       return false;
     
-    assert(M.Kind == serialization::MK_MainFile);
-
     LangOpt = LangOpts;
     InitializedLanguage = true;
     
@@ -538,16 +535,12 @@ public:
     return false;
   }
 
-  virtual bool ReadTargetOptions(const serialization::ModuleFile &M,
-                                 const TargetOptions &TargetOpts,
+  virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
                                  bool Complain) {
     // If we've already initialized the target, don't do it again.
     if (Target)
       return false;
     
-    assert(M.Kind == serialization::MK_MainFile);
-
-    
     this->TargetOpts = new TargetOptions(TargetOpts);
     Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), 
                                           *this->TargetOpts);
index c8e41def8e3e62d0c85adbfe049b83899510af9a..b7b93a9178d0ad39a52144d4081c74a1f72b80de 100644 (file)
 #include "clang/Parse/ParseAST.h"
 #include "clang/Serialization/ASTDeserializationListener.h"
 #include "clang/Serialization/ASTReader.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Timer.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+#include "llvm/Support/Timer.h"
 using namespace clang;
 
 namespace {
@@ -155,6 +157,7 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
   return new MultiplexConsumer(Consumers);
 }
 
+
 bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
                                      const FrontendInputFile &Input) {
   assert(!Instance && "Already processing a source file!");
@@ -224,6 +227,44 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
     return true;
   }
 
+  // If the implicit PCH include is actually a directory, rather than
+  // a single file, search for a suitable PCH file in that directory.
+  if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+    FileManager &FileMgr = CI.getFileManager();
+    PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+    StringRef PCHInclude = PPOpts.ImplicitPCHInclude;
+    if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) {
+      llvm::error_code EC;
+      SmallString<128> DirNative;
+      llvm::sys::path::native(PCHDir->getName(), DirNative);
+      bool Found = false;
+      for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+           Dir != DirEnd && !EC; Dir.increment(EC)) {
+        // Check whether this is an acceptable AST file.
+        if (ASTReader::isAcceptableASTFile(Dir->path(), FileMgr,
+                                           CI.getLangOpts(),
+                                           CI.getTargetOpts())) {
+          for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I) {
+            if (PPOpts.Includes[I] == PPOpts.ImplicitPCHInclude) {
+              PPOpts.Includes[I] = Dir->path();
+              PPOpts.ImplicitPCHInclude = Dir->path();
+              Found = true;
+              break;
+            }
+          }
+
+          assert(Found && "Implicit PCH include not in includes list?");
+          break;
+        }
+      }
+
+      if (!Found) {
+        CI.getDiagnostics().Report(diag::err_fe_no_pch_in_dir) << PCHInclude;
+        return true;
+      }
+    }
+  }
+
   // Set up the preprocessor.
   CI.createPreprocessor();
 
index a541e241417ad1fc92fb64bc2f1f948061b2b22d..613f8b9dc8fb84f012ba806f9a5a5ae37d5e5912 100644 (file)
@@ -63,59 +63,66 @@ using namespace clang::serialization::reader;
 
 ASTReaderListener::~ASTReaderListener() {}
 
-bool
-PCHValidator::ReadLanguageOptions(const ModuleFile &M,
-                                  const LangOptions &LangOpts,
-                                  bool Complain) {
-  const LangOptions &PPLangOpts = PP.getLangOpts();
-  
-#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;                                            \
+/// \brief Compare the given set of language options against an existing set of
+/// language options.
+///
+/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
+///
+/// \returns true if the languagae options mis-match, false otherwise.
+static bool checkLanguageOptions(const LangOptions &LangOpts,
+                                 const LangOptions &ExistingLangOpts,
+                                 DiagnosticsEngine *Diags) {
+#define LANGOPT(Name, Bits, Default, Description)                 \
+  if (ExistingLangOpts.Name != LangOpts.Name) {                   \
+    if (Diags)                                                    \
+      Diags->Report(diag::err_pch_langopt_mismatch)               \
+        << Description << LangOpts.Name << ExistingLangOpts.Name; \
+    return true;                                                  \
   }
 
-#define VALUE_LANGOPT(Name, Bits, Default, Description) \
-  if (PPLangOpts.Name != LangOpts.Name) {               \
-    if (Complain)                                       \
-      Reader.Diag(diag::err_pch_langopt_value_mismatch) \
-        << Description;                                 \
-    return true;                                        \
+#define VALUE_LANGOPT(Name, Bits, Default, Description)   \
+  if (ExistingLangOpts.Name != LangOpts.Name) {           \
+    if (Diags)                                            \
+      Diags->Report(diag::err_pch_langopt_value_mismatch) \
+        << Description;                                   \
+    return true;                                          \
   }
 
-#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
-  if (PPLangOpts.get##Name() != LangOpts.get##Name()) {      \
-    if (Complain)                                            \
-      Reader.Diag(diag::err_pch_langopt_value_mismatch)      \
-        << Description;                                      \
-    return true;                                             \
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)   \
+  if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) {  \
+    if (Diags)                                                 \
+      Diags->Report(diag::err_pch_langopt_value_mismatch)      \
+        << Description;                                        \
+    return true;                                               \
   }
 
 #define BENIGN_LANGOPT(Name, Bits, Default, Description)
 #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
 #include "clang/Basic/LangOptions.def"
 
-  if (PPLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) {
-    if (Complain)
-      Reader.Diag(diag::err_pch_langopt_value_mismatch)
-        << "target Objective-C runtime";
+  if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) {
+    if (Diags)
+      Diags->Report(diag::err_pch_langopt_value_mismatch)
+      << "target Objective-C runtime";
     return true;
   }
-  
+
   return false;
 }
 
-bool PCHValidator::ReadTargetOptions(const ModuleFile &M, 
-                                     const TargetOptions &TargetOpts,
-                                     bool Complain) {
-  const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
-
+/// \brief Compare the given set of target options against an existing set of
+/// target options.
+///
+/// \param Diags If non-NULL, diagnostics will be emitted via this engine.
+///
+/// \returns true if the target options mis-match, false otherwise.
+static bool checkTargetOptions(const TargetOptions &TargetOpts,
+                               const TargetOptions &ExistingTargetOpts,
+                               DiagnosticsEngine *Diags) {
 #define CHECK_TARGET_OPT(Field, Name)                             \
   if (TargetOpts.Field != ExistingTargetOpts.Field) {             \
-    if (Complain)                                                 \
-      Reader.Diag(diag::err_pch_targetopt_mismatch)               \
+    if (Diags)                                                    \
+      Diags->Report(diag::err_pch_targetopt_mismatch)             \
         << Name << TargetOpts.Field << ExistingTargetOpts.Field;  \
     return true;                                                  \
   }
@@ -129,8 +136,8 @@ bool PCHValidator::ReadTargetOptions(const ModuleFile &M,
 
   // Compare feature sets.
   SmallVector<StringRef, 4> ExistingFeatures(
-                              ExistingTargetOpts.FeaturesAsWritten.begin(),
-                              ExistingTargetOpts.FeaturesAsWritten.end());
+                                             ExistingTargetOpts.FeaturesAsWritten.begin(),
+                                             ExistingTargetOpts.FeaturesAsWritten.end());
   SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(),
                                          TargetOpts.FeaturesAsWritten.end());
   std::sort(ExistingFeatures.begin(), ExistingFeatures.end());
@@ -146,28 +153,28 @@ bool PCHValidator::ReadTargetOptions(const ModuleFile &M,
     }
 
     if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) {
-      if (Complain)
-        Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
+      if (Diags)
+        Diags->Report(diag::err_pch_targetopt_feature_mismatch)
           << false << ReadFeatures[ReadIdx];
       return true;
     }
 
-    if (Complain)
-      Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
+    if (Diags)
+      Diags->Report(diag::err_pch_targetopt_feature_mismatch)
         << true << ExistingFeatures[ExistingIdx];
     return true;
   }
 
   if (ExistingIdx < ExistingN) {
-    if (Complain)
-      Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
+    if (Diags)
+      Diags->Report(diag::err_pch_targetopt_feature_mismatch)
         << true << ExistingFeatures[ExistingIdx];
     return true;
   }
 
   if (ReadIdx < ReadN) {
-    if (Complain)
-      Reader.Diag(diag::err_pch_targetopt_feature_mismatch)
+    if (Diags)
+      Diags->Report(diag::err_pch_targetopt_feature_mismatch)
         << false << ReadFeatures[ReadIdx];
     return true;
   }
@@ -175,6 +182,21 @@ bool PCHValidator::ReadTargetOptions(const ModuleFile &M,
   return false;
 }
 
+bool
+PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts,
+                                  bool Complain) {
+  const LangOptions &PPLangOpts = PP.getLangOpts();
+  return checkLanguageOptions(LangOpts, PPLangOpts,
+                              Complain? &Reader.Diags : 0);
+}
+
+bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts,
+                                     bool Complain) {
+  const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts();
+  return checkTargetOptions(TargetOpts, ExistingTargetOpts,
+                            Complain? &Reader.Diags : 0);
+}
+
 namespace {
   struct EmptyStringRef {
     bool operator ()(StringRef r) const { return r.empty(); }
@@ -1970,32 +1992,18 @@ ASTReader::ReadControlBlock(ModuleFile &F,
     case LANGUAGE_OPTIONS: {
       bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0;
       if (Listener && &F == *ModuleMgr.begin() &&
-          ParseLanguageOptions(F, Record, Complain) && !DisableValidation)
+          ParseLanguageOptions(Record, Complain, *Listener) &&
+          !DisableValidation)
         return ConfigurationMismatch;
       break;
     }
 
     case TARGET_OPTIONS: {
-      if (Listener && &F == *ModuleMgr.begin()) {
-        unsigned Idx = 0;
-        TargetOptions TargetOpts;
-        TargetOpts.Triple = ReadString(Record, Idx);
-        TargetOpts.CPU = ReadString(Record, Idx);
-        TargetOpts.ABI = ReadString(Record, Idx);
-        TargetOpts.CXXABI = ReadString(Record, Idx);
-        TargetOpts.LinkerVersion = ReadString(Record, Idx);
-        for (unsigned N = Record[Idx++]; N; --N) {
-          TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx));
-        }
-        for (unsigned N = Record[Idx++]; N; --N) {
-          TargetOpts.Features.push_back(ReadString(Record, Idx));
-        }
-
-        bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
-        if (Listener->ReadTargetOptions(F, TargetOpts, Complain) &&
-            !DisableValidation)
-          return ConfigurationMismatch;
-      }
+      bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0;
+      if (Listener && &F == *ModuleMgr.begin() &&
+          ParseTargetOptions(Record, Complain, *Listener) &&
+          !DisableValidation)
+        return ConfigurationMismatch;
       break;
     }
 
@@ -3339,6 +3347,135 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
   return std::string();
 }
 
+namespace {
+  class SimplePCHValidator : public ASTReaderListener {
+    const LangOptions &ExistingLangOpts;
+    const TargetOptions &ExistingTargetOpts;
+
+  public:
+    SimplePCHValidator(const LangOptions &ExistingLangOpts,
+                       const TargetOptions &ExistingTargetOpts)
+      : ExistingLangOpts(ExistingLangOpts),
+        ExistingTargetOpts(ExistingTargetOpts)
+    {
+    }
+
+    virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
+                                     bool Complain) {
+      return checkLanguageOptions(ExistingLangOpts, LangOpts, 0);
+    }
+    virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
+                                   bool Complain) {
+      return checkTargetOptions(ExistingTargetOpts, TargetOpts, 0);
+    }
+  };
+}
+
+bool ASTReader::isAcceptableASTFile(StringRef Filename,
+                                    FileManager &FileMgr,
+                                    const LangOptions &LangOpts,
+                                    const TargetOptions &TargetOpts) {
+  // Open the AST file.
+  std::string ErrStr;
+  OwningPtr<llvm::MemoryBuffer> Buffer;
+  Buffer.reset(FileMgr.getBufferForFile(Filename, &ErrStr));
+  if (!Buffer) {
+    return false;
+  }
+
+  // Initialize the stream
+  llvm::BitstreamReader StreamFile;
+  llvm::BitstreamCursor Stream;
+  StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+                  (const unsigned char *)Buffer->getBufferEnd());
+  Stream.init(StreamFile);
+
+  // Sniff for the signature.
+  if (Stream.Read(8) != 'C' ||
+      Stream.Read(8) != 'P' ||
+      Stream.Read(8) != 'C' ||
+      Stream.Read(8) != 'H') {
+    return false;
+  }
+
+  SimplePCHValidator Validator(LangOpts, TargetOpts);
+  RecordData Record;
+  bool InControlBlock = false;
+  while (!Stream.AtEndOfStream()) {
+    unsigned Code = Stream.ReadCode();
+
+    if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+      unsigned BlockID = Stream.ReadSubBlockID();
+
+      // We only know the control subblock ID.
+      switch (BlockID) {
+      case CONTROL_BLOCK_ID:
+        if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
+          return false;
+        } else {
+          InControlBlock = true;
+        }
+        break;
+
+      default:
+        if (Stream.SkipBlock())
+          return false;
+        break;
+      }
+      continue;
+    }
+
+    if (Code == llvm::bitc::END_BLOCK) {
+      if (Stream.ReadBlockEnd()) {
+        return false;
+      }
+      InControlBlock = false;
+      continue;
+    }
+
+    if (Code == llvm::bitc::DEFINE_ABBREV) {
+      Stream.ReadAbbrevRecord();
+      continue;
+    }
+
+    Record.clear();
+    const char *BlobStart = 0;
+    unsigned BlobLen = 0;
+    unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+    if (InControlBlock) {
+      switch ((ControlRecordTypes)RecCode) {
+      case METADATA: {
+        if (Record[0] != VERSION_MAJOR) {
+          return false;
+        }
+
+        const std::string &CurBranch = getClangFullRepositoryVersion();
+        StringRef ASTBranch(BlobStart, BlobLen);
+        if (StringRef(CurBranch) != ASTBranch)
+          return false;
+
+        break;
+      }
+      case LANGUAGE_OPTIONS:
+        if (ParseLanguageOptions(Record, false, Validator))
+          return false;
+        break;
+
+      case TARGET_OPTIONS:
+        if (ParseTargetOptions(Record, false, Validator))
+          return false;
+        break;
+
+      default:
+        // No other validation to perform.
+        break;
+      }
+    }
+  }
+  
+  return true;
+}
+
 bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
   // Enter the submodule block.
   if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) {
@@ -3628,29 +3765,45 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
 /// them to the AST listener if one is set.
 ///
 /// \returns true if the listener deems the file unacceptable, false otherwise.
-bool ASTReader::ParseLanguageOptions(const ModuleFile &M,
-                                     const RecordData &Record,
-                                     bool Complain) {
-  if (Listener) {
-    LangOptions LangOpts;
-    unsigned Idx = 0;
+bool ASTReader::ParseLanguageOptions(const RecordData &Record,
+                                     bool Complain,
+                                     ASTReaderListener &Listener) {
+  LangOptions LangOpts;
+  unsigned Idx = 0;
 #define LANGOPT(Name, Bits, Default, Description) \
   LangOpts.Name = Record[Idx++];
 #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
   LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++]));
 #include "clang/Basic/LangOptions.def"
 
-    ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
-    VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
-    LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion);
-    
-    unsigned Length = Record[Idx++];
-    LangOpts.CurrentModule.assign(Record.begin() + Idx, 
-                                  Record.begin() + Idx + Length);
-    return Listener->ReadLanguageOptions(M, LangOpts, Complain);
+  ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
+  VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
+  LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion);
+  
+  unsigned Length = Record[Idx++];
+  LangOpts.CurrentModule.assign(Record.begin() + Idx, 
+                                Record.begin() + Idx + Length);
+  return Listener.ReadLanguageOptions(LangOpts, Complain);
+}
+
+bool ASTReader::ParseTargetOptions(const RecordData &Record,
+                                   bool Complain,
+                                   ASTReaderListener &Listener) {
+  unsigned Idx = 0;
+  TargetOptions TargetOpts;
+  TargetOpts.Triple = ReadString(Record, Idx);
+  TargetOpts.CPU = ReadString(Record, Idx);
+  TargetOpts.ABI = ReadString(Record, Idx);
+  TargetOpts.CXXABI = ReadString(Record, Idx);
+  TargetOpts.LinkerVersion = ReadString(Record, Idx);
+  for (unsigned N = Record[Idx++]; N; --N) {
+    TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx));
+  }
+  for (unsigned N = Record[Idx++]; N; --N) {
+    TargetOpts.Features.push_back(ReadString(Record, Idx));
   }
 
-  return false;
+  return Listener.ReadTargetOptions(TargetOpts, Complain);
 }
 
 std::pair<ModuleFile *, unsigned>
index e687ef32468210ec8d7dc7900c0b754f3ce2ef4d..dfe367786d2c992b0efee2bf9ba53ad8898b08ea 100644 (file)
@@ -10,4 +10,4 @@
 // submitted on 2012-02-06 introduced a segfault in the case where the PCH is
 // an empty file and clang was built with assertions.
 // CHECK-EMPTY: error: input is not a PCH file: '{{.*[/\\]}}badpch-empty.h.gch'
-// CHECK-DIR: error: unable to read PCH file {{.*[/\\]}}badpch-dir.h.gch:
+// CHECK-DIR:error: no suitable precompiled header file found in directory '{{.*[/\\]}}badpch-dir.h.gch
diff --git a/test/PCH/pch-dir.c b/test/PCH/pch-dir.c
new file mode 100644 (file)
index 0000000..64b2cd6
--- /dev/null
@@ -0,0 +1,22 @@
+// RUN: mkdir -p %t.h.gch
+// RUN: %clang -x c-header %S/pch-dir.h -o %t.h.gch/c.gch 
+// RUN: %clang -x c++-header %S/pch-dir.h -o %t.h.gch/cpp.gch 
+// RUN: %clang -include %t.h -fsyntax-only %s -Xclang -print-stats 2> %t.clog
+// RUN: FileCheck -check-prefix=C %s < %t.clog
+// RUN: %clang -x c++ -include %t.h -fsyntax-only %s -Xclang -print-stats 2> %t.cpplog
+// RUN: FileCheck -check-prefix=CPP %s < %t.cpplog
+// RUN: not %clang -x c++ -std=c++11 -include %t.h -fsyntax-only %s 2> %t.cpp11log
+// RUN: FileCheck -check-prefix=CPP11 %s < %t.cpp11log
+
+
+int get() {
+#ifdef __cplusplus
+  // CHECK-CPP: .h.gch/cpp.gch
+  return i;
+#else
+  // CHECK-C: .h.gch/c.gch
+  return j;
+#endif
+}
+
+// CHECK-CPP11: no suitable precompiled header file found in directory
diff --git a/test/PCH/pch-dir.h b/test/PCH/pch-dir.h
new file mode 100644 (file)
index 0000000..e94a8c7
--- /dev/null
@@ -0,0 +1,5 @@
+#ifdef __cplusplus
+extern int i;
+#else
+extern int j;
+#endif