https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/134887
>From a41ba702f42671f7e9c51c29a846a6c7c7324378 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Mon, 7 Apr 2025 13:30:28 -0700 Subject: [PATCH 1/6] [clang] Extract `CompilerInstance` creation out of `compileModuleImpl()` --- clang/lib/Frontend/CompilerInstance.cpp | 68 +++++++++++++++---------- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 9cab17ae70eeb..126398fd6e765 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1150,29 +1150,10 @@ static Language getLanguageFromOptions(const LangOptions &LangOpts) { return LangOpts.CPlusPlus ? Language::CXX : Language::C; } -/// Compile a module file for the given module, using the options -/// provided by the importing compiler instance. Returns true if the module -/// was built without errors. -static bool -compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, - StringRef ModuleName, FrontendInputFile Input, - StringRef OriginalModuleMapFile, StringRef ModuleFileName, - llvm::function_ref<void(CompilerInstance &)> PreBuildStep = - [](CompilerInstance &) {}, - llvm::function_ref<void(CompilerInstance &)> PostBuildStep = - [](CompilerInstance &) {}) { - llvm::TimeTraceScope TimeScope("Module Compile", ModuleName); - - // Never compile a module that's already finalized - this would cause the - // existing module to be freed, causing crashes if it is later referenced - if (ImportingInstance.getModuleCache().getInMemoryModuleCache().isPCMFinal( - ModuleFileName)) { - ImportingInstance.getDiagnostics().Report( - ImportLoc, diag::err_module_rebuild_finalized) - << ModuleName; - return false; - } - +static std::unique_ptr<CompilerInstance> createCompilerInstanceForModuleCompile( + CompilerInstance &ImportingInstance, SourceLocation ImportLoc, + StringRef ModuleName, FrontendInputFile Input, + StringRef OriginalModuleMapFile, StringRef ModuleFileName) { // Construct a compiler invocation for creating this module. auto Invocation = std::make_shared<CompilerInvocation>(ImportingInstance.getInvocation()); @@ -1226,8 +1207,11 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, // module. Since we're sharing an in-memory module cache, // CompilerInstance::CompilerInstance is responsible for finalizing the // buffers to prevent use-after-frees. - CompilerInstance Instance(ImportingInstance.getPCHContainerOperations(), - &ImportingInstance.getModuleCache()); + auto InstancePtr = std::make_unique<CompilerInstance>( + ImportingInstance.getPCHContainerOperations(), + &ImportingInstance.getModuleCache()); + auto &Instance = *InstancePtr; + auto &Inv = *Invocation; Instance.setInvocation(std::move(Invocation)); @@ -1267,6 +1251,38 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, Instance.setModuleDepCollector(ImportingInstance.getModuleDepCollector()); Inv.getDependencyOutputOpts() = DependencyOutputOptions(); + return InstancePtr; +} + +/// Compile a module file for the given module, using the options +/// provided by the importing compiler instance. Returns true if the module +/// was built without errors. +static bool +compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, + StringRef ModuleName, FrontendInputFile Input, + StringRef OriginalModuleMapFile, StringRef ModuleFileName, + llvm::function_ref<void(CompilerInstance &)> PreBuildStep = + [](CompilerInstance &) {}, + llvm::function_ref<void(CompilerInstance &)> PostBuildStep = + [](CompilerInstance &) {}) { + llvm::TimeTraceScope TimeScope("Module Compile", ModuleName); + + // Never compile a module that's already finalized - this would cause the + // existing module to be freed, causing crashes if it is later referenced + if (ImportingInstance.getModuleCache().getInMemoryModuleCache().isPCMFinal( + ModuleFileName)) { + ImportingInstance.getDiagnostics().Report( + ImportLoc, diag::err_module_rebuild_finalized) + << ModuleName; + return false; + } + + std::unique_ptr<CompilerInstance> InstancePtr = + createCompilerInstanceForModuleCompile( + ImportingInstance, ImportLoc, ModuleName, Input, + OriginalModuleMapFile, ModuleFileName); + CompilerInstance &Instance = *InstancePtr; + ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build) << ModuleName << ModuleFileName; @@ -1289,7 +1305,7 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, << ModuleName; // Propagate the statistics to the parent FileManager. - if (!FrontendOpts.ModulesShareFileManager) + if (ImportingInstance.getFileManagerPtr() != Instance.getFileManagerPtr()) ImportingInstance.getFileManager().AddStats(Instance.getFileManager()); if (Crashed) { >From e5f448d78557625d27d8194f88b24d15c2f9ed77 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Mon, 7 Apr 2025 14:43:43 -0700 Subject: [PATCH 2/6] [clang] Pass `CompilerInstance` instance into `compileModuleImpl()` from the outside --- clang/lib/Frontend/CompilerInstance.cpp | 109 +++++++++++------------- 1 file changed, 50 insertions(+), 59 deletions(-) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 126398fd6e765..5ebee46a1116d 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1257,38 +1257,16 @@ static std::unique_ptr<CompilerInstance> createCompilerInstanceForModuleCompile( /// Compile a module file for the given module, using the options /// provided by the importing compiler instance. Returns true if the module /// was built without errors. -static bool -compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, - StringRef ModuleName, FrontendInputFile Input, - StringRef OriginalModuleMapFile, StringRef ModuleFileName, - llvm::function_ref<void(CompilerInstance &)> PreBuildStep = - [](CompilerInstance &) {}, - llvm::function_ref<void(CompilerInstance &)> PostBuildStep = - [](CompilerInstance &) {}) { +static bool compileModuleImpl(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, StringRef ModuleName, + StringRef ModuleFileName, + CompilerInstance &Instance) { llvm::TimeTraceScope TimeScope("Module Compile", ModuleName); - // Never compile a module that's already finalized - this would cause the - // existing module to be freed, causing crashes if it is later referenced - if (ImportingInstance.getModuleCache().getInMemoryModuleCache().isPCMFinal( - ModuleFileName)) { - ImportingInstance.getDiagnostics().Report( - ImportLoc, diag::err_module_rebuild_finalized) - << ModuleName; - return false; - } - - std::unique_ptr<CompilerInstance> InstancePtr = - createCompilerInstanceForModuleCompile( - ImportingInstance, ImportLoc, ModuleName, Input, - OriginalModuleMapFile, ModuleFileName); - CompilerInstance &Instance = *InstancePtr; - ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build) << ModuleName << ModuleFileName; - PreBuildStep(Instance); - // Execute the action to actually build the module in-place. Use a separate // thread so that we get a stack large enough. bool Crashed = !llvm::CrashRecoveryContext().RunSafelyOnThread( @@ -1298,8 +1276,6 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, }, DesiredStackSize); - PostBuildStep(Instance); - ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build_done) << ModuleName; @@ -1343,6 +1319,18 @@ static OptionalFileEntryRef getPublicModuleMap(FileEntryRef File, static bool compileModule(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, Module *Module, StringRef ModuleFileName) { + StringRef ModuleName = Module->getTopLevelModuleName(); + + // Never compile a module that's already finalized - this would cause the + // existing module to be freed, causing crashes if it is later referenced + if (ImportingInstance.getModuleCache().getInMemoryModuleCache().isPCMFinal( + ModuleFileName)) { + ImportingInstance.getDiagnostics().Report( + ImportLoc, diag::err_module_rebuild_finalized) + << ModuleName; + return false; + } + InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()), InputKind::ModuleMap); @@ -1350,7 +1338,8 @@ static bool compileModule(CompilerInstance &ImportingInstance, ModuleMap &ModMap = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); SourceManager &SourceMgr = ImportingInstance.getSourceManager(); - bool Result; + + std::unique_ptr<CompilerInstance> Instance; if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module); ModuleMapFID.isValid()) { // We want to use the top-level module map. If we don't, the compiling @@ -1384,8 +1373,8 @@ static bool compileModule(CompilerInstance &ImportingInstance, bool IsSystem = isSystem(SLoc.getFile().getFileCharacteristic()); // Use the module map where this module resides. - Result = compileModuleImpl( - ImportingInstance, ImportLoc, Module->getTopLevelModuleName(), + Instance = createCompilerInstanceForModuleCompile( + ImportingInstance, ImportLoc, ModuleName, FrontendInputFile(ModuleMapFilePath, IK, IsSystem), ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName); } else { @@ -1400,28 +1389,29 @@ static bool compileModule(CompilerInstance &ImportingInstance, llvm::raw_string_ostream OS(InferredModuleMapContent); Module->print(OS); - Result = compileModuleImpl( - ImportingInstance, ImportLoc, Module->getTopLevelModuleName(), + Instance = createCompilerInstanceForModuleCompile( + ImportingInstance, ImportLoc, ModuleName, FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem), - ModMap.getModuleMapFileForUniquing(Module)->getName(), - ModuleFileName, - [&](CompilerInstance &Instance) { - std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer = - llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent); - FileEntryRef ModuleMapFile = Instance.getFileManager().getVirtualFileRef( - FakeModuleMapFile, InferredModuleMapContent.size(), 0); - Instance.getSourceManager().overrideFileContents( - ModuleMapFile, std::move(ModuleMapBuffer)); - }); + ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName); + + std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer = + llvm::MemoryBuffer::getMemBufferCopy(InferredModuleMapContent); + FileEntryRef ModuleMapFile = Instance->getFileManager().getVirtualFileRef( + FakeModuleMapFile, InferredModuleMapContent.size(), 0); + Instance->getSourceManager().overrideFileContents( + ModuleMapFile, std::move(ModuleMapBuffer)); } + bool Success = compileModuleImpl(ImportingInstance, ImportLoc, ModuleName, + ModuleFileName, *Instance); + // We've rebuilt a module. If we're allowed to generate or update the global // module index, record that fact in the importing compiler instance. if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) { ImportingInstance.setBuildGlobalModuleIndex(true); } - return Result; + return Success; } /// Read the AST right after compiling the module. @@ -2248,25 +2238,26 @@ void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc, std::string NullTerminatedSource(Source.str()); - auto PreBuildStep = [&](CompilerInstance &Other) { - // Create a virtual file containing our desired source. - // FIXME: We shouldn't need to do this. - FileEntryRef ModuleMapFile = Other.getFileManager().getVirtualFileRef( - ModuleMapFileName, NullTerminatedSource.size(), 0); - Other.getSourceManager().overrideFileContents( - ModuleMapFile, llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource)); + auto Other = createCompilerInstanceForModuleCompile( + *this, ImportLoc, ModuleName, Input, StringRef(), ModuleFileName); - Other.BuiltModules = std::move(BuiltModules); - Other.DeleteBuiltModules = false; - }; + // Create a virtual file containing our desired source. + // FIXME: We shouldn't need to do this. + FileEntryRef ModuleMapFile = Other->getFileManager().getVirtualFileRef( + ModuleMapFileName, NullTerminatedSource.size(), 0); + Other->getSourceManager().overrideFileContents( + ModuleMapFile, llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource)); - auto PostBuildStep = [this](CompilerInstance &Other) { - BuiltModules = std::move(Other.BuiltModules); - }; + Other->BuiltModules = std::move(BuiltModules); + Other->DeleteBuiltModules = false; // Build the module, inheriting any modules that we've built locally. - if (compileModuleImpl(*this, ImportLoc, ModuleName, Input, StringRef(), - ModuleFileName, PreBuildStep, PostBuildStep)) { + bool Success = + compileModuleImpl(*this, ImportLoc, ModuleName, ModuleFileName, *Other); + + BuiltModules = std::move(Other->BuiltModules); + + if (Success) { BuiltModules[std::string(ModuleName)] = std::string(ModuleFileName); llvm::sys::RemoveFileOnSignal(ModuleFileName); } >From 5bc798d2924d3c7f844d76c034f40901312ac379 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Tue, 8 Apr 2025 10:24:00 -0700 Subject: [PATCH 3/6] [clang] Also extract the `FrontendInputFile` logic --- clang/lib/Frontend/CompilerInstance.cpp | 221 +++++++++++++----------- 1 file changed, 121 insertions(+), 100 deletions(-) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 5ebee46a1116d..62fff9e2397a1 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1138,22 +1138,16 @@ void CompilerInstance::LoadRequestedPlugins() { } } -/// Determine the appropriate source input kind based on language -/// options. -static Language getLanguageFromOptions(const LangOptions &LangOpts) { - if (LangOpts.OpenCL) - return Language::OpenCL; - if (LangOpts.CUDA) - return Language::CUDA; - if (LangOpts.ObjC) - return LangOpts.CPlusPlus ? Language::ObjCXX : Language::ObjC; - return LangOpts.CPlusPlus ? Language::CXX : Language::C; -} - -static std::unique_ptr<CompilerInstance> createCompilerInstanceForModuleCompile( - CompilerInstance &ImportingInstance, SourceLocation ImportLoc, - StringRef ModuleName, FrontendInputFile Input, - StringRef OriginalModuleMapFile, StringRef ModuleFileName) { +/// Creates a \c CompilerInstance for compiling a module. +/// +/// This expects a properly initialized \c FrontendInputFile. +static std::unique_ptr<CompilerInstance> +createCompilerInstanceForModuleCompileImpl(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, + StringRef ModuleName, + FrontendInputFile Input, + StringRef OriginalModuleMapFile, + StringRef ModuleFileName) { // Construct a compiler invocation for creating this module. auto Invocation = std::make_shared<CompilerInvocation>(ImportingInstance.getInvocation()); @@ -1254,6 +1248,114 @@ static std::unique_ptr<CompilerInstance> createCompilerInstanceForModuleCompile( return InstancePtr; } +/// Determine the appropriate source input kind based on language +/// options. +static Language getLanguageFromOptions(const LangOptions &LangOpts) { + if (LangOpts.OpenCL) + return Language::OpenCL; + if (LangOpts.CUDA) + return Language::CUDA; + if (LangOpts.ObjC) + return LangOpts.CPlusPlus ? Language::ObjCXX : Language::ObjC; + return LangOpts.CPlusPlus ? Language::CXX : Language::C; +} + +static OptionalFileEntryRef getPublicModuleMap(FileEntryRef File, + FileManager &FileMgr) { + StringRef Filename = llvm::sys::path::filename(File.getName()); + SmallString<128> PublicFilename(File.getDir().getName()); + if (Filename == "module_private.map") + llvm::sys::path::append(PublicFilename, "module.map"); + else if (Filename == "module.private.modulemap") + llvm::sys::path::append(PublicFilename, "module.modulemap"); + else + return std::nullopt; + return FileMgr.getOptionalFileRef(PublicFilename); +} + +/// Creates a \c CompilerInstance for compiling a module. +/// +/// This takes care of creating appropriate \c FrontendInputFile for +/// public/private frameworks, inferred modules and such. +static std::unique_ptr<CompilerInstance> +createCompilerInstanceForModuleCompile(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, Module *Module, + StringRef ModuleFileName) { + StringRef ModuleName = Module->getTopLevelModuleName(); + + InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()), + InputKind::ModuleMap); + + // Get or create the module map that we'll use to build this module. + ModuleMap &ModMap = + ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + SourceManager &SourceMgr = ImportingInstance.getSourceManager(); + + if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module); + ModuleMapFID.isValid()) { + // We want to use the top-level module map. If we don't, the compiling + // instance may think the containing module map is a top-level one, while + // the importing instance knows it's included from a parent module map via + // the extern directive. This mismatch could bite us later. + SourceLocation Loc = SourceMgr.getIncludeLoc(ModuleMapFID); + while (Loc.isValid() && isModuleMap(SourceMgr.getFileCharacteristic(Loc))) { + ModuleMapFID = SourceMgr.getFileID(Loc); + Loc = SourceMgr.getIncludeLoc(ModuleMapFID); + } + + OptionalFileEntryRef ModuleMapFile = + SourceMgr.getFileEntryRefForID(ModuleMapFID); + assert(ModuleMapFile && "Top-level module map with no FileID"); + + // Canonicalize compilation to start with the public module map. This is + // vital for submodules declarations in the private module maps to be + // correctly parsed when depending on a top level module in the public one. + if (OptionalFileEntryRef PublicMMFile = getPublicModuleMap( + *ModuleMapFile, ImportingInstance.getFileManager())) + ModuleMapFile = PublicMMFile; + + StringRef ModuleMapFilePath = ModuleMapFile->getNameAsRequested(); + + // Use the systemness of the module map as parsed instead of using the + // IsSystem attribute of the module. If the module has [system] but the + // module map is not in a system path, then this would incorrectly parse + // any other modules in that module map as system too. + const SrcMgr::SLocEntry &SLoc = SourceMgr.getSLocEntry(ModuleMapFID); + bool IsSystem = isSystem(SLoc.getFile().getFileCharacteristic()); + + // Use the module map where this module resides. + return createCompilerInstanceForModuleCompileImpl( + ImportingInstance, ImportLoc, ModuleName, + FrontendInputFile(ModuleMapFilePath, IK, IsSystem), + ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName); + } + + // FIXME: We only need to fake up an input file here as a way of + // transporting the module's directory to the module map parser. We should + // be able to do that more directly, and parse from a memory buffer without + // inventing this file. + SmallString<128> FakeModuleMapFile(Module->Directory->getName()); + llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map"); + + std::string InferredModuleMapContent; + llvm::raw_string_ostream OS(InferredModuleMapContent); + Module->print(OS); + + auto Instance = createCompilerInstanceForModuleCompileImpl( + ImportingInstance, ImportLoc, ModuleName, + FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem), + ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName); + + std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer = + llvm::MemoryBuffer::getMemBufferCopy(InferredModuleMapContent); + FileEntryRef ModuleMapFile = Instance->getFileManager().getVirtualFileRef( + FakeModuleMapFile, InferredModuleMapContent.size(), 0); + Instance->getSourceManager().overrideFileContents(ModuleMapFile, + std::move(ModuleMapBuffer)); + + return Instance; +} + /// Compile a module file for the given module, using the options /// provided by the importing compiler instance. Returns true if the module /// was built without errors. @@ -1300,19 +1402,6 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, Instance.getFrontendOpts().AllowPCMWithCompilerErrors; } -static OptionalFileEntryRef getPublicModuleMap(FileEntryRef File, - FileManager &FileMgr) { - StringRef Filename = llvm::sys::path::filename(File.getName()); - SmallString<128> PublicFilename(File.getDir().getName()); - if (Filename == "module_private.map") - llvm::sys::path::append(PublicFilename, "module.map"); - else if (Filename == "module.private.modulemap") - llvm::sys::path::append(PublicFilename, "module.modulemap"); - else - return std::nullopt; - return FileMgr.getOptionalFileRef(PublicFilename); -} - /// Compile a module file for the given module in a separate compiler instance, /// using the options provided by the importing compiler instance. Returns true /// if the module was built without errors. @@ -1331,76 +1420,8 @@ static bool compileModule(CompilerInstance &ImportingInstance, return false; } - InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()), - InputKind::ModuleMap); - - // Get or create the module map that we'll use to build this module. - ModuleMap &ModMap - = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); - SourceManager &SourceMgr = ImportingInstance.getSourceManager(); - - std::unique_ptr<CompilerInstance> Instance; - if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module); - ModuleMapFID.isValid()) { - // We want to use the top-level module map. If we don't, the compiling - // instance may think the containing module map is a top-level one, while - // the importing instance knows it's included from a parent module map via - // the extern directive. This mismatch could bite us later. - SourceLocation Loc = SourceMgr.getIncludeLoc(ModuleMapFID); - while (Loc.isValid() && isModuleMap(SourceMgr.getFileCharacteristic(Loc))) { - ModuleMapFID = SourceMgr.getFileID(Loc); - Loc = SourceMgr.getIncludeLoc(ModuleMapFID); - } - - OptionalFileEntryRef ModuleMapFile = - SourceMgr.getFileEntryRefForID(ModuleMapFID); - assert(ModuleMapFile && "Top-level module map with no FileID"); - - // Canonicalize compilation to start with the public module map. This is - // vital for submodules declarations in the private module maps to be - // correctly parsed when depending on a top level module in the public one. - if (OptionalFileEntryRef PublicMMFile = getPublicModuleMap( - *ModuleMapFile, ImportingInstance.getFileManager())) - ModuleMapFile = PublicMMFile; - - StringRef ModuleMapFilePath = ModuleMapFile->getNameAsRequested(); - - // Use the systemness of the module map as parsed instead of using the - // IsSystem attribute of the module. If the module has [system] but the - // module map is not in a system path, then this would incorrectly parse - // any other modules in that module map as system too. - const SrcMgr::SLocEntry &SLoc = SourceMgr.getSLocEntry(ModuleMapFID); - bool IsSystem = isSystem(SLoc.getFile().getFileCharacteristic()); - - // Use the module map where this module resides. - Instance = createCompilerInstanceForModuleCompile( - ImportingInstance, ImportLoc, ModuleName, - FrontendInputFile(ModuleMapFilePath, IK, IsSystem), - ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName); - } else { - // FIXME: We only need to fake up an input file here as a way of - // transporting the module's directory to the module map parser. We should - // be able to do that more directly, and parse from a memory buffer without - // inventing this file. - SmallString<128> FakeModuleMapFile(Module->Directory->getName()); - llvm::sys::path::append(FakeModuleMapFile, "__inferred_module.map"); - - std::string InferredModuleMapContent; - llvm::raw_string_ostream OS(InferredModuleMapContent); - Module->print(OS); - - Instance = createCompilerInstanceForModuleCompile( - ImportingInstance, ImportLoc, ModuleName, - FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem), - ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName); - - std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer = - llvm::MemoryBuffer::getMemBufferCopy(InferredModuleMapContent); - FileEntryRef ModuleMapFile = Instance->getFileManager().getVirtualFileRef( - FakeModuleMapFile, InferredModuleMapContent.size(), 0); - Instance->getSourceManager().overrideFileContents( - ModuleMapFile, std::move(ModuleMapBuffer)); - } + auto Instance = createCompilerInstanceForModuleCompile( + ImportingInstance, ImportLoc, Module, ModuleFileName); bool Success = compileModuleImpl(ImportingInstance, ImportLoc, ModuleName, ModuleFileName, *Instance); @@ -2238,7 +2259,7 @@ void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc, std::string NullTerminatedSource(Source.str()); - auto Other = createCompilerInstanceForModuleCompile( + auto Other = createCompilerInstanceForModuleCompileImpl( *this, ImportLoc, ModuleName, Input, StringRef(), ModuleFileName); // Create a virtual file containing our desired source. >From 7baba5b26b9cf5d0161875fdb3c6a88a6e462395 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Thu, 10 Apr 2025 15:39:45 -0700 Subject: [PATCH 4/6] Squash `compileModule()` and `compileModuleImpl()` --- clang/lib/Frontend/CompilerInstance.cpp | 63 ++++++++++--------------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 62fff9e2397a1..db5390fb71af6 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1359,12 +1359,22 @@ createCompilerInstanceForModuleCompile(CompilerInstance &ImportingInstance, /// Compile a module file for the given module, using the options /// provided by the importing compiler instance. Returns true if the module /// was built without errors. -static bool compileModuleImpl(CompilerInstance &ImportingInstance, - SourceLocation ImportLoc, StringRef ModuleName, - StringRef ModuleFileName, - CompilerInstance &Instance) { +static bool compileModule(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, StringRef ModuleName, + StringRef ModuleFileName, + CompilerInstance &Instance) { llvm::TimeTraceScope TimeScope("Module Compile", ModuleName); + // Never compile a module that's already finalized - this would cause the + // existing module to be freed, causing crashes if it is later referenced + if (ImportingInstance.getModuleCache().getInMemoryModuleCache().isPCMFinal( + ModuleFileName)) { + ImportingInstance.getDiagnostics().Report( + ImportLoc, diag::err_module_rebuild_finalized) + << ModuleName; + return false; + } + ImportingInstance.getDiagnostics().Report(ImportLoc, diag::remark_module_build) << ModuleName << ModuleFileName; @@ -1396,43 +1406,16 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, Instance.clearOutputFiles(/*EraseFiles=*/true); } - // If \p AllowPCMWithCompilerErrors is set return 'success' even if errors - // occurred. - return !Instance.getDiagnostics().hasErrorOccurred() || - Instance.getFrontendOpts().AllowPCMWithCompilerErrors; -} - -/// Compile a module file for the given module in a separate compiler instance, -/// using the options provided by the importing compiler instance. Returns true -/// if the module was built without errors. -static bool compileModule(CompilerInstance &ImportingInstance, - SourceLocation ImportLoc, Module *Module, - StringRef ModuleFileName) { - StringRef ModuleName = Module->getTopLevelModuleName(); - - // Never compile a module that's already finalized - this would cause the - // existing module to be freed, causing crashes if it is later referenced - if (ImportingInstance.getModuleCache().getInMemoryModuleCache().isPCMFinal( - ModuleFileName)) { - ImportingInstance.getDiagnostics().Report( - ImportLoc, diag::err_module_rebuild_finalized) - << ModuleName; - return false; - } - - auto Instance = createCompilerInstanceForModuleCompile( - ImportingInstance, ImportLoc, Module, ModuleFileName); - - bool Success = compileModuleImpl(ImportingInstance, ImportLoc, ModuleName, - ModuleFileName, *Instance); - // We've rebuilt a module. If we're allowed to generate or update the global // module index, record that fact in the importing compiler instance. if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) { ImportingInstance.setBuildGlobalModuleIndex(true); } - return Success; + // If \p AllowPCMWithCompilerErrors is set return 'success' even if errors + // occurred. + return !Instance.getDiagnostics().hasErrorOccurred() || + Instance.getFrontendOpts().AllowPCMWithCompilerErrors; } /// Read the AST right after compiling the module. @@ -1482,8 +1465,12 @@ static bool compileModuleAndReadASTImpl(CompilerInstance &ImportingInstance, SourceLocation ModuleNameLoc, Module *Module, StringRef ModuleFileName) { - if (!compileModule(ImportingInstance, ModuleNameLoc, Module, - ModuleFileName)) { + auto Instance = createCompilerInstanceForModuleCompile( + ImportingInstance, ImportLoc, Module, ModuleFileName); + + if (!compileModule(ImportingInstance, ModuleNameLoc, + Module->getTopLevelModuleName(), ModuleFileName, + *Instance)) { ImportingInstance.getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built) << Module->Name << SourceRange(ImportLoc, ModuleNameLoc); @@ -2274,7 +2261,7 @@ void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc, // Build the module, inheriting any modules that we've built locally. bool Success = - compileModuleImpl(*this, ImportLoc, ModuleName, ModuleFileName, *Other); + compileModule(*this, ImportLoc, ModuleName, ModuleFileName, *Other); BuiltModules = std::move(Other->BuiltModules); >From 7de880d67d445a4ce9566efe568ff38171175e11 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Thu, 10 Apr 2025 15:44:29 -0700 Subject: [PATCH 5/6] Minimize diff --- clang/lib/Frontend/CompilerInstance.cpp | 144 ++++++++++++------------ 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index db5390fb71af6..b1dcc190ab988 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1138,6 +1138,18 @@ void CompilerInstance::LoadRequestedPlugins() { } } +/// Determine the appropriate source input kind based on language +/// options. +static Language getLanguageFromOptions(const LangOptions &LangOpts) { + if (LangOpts.OpenCL) + return Language::OpenCL; + if (LangOpts.CUDA) + return Language::CUDA; + if (LangOpts.ObjC) + return LangOpts.CPlusPlus ? Language::ObjCXX : Language::ObjC; + return LangOpts.CPlusPlus ? Language::CXX : Language::C; +} + /// Creates a \c CompilerInstance for compiling a module. /// /// This expects a properly initialized \c FrontendInputFile. @@ -1248,16 +1260,66 @@ createCompilerInstanceForModuleCompileImpl(CompilerInstance &ImportingInstance, return InstancePtr; } -/// Determine the appropriate source input kind based on language -/// options. -static Language getLanguageFromOptions(const LangOptions &LangOpts) { - if (LangOpts.OpenCL) - return Language::OpenCL; - if (LangOpts.CUDA) - return Language::CUDA; - if (LangOpts.ObjC) - return LangOpts.CPlusPlus ? Language::ObjCXX : Language::ObjC; - return LangOpts.CPlusPlus ? Language::CXX : Language::C; +/// Compile a module file for the given module, using the options +/// provided by the importing compiler instance. Returns true if the module +/// was built without errors. +static bool compileModule(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, StringRef ModuleName, + StringRef ModuleFileName, + CompilerInstance &Instance) { + llvm::TimeTraceScope TimeScope("Module Compile", ModuleName); + + // Never compile a module that's already finalized - this would cause the + // existing module to be freed, causing crashes if it is later referenced + if (ImportingInstance.getModuleCache().getInMemoryModuleCache().isPCMFinal( + ModuleFileName)) { + ImportingInstance.getDiagnostics().Report( + ImportLoc, diag::err_module_rebuild_finalized) + << ModuleName; + return false; + } + + ImportingInstance.getDiagnostics().Report(ImportLoc, + diag::remark_module_build) + << ModuleName << ModuleFileName; + + // Execute the action to actually build the module in-place. Use a separate + // thread so that we get a stack large enough. + bool Crashed = !llvm::CrashRecoveryContext().RunSafelyOnThread( + [&]() { + GenerateModuleFromModuleMapAction Action; + Instance.ExecuteAction(Action); + }, + DesiredStackSize); + + ImportingInstance.getDiagnostics().Report(ImportLoc, + diag::remark_module_build_done) + << ModuleName; + + // Propagate the statistics to the parent FileManager. + if (ImportingInstance.getFrontendOpts().ModulesShareFileManager) + ImportingInstance.getFileManager().AddStats(Instance.getFileManager()); + + if (Crashed) { + // Clear the ASTConsumer if it hasn't been already, in case it owns streams + // that must be closed before clearing output files. + Instance.setSema(nullptr); + Instance.setASTConsumer(nullptr); + + // Delete any remaining temporary files related to Instance. + Instance.clearOutputFiles(/*EraseFiles=*/true); + } + + // We've rebuilt a module. If we're allowed to generate or update the global + // module index, record that fact in the importing compiler instance. + if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) { + ImportingInstance.setBuildGlobalModuleIndex(true); + } + + // If \p AllowPCMWithCompilerErrors is set return 'success' even if errors + // occurred. + return !Instance.getDiagnostics().hasErrorOccurred() || + Instance.getFrontendOpts().AllowPCMWithCompilerErrors; } static OptionalFileEntryRef getPublicModuleMap(FileEntryRef File, @@ -1356,68 +1418,6 @@ createCompilerInstanceForModuleCompile(CompilerInstance &ImportingInstance, return Instance; } -/// Compile a module file for the given module, using the options -/// provided by the importing compiler instance. Returns true if the module -/// was built without errors. -static bool compileModule(CompilerInstance &ImportingInstance, - SourceLocation ImportLoc, StringRef ModuleName, - StringRef ModuleFileName, - CompilerInstance &Instance) { - llvm::TimeTraceScope TimeScope("Module Compile", ModuleName); - - // Never compile a module that's already finalized - this would cause the - // existing module to be freed, causing crashes if it is later referenced - if (ImportingInstance.getModuleCache().getInMemoryModuleCache().isPCMFinal( - ModuleFileName)) { - ImportingInstance.getDiagnostics().Report( - ImportLoc, diag::err_module_rebuild_finalized) - << ModuleName; - return false; - } - - ImportingInstance.getDiagnostics().Report(ImportLoc, - diag::remark_module_build) - << ModuleName << ModuleFileName; - - // Execute the action to actually build the module in-place. Use a separate - // thread so that we get a stack large enough. - bool Crashed = !llvm::CrashRecoveryContext().RunSafelyOnThread( - [&]() { - GenerateModuleFromModuleMapAction Action; - Instance.ExecuteAction(Action); - }, - DesiredStackSize); - - ImportingInstance.getDiagnostics().Report(ImportLoc, - diag::remark_module_build_done) - << ModuleName; - - // Propagate the statistics to the parent FileManager. - if (ImportingInstance.getFileManagerPtr() != Instance.getFileManagerPtr()) - ImportingInstance.getFileManager().AddStats(Instance.getFileManager()); - - if (Crashed) { - // Clear the ASTConsumer if it hasn't been already, in case it owns streams - // that must be closed before clearing output files. - Instance.setSema(nullptr); - Instance.setASTConsumer(nullptr); - - // Delete any remaining temporary files related to Instance. - Instance.clearOutputFiles(/*EraseFiles=*/true); - } - - // We've rebuilt a module. If we're allowed to generate or update the global - // module index, record that fact in the importing compiler instance. - if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) { - ImportingInstance.setBuildGlobalModuleIndex(true); - } - - // If \p AllowPCMWithCompilerErrors is set return 'success' even if errors - // occurred. - return !Instance.getDiagnostics().hasErrorOccurred() || - Instance.getFrontendOpts().AllowPCMWithCompilerErrors; -} - /// Read the AST right after compiling the module. static bool readASTAfterCompileModule(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, >From 922ee8a6fe7b04ab097b9ea58f06b7b5c66af9a5 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Thu, 10 Apr 2025 18:16:45 -0700 Subject: [PATCH 6/6] Fix flipped condition --- clang/lib/Frontend/CompilerInstance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index b1dcc190ab988..95b0bfedb7cd8 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1297,7 +1297,7 @@ static bool compileModule(CompilerInstance &ImportingInstance, << ModuleName; // Propagate the statistics to the parent FileManager. - if (ImportingInstance.getFrontendOpts().ModulesShareFileManager) + if (!ImportingInstance.getFrontendOpts().ModulesShareFileManager) ImportingInstance.getFileManager().AddStats(Instance.getFileManager()); if (Crashed) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits