aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td2
-rw-r--r--include/clang/Serialization/ASTReader.h31
-rw-r--r--lib/Frontend/ASTUnit.cpp11
-rw-r--r--lib/Frontend/FrontendAction.cpp45
-rw-r--r--lib/Serialization/ASTReader.cpp317
-rw-r--r--test/PCH/badpch.c2
-rw-r--r--test/PCH/pch-dir.c22
-rw-r--r--test/PCH/pch-dir.h5
8 files changed, 328 insertions, 107 deletions
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index c0099310cb..b7a8476439 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -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)">,
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index e72e451749..e9920efaa8 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -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);
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index a340d7db33..11cddc7886 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -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);
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index c8e41def8e..b7b93a9178 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -23,10 +23,12 @@
#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();
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index a541e24141..613f8b9dc8 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -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>
diff --git a/test/PCH/badpch.c b/test/PCH/badpch.c
index e687ef3246..dfe367786d 100644
--- a/test/PCH/badpch.c
+++ b/test/PCH/badpch.c
@@ -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
index 0000000000..64b2cd6ea4
--- /dev/null
+++ b/test/PCH/pch-dir.c
@@ -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
index 0000000000..e94a8c7ad9
--- /dev/null
+++ b/test/PCH/pch-dir.h
@@ -0,0 +1,5 @@
+#ifdef __cplusplus
+extern int i;
+#else
+extern int j;
+#endif