aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Frontend/ASTUnit.cpp11
-rw-r--r--lib/Frontend/FrontendAction.cpp45
-rw-r--r--lib/Serialization/ASTReader.cpp317
3 files changed, 280 insertions, 93 deletions
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>