https://github.com/yronglin updated 
https://github.com/llvm/llvm-project/pull/192073

>From d5c3cd1f77a34e6b0b281d2a40f23a16dc760457 Mon Sep 17 00:00:00 2001
From: yronglin <[email protected]>
Date: Tue, 14 Apr 2026 22:44:09 +0800
Subject: [PATCH 1/3] [NFC][Clang] Add test for P2843R3 - Preprocessing is
 never undefined

Signed-off-by: yronglin <[email protected]>
---
 clang/docs/ReleaseNotes.rst         |  4 ++++
 clang/test/Preprocessor/p2843r3.cpp | 35 +++++++++++++++++++++++++++++
 clang/www/cxx_status.html           |  2 +-
 3 files changed, 40 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/Preprocessor/p2843r3.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3e2d287d1eb1f..859b7e999848a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -133,6 +133,10 @@ C++ Language Changes
 C++2c Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
+- Implemented `P2843R3 <https://wg21.link/P2843R3>`_ Preprocessing is never 
undefined.
+  The constructs it makes ill-formed were already diagnosed by Clang under
+  ``-pedantic``; no behavior change, just conformance.
+
 C++23 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/test/Preprocessor/p2843r3.cpp 
b/clang/test/Preprocessor/p2843r3.cpp
new file mode 100644
index 0000000000000..53c272390527c
--- /dev/null
+++ b/clang/test/Preprocessor/p2843r3.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c++26 -pedantic -verify -Wno-invalid-pp-token %s
+// RUN: %clang_cc1 -std=c++23 -pedantic -verify -Wno-invalid-pp-token %s
+
+// P2843R3: Preprocessing is never undefined.
+// These constructs were previously "undefined behavior" in the preprocessor;
+// as of C++26 they are ill-formed (diagnostic required). Clang already
+// diagnoses them under -pedantic, so this test just pins that behavior down.
+
+// [cpp.cond] A macro that expands to 'defined' in a conditional expression.
+#define DEFINED defined
+#if DEFINED(bar) // expected-warning {{macro expansion producing 'defined' has 
undefined behavior}}
+#endif
+
+// [cpp.replace.general] A preprocessing directive inside the arguments of a
+// function-like macro invocation.
+#define FUNCTION_MACRO(...)
+FUNCTION_MACRO(
+    #if 0 // expected-warning {{embedding a directive within macro arguments 
has undefined behavior}}
+    #endif
+)
+
+// [cpp.concat] Concatenation that does not form a valid preprocessing token.
+#define CONCAT(A, B) A ## B
+CONCAT(=, >) // expected-error {{pasting formed '=>', an invalid preprocessing 
token}}
+// expected-error@-1 {{expected unqualified-id}}
+
+// [cpp.predefined] #undef of a reserved identifier / builtin macro.
+#undef defined  // expected-error {{'defined' cannot be used as a macro name}}
+#undef __DATE__ // expected-warning {{undefining builtin macro}}
+
+// [cpp.line] #line with a non-positive or out-of-range argument.
+#line 0          // expected-warning {{#line directive with zero argument is a 
GNU extension}}
+#line -1         // expected-error {{#line directive requires a positive 
integer argument}}
+#line 2147483647 // ok, largest value required to be accepted
+#line 2147483648 // expected-warning {{C requires #line number to be less than 
2147483648, allowed as extension}}
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 2c834b07f9a8f..4a669ff4da8a1 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -330,7 +330,7 @@ <h2 id="cxx26">C++2c implementation status</h2>
  <tr>
    <td>Preprocessing is never undefined</td>
    <td><a href="https://wg21.link/P2843";>P2843R3</a></td>
-   <td class="none" align="center">No</td>
+   <td class="full" align="center">Clang 23</td>
  </tr>
  <!-- Kona, Fall 2025-->
  <tr>

>From 3cf297853d16cb4215fb1b98468b4537c0c98406 Mon Sep 17 00:00:00 2001
From: yronglin <[email protected]>
Date: Tue, 14 Apr 2026 23:00:19 +0800
Subject: [PATCH 2/3] Update ReleaseNotes

Signed-off-by: yronglin <[email protected]>
---
 clang/docs/ReleaseNotes.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 859b7e999848a..8d69c4716620b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -133,7 +133,7 @@ C++ Language Changes
 C++2c Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
-- Implemented `P2843R3 <https://wg21.link/P2843R3>`_ Preprocessing is never 
undefined.
+- Mark `P2843R3 <https://wg21.link/P2843R3>`_ Preprocessing is never undefined 
as implemented.
   The constructs it makes ill-formed were already diagnosed by Clang under
   ``-pedantic``; no behavior change, just conformance.
 

>From f374e17bf507f7786d3268c5fcdbb46a94d47894 Mon Sep 17 00:00:00 2001
From: yronglin <[email protected]>
Date: Wed, 15 Apr 2026 00:32:18 +0800
Subject: [PATCH 3/3] Convert ext_embedded_directive to hard error and add more
 test

Signed-off-by: yronglin <[email protected]>
---
 .../include/clang/Basic/DiagnosticLexKinds.td |  2 +
 clang/lib/Lex/PPDirectives.cpp                | 42 +++++++++++++------
 clang/lib/Lex/PPExpressions.cpp               |  4 +-
 clang/test/Lexer/cxx-features.cpp             | 20 +++++----
 clang/test/Preprocessor/p2843r3.cpp           | 36 +++++++++++-----
 5 files changed, 72 insertions(+), 32 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 30efb0d90c124..2d80538efb932 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -1053,6 +1053,8 @@ def warn_defined_in_object_type_macro : Warning<
 def warn_defined_in_function_type_macro : Extension<
   "macro expansion producing 'defined' has undefined behavior">,
   InGroup<ExpansionToDefined>;
+def err_defined_in_macro : Error<
+  "macro expansion producing 'defined' is not allowed">;
 
 let CategoryName = "Nullability Issue" in {
 
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index be2878076510d..be68a61db4051 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -1351,8 +1351,14 @@ void Preprocessor::HandleDirective(Token &Result) {
   // not support this for #include-like directives, since that can result in
   // terrible diagnostics, and does not work in GCC.
   if (InMacroArgs) {
-    if (IdentifierInfo *II = Result.getIdentifierInfo()) {
-      switch (II->getPPKeywordID()) {
+    IdentifierInfo *II = Result.getIdentifierInfo();
+
+    // Certain #include-like and module-related directives never work inside
+    // a macro argument list: supporting them would produce terrible
+    // diagnostics and is already incompatible with GCC. They are always an
+    // error regardless of language mode.
+    auto IsAlwaysUnsupported = [](tok::PPKeywordKind K) {
+      switch (K) {
       case tok::pp_include:
       case tok::pp_import:
       case tok::pp_include_next:
@@ -1362,20 +1368,30 @@ void Preprocessor::HandleDirective(Token &Result) {
       case tok::pp_module:
       case tok::pp___preprocessed_module:
       case tok::pp___preprocessed_import:
-        Diag(Result, diag::err_embedded_directive)
-            << (getLangOpts().CPlusPlusModules &&
-                Introducer.isModuleContextualKeyword(
-                    /*AllowExport=*/false))
-            << II->getName();
-        Diag(*ArgMacro, diag::note_macro_expansion_here)
-            << ArgMacro->getIdentifierInfo();
-        DiscardUntilEndOfDirective();
-        return;
+        return true;
       default:
-        break;
+        return false;
       }
+    };
+
+    // [cpp.replace.general] makes any embedded directive ill-formed in
+    // C++26; in earlier modes the construct is undefined behavior and only
+    // pedantically warned about.
+    const bool IsError = LangOpts.CPlusPlus26 ||
+                         (II && IsAlwaysUnsupported(II->getPPKeywordID()));
+
+    if (!IsError) {
+      Diag(Result, diag::ext_embedded_directive);
+    } else {
+      Diag(Result, diag::err_embedded_directive)
+          << (LangOpts.CPlusPlusModules &&
+              Introducer.isModuleContextualKeyword(/*AllowExport=*/false))
+          << (II ? II->getName() : StringRef());
+      Diag(*ArgMacro, diag::note_macro_expansion_here)
+          << ArgMacro->getIdentifierInfo();
+      DiscardUntilEndOfDirective();
+      return;
     }
-    Diag(Result, diag::ext_embedded_directive);
   }
 
   // Temporarily enable macro expansion if set so
diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp
index 887fd25ac318d..46eb66a2eac7e 100644
--- a/clang/lib/Lex/PPExpressions.cpp
+++ b/clang/lib/Lex/PPExpressions.cpp
@@ -204,7 +204,9 @@ static bool EvaluateDefined(PPValue &Result, Token 
&PeekTok, DefinedTracker &DT,
     // in a different way, and compilers seem to agree on how to behave here.
     // So warn by default on object-type macros, but only warn in -pedantic
     // mode on function-type macros.
-    if (IsFunctionTypeMacro)
+    if (PP.getLangOpts().CPlusPlus26)
+      PP.Diag(beginLoc, diag::err_defined_in_macro);
+    else if (IsFunctionTypeMacro)
       PP.Diag(beginLoc, diag::warn_defined_in_function_type_macro);
     else
       PP.Diag(beginLoc, diag::warn_defined_in_object_type_macro);
diff --git a/clang/test/Lexer/cxx-features.cpp 
b/clang/test/Lexer/cxx-features.cpp
index 8eb9ea032879c..446bb0ac76056 100644
--- a/clang/test/Lexer/cxx-features.cpp
+++ b/clang/test/Lexer/cxx-features.cpp
@@ -14,21 +14,25 @@
 
 // expected-no-diagnostics
 
-// FIXME using `defined` in a macro has undefined behavior.
+// An undefined feature-test macro evaluates to 0 in an #if expression, so
+// `__cpp_##macro != N` tests the feature is defined with the exact value N
+// when N is nonzero, and tests the feature is not defined (or is defined to 0,
+// which feature-test macros never are) when N is 0. Avoiding `defined` inside
+// a macro expansion is required for conformance with [cpp.cond].
 #if __cplusplus < 201103L
-#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx98 
== 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx98)
+#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) 
(__cpp_##macro != cxx98)
 #elif __cplusplus < 201402L
-#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx11 
== 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx11)
+#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) 
(__cpp_##macro != cxx11)
 #elif __cplusplus < 201703L
-#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx14 
== 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx14)
+#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) 
(__cpp_##macro != cxx14)
 #elif __cplusplus < 202002L
-#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx17 
== 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx17)
+#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) 
(__cpp_##macro != cxx17)
 #elif __cplusplus < 202302L
-#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx20 
== 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx20)
+#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) 
(__cpp_##macro != cxx20)
 #elif __cplusplus == 202302L
-#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx23 
== 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx23)
+#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) 
(__cpp_##macro != cxx23)
 #else
-#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) (cxx26 
== 0 ? defined(__cpp_##macro) : __cpp_##macro != cxx26)
+#define check(macro, cxx98, cxx11, cxx14, cxx17, cxx20, cxx23, cxx26) 
(__cpp_##macro != cxx26)
 #endif
 
 // --- C++26 features ---
diff --git a/clang/test/Preprocessor/p2843r3.cpp 
b/clang/test/Preprocessor/p2843r3.cpp
index 53c272390527c..747fe59e25e45 100644
--- a/clang/test/Preprocessor/p2843r3.cpp
+++ b/clang/test/Preprocessor/p2843r3.cpp
@@ -1,21 +1,37 @@
-// RUN: %clang_cc1 -std=c++26 -pedantic -verify -Wno-invalid-pp-token %s
-// RUN: %clang_cc1 -std=c++23 -pedantic -verify -Wno-invalid-pp-token %s
+// RUN: %clang_cc1 -std=c++26 -pedantic -verify=cxx26,expected 
-Wno-invalid-pp-token %s
+// RUN: %clang_cc1 -std=c++23 -pedantic -verify=cxx23,expected 
-Wno-invalid-pp-token %s
 
-// P2843R3: Preprocessing is never undefined.
-// These constructs were previously "undefined behavior" in the preprocessor;
-// as of C++26 they are ill-formed (diagnostic required). Clang already
-// diagnoses them under -pedantic, so this test just pins that behavior down.
+// P2843R3: Preprocessing is never undefined. The constructs this paper makes
+// ill-formed were previously undefined behavior; under C++26 Clang now
+// diagnoses them as errors, while retaining the pre-existing pedantic warning
+// in earlier language modes for compatibility.
 
-// [cpp.cond] A macro that expands to 'defined' in a conditional expression.
+// [cpp.cond] A macro expansion that produces 'defined' in a conditional
+// expression. P2843R3 makes this ill-formed; promoted to a hard error in
+// C++26.
 #define DEFINED defined
-#if DEFINED(bar) // expected-warning {{macro expansion producing 'defined' has 
undefined behavior}}
+// cxx26-error@+2 {{macro expansion producing 'defined' is not allowed}}
+// cxx23-warning@+1 {{macro expansion producing 'defined' has undefined 
behavior}}
+#if DEFINED(bar)
+#endif
+
+// Malformed 'defined' operands are ill-formed in all modes.
+#if defined()      // expected-error {{macro name must be an identifier}}
+#endif
+#if defined(a b)   // expected-error {{missing ')' after 'defined'}} 
expected-note {{to match this '('}}
+#endif
+#if defined(a, b)  // expected-error {{missing ')' after 'defined'}} 
expected-note {{to match this '('}}
 #endif
 
 // [cpp.replace.general] A preprocessing directive inside the arguments of a
-// function-like macro invocation.
+// function-like macro invocation. Promoted to a hard error in C++26.
 #define FUNCTION_MACRO(...)
+// cxx26-note@+1 2 {{expansion of macro 'FUNCTION_MACRO' requested here}}
 FUNCTION_MACRO(
-    #if 0 // expected-warning {{embedding a directive within macro arguments 
has undefined behavior}}
+    // cxx26-error@+2 {{embedding a #if directive within macro arguments is 
not supported}}
+    // cxx23-warning@+1 {{embedding a directive within macro arguments has 
undefined behavior}}
+    #if 0
+    // cxx26-error@+1 {{embedding a #endif directive within macro arguments is 
not supported}}
     #endif
 )
 

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

Reply via email to