https://github.com/ianayl updated 
https://github.com/llvm/llvm-project/pull/224769

>From fd0ec1d6dd50bdd02a1e32ba49c7146dcf8bad73 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Fri, 18 Sep 2026 15:34:24 -0700
Subject: [PATCH 1/9] Implement CWG3013 in clang, but only for C++

---
 clang/docs/ReleaseNotes.md                    | 18 ++++++
 clang/include/clang/Basic/DiagnosticGroups.td |  4 +-
 .../include/clang/Basic/DiagnosticLexKinds.td |  8 +++
 clang/include/clang/Lex/Preprocessor.h        |  4 ++
 clang/lib/Lex/PPDirectives.cpp                |  4 ++
 clang/lib/Lex/Preprocessor.cpp                | 24 ++++++++
 clang/test/CXX/drs/cwg3013.cpp                | 58 +++++++++++++++++++
 clang/test/CXX/drs/inputs/media/art.txt       | 13 +++++
 clang/test/CXX/drs/inputs/media/empty         |  0
 9 files changed, 132 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CXX/drs/cwg3013.cpp
 create mode 100644 clang/test/CXX/drs/inputs/media/art.txt
 create mode 100644 clang/test/CXX/drs/inputs/media/empty

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index f4a34a37aff52..da925b260ee1c 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -54,6 +54,13 @@ in a future version of Clang.
   mode, as it was removed from the standard by
   [P3475R2](https://wg21.link/P3475R2).
 
+- An error diagnostic is now issued if an `#embed` directive or a `__has_embed`
+  expression contains a parameter (i.e. `limit`, `prefix`, `suffix`, 
`if_empty`)
+  that has previously been defined as a macro, as per
+  [CWG3013](https://wg21.link/cwg3013). Previously macros that shared names 
with
+  `#embed` parameter names were expanded regardless, similar to its behavior in
+  C: Note that this expansion behavior is still present in C since there are no
+  rule analogue to CWG3013 in C.
 
 ### Objective-C Specific Potentially Breaking Changes
 
@@ -194,6 +201,11 @@ features cannot lower the translation-unit ABI level;
   them to an enumeration type with a fixed `bool` underlying type. This
   resolves [CWG1094](https://wg21.link/cwg1094).
 
+- Clang now diagnoses an error if an `#embed` directive or `__has_embed`
+  statement uses a parameter name (i.e. `limit`, `prefix`, `suffix`, 
`if_empty`)
+  that has previously been defined as a macro. This resolves
+  [CWG3013](https://wg21.link/cwg3013), which marks such code as ill-formed.
+
 ### C Language Changes
 
 #### C2y Feature Support
@@ -518,6 +530,12 @@ features cannot lower the translation-unit ABI level;
 
 - Improve Clang diagnoses when unary `__imag` operator with non-complex type 
operand is used as lvalue. (GH222383)
 
+- Added `-Wembed-parameter-is-macro`, which warns in C if an `#embed` directive
+  or a `__has_embed` expression uses a parameter (i.e. `limit`, `prefix`,
+  `suffix`, `if_empty`) that has also been defined as a macro. C expands the
+  macro, but the same code is ill-formed in C++, so 
`-Wembed-parameter-is-macro`
+  is also part of `-Wc++-compat`; this warning is disabled by default 
otherwise.
+
 ### Improvements to Clang's time-trace
 
 ### Improvements to Coverage Mapping
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 1da7698944b24..b3c36c76d490b 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -187,6 +187,7 @@ def C23Compat : DiagGroup<"c23-compat">;
 def : DiagGroup<"c2x-compat", [C23Compat]>;
 
 def CppKeywordInC : DiagGroup<"c++-keyword">;
+def EmbedParameterIsMacro : DiagGroup<"embed-parameter-is-macro">;
 def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">;
 def InitStringTooLongMissingNonString :
   DiagGroup<"unterminated-string-initialization">;
@@ -212,7 +213,8 @@ def CXXCompat: DiagGroup<"c++-compat", 
[ImplicitVoidPtrCast, DefaultConstInit,
                                         ImplicitIntToEnumCast, HiddenCppDecl,
                                         InitStringTooLongForCpp, CppKeywordInC,
                                         TentativeDefnCompat, JumpBypassesInit,
-                                        DuplicateDeclSpecifier]>;
+                                        DuplicateDeclSpecifier,
+                                        EmbedParameterIsMacro]>;
 
 def ExternCCompat : DiagGroup<"extern-c-compat">;
 def KeywordCompat : DiagGroup<"keyword-compat">;
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index ff51485a1810b..006da9a53e96a 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -492,6 +492,14 @@ def warn_compat_pp_embed_directive : Warning<
   InGroup<CPre23Compat>, DefaultIgnore;
 def err_pp_embed_dup_params : Error<
   "cannot specify parameter '%0' twice in the same '#embed' directive">;
+def err_pp_embed_parameter_is_macro : Error<
+  "cannot use %0 as %select{an '#embed'|a '__has_embed'}1 parameter if also"
+  " defined as a macro">;
+def warn_c_pp_embed_parameter_is_macro : Warning<
+  "%0 is defined as a macro and gets expanded when used as a "
+  "%select{an '#embed'|a '__has_embed'}1 parameter in C; this is "
+  "ill-formed in C++">,
+  InGroup<EmbedParameterIsMacro>, DefaultIgnore;
 def err_pp_embed_device_file : Error<
   "device files are not yet supported by '#embed' directive">;
 
diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index 31b68a0fd0670..4711728b1b764 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -302,6 +302,10 @@ class Preprocessor {
   /// True if we are currently preprocessing a #if or #elif directive
   bool ParsingIfOrElifDirective;
 
+  /// True if we are preprocessing the parameters of an #embed directive or a
+  /// __has_embed expression.
+  bool ParsingEmbedParameters;
+
   /// True if we are pre-expanding macro arguments.
   bool InMacroArgPreExpansion;
 
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index f1e9aaa72ff04..0b7c727d2ce89 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -3771,6 +3771,10 @@ void Preprocessor::HandleElifFamilyDirective(Token 
&ElifToken,
 std::optional<LexEmbedParametersResult>
 Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {
   LexEmbedParametersResult Result{};
+  if (ForHasEmbed)
+    assert(isParsingIfOrElifDirective() &&
+           "__has_embed outside of #if or #elif directive?");
+  llvm::SaveAndRestore InEmbedParams(ParsingEmbedParameters, true);
   tok::TokenKind EndTokenKind = ForHasEmbed ? tok::r_paren : tok::eod;
 
   auto DiagMismatchedBracesAndSkipToEOD =
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 84907adc5d744..9bab63818007c 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -119,6 +119,7 @@ Preprocessor::Preprocessor(const PreprocessorOptions 
&PPOpts,
   NumCachedTokenLexers = 0;
   PragmasEnabled = true;
   ParsingIfOrElifDirective = false;
+  ParsingEmbedParameters = false;
   PreprocessedOutput = false;
 
   // We haven't read anything from the external source.
@@ -879,6 +880,11 @@ void Preprocessor::updateOutOfDateIdentifier(const 
IdentifierInfo &II) const {
   getExternalSource()->updateOutOfDateIdentifier(II);
 }
 
+static bool isProtectedEmbedParameterName(const IdentifierInfo *II) {
+  return II->isStr("limit") || II->isStr("prefix") || II->isStr("suffix") ||
+         II->isStr("if_empty");
+}
+
 /// HandleIdentifier - This callback is invoked when the lexer reads an
 /// identifier.  This callback looks up the identifier in the map and/or
 /// potentially macro expands it or turns it into a named token (like 'for').
@@ -922,6 +928,24 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
   if (const MacroDefinition MD = getMacroDefinition(&II)) {
     const auto *MI = MD.getMacroInfo();
     assert(MI && "macro definition with no macro info?");
+    // C++ [cpp.pre]/p4, [cpp.cond]/p9: if one of the pp-tokens of a #embed
+    // directive (or a has-embed-expression) is the identifier limit, prefix,
+    // suffix, or if_empty and that identifier is defined as a macro, the
+    // program is ill-formed.
+    //
+    // Thus, do not continue processing if compiling for C++. C doesn't have
+    // this restriction however, so only issue a warning for C if -Wc++-compat
+    // is enabled.
+    if (ParsingEmbedParameters && isProtectedEmbedParameterName(&II)) {
+      Diag(Identifier, getLangOpts().CPlusPlus
+                           ? diag::err_pp_embed_parameter_is_macro
+                           : diag::warn_c_pp_embed_parameter_is_macro)
+          << &II << isParsingIfOrElifDirective();
+      Diag(MI->getDefinitionLoc(), diag::note_macro_here) << &II;
+      if (getLangOpts().CPlusPlus)
+        return true;
+    }
+
     if (!DisableMacroExpansion) {
       if (!Identifier.isExpandDisabled() && MI->isEnabled()) {
         // C99 6.10.3p10: If the preprocessing token immediately after the
diff --git a/clang/test/CXX/drs/cwg3013.cpp b/clang/test/CXX/drs/cwg3013.cpp
new file mode 100644
index 0000000000000..95f4f6fc6f9e2
--- /dev/null
+++ b/clang/test/CXX/drs/cwg3013.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 --embed-dir=%S/inputs -Wno-c23-extensions -fsyntax-only 
-verify=cxx,common -x c++ %s
+// RUN: %clang_cc1 --embed-dir=%S/inputs -fsyntax-only -verify=c -std=c23 -x c 
%s
+// RUN: %clang_cc1 --embed-dir=%S/inputs -fsyntax-only -verify=c-compat,common 
-std=c23 -Wc++-compat -x c %s
+//
+// Test -Wembed-parameter-is-macro:
+// RUN: %clang_cc1 --embed-dir=%S/inputs -fsyntax-only -verify=c-compat,common 
-std=c23 -Wembed-parameter-is-macro -x c %s
+// RUN: %clang_cc1 --embed-dir=%S/inputs -fsyntax-only -verify=c -std=c23 
-Wc++-compat -Wno-embed-parameter-is-macro -x c %s
+
+// CWG3013: if one of the pp-tokens of a #embed directive (or a
+// has-embed-expression) is the identifier limit, prefix, suffix, or if_empty
+// and that identifier is defined as a macro, the program is ill-formed.
+// (C++ [cpp.pre]/p4, [cpp.cond]/p9)
+//
+// However, C doesn't have this restriction, so we should only issue a warning
+// for C if -Wc++-compat/-Wembed-parameter-is-macro is enabled.
+
+// c-no-diagnostics
+
+#define limit limit
+// common-note@-1 2 {{macro 'limit' defined here}}
+const int a[] = {
+#embed <media/art.txt> limit(2)
+// cxx-error@-1 {{cannot use 'limit' as an '#embed' parameter if also defined 
as a macro}}
+// c-compat-warning@-2 {{'limit' is defined as a macro and gets expanded when 
used as an '#embed' parameter in C; this is ill-formed in C++}}
+};
+
+#define prefix prefix
+// common-note@-1 {{macro 'prefix' defined here}}
+const int b[] = {
+#embed <media/art.txt> prefix(0,)
+// cxx-error@-1 {{cannot use 'prefix' as an '#embed' parameter if also defined 
as a macro}}
+// c-compat-warning@-2 {{'prefix' is defined as a macro and gets expanded when 
used as an '#embed' parameter in C; this is ill-formed in C++}}
+};
+
+#define suffix suffix
+// common-note@-1 2 {{macro 'suffix' defined here}}
+const int c[] = {
+#embed <media/art.txt> suffix(,0)
+// cxx-error@-1 {{cannot use 'suffix' as an '#embed' parameter if also defined 
as a macro}}
+// c-compat-warning@-2 {{'suffix' is defined as a macro and gets expanded when 
used as an '#embed' parameter in C; this is ill-formed in C++}}
+};
+
+#define if_empty if_empty
+// common-note@-1 {{macro 'if_empty' defined here}}
+const int d[] = {
+#embed <media/empty> if_empty(0)
+// cxx-error@-1 {{cannot use 'if_empty' as an '#embed' parameter if also 
defined as a macro}}
+// c-compat-warning@-2 {{'if_empty' is defined as a macro and gets expanded 
when used as an '#embed' parameter in C; this is ill-formed in C++}}
+};
+
+// The prohibition also covers the __has_embed argument.
+#if __has_embed(<media/art.txt> limit(1) suffix(0))
+// cxx-error@-1 {{cannot use 'limit' as a '__has_embed' parameter if also 
defined as a macro}}
+// cxx-error@-2 {{cannot use 'suffix' as a '__has_embed' parameter if also 
defined as a macro}}
+// c-compat-warning@-3 {{'limit' is defined as a macro and gets expanded when 
used as a '__has_embed' parameter in C; this is ill-formed in C++}}
+// c-compat-warning@-4 {{'suffix' is defined as a macro and gets expanded when 
used as a '__has_embed' parameter in C; this is ill-formed in C++}}
+int e;
+#endif
diff --git a/clang/test/CXX/drs/inputs/media/art.txt 
b/clang/test/CXX/drs/inputs/media/art.txt
new file mode 100644
index 0000000000000..f4536f39af349
--- /dev/null
+++ b/clang/test/CXX/drs/inputs/media/art.txt
@@ -0,0 +1,13 @@
+   
+   -------------------------------------------
+   .                                         .
+   .                       _                 .
+   .     _        _      >(. )      _        .
+   .   >(. )__  >(- )__    //___  >(. )__    .
+   .   ~(____/ -~(_(=-/-~~(_(__/-~~(____/~   .
+   .      ~.  -~~~ .  -~.             ~~-    .
+   .           ~-                            .
+   .                                         .
+   -------------------------------------------
+   
+                     O Pato
\ No newline at end of file
diff --git a/clang/test/CXX/drs/inputs/media/empty 
b/clang/test/CXX/drs/inputs/media/empty
new file mode 100644
index 0000000000000..e69de29bb2d1d

>From f3284b6d51d229603ef0ac32a22d02f495ed2b9d Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Fri, 18 Sep 2026 16:14:30 -0700
Subject: [PATCH 2/9] typo

---
 clang/include/clang/Basic/DiagnosticLexKinds.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 006da9a53e96a..fbe9fc1461f09 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -496,7 +496,7 @@ def err_pp_embed_parameter_is_macro : Error<
   "cannot use %0 as %select{an '#embed'|a '__has_embed'}1 parameter if also"
   " defined as a macro">;
 def warn_c_pp_embed_parameter_is_macro : Warning<
-  "%0 is defined as a macro and gets expanded when used as a "
+  "%0 is defined as a macro and gets expanded when used as "
   "%select{an '#embed'|a '__has_embed'}1 parameter in C; this is "
   "ill-formed in C++">,
   InGroup<EmbedParameterIsMacro>, DefaultIgnore;

>From f32f333e7872597bbdfb8fbdaf16cff61ad6ad1c Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Mon, 21 Sep 2026 20:39:07 -0700
Subject: [PATCH 3/9] split c/c++ tests and make cwg test conform to other dr
 tests

---
 clang/test/CXX/drs/cwg3013.cpp             | 75 +++++++++-------------
 clang/test/CXX/drs/cwg30xx.cpp             |  2 +
 clang/test/Preprocessor/embed_cxx_compat.c | 51 +++++++++++++++
 3 files changed, 84 insertions(+), 44 deletions(-)
 create mode 100644 clang/test/Preprocessor/embed_cxx_compat.c

diff --git a/clang/test/CXX/drs/cwg3013.cpp b/clang/test/CXX/drs/cwg3013.cpp
index 95f4f6fc6f9e2..965ac8d180369 100644
--- a/clang/test/CXX/drs/cwg3013.cpp
+++ b/clang/test/CXX/drs/cwg3013.cpp
@@ -1,58 +1,45 @@
-// RUN: %clang_cc1 --embed-dir=%S/inputs -Wno-c23-extensions -fsyntax-only 
-verify=cxx,common -x c++ %s
-// RUN: %clang_cc1 --embed-dir=%S/inputs -fsyntax-only -verify=c -std=c23 -x c 
%s
-// RUN: %clang_cc1 --embed-dir=%S/inputs -fsyntax-only -verify=c-compat,common 
-std=c23 -Wc++-compat -x c %s
-//
-// Test -Wembed-parameter-is-macro:
-// RUN: %clang_cc1 --embed-dir=%S/inputs -fsyntax-only -verify=c-compat,common 
-std=c23 -Wembed-parameter-is-macro -x c %s
-// RUN: %clang_cc1 --embed-dir=%S/inputs -fsyntax-only -verify=c -std=c23 
-Wc++-compat -Wno-embed-parameter-is-macro -x c %s
-
-// CWG3013: if one of the pp-tokens of a #embed directive (or a
-// has-embed-expression) is the identifier limit, prefix, suffix, or if_empty
-// and that identifier is defined as a macro, the program is ill-formed.
-// (C++ [cpp.pre]/p4, [cpp.cond]/p9)
-//
-// However, C doesn't have this restriction, so we should only issue a warning
-// for C if -Wc++-compat/-Wembed-parameter-is-macro is enabled.
-
-// c-no-diagnostics
-
-#define limit limit
-// common-note@-1 2 {{macro 'limit' defined here}}
+// RUN: %clang_cc1 -std=c++2c -fexceptions -fcxx-exceptions -pedantic-errors 
-verify-directives -Wno-c23-extensions -verify %s
+
+// C doesn't have an analogue to CWG3013: There is a corresponding C test at
+// clang/test/Preprocessor/embed_cxx_compat.c testing an opt-in CXX-compat
+// diagnostic.
+
+namespace cwg3013 { // cwg3013: 24
+
+#define limit limit // #cwg3013-limit
 const int a[] = {
-#embed <media/art.txt> limit(2)
-// cxx-error@-1 {{cannot use 'limit' as an '#embed' parameter if also defined 
as a macro}}
-// c-compat-warning@-2 {{'limit' is defined as a macro and gets expanded when 
used as an '#embed' parameter in C; this is ill-formed in C++}}
+#embed __FILE__ limit(2)
+// expected-error@-1 {{cannot use 'limit' as an '#embed' parameter if also 
defined as a macro}}
+//   expected-note@#cwg3013-limit {{macro 'limit' defined here}}
 };
 
-#define prefix prefix
-// common-note@-1 {{macro 'prefix' defined here}}
+#define prefix prefix // #cwg3013-prefix
 const int b[] = {
-#embed <media/art.txt> prefix(0,)
-// cxx-error@-1 {{cannot use 'prefix' as an '#embed' parameter if also defined 
as a macro}}
-// c-compat-warning@-2 {{'prefix' is defined as a macro and gets expanded when 
used as an '#embed' parameter in C; this is ill-formed in C++}}
+#embed __FILE__ prefix(0,)
+// expected-error@-1 {{cannot use 'prefix' as an '#embed' parameter if also 
defined as a macro}}
+//   expected-note@#cwg3013-prefix {{macro 'prefix' defined here}}
 };
 
-#define suffix suffix
-// common-note@-1 2 {{macro 'suffix' defined here}}
+#define suffix suffix // #cwg3013-suffix
 const int c[] = {
-#embed <media/art.txt> suffix(,0)
-// cxx-error@-1 {{cannot use 'suffix' as an '#embed' parameter if also defined 
as a macro}}
-// c-compat-warning@-2 {{'suffix' is defined as a macro and gets expanded when 
used as an '#embed' parameter in C; this is ill-formed in C++}}
+#embed __FILE__ suffix(,0)
+// expected-error@-1 {{cannot use 'suffix' as an '#embed' parameter if also 
defined as a macro}}
+//   expected-note@#cwg3013-suffix {{macro 'suffix' defined here}}
 };
 
-#define if_empty if_empty
-// common-note@-1 {{macro 'if_empty' defined here}}
+#define if_empty if_empty // #cwg3013-if_empty
 const int d[] = {
-#embed <media/empty> if_empty(0)
-// cxx-error@-1 {{cannot use 'if_empty' as an '#embed' parameter if also 
defined as a macro}}
-// c-compat-warning@-2 {{'if_empty' is defined as a macro and gets expanded 
when used as an '#embed' parameter in C; this is ill-formed in C++}}
+#embed __FILE__ if_empty(0)
+// expected-error@-1 {{cannot use 'if_empty' as an '#embed' parameter if also 
defined as a macro}}
+//   expected-note@#cwg3013-if_empty {{macro 'if_empty' defined here}}
 };
 
-// The prohibition also covers the __has_embed argument.
-#if __has_embed(<media/art.txt> limit(1) suffix(0))
-// cxx-error@-1 {{cannot use 'limit' as a '__has_embed' parameter if also 
defined as a macro}}
-// cxx-error@-2 {{cannot use 'suffix' as a '__has_embed' parameter if also 
defined as a macro}}
-// c-compat-warning@-3 {{'limit' is defined as a macro and gets expanded when 
used as a '__has_embed' parameter in C; this is ill-formed in C++}}
-// c-compat-warning@-4 {{'suffix' is defined as a macro and gets expanded when 
used as a '__has_embed' parameter in C; this is ill-formed in C++}}
+#if __has_embed(__FILE__ limit(1) suffix(0))
+// expected-error@-1 {{cannot use 'limit' as a '__has_embed' parameter if also 
defined as a macro}}
+//   expected-note@#cwg3013-limit {{macro 'limit' defined here}}
+// expected-error@-3 {{cannot use 'suffix' as a '__has_embed' parameter if 
also defined as a macro}}
+//   expected-note@#cwg3013-suffix {{macro 'suffix' defined here}}
 int e;
 #endif
+
+} // namespace cwg3013
\ No newline at end of file
diff --git a/clang/test/CXX/drs/cwg30xx.cpp b/clang/test/CXX/drs/cwg30xx.cpp
index a664fe6b3f073..a4053b55cd751 100644
--- a/clang/test/CXX/drs/cwg30xx.cpp
+++ b/clang/test/CXX/drs/cwg30xx.cpp
@@ -22,6 +22,8 @@ void f(
 
 } // namespace cwg3005
 
+// cwg3013 is in cwg3013.cpp
+
 namespace cwg3035 { // cwg3035: no
 #if __cplusplus >= 201103L
 static union {
diff --git a/clang/test/Preprocessor/embed_cxx_compat.c 
b/clang/test/Preprocessor/embed_cxx_compat.c
new file mode 100644
index 0000000000000..96c7c19682cfd
--- /dev/null
+++ b/clang/test/Preprocessor/embed_cxx_compat.c
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -std=c23 --embed-dir=%S/Inputs -fsyntax-only -verify=silent 
%s
+// RUN: %clang_cc1 -std=c23 --embed-dir=%S/Inputs -fsyntax-only -verify=compat 
-Wc++-compat %s
+//
+// Test -Wembed-parameter-is-macro:
+// RUN: %clang_cc1 -std=c23 --embed-dir=%S/Inputs -fsyntax-only -verify=compat 
-Wembed-parameter-is-macro %s
+// RUN: %clang_cc1 -std=c23 --embed-dir=%S/Inputs -fsyntax-only -verify=silent 
-Wc++-compat -Wno-embed-parameter-is-macro %s
+
+// C++ has CWG3013: if one of the pp-tokens of a #embed directive (or a
+// has-embed-expression) is the identifier limit, prefix, suffix, or if_empty
+// and that identifier is defined as a macro, the program is ill-formed.
+// (C++ [cpp.pre]/p4, [cpp.cond]/p9)
+//
+// ... But C doesn't seem to have this restriction, so we allow macro-expansion
+// and only warn if -Wc++-compat or -Wembed-parameter-is-macro is enabled. C++
+// conformance with CWG3013 is tested in clang/test/CXX/drs/cwg3013.cpp.
+
+// silent-no-diagnostics
+
+#define limit limit
+// compat-note@-1 2 {{macro 'limit' defined here}}
+const int a[] = {
+#embed __FILE__ limit(2)
+// compat-warning@-1 {{'limit' is defined as a macro and gets expanded when 
used as an '#embed' parameter in C; this is ill-formed in C++}}
+};
+
+#define prefix prefix
+// compat-note@-1 {{macro 'prefix' defined here}}
+const int b[] = {
+#embed __FILE__ prefix(0,)
+// compat-warning@-1 {{'prefix' is defined as a macro and gets expanded when 
used as an '#embed' parameter in C; this is ill-formed in C++}}
+};
+
+#define suffix suffix
+// compat-note@-1 2 {{macro 'suffix' defined here}}
+const int c[] = {
+#embed __FILE__ suffix(,0)
+// compat-warning@-1 {{'suffix' is defined as a macro and gets expanded when 
used as an '#embed' parameter in C; this is ill-formed in C++}}
+};
+
+#define if_empty if_empty
+// compat-note@-1 {{macro 'if_empty' defined here}}
+const int d[] = {
+#embed __FILE__ if_empty(0)
+// compat-warning@-1 {{'if_empty' is defined as a macro and gets expanded when 
used as an '#embed' parameter in C; this is ill-formed in C++}}
+};
+
+#if __has_embed(__FILE__ limit(1) suffix(0))
+// compat-warning@-1 {{'limit' is defined as a macro and gets expanded when 
used as a '__has_embed' parameter in C; this is ill-formed in C++}}
+// compat-warning@-2 {{'suffix' is defined as a macro and gets expanded when 
used as a '__has_embed' parameter in C; this is ill-formed in C++}}
+int e;
+#endif

>From 667e78bf7a6e94576c8758b6f8b1c2e3b11b7474 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Mon, 21 Sep 2026 20:39:50 -0700
Subject: [PATCH 4/9] rerun clang/www/make_cxx_dr_status

---
 clang/www/cxx_dr_status.html | 128 +++++++++++++++++++++++++++++------
 1 file changed, 106 insertions(+), 22 deletions(-)

diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index e7679da30d5c2..b1e31e20b7078 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -1413,12 +1413,12 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
     <td>Converting between function and object pointers</td>
     <td class="full" align="center">Clang 2.7</td>
   </tr>
-  <tr class="open" id="196">
+  <tr id="196">
     <td><a href="https://cplusplus.github.io/CWG/issues/196.html";>196</a></td>
     <td>[<a href="https://wg21.link/expr.delete";>expr.delete</a>]</td>
-    <td>open</td>
+    <td>C++17</td>
     <td>Arguments to deallocation functions</td>
-    <td align="center">Not resolved</td>
+    <td class="unknown" align="center">Unknown</td>
   </tr>
   <tr id="197">
     <td><a href="https://cplusplus.github.io/CWG/issues/197.html";>197</a></td>
@@ -1910,12 +1910,12 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
     <td>No grammar sentence symbol</td>
     <td class="na" align="center">N/A</td>
   </tr>
-  <tr class="open" id="267">
+  <tr id="267">
     <td><a href="https://cplusplus.github.io/CWG/issues/267.html";>267</a></td>
     <td>[<a href="https://wg21.link/expr.new";>expr.new</a>]</td>
-    <td>open</td>
+    <td>NAD</td>
     <td>Alignment requirement for <I>new-expression</I>s</td>
-    <td align="center">Not resolved</td>
+    <td class="unknown" align="center">Unknown</td>
   </tr>
   <tr class="open" id="268">
     <td><a href="https://cplusplus.github.io/CWG/issues/268.html";>268</a></td>
@@ -10017,12 +10017,12 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
     <td>Deduction failure vs &#8220;ill-formed, no diagnostic 
required&#8221;</td>
     <td class="unknown" align="center">Unknown</td>
   </tr>
-  <tr class="open" id="1463">
+  <tr id="1463">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/1463.html";>1463</a></td>
     <td>[<a href="https://wg21.link/temp.pre";>temp.pre</a>]</td>
-    <td>drafting</td>
+    <td>DR</td>
     <td><TT>extern "C"</TT> alias templates</td>
-    <td align="center">Not resolved</td>
+    <td class="unknown" align="center">Unknown</td>
   </tr>
   <tr id="1464">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/1464.html";>1464</a></td>
@@ -11179,7 +11179,7 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
   <tr class="open" id="1628">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/1628.html";>1628</a></td>
     <td>[<a href="https://wg21.link/expr.new";>expr.new</a>]</td>
-    <td>open</td>
+    <td>review</td>
     <td>Deallocation function templates</td>
     <td align="center">Not resolved</td>
   </tr>
@@ -13255,7 +13255,7 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
   <tr class="open" id="1924">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/1924.html";>1924</a></td>
     <td>[<a href="https://wg21.link/lex.literal";>lex.literal</a>]</td>
-    <td>review</td>
+    <td>open</td>
     <td>Definition of &#8220;literal&#8221; and kinds of literals</td>
     <td align="center">Not resolved</td>
   </tr>
@@ -20908,7 +20908,7 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
     <td>[<a href="https://wg21.link/cpp.embed.gen";>cpp.embed.gen</a>]</td>
     <td>CD7</td>
     <td>Disallowing macros for <TT>#embed</TT> parameters</td>
-    <td class="unknown" align="center">Unknown</td>
+    <td class="unreleased" align="center">Clang 24</td>
   </tr>
   <tr id="3014">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/3014.html";>3014</a></td>
@@ -20969,7 +20969,7 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
   <tr class="open" id="3022">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/3022.html";>3022</a></td>
     <td>[<a href="https://wg21.link/class.dtor";>class.dtor</a>]</td>
-    <td>review</td>
+    <td>tentatively ready</td>
     <td>Redundant specification of explicit destructor calls</td>
     <td align="center">Not resolved</td>
   </tr>
@@ -22194,7 +22194,7 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
   <tr class="open" id="3197">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/3197.html";>3197</a></td>
     <td>[<a href="https://wg21.link/diff.basic";>diff.basic</a>]</td>
-    <td>review</td>
+    <td>tentatively ready</td>
     <td>Relaxed requirements for integer representations</td>
     <td align="center">Not resolved</td>
   </tr>
@@ -22271,7 +22271,7 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
   <tr class="open" id="3208">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/3208.html";>3208</a></td>
     <td>[<a href="https://wg21.link/basic.life";>basic.life</a>]</td>
-    <td>open</td>
+    <td>tentatively ready</td>
     <td>Base classes of virtual base classes</td>
     <td align="center">Not resolved</td>
   </tr>
@@ -22285,42 +22285,42 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
   <tr class="open" id="3210">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/3210.html";>3210</a></td>
     <td>[<a href="https://wg21.link/stmt.expand";>stmt.expand</a>]</td>
-    <td>open</td>
+    <td>tentatively ready</td>
     <td>constexpr for empty destructuring expansion statements</td>
     <td align="center">Not resolved</td>
   </tr>
   <tr class="open" id="3211">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/3211.html";>3211</a></td>
     <td>[<a href="https://wg21.link/basic.def.odr";>basic.def.odr</a>]</td>
-    <td>open</td>
+    <td>tentatively ready</td>
     <td>Explicitly captured variable is not odr-usable in lambda contract</td>
     <td align="center">Not resolved</td>
   </tr>
   <tr class="open" id="3212">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/3212.html";>3212</a></td>
     <td>[<a href="https://wg21.link/stmt.if";>stmt.if</a>]</td>
-    <td>open</td>
+    <td>drafting</td>
     <td>Misleading disambiguation rule for nested <TT>if</TT></td>
     <td align="center">Not resolved</td>
   </tr>
   <tr class="open" id="3213">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/3213.html";>3213</a></td>
     <td>[<a href="https://wg21.link/temp.param";>temp.param</a>]</td>
-    <td>open</td>
+    <td>tentatively ready</td>
     <td>Restrictions on the <I>template-head</I> of a concept definition</td>
     <td align="center">Not resolved</td>
   </tr>
   <tr class="open" id="3214">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/3214.html";>3214</a></td>
     <td>[<a href="https://wg21.link/basic.link";>basic.link</a>]</td>
-    <td>open</td>
+    <td>tentatively ready</td>
     <td>Redeclaration of types and namespaces and their aliases</td>
     <td align="center">Not resolved</td>
   </tr>
   <tr class="open" id="3215">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/3215.html";>3215</a></td>
     <td>[<a href="https://wg21.link/expr.const.core";>expr.const.core</a>]</td>
-    <td>open</td>
+    <td>tentatively ready</td>
     <td><TT>this</TT> in a default member initializer during constant 
evaluation</td>
     <td align="center">Not resolved</td>
   </tr>
@@ -22341,7 +22341,7 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
   <tr class="open" id="3218">
     <td><a 
href="https://cplusplus.github.io/CWG/issues/3218.html";>3218</a></td>
     <td>[<a href="https://wg21.link/temp.variadic";>temp.variadic</a>]</td>
-    <td>open</td>
+    <td>tentatively ready</td>
     <td>Expanding packs created within a pack expansion</td>
     <td align="center">Not resolved</td>
   </tr>
@@ -22351,6 +22351,90 @@ <h2 id="cxxdr">C++ defect report implementation 
status</h2>
     <td>open</td>
     <td>Acquiring value representations and indeterminate or erroneous 
values</td>
     <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3220">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3220.html";>3220</a></td>
+    <td>[<a href="https://wg21.link/basic.link";>basic.link</a>]</td>
+    <td>open</td>
+    <td>Regression in module attachment rules introduced by CWG3171</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3221">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3221.html";>3221</a></td>
+    <td>[<a 
href="https://wg21.link/basic.scope.block";>basic.scope.block</a>]</td>
+    <td>tentatively ready</td>
+    <td>Missing Annex C entry for conflicting declarations in for-loops</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3222">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3222.html";>3222</a></td>
+    <td>[<a href="https://wg21.link/cpp.module";>cpp.module</a>]</td>
+    <td>tentatively ready</td>
+    <td>Deleted module directives</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3223">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3223.html";>3223</a></td>
+    <td>[<a href="https://wg21.link/class.base.init";>class.base.init</a>]</td>
+    <td>tentatively ready</td>
+    <td>Undefined behavior for constructor preconditions and destructor 
postconditions</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3224">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3224.html";>3224</a></td>
+    <td>[<a 
href="https://wg21.link/cpp.replace.general";>cpp.replace.general</a>]</td>
+    <td>tentatively ready</td>
+    <td>Directives in multi-line macro arguments</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3225">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3225.html";>3225</a></td>
+    <td>[<a href="https://wg21.link/conv.integral";>conv.integral</a>]</td>
+    <td>tentatively ready</td>
+    <td>Conversion of <TT>bool</TT> to signed integer of width 1</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3226">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3226.html";>3226</a></td>
+    <td>[<a 
href="https://wg21.link/temp.res.general";>temp.res.general</a>]</td>
+    <td>tentatively ready</td>
+    <td>Conflict of templated entity vs. enclosing template</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3227">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3227.html";>3227</a></td>
+    <td>[<a 
href="https://wg21.link/temp.res.general";>temp.res.general</a>]</td>
+    <td>tentatively ready</td>
+    <td>IFNDR for always-empty packs</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3228">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3228.html";>3228</a></td>
+    <td>[<a href="https://wg21.link/dcl.init";>dcl.init</a>]</td>
+    <td>tentatively ready</td>
+    <td>Empty initializers vs. empty packs</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3229">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3229.html";>3229</a></td>
+    <td>[<a href="https://wg21.link/basic.def.odr";>basic.def.odr</a>]</td>
+    <td>tentatively ready</td>
+    <td>Incomplete restrictions on same meaning for same tokens</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3230">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3230.html";>3230</a></td>
+    <td>[<a href="https://wg21.link/basic.pre";>basic.pre</a>]</td>
+    <td>open</td>
+    <td>Are non-static data members "variables"?</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3231">
+    <td><a 
href="https://cplusplus.github.io/CWG/issues/3231.html";>3231</a></td>
+    <td>[<a href="https://wg21.link/temp.concept";>temp.concept</a>]</td>
+    <td>open</td>
+    <td>Default template argument for the prototype parameter of a concept</td>
+    <td align="center">Not resolved</td>
   </tr></table>
 
 </div>

>From 0fd92492049832121df4989c3095b1cab063cc3d Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Mon, 21 Sep 2026 20:46:01 -0700
Subject: [PATCH 5/9] delete duplicate point in release notes

---
 clang/docs/ReleaseNotes.md | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index da925b260ee1c..dc5c765cb8418 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -201,11 +201,6 @@ features cannot lower the translation-unit ABI level;
   them to an enumeration type with a fixed `bool` underlying type. This
   resolves [CWG1094](https://wg21.link/cwg1094).
 
-- Clang now diagnoses an error if an `#embed` directive or `__has_embed`
-  statement uses a parameter name (i.e. `limit`, `prefix`, `suffix`, 
`if_empty`)
-  that has previously been defined as a macro. This resolves
-  [CWG3013](https://wg21.link/cwg3013), which marks such code as ill-formed.
-
 ### C Language Changes
 
 #### C2y Feature Support

>From cf667c5993041b9d77ff557fb998588e16aedd3c Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Mon, 21 Sep 2026 22:02:30 -0700
Subject: [PATCH 6/9] ate logo o pato

---
 clang/test/CXX/drs/inputs/media/art.txt | 13 -------------
 clang/test/CXX/drs/inputs/media/empty   |  0
 2 files changed, 13 deletions(-)
 delete mode 100644 clang/test/CXX/drs/inputs/media/art.txt
 delete mode 100644 clang/test/CXX/drs/inputs/media/empty

diff --git a/clang/test/CXX/drs/inputs/media/art.txt 
b/clang/test/CXX/drs/inputs/media/art.txt
deleted file mode 100644
index f4536f39af349..0000000000000
--- a/clang/test/CXX/drs/inputs/media/art.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-   
-   -------------------------------------------
-   .                                         .
-   .                       _                 .
-   .     _        _      >(. )      _        .
-   .   >(. )__  >(- )__    //___  >(. )__    .
-   .   ~(____/ -~(_(=-/-~~(_(__/-~~(____/~   .
-   .      ~.  -~~~ .  -~.             ~~-    .
-   .           ~-                            .
-   .                                         .
-   -------------------------------------------
-   
-                     O Pato
\ No newline at end of file
diff --git a/clang/test/CXX/drs/inputs/media/empty 
b/clang/test/CXX/drs/inputs/media/empty
deleted file mode 100644
index e69de29bb2d1d..0000000000000

>From b2986ddf69c821872eee12aac2301164686f7cc4 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Mon, 21 Sep 2026 22:02:54 -0700
Subject: [PATCH 7/9] use ExtWarn for warn_c_pp_embed_parameter_is_macro

---
 clang/include/clang/Basic/DiagnosticLexKinds.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index fbe9fc1461f09..fdb9ffba01613 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -495,7 +495,7 @@ def err_pp_embed_dup_params : Error<
 def err_pp_embed_parameter_is_macro : Error<
   "cannot use %0 as %select{an '#embed'|a '__has_embed'}1 parameter if also"
   " defined as a macro">;
-def warn_c_pp_embed_parameter_is_macro : Warning<
+def warn_c_pp_embed_parameter_is_macro : ExtWarn<
   "%0 is defined as a macro and gets expanded when used as "
   "%select{an '#embed'|a '__has_embed'}1 parameter in C; this is "
   "ill-formed in C++">,

>From ea6b88cefbfc58af8e8797e33e59a048f59804eb Mon Sep 17 00:00:00 2001
From: Ian Li <[email protected]>
Date: Tue, 22 Sep 2026 01:11:50 -0400
Subject: [PATCH 8/9] Apply suggestion from @Fznamznon

Co-authored-by: Mariya Podchishchaeva <[email protected]>
---
 clang/lib/Lex/PPDirectives.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 0b7c727d2ce89..bcf6a554b77f6 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -3771,8 +3771,7 @@ void Preprocessor::HandleElifFamilyDirective(Token 
&ElifToken,
 std::optional<LexEmbedParametersResult>
 Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {
   LexEmbedParametersResult Result{};
-  if (ForHasEmbed)
-    assert(isParsingIfOrElifDirective() &&
+    assert(!ForHasEmbed || isParsingIfOrElifDirective() &&
            "__has_embed outside of #if or #elif directive?");
   llvm::SaveAndRestore InEmbedParams(ParsingEmbedParameters, true);
   tok::TokenKind EndTokenKind = ForHasEmbed ? tok::r_paren : tok::eod;

>From d371eae8b8dc38cfa145cca04bf2930c2dd61bc8 Mon Sep 17 00:00:00 2001
From: "Li, Ian" <[email protected]>
Date: Mon, 21 Sep 2026 22:18:39 -0700
Subject: [PATCH 9/9] clang-format

---
 clang/lib/Lex/PPDirectives.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index bcf6a554b77f6..35697284e682b 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -3771,8 +3771,8 @@ void Preprocessor::HandleElifFamilyDirective(Token 
&ElifToken,
 std::optional<LexEmbedParametersResult>
 Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) {
   LexEmbedParametersResult Result{};
-    assert(!ForHasEmbed || isParsingIfOrElifDirective() &&
-           "__has_embed outside of #if or #elif directive?");
+  assert(!ForHasEmbed || isParsingIfOrElifDirective() &&
+                             "__has_embed outside of #if or #elif directive?");
   llvm::SaveAndRestore InEmbedParams(ParsingEmbedParameters, true);
   tok::TokenKind EndTokenKind = ForHasEmbed ? tok::r_paren : tok::eod;
 

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

Reply via email to