Author: Qiongsi Wu
Date: 2026-03-04T08:26:50-08:00
New Revision: 668d09b2846d9794b35daa2744bf6d4c66c5ec42

URL: 
https://github.com/llvm/llvm-project/commit/668d09b2846d9794b35daa2744bf6d4c66c5ec42
DIFF: 
https://github.com/llvm/llvm-project/commit/668d09b2846d9794b35daa2744bf6d4c66c5ec42.diff

LOG: [clang][Modules] Fixing unexpected warnings triggered by a PCH and a 
module with config macros  (#177078)

When a PCH is compiled with macro definitions on the command line, such
as `-DCONFIG1`, an unexpected warning can occur if the macro definitions
happen to belong to an imported module's config macros. The warning may
look like the following:
```
definition of configuration macro 'CONFIG1' has no effect on the import of 
'Mod1'; pass '-DCONFIG1=...' on the command line to configure the module
```
while `-DCONFIG1` is clearly on the command line when `clang` compiles
the source that uses the PCH and the module.

The reason this can happen is a combination of two things:
1. The logic that checks for config macros is not aware of any command
line macros passed through the PCH

([here](https://github.com/llvm/llvm-project/blob/7976ac990000a58a7474269a3ca95e16aed8c35b/clang/lib/Frontend/CompilerInstance.cpp#L1562)).
2. `clang` _replaces_ the predefined macros on the command line with the
predefined macros from the PCH, which does not include any builtins
([here](https://github.com/llvm/llvm-project/blob/7976ac990000a58a7474269a3ca95e16aed8c35b/clang/lib/Frontend/CompilerInstance.cpp#L679)).

This PR teaches the preprocessor to recognize the command line macro
definitions passed transitively through the PCH, so that the error check
does not miss these definitions by mistake. The config macro itself
works fine, and it is only the error check that needs fixing.

rdar://95261458

Added: 
    clang/test/Modules/Inputs/pch-config-macros/include/Mod1.h
    clang/test/Modules/Inputs/pch-config-macros/include/module.modulemap
    clang/test/Modules/pch-config-macros.c

Modified: 
    clang/lib/Frontend/CompilerInstance.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Frontend/CompilerInstance.cpp 
b/clang/lib/Frontend/CompilerInstance.cpp
index 135923058bc55..dd774f7319bb2 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -1578,9 +1578,14 @@ static void checkConfigMacro(Preprocessor &PP, StringRef 
ConfigMacro,
   // Find the macro definition from the command line.
   MacroInfo *CmdLineDefinition = nullptr;
   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())
+    SourceLocation MDLoc = MD->getLocation();
+    FileID FID = SourceMgr.getFileID(MDLoc);
+    if (FID.isInvalid())
+      continue;
+    // We only care about the predefines buffer, or if the macro is defined
+    // over the command line transitively through a PCH.
+    if (FID != PP.getPredefinesFileID() &&
+        !SourceMgr.isWrittenInCommandLineFile(MDLoc))
       continue;
     if (auto *DMD = dyn_cast<DefMacroDirective>(MD))
       CmdLineDefinition = DMD->getMacroInfo();
@@ -1602,7 +1607,7 @@ static void checkConfigMacro(Preprocessor &PP, StringRef 
ConfigMacro,
       << true;
     return;
   } else if (!CmdLineDefinition) {
-    // There was no definition for this macro in the predefines buffer,
+    // There was no definition for this macro in the command line,
     // but there was a local definition. Complain.
     PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
       << false << ConfigMacro << Mod->getFullModuleName();

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..3018629d31d25
--- /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,CONFIG3
+}

diff  --git a/clang/test/Modules/pch-config-macros.c 
b/clang/test/Modules/pch-config-macros.c
new file mode 100644
index 0000000000000..348d079d34dad
--- /dev/null
+++ b/clang/test/Modules/pch-config-macros.c
@@ -0,0 +1,93 @@
+// 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.
+// The warnings should not fire if the config macros are specified when
+// building the pch and the main TU.
+// 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:   %t/h1.h -emit-pch -o %t/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 %t/h1.h.pch %t/bridging.h -emit-pch -o 
%t/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 %t/main.o %t/main.c -include-pch %t/bridging.h.pch \
+// RUN:   -DCONFIG1 -DCONFIG2 -verify
+
+// Checking that the warnings fire correctly when we compile with a chain of
+// PCHs.
+// 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 %t/compile_warning_1.o %t/compile_warning_1.c 
-include-pch \
+// RUN:    %t/bridging.h.pch -DCONFIG1 -DCONFIG2 -verify
+// 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 %t/compile_warning_2.o %t/compile_warning_2.c 
-include-pch \
+// RUN:    %t/bridging.h.pch -DCONFIG1 -DCONFIG2 -verify
+// 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 %t/compile_warning_3.o %t/compile_warning_3.c 
-include-pch \
+// RUN:    %t/bridging.h.pch -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(); 
+}
+
+// Checks against expected warnings.
+//--- compile_warning_1.c
+#undef CONFIG1 // expected-note{{macro was #undef'd here}}
+#include "Mod1.h" // expected-warning{{#undef of configuration macro 'CONFIG1' 
has no effect on the import of 'Mod1'; pass '-UCONFIG1' on the command line to 
configure the module}}
+
+int main_func() {
+    return foo() + bar();
+}
+
+//--- compile_warning_2.c
+#define CONFIG3  // expected-note{{macro was defined here}}
+#include "Mod1.h" // expected-warning{{definition of configuration macro 
'CONFIG3' has no effect on the import of 'Mod1'; pass '-DCONFIG3=...' on the 
command line to configure the module}}
+
+int main_func() {
+    return foo() + bar();
+}
+
+//--- compile_warning_3.c
+#define CONFIG1 2 // expected-warning{{'CONFIG1' macro redefined}} 
expected-note{{previous definition is here}} expected-note{{macro was defined 
here}}
+#include "Mod1.h" // expected-warning{{definition of configuration macro 
'CONFIG1' has no effect on the import of 'Mod1'; pass '-DCONFIG1=...' on the 
command line to configure the module}}
+
+int main_func() {
+    return foo() + bar();
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to