From: Douglas Gregor Date: Tue, 27 Jul 2010 00:27:13 +0000 (+0000) Subject: Implement -fno-validate-pch at the -cc1 level, which suppresses most X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fae3b2f4743dad616623c4df2fdb0f5128bd36d9;p=clang Implement -fno-validate-pch at the -cc1 level, which suppresses most of the usual consistency checks used to determine when a precompiled header is incompatible with the translation unit it's being loaded into. Enable this option when loading a precompiled preamble, because the preamble loader will be performing all of this checking itself. Enable the preamble-based test now that it's working. This option is also useful for debugging Clang's PCH (). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@109475 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td index b813fea75c..cd4b9f75b0 100644 --- a/include/clang/Driver/CC1Options.td +++ b/include/clang/Driver/CC1Options.td @@ -441,6 +441,8 @@ def fpascal_strings : Flag<"-fpascal-strings">, HelpText<"Recognize and construct Pascal-style string literals">; def fno_rtti : Flag<"-fno-rtti">, HelpText<"Disable generation of rtti information">; +def fno_validate_pch : Flag<"-fno-validate-pch">, + HelpText<"Disable validation of precompiled headers">; def fshort_wchar : Flag<"-fshort-wchar">, HelpText<"Force wchar_t to be a short unsigned int">; def static_define : Flag<"-static-define">, diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index 54ce8bfe3b..89df8f584b 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -502,13 +502,15 @@ public: /// Create an external AST source to read a PCH file and attach it to the AST /// context. - void createPCHExternalASTSource(llvm::StringRef Path); + void createPCHExternalASTSource(llvm::StringRef Path, + bool DisablePCHValidation); /// Create an external AST source to read a PCH file. /// /// \return - The new object on success, or null on failure. static ExternalASTSource * createPCHExternalASTSource(llvm::StringRef Path, const std::string &Sysroot, + bool DisablePCHValidation, Preprocessor &PP, ASTContext &Context); /// Get the PCH reader, if any. diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 17a0cd076f..49579dc1b1 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -409,6 +409,10 @@ private: /// precompiled header. const char *isysroot; + /// \brief Whether to disable the normal validation performed on precompiled + /// headers when they are loaded. + bool DisableValidation; + /// \brief Mapping from switch-case IDs in the PCH file to /// switch-case statements. std::map SwitchCaseStmts; @@ -599,7 +603,12 @@ public: /// \param isysroot If non-NULL, the system include path specified by the /// user. This is only used with relocatable PCH files. If non-NULL, /// a relocatable PCH file will use the default path "/". - PCHReader(Preprocessor &PP, ASTContext *Context, const char *isysroot = 0); + /// + /// \param DisableValidation If true, the PCH reader will suppress most + /// of its regular consistency checking, allowing the use of precompiled + /// headers that cannot be determined to be compatible. + PCHReader(Preprocessor &PP, ASTContext *Context, const char *isysroot = 0, + bool DisableValidation = false); /// \brief Load the PCH file without using any pre-initialized Preprocessor. /// @@ -618,8 +627,13 @@ public: /// \param isysroot If non-NULL, the system include path specified by the /// user. This is only used with relocatable PCH files. If non-NULL, /// a relocatable PCH file will use the default path "/". - PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, - Diagnostic &Diags, const char *isysroot = 0); + /// + /// \param DisableValidation If true, the PCH reader will suppress most + /// of its regular consistency checking, allowing the use of precompiled + /// headers that cannot be determined to be compatible. + PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, + Diagnostic &Diags, const char *isysroot = 0, + bool DisableValidation = false); ~PCHReader(); /// \brief Load the precompiled header designated by the given file diff --git a/include/clang/Frontend/PreprocessorOptions.h b/include/clang/Frontend/PreprocessorOptions.h index f2154955c2..851c1f0108 100644 --- a/include/clang/Frontend/PreprocessorOptions.h +++ b/include/clang/Frontend/PreprocessorOptions.h @@ -43,6 +43,10 @@ public: /// The implicit PCH included at the start of the translation unit, or empty. std::string ImplicitPCHInclude; + /// \brief When true, disables most of the normal validation performed on + /// precompiled headers. + bool DisablePCHValidation; + /// \brief If non-zero, the implicit PCH include is actually a precompiled /// preamble that covers this number of bytes in the main source file. /// @@ -113,6 +117,7 @@ public: public: PreprocessorOptions() : UsePredefines(true), DetailedRecord(false), + DisablePCHValidation(false), PrecompiledPreambleBytes(0, true), RetainRemappedFileBuffers(false) { } diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 7ff3cdc5b9..0463db18dc 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -394,6 +394,7 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine; PreprocessorOpts.ImplicitPCHInclude = PreambleFile.str(); + PreprocessorOpts.DisablePCHValidation = true; } llvm::OwningPtr Act; @@ -415,9 +416,11 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { Act->EndSourceFile(); // Remove the overridden buffer we used for the preamble. - if (OverrideMainBuffer) + if (OverrideMainBuffer) { PreprocessorOpts.eraseRemappedFile( PreprocessorOpts.remapped_file_buffer_end() - 1); + PreprocessorOpts.DisablePCHValidation = true; + } Clang.takeDiagnosticClient(); @@ -426,9 +429,11 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { error: // Remove the overridden buffer we used for the preamble. - if (OverrideMainBuffer) + if (OverrideMainBuffer) { PreprocessorOpts.eraseRemappedFile( PreprocessorOpts.remapped_file_buffer_end() - 1); + PreprocessorOpts.DisablePCHValidation = true; + } Clang.takeSourceManager(); Clang.takeFileManager(); diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 0b1041f841..ea295687aa 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -250,9 +250,11 @@ void CompilerInstance::createASTContext() { // ExternalASTSource -void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) { +void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, + bool DisablePCHValidation) { llvm::OwningPtr Source; Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, + DisablePCHValidation, getPreprocessor(), getASTContext())); // Remember the PCHReader, but in a non-owning way. Reader = static_cast(Source.get()); @@ -262,11 +264,13 @@ void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) { ExternalASTSource * CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, const std::string &Sysroot, + bool DisablePCHValidation, Preprocessor &PP, ASTContext &Context) { llvm::OwningPtr Reader; Reader.reset(new PCHReader(PP, &Context, - Sysroot.empty() ? 0 : Sysroot.c_str())); + Sysroot.empty() ? 0 : Sysroot.c_str(), + DisablePCHValidation)); switch (Reader->ReadPCH(Path)) { case PCHReader::Success: diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 68703c22fb..0ae4739b41 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1353,7 +1353,8 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.TokenCache = Opts.ImplicitPTHInclude; Opts.UsePredefines = !Args.hasArg(OPT_undef); Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record); - + Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch); + if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { llvm::StringRef Value(A->getValue(Args)); size_t Comma = Value.find(','); diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index dbbf69c8b1..9efa8c61db 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -118,7 +118,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { assert(hasPCHSupport() && "This action does not have PCH support!"); CI.createPCHExternalASTSource( - CI.getPreprocessorOpts().ImplicitPCHInclude); + CI.getPreprocessorOpts().ImplicitPCHInclude, + CI.getPreprocessorOpts().DisablePCHValidation); if (!CI.getASTContext().getExternalSource()) goto failure; } diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index f454477c50..37e11249f8 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -414,13 +414,14 @@ void PCHValidator::ReadCounter(unsigned Value) { //===----------------------------------------------------------------------===// PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, - const char *isysroot) + const char *isysroot, bool DisableValidation) : Listener(new PCHValidator(PP, *this)), DeserializationListener(0), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()), SemaObj(0), PP(&PP), Context(Context), Consumer(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), TotalSelectorsInMethodPool(0), SelectorOffsets(0), - TotalNumSelectors(0), isysroot(isysroot), NumStatHits(0), NumStatMisses(0), + TotalNumSelectors(0), isysroot(isysroot), + DisableValidation(DisableValidation), NumStatHits(0), NumStatMisses(0), NumSLocEntriesRead(0), TotalNumSLocEntries(0), NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0), TotalNumMacros(0), NumLexicalDeclContextsRead(0), @@ -430,12 +431,14 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, } PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, - Diagnostic &Diags, const char *isysroot) + Diagnostic &Diags, const char *isysroot, + bool DisableValidation) : DeserializationListener(0), SourceMgr(SourceMgr), FileMgr(FileMgr), Diags(Diags), SemaObj(0), PP(0), Context(0), Consumer(0), MethodPoolLookupTable(0), MethodPoolLookupTableData(0), TotalSelectorsInMethodPool(0), SelectorOffsets(0), - TotalNumSelectors(0), isysroot(isysroot), NumStatHits(0), NumStatMisses(0), + TotalNumSelectors(0), isysroot(isysroot), + DisableValidation(DisableValidation), NumStatHits(0), NumStatMisses(0), NumSLocEntriesRead(0), TotalNumSLocEntries(0), NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0), TotalNumMacros(0), NumLexicalDeclContextsRead(0), @@ -1019,14 +1022,15 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { return Failure; } - if ((off_t)Record[4] != File->getSize() + if (!DisableValidation && + ((off_t)Record[4] != File->getSize() #if !defined(LLVM_ON_WIN32) // In our regression testing, the Windows file system seems to // have inconsistent modification times that sometimes // erroneously trigger this error-handling path. - || (time_t)Record[5] != File->getModificationTime() + || (time_t)Record[5] != File->getModificationTime() #endif - ) { + )) { Diag(diag::err_fe_pch_file_modified) << Filename; return Failure; @@ -1481,7 +1485,7 @@ PCHReader::ReadPCHBlock(PerFileData &F) { break; case pch::METADATA: { - if (Record[0] != pch::VERSION_MAJOR) { + if (Record[0] != pch::VERSION_MAJOR && !DisableValidation) { Diag(Record[0] < pch::VERSION_MAJOR? diag::warn_pch_version_too_old : diag::warn_pch_version_too_new); return IgnorePCH; @@ -1501,7 +1505,7 @@ PCHReader::ReadPCHBlock(PerFileData &F) { Error("CHAINED_METADATA is not first record in block"); return Failure; } - if (Record[0] != pch::VERSION_MAJOR) { + if (Record[0] != pch::VERSION_MAJOR && !DisableValidation) { Diag(Record[0] < pch::VERSION_MAJOR? diag::warn_pch_version_too_old : diag::warn_pch_version_too_new); return IgnorePCH; @@ -1536,7 +1540,7 @@ PCHReader::ReadPCHBlock(PerFileData &F) { break; case pch::LANGUAGE_OPTIONS: - if (ParseLanguageOptions(Record)) + if (ParseLanguageOptions(Record) && !DisableValidation) return IgnorePCH; break; @@ -1704,7 +1708,7 @@ PCHReader::ReadPCHBlock(PerFileData &F) { case pch::VERSION_CONTROL_BRANCH_REVISION: { const std::string &CurBranch = getClangFullRepositoryVersion(); llvm::StringRef PCHBranch(BlobStart, BlobLen); - if (llvm::StringRef(CurBranch) != PCHBranch) { + if (llvm::StringRef(CurBranch) != PCHBranch && !DisableValidation) { Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch; return IgnorePCH; } @@ -1759,7 +1763,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { } // Check the predefines buffers. - if (CheckPredefinesBuffers()) + if (!DisableValidation && CheckPredefinesBuffers()) return IgnorePCH; if (PP) { diff --git a/test/Index/preamble.c b/test/Index/preamble.c index ad64a43554..7ab1be5f73 100644 --- a/test/Index/preamble.c +++ b/test/Index/preamble.c @@ -2,12 +2,7 @@ #include "preamble.h" int wibble(int); -// FIXME: Turn on use of preamble files - // RUN: %clang -x c-header -o %t.pch %S/Inputs/prefix.h -// RUN: c-index-test -test-load-source-reparse 5 local -I %S/Inputs -include %t %s | FileCheck %s - -// CHECK: preamble.h:1:5: FunctionDecl=bar:1:5 Extent=[1:5 - 1:13] -// CHECK: preamble.h:1:12: ParmDecl=:1:12 (Definition) Extent=[1:9 - 1:13] +// RUN: CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -I %S/Inputs -include %t %s | FileCheck %s // CHECK: preamble.c:3:5: FunctionDecl=wibble:3:5 Extent=[3:5 - 3:16] // CHECK: preamble.c:3:15: ParmDecl=:3:15 (Definition) Extent=[3:12 - 3:16]