diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4356,6 +4356,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">, diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/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: diff --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h --- a/clang/include/clang/Frontend/FrontendActions.h +++ b/clang/include/clang/Frontend/FrontendActions.h @@ -117,6 +117,8 @@ } bool hasASTFileSupport() const override { return false; } + + bool shouldEraseOutputFiles() override; }; class GenerateInterfaceStubsAction : public ASTFrontendAction { diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/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. diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/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, diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/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)); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/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" @@ -3611,7 +3612,8 @@ Opts.UsePredefines = !Args.hasArg(OPT_undef); Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record); Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch); - Opts.AllowPCHWithCompilerErrors = Args.hasArg(OPT_fallow_pch_with_errors); + Opts.AllowPCHWithCompilerErrors = + Args.hasArg(OPT_fallow_pch_with_errors, OPT_fallow_pcm_with_errors); Opts.DumpDeserializedPCHDecls = Args.hasArg(OPT_dump_deserialized_pch_decls); for (const auto *A : Args.filtered(OPT_error_on_deserialized_pch_decl)) diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/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)); diff --git a/clang/test/Modules/Inputs/error.h b/clang/test/Modules/Inputs/error.h new file mode 100644 --- /dev/null +++ b/clang/test/Modules/Inputs/error.h @@ -0,0 +1,8 @@ +@import undefined + +@interface Error +- (int)method; +undefined +@end + +undefined diff --git a/clang/test/Modules/Inputs/module.map b/clang/test/Modules/Inputs/module.map --- a/clang/test/Modules/Inputs/module.map +++ b/clang/test/Modules/Inputs/module.map @@ -483,3 +483,4 @@ header "template-nontrivial1.h" export * } +module error { header "error.h" } diff --git a/clang/test/Modules/load-module-with-errors.m b/clang/test/Modules/load-module-with-errors.m new file mode 100644 --- /dev/null +++ b/clang/test/Modules/load-module-with-errors.m @@ -0,0 +1,25 @@ +// RUN: rm -rf %t +// RUN: mkdir %t + +// Write out a module with errors make sure it can be read +// RUN: %clang_cc1 -fmodules -fallow-pcm-with-compiler-errors \ +// RUN: -fmodules-cache-path=%t -x objective-c -emit-module \ +// RUN: -fmodule-name=error %S/Inputs/module.map +// RUN: %clang_cc1 -fmodules -fallow-pcm-with-compiler-errors \ +// RUN: -fmodules-cache-path=%t -x objective-c -I %S/Inputs \ +// RUN: -fimplicit-module-maps -ast-print %s | FileCheck %s + +// allow-pcm-with-compiler-errors should also allow errors in PCH +// RUN: %clang_cc1 -fallow-pcm-with-compiler-errors -x c++ -emit-pch \ +// RUN: -o %t/check.pch %S/Inputs/error.h + +@import error; + +void test(id x) { + [x method]; +} + +// CHECK: @interface Error +// CHECK-NEXT: - (int)method; +// CHECK-NEXT: @end +// CHECK: void test(id x) diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp --- a/clang/tools/c-index-test/core_main.cpp +++ b/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'; diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp --- a/clang/tools/libclang/CIndex.cpp +++ b/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;