@@ -711,22 +711,73 @@ addCommonInvocationArguments(std::vector<std::string> &invocationArgStrs,
711
711
}
712
712
713
713
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
+ }
721
770
}
722
771
723
772
Optional<std::string>
724
773
ClangImporter::getPCHFilename (const ClangImporterOptions &ImporterOptions,
725
- const std::string &SwiftPCHHash ) {
774
+ StringRef SwiftPCHHash, bool &isExplicit ) {
726
775
if (llvm::sys::path::extension (ImporterOptions.BridgingHeader )
727
776
.endswith (PCH_EXTENSION)) {
777
+ isExplicit = true ;
728
778
return ImporterOptions.BridgingHeader ;
729
779
}
780
+ isExplicit = false ;
730
781
731
782
const auto &BridgingHeader = ImporterOptions.BridgingHeader ;
732
783
const auto &PCHOutputDir = ImporterOptions.PrecompiledHeaderOutputDir ;
@@ -749,18 +800,27 @@ ClangImporter::getPCHFilename(const ClangImporterOptions &ImporterOptions,
749
800
750
801
Optional<std::string>
751
802
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);
754
807
if (!PCHFilename.hasValue ()) {
755
808
return None;
756
809
}
757
- if (!canReadPCH (PCHFilename.getValue ())) {
810
+ if (!isExplicit && ! canReadPCH (PCHFilename.getValue ())) {
758
811
SmallString<256 > Message;
759
812
llvm::raw_svector_ostream OS (Message);
760
813
auto Diags = new clang::TextDiagnosticPrinter {
761
814
llvm::errs (),
762
815
&Impl.Instance ->getDiagnosticOpts ()
763
816
};
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
+ }
764
824
auto FailedToEmit = emitBridgingPCH (ImporterOptions.BridgingHeader ,
765
825
PCHFilename.getValue (),
766
826
Diags);
0 commit comments