Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -4351,6 +4351,8 @@ HelpText<"Disable validation of precompiled headers">; def fallow_pch_with_errors : Flag<["-"], "fallow-pch-with-compiler-errors">, HelpText<"Accept a PCH file that was created with compiler errors">; +def fallow_pcm_with_errors : Flag<["-"], "fallow-pcm-with-compiler-errors">, + HelpText<"Accept a PCM file that was created with compiler errors">; def dump_deserialized_pch_decls : Flag<["-"], "dump-deserialized-decls">, HelpText<"Dump declarations that are deserialized from PCH, for testing">; def error_on_deserialized_pch_decl : Separate<["-"], "error-on-deserialized-decl">, Index: clang/include/clang/Frontend/ASTUnit.h =================================================================== --- clang/include/clang/Frontend/ASTUnit.h +++ clang/include/clang/Frontend/ASTUnit.h @@ -694,7 +694,7 @@ const FileSystemOptions &FileSystemOpts, bool UseDebugInfo = false, bool OnlyLocalDecls = false, ArrayRef RemappedFiles = None, CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, - bool AllowPCHWithCompilerErrors = false, + bool AllowASTWithCompilerErrors = false, bool UserFilesAreVolatile = false); private: Index: clang/include/clang/Frontend/FrontendActions.h =================================================================== --- clang/include/clang/Frontend/FrontendActions.h +++ clang/include/clang/Frontend/FrontendActions.h @@ -117,6 +117,8 @@ } bool hasASTFileSupport() const override { return false; } + + bool shouldEraseOutputFiles() override; }; class GenerateInterfaceStubsAction : public ASTFrontendAction { Index: clang/include/clang/Frontend/FrontendOptions.h =================================================================== --- clang/include/clang/Frontend/FrontendOptions.h +++ clang/include/clang/Frontend/FrontendOptions.h @@ -303,6 +303,9 @@ /// When using -emit-module, treat the modulemap as a system module. unsigned IsSystemModule : 1; + /// Output (and read) PCM files regardless of compiler errors. + unsigned AllowPCMWithCompilerErrors : 1; + CodeCompleteOptions CodeCompleteOpts; /// Specifies the output format of the AST. @@ -457,7 +460,8 @@ UseGlobalModuleIndex(true), GenerateGlobalModuleIndex(true), ASTDumpDecls(false), ASTDumpLookups(false), BuildingImplicitModule(false), ModulesEmbedAllFiles(false), - IncludeTimestamps(true), UseTemporary(true), TimeTraceGranularity(500) {} + IncludeTimestamps(true), UseTemporary(true), + AllowPCMWithCompilerErrors(false), TimeTraceGranularity(500) {} /// getInputKindForExtension - Return the appropriate input kind for a file /// extension. For example, "c" would return Language::C. Index: clang/lib/Frontend/ASTUnit.cpp =================================================================== --- clang/lib/Frontend/ASTUnit.cpp +++ clang/lib/Frontend/ASTUnit.cpp @@ -759,7 +759,7 @@ WhatToLoad ToLoad, IntrusiveRefCntPtr Diags, const FileSystemOptions &FileSystemOpts, bool UseDebugInfo, bool OnlyLocalDecls, ArrayRef RemappedFiles, - CaptureDiagsKind CaptureDiagnostics, bool AllowPCHWithCompilerErrors, + CaptureDiagsKind CaptureDiagnostics, bool AllowASTWithCompilerErrors, bool UserFilesAreVolatile) { std::unique_ptr AST(new ASTUnit(true)); @@ -819,7 +819,7 @@ AST->Reader = new ASTReader( PP, *AST->ModuleCache, AST->Ctx.get(), PCHContainerRdr, {}, /*isysroot=*/"", - /*DisableValidation=*/disableValid, AllowPCHWithCompilerErrors); + /*DisableValidation=*/disableValid, AllowASTWithCompilerErrors); AST->Reader->setListener(std::make_unique( *AST->PP, AST->Ctx.get(), *AST->HSOpts, *AST->PPOpts, *AST->LangOpts, Index: clang/lib/Frontend/CompilerInstance.cpp =================================================================== --- clang/lib/Frontend/CompilerInstance.cpp +++ clang/lib/Frontend/CompilerInstance.cpp @@ -1523,7 +1523,9 @@ HeaderSearchOptions &HSOpts = getHeaderSearchOpts(); std::string Sysroot = HSOpts.Sysroot; const PreprocessorOptions &PPOpts = getPreprocessorOpts(); + const FrontendOptions &FEOpts = getFrontendOpts(); std::unique_ptr ReadTimer; + if (FrontendTimerGroup) ReadTimer = std::make_unique("reading_modules", "Reading modules", @@ -1532,7 +1534,7 @@ getPreprocessor(), getModuleCache(), &getASTContext(), getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions, Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation, - /*AllowASTWithCompilerErrors=*/false, + /*AllowASTWithCompilerErrors=*/FEOpts.AllowPCMWithCompilerErrors, /*AllowConfigurationMismatch=*/false, HSOpts.ModulesValidateSystemHeaders, HSOpts.ValidateASTInputFilesContent, getFrontendOpts().UseGlobalModuleIndex, std::move(ReadTimer)); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -2027,6 +2027,7 @@ Opts.IncludeTimestamps = !Args.hasArg(OPT_fno_pch_timestamp); Opts.UseTemporary = !Args.hasArg(OPT_fno_temp_file); Opts.IsSystemModule = Args.hasArg(OPT_fsystem_module); + Opts.AllowPCMWithCompilerErrors = Args.hasArg(OPT_fallow_pcm_with_errors); if (Opts.ProgramAction != frontend::GenerateModule && Opts.IsSystemModule) Diags.Report(diag::err_drv_argument_only_allowed_with) << "-fsystem-module" Index: clang/lib/Frontend/FrontendActions.cpp =================================================================== --- clang/lib/Frontend/FrontendActions.cpp +++ clang/lib/Frontend/FrontendActions.cpp @@ -177,7 +177,8 @@ Consumers.push_back(std::make_unique( CI.getPreprocessor(), CI.getModuleCache(), OutputFile, Sysroot, Buffer, CI.getFrontendOpts().ModuleFileExtensions, - /*AllowASTWithErrors=*/false, + /*AllowASTWithErrors=*/ + +CI.getFrontendOpts().AllowPCMWithCompilerErrors, /*IncludeTimestamps=*/ +CI.getFrontendOpts().BuildingImplicitModule, /*ShouldCacheASTInMemory=*/ @@ -187,6 +188,11 @@ return std::make_unique(std::move(Consumers)); } +bool GenerateModuleAction::shouldEraseOutputFiles() { + return !getCompilerInstance().getFrontendOpts().AllowPCMWithCompilerErrors && + ASTFrontendAction::shouldEraseOutputFiles(); +} + bool GenerateModuleFromModuleMapAction::BeginSourceFileAction( CompilerInstance &CI) { if (!CI.getLangOpts().Modules) { @@ -339,7 +345,7 @@ CI.getPCHContainerReader(), CI.getFrontendOpts().ModuleFileExtensions, Sysroot.empty() ? "" : Sysroot.c_str(), /*DisableValidation*/ false, - /*AllowPCHWithCompilerErrors*/ false, + /*AllowASTWithCompilerErrors*/ false, /*AllowConfigurationMismatch*/ true, /*ValidateSystemInputs*/ true)); Index: clang/test/Modules/Inputs/error.h =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/error.h @@ -0,0 +1,8 @@ +@import undefined + +@interface Error +- (int)method; +undefined +@end + +undefined Index: clang/test/Modules/Inputs/module.map =================================================================== --- clang/test/Modules/Inputs/module.map +++ clang/test/Modules/Inputs/module.map @@ -483,3 +483,4 @@ header "template-nontrivial1.h" export * } +module error { header "error.h" } Index: clang/test/Modules/load-module-with-errors.m =================================================================== --- /dev/null +++ clang/test/Modules/load-module-with-errors.m @@ -0,0 +1,14 @@ +// RUN: rm -rf %t + +// RUN: %clang_cc1 -fmodules -fdisable-module-hash -fallow-pcm-with-compiler-errors -fmodules-cache-path=%t -emit-module -x objective-c -fmodule-name=error %S/Inputs/module.map +// RUN: %clang_cc1 -fmodules -fdisable-module-hash -fimplicit-module-maps -fallow-pcm-with-compiler-errors -ast-print -x objective-c -fmodules-cache-path=%t -I %S/Inputs %s | FileCheck -check-prefix=CHECK-PRINT %s + +@import error; + +void test(id x) { + [x method]; +} + +// CHECK-PRINT: @interface Error +// CHECK-PRINT-NEXT: - (int)method; +// CHECK-PRINT: void test(id x) Index: clang/tools/c-index-test/core_main.cpp =================================================================== --- clang/tools/c-index-test/core_main.cpp +++ clang/tools/c-index-test/core_main.cpp @@ -263,7 +263,7 @@ std::string(modulePath), *pchRdr, ASTUnit::LoadASTOnly, Diags, FileSystemOpts, /*UseDebugInfo=*/false, /*OnlyLocalDecls=*/true, None, CaptureDiagsKind::None, - /*AllowPCHWithCompilerErrors=*/true, + /*AllowASTWithCompilerErrors=*/true, /*UserFilesAreVolatile=*/false); if (!AU) { errs() << "failed to create TU for: " << modulePath << '\n'; Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -3476,7 +3476,7 @@ ast_filename, CXXIdx->getPCHContainerOperations()->getRawReader(), ASTUnit::LoadEverything, Diags, FileSystemOpts, /*UseDebugInfo=*/false, CXXIdx->getOnlyLocalDecls(), None, CaptureDiagsKind::All, - /*AllowPCHWithCompilerErrors=*/true, + /*AllowASTWithCompilerErrors=*/true, /*UserFilesAreVolatile=*/true); *out_TU = MakeCXTranslationUnit(CXXIdx, std::move(AU)); return *out_TU ? CXError_Success : CXError_Failure;