https://github.com/nfedotenko created 
https://github.com/llvm/llvm-project/pull/233285

`#embed` was adopted into C++26, but Clang still diagnosed it as "a Clang 
extension" in every C++ mode and did not define the feature-test macro.

- Move the `#embed` extension/compatibility diagnostics to the 
C23Compat/CXX26Compat framework: no diagnostic in C++26 mode, "#embed is a 
C++2c extension" (`-Wc++26-extensions`) in earlier C++ modes, and a 
`-Wpre-c++26-compat` compatibility warning in C++26 mode. C mode diagnostics 
are unchanged.
- Define `__cpp_pp_embed` to `202502L` in all C++ modes, like the other C++26 
features that Clang supports as extensions in earlier modes.
- Update the status page to Partial: the remaining known issues are the 
braced-list initialization bugs around multi-byte `#embed` (#222796 and 
friends), which are being fixed separately (#218262, #231938).

Part of #127610.

LLM tools were used for this contribution. I've reviewed, built, and tested the 
change myself before pushing to GitHub.

>From 1167b9bb2147dc1e353b7fd4732012ad91a3a2d0 Mon Sep 17 00:00:00 2001
From: Nikolay Fedotenko <[email protected]>
Date: Sun, 18 Oct 2026 23:38:19 +0400
Subject: [PATCH] [clang] Finalize #embed support for C++26 (P1967R14)

#embed was adopted into C++26, but Clang still diagnosed it as "a Clang
extension" in every C++ mode and did not define the feature-test macro.

- Move the #embed extension/compatibility diagnostics to the
  C23Compat/CXX26Compat framework: no diagnostic in C++26 mode,
  "#embed is a C++2c extension" (-Wc++26-extensions) in earlier C++
  modes, and a -Wpre-c++26-compat compatibility warning in C++26 mode.
  C mode diagnostics are unchanged.
- Define __cpp_pp_embed to 202502L in all C++ modes, like the other
  C++26 features that Clang supports as extensions in earlier modes.
- Update the status page to Partial: the remaining known issues are the
  braced-list initialization bugs around multi-byte #embed (#222796 and
  friends), which are being fixed separately (#218262, #231938).

Part of #127610.
---
 clang/docs/ReleaseNotes.md                       |  7 +++++++
 clang/include/clang/Basic/DiagnosticLexKinds.td  |  8 ++------
 clang/lib/Frontend/InitPreprocessor.cpp          |  1 +
 clang/lib/Lex/PPDirectives.cpp                   |  8 +++-----
 clang/test/Lexer/cxx-features.cpp                |  4 ++++
 clang/test/Preprocessor/cxx_oper_comma.cpp       |  4 ++--
 clang/test/Preprocessor/embed_constexpr.cpp      |  4 ++--
 clang/test/Preprocessor/embed_ext_compat_diags.c |  8 +++++---
 clang/test/Preprocessor/embed_feature_test.cpp   | 10 ++++++++++
 clang/test/Preprocessor/embed_weird.cpp          |  4 ++--
 clang/test/Sema/embed_compound_literal.c         |  2 +-
 clang/test/Sema/excess-embed-data.c              |  2 +-
 clang/test/SemaCXX/GH128985.cpp                  |  2 +-
 clang/test/SemaCXX/embed-init-list.cpp           |  2 +-
 clang/www/cxx_status.html                        | 10 +++++++++-
 15 files changed, 51 insertions(+), 25 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 7d6347414cc5c8..85ecc5c2722d34 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -191,6 +191,13 @@ features cannot lower the translation-unit ABI level;
 
 #### C++2c Feature Support
 
+- `#embed` ([P1967R14](https://wg21.link/P1967R14)) is no longer diagnosed as
+  an extension in C++26 mode, and the `__cpp_pp_embed` feature-test macro is
+  now defined. In earlier C++ language modes, the directive is now diagnosed
+  as a C++26 extension under `-Wc++26-extensions` (previously it was diagnosed
+  as a Clang extension under `-Wc23-extensions`), and a new
+  `-Wpre-c++26-compat` warning is available in C++26 mode.
+
 - Added `__builtin_type_order` for compatibility with GCC as part of the
   implementation of 
[P2830R10](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2830r10.html)
 (Constexpr Type Ordering).
 
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 85f4dc6eab88a5..ee3fb0e74d2209 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -14,6 +14,7 @@ let Component = "Lex", CategoryName = "Lexical or 
Preprocessor Issue" in {
 // C23 compatibility with C17 and earlier.
 defm c23_pp_directive : C23Compat<
   "use of a '#%select{<BUG IF SEEN>|elifdef|elifndef}0' directive is", 
/*ext_warn*/true>;
+defm c23_pp_embed_directive : C23Compat<"#embed is", /*ext_warn*/true>;
 
 // C++11 compatibility with C++98.
 defm empty_fnmacro_arg : CXX11Compat<
@@ -30,6 +31,7 @@ defm cxx23_pp_directive : CXX23Compat<
 // C++26 compatibility with C++23 and earlier.
 defm raw_string_literal_character_set : CXX26Compat<
   "'%0' in a raw string literal delimiter is", /*ext_warn*/false>;
+defm cxx26_pp_embed_directive : CXX26Compat<"#embed is">;
 
 def null_in_char_or_string : Warning<
   "null character(s) preserved in %select{char|string}0 literal">,
@@ -485,12 +487,6 @@ def warn_cxx23_compat_warning_directive : Warning<
 def warn_c23_compat_warning_directive : Warning<
   "#warning is incompatible with C standards before C23">,
   InGroup<CPre23Compat>, DefaultIgnore;
-def ext_pp_embed_directive : ExtWarn<
-  "#embed is a %select{C23|Clang}0 extension">,
-  InGroup<C23>;
-def warn_compat_pp_embed_directive : Warning<
-  "#embed is incompatible with C standards before C23">,
-  InGroup<CPre23Compat>, DefaultIgnore;
 def err_pp_embed_dup_params : Error<
   "cannot specify parameter '%0' twice in the same '#embed' directive">;
 def err_pp_embed_device_file : Error<
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp 
b/clang/lib/Frontend/InitPreprocessor.cpp
index 784ff9951a25ad..4f2a2a1bd28b79 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -765,6 +765,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const 
LangOptions &LangOpts,
   Builder.defineMacro("__cpp_deleted_function", "202403L");
   Builder.defineMacro("__cpp_variadic_friend", "202403L");
   Builder.defineMacro("__cpp_trivial_relocatability", "202502L");
+  Builder.defineMacro("__cpp_pp_embed", "202502L");
 
   if (LangOpts.Char8)
     Builder.defineMacro("__cpp_char8_t", "202207L");
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 3d991c411378e0..5d8adf36e755cf 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -4086,11 +4086,9 @@ void Preprocessor::HandleEmbedDirectiveImpl(
 void Preprocessor::HandleEmbedDirective(SourceLocation HashLoc,
                                         Token &EmbedTok) {
   // Give the usual extension/compatibility warnings.
-  if (LangOpts.C23)
-    Diag(EmbedTok, diag::warn_compat_pp_embed_directive);
-  else
-    Diag(EmbedTok, diag::ext_pp_embed_directive)
-        << (LangOpts.CPlusPlus ? /*Clang*/ 1 : /*C23*/ 0);
+  DiagCompat(EmbedTok, LangOpts.CPlusPlus
+                           ? diag_compat::cxx26_pp_embed_directive
+                           : diag_compat::c23_pp_embed_directive);
 
   // Parse the filename header
   Token FilenameTok;
diff --git a/clang/test/Lexer/cxx-features.cpp 
b/clang/test/Lexer/cxx-features.cpp
index b505f18dff14fe..f920ad64ba056b 100644
--- a/clang/test/Lexer/cxx-features.cpp
+++ b/clang/test/Lexer/cxx-features.cpp
@@ -54,6 +54,10 @@
 #error "wrong value for __cpp_placeholder_variables"
 #endif
 
+#if check(pp_embed, 202502, 202502, 202502, 202502, 202502, 202502, 202502)
+#error "wrong value for __cpp_pp_embed"
+#endif
+
 #if check(trivial_relocatability, 202502, 202502, 202502, 202502, 202502, 
202502, 202502)
 #error "wrong value for __cpp_trivial_relocatability"
 #endif
diff --git a/clang/test/Preprocessor/cxx_oper_comma.cpp 
b/clang/test/Preprocessor/cxx_oper_comma.cpp
index 5db803ae41f328..cef2a0d905b20d 100644
--- a/clang/test/Preprocessor/cxx_oper_comma.cpp
+++ b/clang/test/Preprocessor/cxx_oper_comma.cpp
@@ -3,8 +3,8 @@
 // RUN: %clang_cc1 -E -pedantic-errors %s -verify -std=c++14
 // RUN: %clang_cc1 -E -pedantic-errors %s -verify -std=c++17
 // RUN: %clang_cc1 -E -pedantic-errors %s -verify -std=c++20
-// RUN: %clang_cc1 -E -pedantic-errors %s -verify=expected,since-cxx23 
-std=c++23 -Wno-c23-extensions
-// RUN: %clang_cc1 -E -pedantic-errors %s -verify=expected,since-cxx23 
-std=c++2c -Wno-c23-extensions
+// RUN: %clang_cc1 -E -pedantic-errors %s -verify=expected,since-cxx23 
-std=c++23 -Wno-c++26-extensions
+// RUN: %clang_cc1 -E -pedantic-errors %s -verify=expected,since-cxx23 
-std=c++2c -Wno-c++26-extensions
 
 // Test 1: Top-level comma
 // expected-error@+1 {{expected end of line in preprocessor expression}}
diff --git a/clang/test/Preprocessor/embed_constexpr.cpp 
b/clang/test/Preprocessor/embed_constexpr.cpp
index c51c02def7dfb5..d82c194d7d5f42 100644
--- a/clang/test/Preprocessor/embed_constexpr.cpp
+++ b/clang/test/Preprocessor/embed_constexpr.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%S/Inputs -verify 
-Wno-c23-extensions
-// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%S/Inputs -verify 
-fexperimental-new-constant-interpreter -Wno-c23-extensions
+// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%S/Inputs -verify 
-Wno-c++26-extensions
+// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%S/Inputs -verify 
-fexperimental-new-constant-interpreter -Wno-c++26-extensions
 // expected-no-diagnostics
 
 constexpr int value(int a, int b) {
diff --git a/clang/test/Preprocessor/embed_ext_compat_diags.c 
b/clang/test/Preprocessor/embed_ext_compat_diags.c
index 74f24176d9ccab..4195014ea39b34 100644
--- a/clang/test/Preprocessor/embed_ext_compat_diags.c
+++ b/clang/test/Preprocessor/embed_ext_compat_diags.c
@@ -1,7 +1,9 @@
 // RUN: %clang_cc1 -std=c23 %s -fsyntax-only --embed-dir=%S/Inputs 
-verify=none -pedantic
 // RUN: %clang_cc1 -std=c23 %s -fsyntax-only --embed-dir=%S/Inputs 
-verify=compat -Wpre-c23-compat
 // RUN: %clang_cc1 -std=c17 %s -fsyntax-only --embed-dir=%S/Inputs -verify=ext 
-pedantic
-// RUN: %clang_cc1 -x c++ %s -fsyntax-only --embed-dir=%S/Inputs -verify=cxx 
-pedantic
+// RUN: %clang_cc1 -x c++ -std=c++26 %s -fsyntax-only --embed-dir=%S/Inputs 
-verify=none -pedantic
+// RUN: %clang_cc1 -x c++ -std=c++26 %s -fsyntax-only --embed-dir=%S/Inputs 
-verify=cxx-compat -Wpre-c++26-compat
+// RUN: %clang_cc1 -x c++ -std=c++23 %s -fsyntax-only --embed-dir=%S/Inputs 
-verify=cxx-ext -pedantic
 // none-no-diagnostics
 
 #if __has_embed("jk.txt")
@@ -9,8 +11,8 @@
 const char buffer[] = {
 #embed "jk.txt" /* compat-warning {{#embed is incompatible with C standards 
before C23}}
                    ext-warning {{#embed is a C23 extension}}
-                   cxx-warning {{#embed is a Clang extension}}
+                   cxx-compat-warning {{#embed is incompatible with C++ 
standards before C++2c}}
+                   cxx-ext-warning {{#embed is a C++2c extension}}
                  */
 };
 #endif
-
diff --git a/clang/test/Preprocessor/embed_feature_test.cpp 
b/clang/test/Preprocessor/embed_feature_test.cpp
index 2648804132599b..2b44586012a168 100644
--- a/clang/test/Preprocessor/embed_feature_test.cpp
+++ b/clang/test/Preprocessor/embed_feature_test.cpp
@@ -5,3 +5,13 @@
 #if !defined(__has_embed)
 #error 1
 #endif
+
+#ifdef __cplusplus
+#if __cpp_pp_embed != 202502L
+#error 2
+#endif
+#else
+#ifdef __cpp_pp_embed
+#error 3
+#endif
+#endif
diff --git a/clang/test/Preprocessor/embed_weird.cpp 
b/clang/test/Preprocessor/embed_weird.cpp
index e44aff55c59e22..fd7cc921891a9a 100644
--- a/clang/test/Preprocessor/embed_weird.cpp
+++ b/clang/test/Preprocessor/embed_weird.cpp
@@ -2,9 +2,9 @@
 // RUN: cp %S/Inputs/single_byte.txt %S/Inputs/jk.txt %S/Inputs/numbers.txt %t/
 // RUN: cp %S/Inputs/media/empty %t/media/
 // RUN: printf "\0" > %t/null_byte.bin
-// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%t -verify=expected,cxx 
-Wno-c23-extensions
+// RUN: %clang_cc1 %s -fsyntax-only --embed-dir=%t -verify=expected,cxx 
-Wno-c++26-extensions
 // RUN: %clang_cc1 -x c -std=c23 %s -fsyntax-only --embed-dir=%t 
-verify=expected,c
-// RUN: %clang_cc1 %s -fsyntax-only -fexperimental-new-constant-interpreter 
--embed-dir=%t -verify=expected,cxx -Wno-c23-extensions
+// RUN: %clang_cc1 %s -fsyntax-only -fexperimental-new-constant-interpreter 
--embed-dir=%t -verify=expected,cxx -Wno-c++26-extensions
 // RUN: %clang_cc1 -x c -std=c23 %s -fsyntax-only 
-fexperimental-new-constant-interpreter --embed-dir=%t -verify=expected,c
 #embed <media/empty>
 ;
diff --git a/clang/test/Sema/embed_compound_literal.c 
b/clang/test/Sema/embed_compound_literal.c
index 7ba6fd8e649683..895ef8869b21d0 100644
--- a/clang/test/Sema/embed_compound_literal.c
+++ b/clang/test/Sema/embed_compound_literal.c
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -std=c23 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -verify -x c++ -Wno-c23-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -x c++ -Wno-c++26-extensions %s
 // expected-no-diagnostics
 
 char *p1 = (char[]){
diff --git a/clang/test/Sema/excess-embed-data.c 
b/clang/test/Sema/excess-embed-data.c
index d5b84921abc894..7bc9c4faf3f151 100644
--- a/clang/test/Sema/excess-embed-data.c
+++ b/clang/test/Sema/excess-embed-data.c
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -std=c23 -fsyntax-only -verify=c %s
-// RUN: %clang_cc1 -fsyntax-only -verify=cpp -x c++ -Wno-c23-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify=cpp -x c++ -Wno-c++26-extensions %s
 
 
 struct S {
diff --git a/clang/test/SemaCXX/GH128985.cpp b/clang/test/SemaCXX/GH128985.cpp
index 0d51e3e53582f6..9a6d24d773f458 100644
--- a/clang/test/SemaCXX/GH128985.cpp
+++ b/clang/test/SemaCXX/GH128985.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c23-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++26-extensions %s
 
 struct S {
   int a, b;
diff --git a/clang/test/SemaCXX/embed-init-list.cpp 
b/clang/test/SemaCXX/embed-init-list.cpp
index c511ca707a537d..3e596475a2d938 100644
--- a/clang/test/SemaCXX/embed-init-list.cpp
+++ b/clang/test/SemaCXX/embed-init-list.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c23-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++26-extensions %s
 // expected-no-diagnostics
 
 namespace std {
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 3f105f831f9b76..780009948672f5 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -400,7 +400,15 @@ <h2 id="cxx26">C++2c implementation status</h2>
  <tr>
   <td><pre>#embed</pre></td>
   <td><a href="https://wg21.link/P1967";>P1967R14</a></td>
-  <td class="none" align="center">No</td>
+  <td class="partial" align="center">
+    <details>
+      <summary>Clang 24 (Partial)</summary>
+      The directive and its parameters are supported since Clang 19, and the
+      <tt>__cpp_pp_embed</tt> feature-test macro since Clang 24. A multi-byte
+      <tt>#embed</tt> in a braced initializer list that initializes a
+      non-aggregate object is not yet handled correctly in some contexts.
+    </details>
+  </td>
  </tr>
  <!-- Bulgaria, Spring 2025 -->
  <tr>

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

Reply via email to