diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-10-23 06:18:24 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-10-23 06:18:24 +0000 |
commit | 27ffa6caf965ef20fdef5ae23b81cdc3d05e7afb (patch) | |
tree | 33fb976c8d68d2007e18cc34f98e6caaf2df927d | |
parent | 84c3b9745f813a784b5d8ce77f2785750523d9eb (diff) |
If the precompiled header named by "-include" is actually a directory,
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
-rw-r--r-- | include/clang/Basic/DiagnosticFrontendKinds.td | 2 | ||||
-rw-r--r-- | include/clang/Serialization/ASTReader.h | 31 | ||||
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 11 | ||||
-rw-r--r-- | lib/Frontend/FrontendAction.cpp | 45 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 317 | ||||
-rw-r--r-- | test/PCH/badpch.c | 2 | ||||
-rw-r--r-- | test/PCH/pch-dir.c | 22 | ||||
-rw-r--r-- | test/PCH/pch-dir.h | 5 |
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 |