[clang] [clang][Modules] Fix unexpected warnings triggered by a PCH and a module with config macros (PR #174034)
Qiongsi Wu via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 5 09:07:12 PST 2026
https://github.com/qiongsiwu updated https://github.com/llvm/llvm-project/pull/174034
>From 8d00ccc86f1d9c0354ce15514da9cbb3c6dafc0d Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qiongsi_wu at apple.com>
Date: Tue, 30 Dec 2025 15:10:04 -0800
Subject: [PATCH 1/2] Fixing unexpected config macro diagnostics when a PCH is
included.
---
clang/include/clang/Lex/Preprocessor.h | 11 +++++
clang/lib/Frontend/CompilerInstance.cpp | 4 +-
clang/lib/Lex/PPMacroExpansion.cpp | 32 +++++++++++++
.../Inputs/pch-config-macros/include/Mod1.h | 5 ++
.../include/module.modulemap | 4 ++
clang/test/Modules/pch-config-macros.c | 48 +++++++++++++++++++
6 files changed, 103 insertions(+), 1 deletion(-)
create mode 100644 clang/test/Modules/Inputs/pch-config-macros/include/Mod1.h
create mode 100644 clang/test/Modules/Inputs/pch-config-macros/include/module.modulemap
create mode 100644 clang/test/Modules/pch-config-macros.c
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index b1c648e647f41..4bff1b395b5fc 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1119,6 +1119,10 @@ class Preprocessor {
/// The file ID for the PCH through header.
FileID PCHThroughHeaderFileID;
+ /// The file ID for the predefines that come from the PCH.
+ /// This is only set when modules are in effect.
+ FileID PCHPredefinesFileID;
+
/// Whether tokens are being skipped until a #pragma hdrstop is seen.
bool SkippingUntilPragmaHdrStop = false;
@@ -1315,6 +1319,13 @@ class Preprocessor {
/// Returns the FileID for the preprocessor predefines.
FileID getPredefinesFileID() const { return PredefinesFileID; }
+ /// Returns the FileID for the predefines loaded from the PCH.
+ FileID getPCHPredefinesFileID() const {
+ assert(getLangOpts().Modules &&
+ "PCHPredefinedFileID is only set when modules is in effect!");
+ return PCHPredefinesFileID;
+ }
+
/// \{
/// Accessors for preprocessor callbacks.
///
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index f7f0ea3317932..ac27ae692b2a2 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -1548,7 +1548,9 @@ static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
for (auto *MD = LatestLocalMD; MD; MD = MD->getPrevious()) {
// We only care about the predefines buffer.
FileID FID = SourceMgr.getFileID(MD->getLocation());
- if (FID.isInvalid() || FID != PP.getPredefinesFileID())
+ if (FID.isInvalid())
+ continue;
+ if (FID != PP.getPredefinesFileID() && FID != PP.getPCHPredefinesFileID())
continue;
if (auto *DMD = dyn_cast<DefMacroDirective>(MD))
CmdLineDefinition = DMD->getMacroInfo();
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index 5efa4b5b3f872..6b6ef9fe9f3ed 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -125,6 +125,38 @@ void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II,
II->setHasMacroDefinition(true);
if (!MD->isDefined() && !LeafModuleMacros.contains(II))
II->setHasMacroDefinition(false);
+
+ if (getLangOpts().Modules) {
+ // When both modules and a PCH are used, we may run into the following
+ // situation:
+ // - the PCH is compiled with macro definitions on the command line.
+ // - the modules are compiled with the same set of macros on the command
+ // line.
+ // In this case, clang needs to know that some predefined macros exist
+ // over the command line transitively through the PCH and some are passed
+ // directly over the command line. The preprocessor stores
+ // PCHPredefinesFileID so later it is aware of macros defined transitively
+ // through the PCH's compilation.
+ auto MDLoc = MD->getLocation();
+
+ // The PCH loads the command line macros into the <built-in> buffer.
+ // This is not the same as SourceMgr.isWrittenInBuiltinFile(MDLoc),
+ // since we are not looking at the Presumed location.
+ if (SourceMgr.getBufferName(MDLoc) == "<built-in>") {
+ auto MDFileID = SourceMgr.getFileID(MDLoc);
+ if (PCHPredefinesFileID.isInvalid())
+ PCHPredefinesFileID = MDFileID;
+ else {
+ // The PCH and all the chain of headers it includes must be
+ // compiled with the exact same set of macros defined over the
+ // command line. No different macros should be defined over
+ // different command line invocations. This means that all the macros'
+ // source locations should have the same MDFileID.
+ assert(MDFileID == PCHPredefinesFileID &&
+ "PCHBuiltinFileID must be consistent!");
+ }
+ }
+ }
}
ModuleMacro *Preprocessor::addModuleMacro(Module *Mod, IdentifierInfo *II,
diff --git a/clang/test/Modules/Inputs/pch-config-macros/include/Mod1.h b/clang/test/Modules/Inputs/pch-config-macros/include/Mod1.h
new file mode 100644
index 0000000000000..3b8f33877dcd2
--- /dev/null
+++ b/clang/test/Modules/Inputs/pch-config-macros/include/Mod1.h
@@ -0,0 +1,5 @@
+#if CONFIG1
+int foo() { return 42; }
+#else
+int foo() { return 43; }
+#endif
diff --git a/clang/test/Modules/Inputs/pch-config-macros/include/module.modulemap b/clang/test/Modules/Inputs/pch-config-macros/include/module.modulemap
new file mode 100644
index 0000000000000..9d5f2e714ec88
--- /dev/null
+++ b/clang/test/Modules/Inputs/pch-config-macros/include/module.modulemap
@@ -0,0 +1,4 @@
+module Mod1 {
+ header "Mod1.h"
+ config_macros CONFIG1,CONFIG2
+}
diff --git a/clang/test/Modules/pch-config-macros.c b/clang/test/Modules/pch-config-macros.c
new file mode 100644
index 0000000000000..1cf7f60eea11a
--- /dev/null
+++ b/clang/test/Modules/pch-config-macros.c
@@ -0,0 +1,48 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: cd %t
+
+// This test builds two PCHs. bridging.h.pch depends on h1.h.pch.
+// Then the test uses bridiging.h.pch in a source file that imports
+// a module with config macros.
+// This is a normal use case and no warnings should be issued.
+// RUN: %clang_cc1 -fmodules \
+// RUN: -fmodule-map-file=%S/Inputs/pch-config-macros/include/module.modulemap \
+// RUN: -fmodules-cache-path=%t/cache -I %S/Inputs/pch-config-macros/include \
+// RUN: h1.h -emit-pch -o h1.h.pch -DCONFIG1 -DCONFIG2
+// RUN: %clang_cc1 -fmodules \
+// RUN: -fmodule-map-file=%S/Inputs/pch-config-macros/include/module.modulemap \
+// RUN: -fmodules-cache-path=%t/cache -I %S/Inputs/pch-config-macros/include \
+// RUN: -include-pch h1.h.pch bridging.h -emit-pch -o bridging.h.pch \
+// RUN: -DCONFIG1 -DCONFIG2
+// RUN: %clang_cc1 -fmodules \
+// RUN: -fmodule-map-file=%S/Inputs/pch-config-macros/include/module.modulemap \
+// RUN: -fmodules-cache-path=%t/cache -I %S/Inputs/pch-config-macros/include \
+// RUN: -emit-obj -o main.o main.c -include-pch bridging.h.pch \
+// RUN: -DCONFIG1 -DCONFIG2 -verify
+
+//--- h1.h
+#if CONFIG1
+int bar1() { return 42; }
+#else
+int bar2() { return 43; }
+#endif
+
+//--- bridging.h
+#if CONFIG1
+int bar() { return bar1(); }
+#else
+int bar() { return bar2(); }
+#endif
+
+#if CONFIG2
+int baz() { return 77; }
+#endif
+
+//--- main.c
+#include "Mod1.h"
+// expected-no-diagnostics
+
+int main_func() {
+ return foo() + bar();
+}
>From 664c492bcda613165ec8a2b0781439ee62eac39c Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qiongsi_wu at apple.com>
Date: Mon, 5 Jan 2026 09:06:58 -0800
Subject: [PATCH 2/2] Use isWrittenInCommandLineFile to check if a macro is
defined on the command line.
---
clang/lib/Lex/PPMacroExpansion.cpp | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index 6b6ef9fe9f3ed..09cf778938427 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -139,10 +139,7 @@ void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II,
// through the PCH's compilation.
auto MDLoc = MD->getLocation();
- // The PCH loads the command line macros into the <built-in> buffer.
- // This is not the same as SourceMgr.isWrittenInBuiltinFile(MDLoc),
- // since we are not looking at the Presumed location.
- if (SourceMgr.getBufferName(MDLoc) == "<built-in>") {
+ if (SourceMgr.isWrittenInCommandLineFile(MDLoc)) {
auto MDFileID = SourceMgr.getFileID(MDLoc);
if (PCHPredefinesFileID.isInvalid())
PCHPredefinesFileID = MDFileID;
More information about the cfe-commits
mailing list