https://github.com/jthackray updated 
https://github.com/llvm/llvm-project/pull/202919

>From d988b381e3461880d5b3b62b524d0de3aea75291 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <[email protected]>
Date: Wed, 10 Jun 2026 11:31:05 +0100
Subject: [PATCH 1/2] [clang][Driver] Include stdc-predef.h by default on musl

Match GCC behavior for musl-based Linux targets by implicitly passing
`-include stdc-predef.h` for non-freestanding compilations.

Unlike glibc, musl does not arrange for this header to be included through
its normal system headers. As a result, Clang may miss predefined C macros
provided by musl's stdc-predef.h unless users include it manually, while the
same code works with GCC.

Add Driver tests covering musl, non-musl, freestanding, preprocessed input,
missing-header diagnostics, and actual macro visibility.

This patch is based on: https://reviews.llvm.org/D137043 and
slightly tweaks it, as the code has drifted since 2023 when
that was authored.

Co-authored-by: Tao Liang <[email protected]>
Co-authored-by: YingChi Long <[email protected]>
---
 clang/docs/ReleaseNotes.rst                   |  3 +
 clang/lib/Driver/ToolChains/Linux.cpp         |  9 ++
 .../Driver/Inputs/stdc-predef/preprocessed.i  |  1 +
 .../stdc-predef/usr/include/stdc-predef.h     |  4 +
 clang/test/Driver/stdc-predef.c               | 95 +++++++++++++++++++
 5 files changed, 112 insertions(+)
 create mode 100644 clang/test/Driver/Inputs/stdc-predef/preprocessed.i
 create mode 100644 
clang/test/Driver/Inputs/stdc-predef/usr/include/stdc-predef.h
 create mode 100644 clang/test/Driver/stdc-predef.c

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7828135a6edbc..f28f0bea048e5 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -334,6 +334,9 @@ Non-comprehensive list of changes in this release
   and ``__builtin___get_unsafe_stack_start`` are now deprecated. Use the
   corresponding functions from ``<sanitizer/safestack_interface.h>`` instead.
 
+- Clang now implicitly includes ``stdc-predef.h`` for non-freestanding
+  compilations targeting musl-based Linux systems, matching GCC behavior.
+
 New Compiler Flags
 ------------------
 - New option ``-fms-anonymous-structs`` / ``-fno-ms-anonymous-structs`` added
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp 
b/clang/lib/Driver/ToolChains/Linux.cpp
index 512788d235fec..6709638fc7c28 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -825,6 +825,15 @@ void Linux::AddClangSystemIncludeArgs(const ArgList 
&DriverArgs,
 
   if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && getTriple().isMusl())
     addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
+
+  // For GCC compatibility, add an implicit include for musl-based
+  // non-freestanding systems.
+  if (getTriple().isMusl() &&
+      !DriverArgs.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted,
+                          false)) {
+    CC1Args.push_back("-include");
+    CC1Args.push_back("stdc-predef.h");
+  }
 }
 
 void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
diff --git a/clang/test/Driver/Inputs/stdc-predef/preprocessed.i 
b/clang/test/Driver/Inputs/stdc-predef/preprocessed.i
new file mode 100644
index 0000000000000..048f715b4656f
--- /dev/null
+++ b/clang/test/Driver/Inputs/stdc-predef/preprocessed.i
@@ -0,0 +1 @@
+int i;
diff --git a/clang/test/Driver/Inputs/stdc-predef/usr/include/stdc-predef.h 
b/clang/test/Driver/Inputs/stdc-predef/usr/include/stdc-predef.h
new file mode 100644
index 0000000000000..0a8bef6e196ea
--- /dev/null
+++ b/clang/test/Driver/Inputs/stdc-predef/usr/include/stdc-predef.h
@@ -0,0 +1,4 @@
+#ifndef _STDC_PREDEF_H
+#define _STDC_PREDEF_H 1
+#define DUMMY_STDC_PREDEF 1
+#endif
diff --git a/clang/test/Driver/stdc-predef.c b/clang/test/Driver/stdc-predef.c
new file mode 100644
index 0000000000000..fd8d526eb817e
--- /dev/null
+++ b/clang/test/Driver/stdc-predef.c
@@ -0,0 +1,95 @@
+// Test that clang preincludes stdc-predef.h if we are using a libc that does
+// not pre-include it, e.g. musl.
+
+// Musl-based systems need this additional include.
+//
+// RUN: %clang %s -### -c 2>&1 \
+// RUN: -target x86_64-unknown-linux-musl \
+// RUN: --sysroot=%S/Inputs/stdc-predef \
+// RUN: | FileCheck -check-prefix CHECK-CPP-FLAG %s
+
+// GNU-based systems do not need this additional include.
+//
+// RUN: %clang %s -### -c 2>&1 \
+// RUN: -target x86_64-unknown-linux-gnu \
+// RUN: --sysroot=%S/Inputs/stdc-predef \
+// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+
+// Freestanding compilations do not need this additional include.
+//
+// RUN: %clang %s -### -c 2>&1 \
+// RUN: -target x86_64-unknown-linux-musl -ffreestanding \
+// RUN: --sysroot=%S/Inputs/stdc-predef \
+// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+
+// The last of -ffreestanding and -fhosted determines whether this additional
+// include is needed.
+//
+// RUN: %clang %s -### -c 2>&1 \
+// RUN: -target x86_64-unknown-linux-musl -ffreestanding -fhosted \
+// RUN: --sysroot=%S/Inputs/stdc-predef \
+// RUN: | FileCheck -check-prefix CHECK-CPP-FLAG %s
+//
+// RUN: %clang %s -### -c 2>&1 \
+// RUN: -target x86_64-unknown-linux-musl -fhosted -ffreestanding \
+// RUN: --sysroot=%S/Inputs/stdc-predef \
+// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+
+// Disabling standard include directories also disables this additional 
include.
+//
+// RUN: %clang %s -### -c 2>&1 \
+// RUN: -target x86_64-unknown-linux-musl -nostdinc \
+// RUN: --sysroot=%S/Inputs/stdc-predef \
+// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+//
+// RUN: %clang %s -### -c 2>&1 \
+// RUN: -target x86_64-unknown-linux-musl -nostdlibinc \
+// RUN: --sysroot=%S/Inputs/stdc-predef \
+// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+
+// Because this behavior is implemented by adding preprocessor flags in the
+// driver, disabling preprocessing means the include flag should not appear.
+//
+// RUN: %clang -x cpp-output %s -### -c 2>&1 \
+// RUN: -target x86_64-unknown-linux-musl \
+// RUN: --sysroot=%S/Inputs/stdc-predef \
+// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+
+// The automatic preinclude of stdc-predef.h should not occur if
+// the source filename indicates a preprocessed file.
+//
+// RUN: %clang %S/Inputs/stdc-predef/preprocessed.i -### -c 2>&1 \
+// RUN: --sysroot=%S/Inputs/stdc-predef \
+// RUN: -target x86_64-unknown-linux-musl \
+// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+
+// This behavior should appear in all files clang accepts that use the C
+// preprocessor, including C, C++ and Objective-C files, as long as the system
+// uses musl.
+//
+// RUN: %clang -x objective-c %s -### -c 2>&1 \
+// RUN: -target x86_64-unknown-linux-musl \
+// RUN: --sysroot=%S/Inputs/stdc-predef \
+// RUN: | FileCheck -check-prefix CHECK-CPP-FLAG %s
+
+// If a musl-based system does not have this header, give an error at line 1.
+//
+// RUN: %clang %s -c -Xclang -verify=expected 2>&1 \
+// RUN: -target x86_64-unknown-linux-musl \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree
+// expected-error@1 {{'stdc-predef.h' file not found}}
+
+// Check if the file is really included by macro.
+//
+// RUN: %clang %s -c -Xclang -verify=ok -DCHECK_DUMMY=1 \
+// RUN: -target x86_64-unknown-linux-musl \
+// RUN: --sysroot=%S/Inputs/stdc-predef
+// ok-no-diagnostics
+
+// CHECK-CPP-FLAG: "-include" "stdc-predef.h"
+int i;
+#if CHECK_DUMMY
+#if !DUMMY_STDC_PREDEF
+#error "Expected macro symbol DUMMY_STDC_PREDEF is not defined."
+#endif
+#endif

>From 2fd832d0115539f7e31b4a7779b0bfbe52b45c00 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <[email protected]>
Date: Tue, 16 Jun 2026 10:52:43 +0100
Subject: [PATCH 2/2] fixup! Address PR comments

---
 clang/docs/ReleaseNotes.rst           |   3 +-
 clang/lib/Driver/ToolChains/Linux.cpp |  15 +++-
 clang/test/Driver/stdc-predef.c       | 106 +++++++++++---------------
 3 files changed, 57 insertions(+), 67 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f28f0bea048e5..2136cda29d3ca 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -335,7 +335,8 @@ Non-comprehensive list of changes in this release
   corresponding functions from ``<sanitizer/safestack_interface.h>`` instead.
 
 - Clang now implicitly includes ``stdc-predef.h`` for non-freestanding
-  compilations targeting musl-based Linux systems, matching GCC behavior.
+  compilations targeting musl Linux systems, and for glibc Linux sysroots
+  that provide the header, matching GCC behavior.
 
 New Compiler Flags
 ------------------
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp 
b/clang/lib/Driver/ToolChains/Linux.cpp
index 6709638fc7c28..38b8f8a943ad7 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -826,11 +826,18 @@ void Linux::AddClangSystemIncludeArgs(const ArgList 
&DriverArgs,
   if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && getTriple().isMusl())
     addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
 
-  // For GCC compatibility, add an implicit include for musl-based
-  // non-freestanding systems.
-  if (getTriple().isMusl() &&
+  // For GCC compatibility, add an implicit include for musl-based or
+  // non-freestanding GNU systems where the target libc provides stdc-predef.h.
+  bool HasGlibcStdcPredef =
+      getTriple().isGNUEnvironment() && !SysRoot.empty() &&
+      D.getVFS().exists(concat(SysRoot, "/usr/include/stdc-predef.h"));
+
+  bool ShouldPreincludeStdcPredef =
+      (getTriple().isMusl() || HasGlibcStdcPredef) &&
       !DriverArgs.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted,
-                          false)) {
+                          false);
+
+  if (ShouldPreincludeStdcPredef) {
     CC1Args.push_back("-include");
     CC1Args.push_back("stdc-predef.h");
   }
diff --git a/clang/test/Driver/stdc-predef.c b/clang/test/Driver/stdc-predef.c
index fd8d526eb817e..f1f116393cd7d 100644
--- a/clang/test/Driver/stdc-predef.c
+++ b/clang/test/Driver/stdc-predef.c
@@ -1,89 +1,71 @@
-// Test that clang preincludes stdc-predef.h if we are using a libc that does
-// not pre-include it, e.g. musl.
+// Test that clang preincludes stdc-predef.h for musl Linux targets and
+// glibc Linux sysroots that provide the header.
 
 // Musl-based systems need this additional include.
-//
-// RUN: %clang %s -### -c 2>&1 \
-// RUN: -target x86_64-unknown-linux-musl \
-// RUN: --sysroot=%S/Inputs/stdc-predef \
-// RUN: | FileCheck -check-prefix CHECK-CPP-FLAG %s
+// RUN: %clang %s -### -c --target=x86_64-unknown-linux-musl \
+// RUN:   --sysroot=%S/Inputs/stdc-predef 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-CPP-FLAG %s
 
-// GNU-based systems do not need this additional include.
-//
-// RUN: %clang %s -### -c 2>&1 \
-// RUN: -target x86_64-unknown-linux-gnu \
-// RUN: --sysroot=%S/Inputs/stdc-predef \
-// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+// GNU-based sysroots with stdc-predef.h also need this additional include.
+// RUN: %clang %s -### -c --target=x86_64-unknown-linux-gnu \
+// RUN:   --sysroot=%S/Inputs/stdc-predef 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-CPP-FLAG %s
+
+// GNU-based sysroots without stdc-predef.h should not inject a host header.
+// RUN: %clang %s -### -c --target=x86_64-unknown-linux-gnu \
+// RUN:   --sysroot=%S/Inputs/basic_linux_tree 2>&1 \
+// RUN:   | FileCheck --implicit-check-not "stdc-predef.h" %s
 
 // Freestanding compilations do not need this additional include.
-//
-// RUN: %clang %s -### -c 2>&1 \
-// RUN: -target x86_64-unknown-linux-musl -ffreestanding \
-// RUN: --sysroot=%S/Inputs/stdc-predef \
-// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+// RUN: %clang %s -### -c --target=x86_64-unknown-linux-musl -ffreestanding \
+// RUN:   --sysroot=%S/Inputs/stdc-predef 2>&1 \
+// RUN:   | FileCheck --implicit-check-not "stdc-predef.h" %s
 
 // The last of -ffreestanding and -fhosted determines whether this additional
 // include is needed.
-//
-// RUN: %clang %s -### -c 2>&1 \
-// RUN: -target x86_64-unknown-linux-musl -ffreestanding -fhosted \
-// RUN: --sysroot=%S/Inputs/stdc-predef \
-// RUN: | FileCheck -check-prefix CHECK-CPP-FLAG %s
-//
-// RUN: %clang %s -### -c 2>&1 \
-// RUN: -target x86_64-unknown-linux-musl -fhosted -ffreestanding \
-// RUN: --sysroot=%S/Inputs/stdc-predef \
-// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+// RUN: %clang %s -### -c --target=x86_64-unknown-linux-musl \
+// RUN:   -ffreestanding -fhosted --sysroot=%S/Inputs/stdc-predef 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-CPP-FLAG %s
+// RUN: %clang %s -### -c --target=x86_64-unknown-linux-musl \
+// RUN:   -fhosted -ffreestanding --sysroot=%S/Inputs/stdc-predef 2>&1 \
+// RUN:   | FileCheck --implicit-check-not "stdc-predef.h" %s
 
 // Disabling standard include directories also disables this additional 
include.
-//
-// RUN: %clang %s -### -c 2>&1 \
-// RUN: -target x86_64-unknown-linux-musl -nostdinc \
-// RUN: --sysroot=%S/Inputs/stdc-predef \
-// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
-//
-// RUN: %clang %s -### -c 2>&1 \
-// RUN: -target x86_64-unknown-linux-musl -nostdlibinc \
-// RUN: --sysroot=%S/Inputs/stdc-predef \
-// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+// RUN: %clang %s -### -c --target=x86_64-unknown-linux-musl -nostdinc \
+// RUN:   --sysroot=%S/Inputs/stdc-predef 2>&1 \
+// RUN:   | FileCheck --implicit-check-not "stdc-predef.h" %s
+// RUN: %clang %s -### -c --target=x86_64-unknown-linux-musl -nostdlibinc \
+// RUN:   --sysroot=%S/Inputs/stdc-predef 2>&1 \
+// RUN:   | FileCheck --implicit-check-not "stdc-predef.h" %s
 
 // Because this behavior is implemented by adding preprocessor flags in the
 // driver, disabling preprocessing means the include flag should not appear.
-//
-// RUN: %clang -x cpp-output %s -### -c 2>&1 \
-// RUN: -target x86_64-unknown-linux-musl \
-// RUN: --sysroot=%S/Inputs/stdc-predef \
-// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+// RUN: %clang -x cpp-output %s -### -c --target=x86_64-unknown-linux-musl \
+// RUN:   --sysroot=%S/Inputs/stdc-predef 2>&1 \
+// RUN:   | FileCheck --implicit-check-not "stdc-predef.h" %s
 
 // The automatic preinclude of stdc-predef.h should not occur if
 // the source filename indicates a preprocessed file.
-//
-// RUN: %clang %S/Inputs/stdc-predef/preprocessed.i -### -c 2>&1 \
-// RUN: --sysroot=%S/Inputs/stdc-predef \
-// RUN: -target x86_64-unknown-linux-musl \
-// RUN: | FileCheck --implicit-check-not "stdc-predef.h" %s
+// RUN: %clang %S/Inputs/stdc-predef/preprocessed.i -### -c \
+// RUN:   --target=x86_64-unknown-linux-musl --sysroot=%S/Inputs/stdc-predef 
2>&1 \
+// RUN:   | FileCheck --implicit-check-not "stdc-predef.h" %s
 
 // This behavior should appear in all files clang accepts that use the C
 // preprocessor, including C, C++ and Objective-C files, as long as the system
-// uses musl.
-//
-// RUN: %clang -x objective-c %s -### -c 2>&1 \
-// RUN: -target x86_64-unknown-linux-musl \
-// RUN: --sysroot=%S/Inputs/stdc-predef \
-// RUN: | FileCheck -check-prefix CHECK-CPP-FLAG %s
+// uses musl or a glibc sysroot that provides the header.
+// RUN: %clang -x objective-c %s -### -c \
+// RUN:   --target=x86_64-unknown-linux-musl --sysroot=%S/Inputs/stdc-predef 
2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-CPP-FLAG %s
 
-// If a musl-based system does not have this header, give an error at line 1.
-//
-// RUN: %clang %s -c -Xclang -verify=expected 2>&1 \
-// RUN: -target x86_64-unknown-linux-musl \
-// RUN: --sysroot=%S/Inputs/basic_linux_tree
+// If a target system does not have this header, give an error at line 1.
+// RUN: %clang %s -c -Xclang -verify=expected \
+// RUN:   --target=x86_64-unknown-linux-musl \
+// RUN:   --sysroot=%S/Inputs/basic_linux_tree 2>&1
 // expected-error@1 {{'stdc-predef.h' file not found}}
 
 // Check if the file is really included by macro.
-//
 // RUN: %clang %s -c -Xclang -verify=ok -DCHECK_DUMMY=1 \
-// RUN: -target x86_64-unknown-linux-musl \
-// RUN: --sysroot=%S/Inputs/stdc-predef
+// RUN:   --target=x86_64-unknown-linux-musl --sysroot=%S/Inputs/stdc-predef
 // ok-no-diagnostics
 
 // CHECK-CPP-FLAG: "-include" "stdc-predef.h"

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

Reply via email to