Skip to content

Commit ba9202e

Browse files
authored
Merge pull request #9416 from akyrtzi/persisten-pch-update-check
[ClangImporter] For ClangImporter::canReadPCH() do a ReadAST invocation to verify if the PCH is up-to-date or not
2 parents 37ed4e5 + 8df20d7 commit ba9202e

File tree

3 files changed

+80
-13
lines changed

3 files changed

+80
-13
lines changed

include/swift/ClangImporter/ClangImporter.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,10 +308,12 @@ class ClangImporter final : public ClangModuleLoader {
308308

309309
Optional<std::string>
310310
getOrCreatePCH(const ClangImporterOptions &ImporterOptions,
311-
const std::string &SwiftPCHHash);
311+
StringRef SwiftPCHHash);
312312
Optional<std::string>
313+
/// \param isExplicit true if the PCH filename was passed directly
314+
/// with -import-objc-header option.
313315
getPCHFilename(const ClangImporterOptions &ImporterOptions,
314-
const std::string &SwiftPCHHash);
316+
StringRef SwiftPCHHash, bool &isExplicit);
315317
};
316318

317319
ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,

lib/ClangImporter/ClangImporter.cpp

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -711,22 +711,73 @@ addCommonInvocationArguments(std::vector<std::string> &invocationArgStrs,
711711
}
712712

713713
bool ClangImporter::canReadPCH(StringRef PCHFilename) {
714-
return clang::ASTReader::isAcceptableASTFile(PCHFilename,
715-
Impl.Instance->getFileManager(),
716-
Impl.Instance->getPCHContainerReader(),
717-
Impl.Instance->getLangOpts(),
718-
Impl.Instance->getTargetOpts(),
719-
Impl.Instance->getPreprocessorOpts(),
720-
Impl.Instance->getSpecificModuleCachePath());
714+
if (!llvm::sys::fs::exists(PCHFilename))
715+
return false;
716+
717+
// FIXME: The following attempts to do an initial ReadAST invocation to verify
718+
// the PCH, without affecting the existing CompilerInstance.
719+
// Look into combining creating the ASTReader along with verification + update
720+
// if necesary, so that we can create and use one ASTReader in the common case
721+
// when there is no need for update.
722+
723+
CompilerInstance &CI = *Impl.Instance;
724+
auto clangDiags = CompilerInstance::createDiagnostics(
725+
new clang::DiagnosticOptions());
726+
clang::SourceManager clangSrcMgr(*clangDiags, CI.getFileManager());
727+
auto FID = clangSrcMgr.createFileID(
728+
llvm::make_unique<ZeroFilledMemoryBuffer>(1, "<main>"));
729+
clangSrcMgr.setMainFileID(FID);
730+
clang::Preprocessor PP(CI.getInvocation().getPreprocessorOptsPtr(),
731+
*clangDiags,
732+
CI.getLangOpts(),
733+
clangSrcMgr,
734+
CI.getPCMCache(),
735+
CI.getPreprocessor().getHeaderSearchInfo(), CI,
736+
/*IILookup=*/nullptr,
737+
/*OwnsHeaderSearch=*/false);
738+
PP.Initialize(CI.getTarget());
739+
clang::ASTContext ctx(CI.getLangOpts(), clangSrcMgr,
740+
PP.getIdentifierTable(), PP.getSelectorTable(),
741+
PP.getBuiltinInfo());
742+
743+
std::unique_ptr<clang::ASTReader> Reader(new clang::ASTReader(
744+
PP, ctx, CI.getPCHContainerReader(),
745+
CI.getFrontendOpts().ModuleFileExtensions,
746+
CI.getHeaderSearchOpts().Sysroot,
747+
/*DisableValidation*/ false,
748+
/*AllowPCHWithCompilerErrors*/ false,
749+
/*AllowConfigurationMismatch*/ false,
750+
/*ValidateSystemInputs*/ true));
751+
ctx.InitBuiltinTypes(CI.getTarget());
752+
753+
auto result = Reader->ReadAST(PCHFilename,
754+
clang::serialization::MK_PCH,
755+
clang::SourceLocation(),
756+
clang::ASTReader::ARR_None);
757+
switch (result) {
758+
case clang::ASTReader::Success:
759+
return true;
760+
case clang::ASTReader::Failure:
761+
case clang::ASTReader::Missing:
762+
case clang::ASTReader::OutOfDate:
763+
case clang::ASTReader::VersionMismatch:
764+
return false;
765+
case clang::ASTReader::ConfigurationMismatch:
766+
case clang::ASTReader::HadErrors:
767+
assert(0 && "unexpected ASTReader failure for PCH validation");
768+
return false;
769+
}
721770
}
722771

723772
Optional<std::string>
724773
ClangImporter::getPCHFilename(const ClangImporterOptions &ImporterOptions,
725-
const std::string &SwiftPCHHash) {
774+
StringRef SwiftPCHHash, bool &isExplicit) {
726775
if (llvm::sys::path::extension(ImporterOptions.BridgingHeader)
727776
.endswith(PCH_EXTENSION)) {
777+
isExplicit = true;
728778
return ImporterOptions.BridgingHeader;
729779
}
780+
isExplicit = false;
730781

731782
const auto &BridgingHeader = ImporterOptions.BridgingHeader;
732783
const auto &PCHOutputDir = ImporterOptions.PrecompiledHeaderOutputDir;
@@ -749,18 +800,27 @@ ClangImporter::getPCHFilename(const ClangImporterOptions &ImporterOptions,
749800

750801
Optional<std::string>
751802
ClangImporter::getOrCreatePCH(const ClangImporterOptions &ImporterOptions,
752-
const std::string &SwiftPCHHash) {
753-
auto PCHFilename = getPCHFilename(ImporterOptions, SwiftPCHHash);
803+
StringRef SwiftPCHHash) {
804+
bool isExplicit;
805+
auto PCHFilename = getPCHFilename(ImporterOptions, SwiftPCHHash,
806+
isExplicit);
754807
if (!PCHFilename.hasValue()) {
755808
return None;
756809
}
757-
if (!canReadPCH(PCHFilename.getValue())) {
810+
if (!isExplicit && !canReadPCH(PCHFilename.getValue())) {
758811
SmallString<256> Message;
759812
llvm::raw_svector_ostream OS(Message);
760813
auto Diags = new clang::TextDiagnosticPrinter {
761814
llvm::errs(),
762815
&Impl.Instance->getDiagnosticOpts()
763816
};
817+
StringRef parentDir = llvm::sys::path::parent_path(PCHFilename.getValue());
818+
std::error_code EC = llvm::sys::fs::create_directories(parentDir);
819+
if (EC) {
820+
llvm::errs() << "failed to create directory '" << parentDir << "': "
821+
<< EC.message();
822+
return None;
823+
}
764824
auto FailedToEmit = emitBridgingPCH(ImporterOptions.BridgingHeader,
765825
PCHFilename.getValue(),
766826
Diags);

test/IDE/complete_with_header_import.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
// RUN: %target-swift-ide-test -code-completion -pch-output-dir %t -source-filename %s -code-completion-token=TOP -import-objc-header %S/Inputs/header.h | %FileCheck %s -check-prefix=CHECK-TOP
55
// RUN: %target-swift-ide-test -code-completion -pch-output-dir %t -source-filename %s -code-completion-token=TYPE -import-objc-header %S/Inputs/header.h | %FileCheck %s -check-prefix=CHECK-TYPE
66
// RUN: stat %t/*.pch
7+
// RUN: cp %S/Inputs/header.h %t
8+
// RUN: %target-swift-ide-test -code-completion -pch-output-dir %t/pch -source-filename %s -code-completion-token=TOP -import-objc-header %t/header.h | %FileCheck %s -check-prefix=CHECK-TOP
9+
// RUN: stat %t/pch/*.pch
10+
// RUN: echo '// new stuff' >> %t/header.h
11+
// RUN: %target-swift-ide-test -code-completion -pch-output-dir %t/pch -source-filename %s -code-completion-token=TOP -import-objc-header %t/header.h | %FileCheck %s -check-prefix=CHECK-TOP
712

813
// REQUIRES: objc_interop
914

0 commit comments

Comments
 (0)