https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/179714
>From 4241a6d06b8bda654d6cc71799ffec897c2fbcbc Mon Sep 17 00:00:00 2001 From: Jan Svoboda <[email protected]> Date: Tue, 3 Feb 2026 21:28:07 -0800 Subject: [PATCH 1/3] [clang][modules] Support every import syntax in single-module-parse-mode Previously, `-fmodules-single-module-parse-mode` only prevented module compilation/loading when initiated from an `#include` or `#import` directive. This PR does the same for `@import`, `#pragma clang module import` and `#pragma clang module load`. This is done by sinking the logic down into `CompilerInstance::loadModule()`. --- clang/lib/Frontend/CompilerInstance.cpp | 16 +++++++++ clang/lib/Lex/PPDirectives.cpp | 9 ++--- .../single-module-parse-mode-compiles.m | 36 +++++++++++++++++++ 3 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 clang/test/Modules/single-module-parse-mode-compiles.m diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index ec4e80832b963..ddfabab5fe856 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1988,6 +1988,22 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // * `Preprocessor::HandleHeaderIncludeOrImport` will never call this // function as the `#include` or `#import` is textual. + MM.cacheModuleLoad(*Path[0].getIdentifierInfo(), Module); + } else if (getPreprocessorOpts().SingleModuleParseMode) { + // This mimics how findOrCompileModuleAndReadAST() find the module. + Module = getPreprocessor().getHeaderSearchInfo().lookupModule( + ModuleName, ImportLoc, true, !IsInclusionDirective); + if (Module) { + // Mark the module and its submodules as if they were loaded from a PCM. + std::vector Worklist{Module}; + while (!Worklist.empty()) { + auto *M = Worklist.back(); + Worklist.pop_back(); + M->IsFromModuleFile = true; + for (auto *SubM : M->submodules()) + Worklist.push_back(SubM); + } + } MM.cacheModuleLoad(*Path[0].getIdentifierInfo(), Module); } else { SourceLocation ModuleNameEndLoc = Path.back().getLoc().getLocWithOffset( diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 8d4c9c49f756a..c4b9f9e61c876 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -2494,15 +2494,10 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( (getLangOpts().CPlusPlusModules || getLangOpts().Modules) && ModuleToImport && !ModuleToImport->isHeaderUnit(); - if (MaybeTranslateInclude && (UsableHeaderUnit || UsableClangHeaderModule) && - PPOpts.SingleModuleParseMode) { - Action = IncludeLimitReached; - } // Determine whether we should try to import the module for this #include, if // there is one. Don't do so if precompiled module support is disabled or we // are processing this module textually (because we're building the module). - else if (MaybeTranslateInclude && - (UsableHeaderUnit || UsableClangHeaderModule)) { + if (MaybeTranslateInclude && (UsableHeaderUnit || UsableClangHeaderModule)) { // If this include corresponds to a module but that module is // unavailable, diagnose the situation and bail out. // FIXME: Remove this; loadModule does the same check (but produces @@ -2539,7 +2534,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( "the imported module is different than the suggested one"); if (Imported) { - Action = Import; + Action = PPOpts.SingleModuleParseMode ? Skip : Import; } else if (Imported.isMissingExpected()) { markClangModuleAsAffecting( static_cast<Module *>(Imported)->getTopLevelModule()); diff --git a/clang/test/Modules/single-module-parse-mode-compiles.m b/clang/test/Modules/single-module-parse-mode-compiles.m new file mode 100644 index 0000000000000..8e9b92c86fe61 --- /dev/null +++ b/clang/test/Modules/single-module-parse-mode-compiles.m @@ -0,0 +1,36 @@ +// This test checks that with -fmodules-single-module-parse-mode, no modules get +// compiled into PCM files from any of the import syntax Clang supports. + +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: mkdir %t/cache + +// With -fmodules-single-module-parse-mode, no modules get compiled. +// RUN: %clang_cc1 -x objective-c -fmodules -fmodules-cache-path=%t/cache \ +// RUN: -emit-module %t/module.modulemap -fmodule-name=Mod -o %t/Mod.pcm \ +// RUN: -fmodules-single-module-parse-mode +// RUN: find %t/cache -name "*.pcm" | count 0 + +// Without -fmodules-single-module-parse-mode, loaded modules get compiled. +// RUN: %clang_cc1 -x objective-c -fmodules -fmodules-cache-path=%t/cache \ +// RUN: -emit-module %t/module.modulemap -fmodule-name=Mod -o %t/Mod.pcm +// RUN: find %t/cache -name "*.pcm" | count 5 + +//--- module.modulemap +module Mod { header "Mod.h" } +module Load1 { header "Load1.h" } +module Load2 { header "Load2.h" } +module Load3 { header "Load3.h" } +module Load4 { header "Load4.h" } +module Load5 { header "Load5.h" } +//--- Mod.h +#include "Load1.h" +#import "Load2.h" +@import Load3; +#pragma clang module import Load4 +#pragma clang module load Load5 +//--- Load1.h +//--- Load2.h +//--- Load3.h +//--- Load4.h +//--- Load5.h >From 48ceca5d968cbc3cdd01964373173d281fd4c331 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <[email protected]> Date: Tue, 3 Feb 2026 21:43:34 -0800 Subject: [PATCH 2/3] Undo (likely) unnecessary change --- clang/lib/Lex/PPDirectives.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index c4b9f9e61c876..85edbabf09ed3 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -2534,7 +2534,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( "the imported module is different than the suggested one"); if (Imported) { - Action = PPOpts.SingleModuleParseMode ? Skip : Import; + Action = Import; } else if (Imported.isMissingExpected()) { markClangModuleAsAffecting( static_cast<Module *>(Imported)->getTopLevelModule()); >From 0be1a4f26ce2b2a246c1868dc1e3aa2d6d8302fd Mon Sep 17 00:00:00 2001 From: Jan Svoboda <[email protected]> Date: Wed, 4 Feb 2026 09:34:06 -0800 Subject: [PATCH 3/3] [clang][modules] Add single-module-parse-mode callback --- clang/include/clang/Lex/PPCallbacks.h | 12 ++++++++++++ clang/lib/Frontend/CompilerInstance.cpp | 2 ++ 2 files changed, 14 insertions(+) diff --git a/clang/include/clang/Lex/PPCallbacks.h b/clang/include/clang/Lex/PPCallbacks.h index e6120c5648798..51c6a31e143b8 100644 --- a/clang/include/clang/Lex/PPCallbacks.h +++ b/clang/include/clang/Lex/PPCallbacks.h @@ -212,6 +212,13 @@ class PPCallbacks { const Module *Imported) { } + /// Callback invoked whenever a module load was skipped due to enabled + /// single-module-parse-mode. + /// + /// \param Skipped The module that was not loaded. + /// + virtual void moduleLoadSkipped(Module *Skipped) {} + /// Callback invoked when the end of the main file is reached. /// /// No subsequent callbacks will be made. @@ -554,6 +561,11 @@ class PPChainedCallbacks : public PPCallbacks { Second->moduleImport(ImportLoc, Path, Imported); } + void moduleLoadSkipped(Module *Skipped) override { + First->moduleLoadSkipped(Skipped); + Second->moduleLoadSkipped(Skipped); + } + void EndOfMainFile() override { First->EndOfMainFile(); Second->EndOfMainFile(); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index ddfabab5fe856..5d5da7a9e5643 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1994,6 +1994,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, Module = getPreprocessor().getHeaderSearchInfo().lookupModule( ModuleName, ImportLoc, true, !IsInclusionDirective); if (Module) { + if (PPCallbacks *PPCb = getPreprocessor().getPPCallbacks()) + PPCb->moduleLoadSkipped(Module); // Mark the module and its submodules as if they were loaded from a PCM. std::vector Worklist{Module}; while (!Worklist.empty()) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
