https://github.com/ChenMiaoi updated 
https://github.com/llvm/llvm-project/pull/230927

>From 09394ace8975bf78ab78b364067595e92db7f540 Mon Sep 17 00:00:00 2001
From: Chen Miao <[email protected]>
Date: Sun, 11 Oct 2026 15:16:17 +0800
Subject: [PATCH 1/4] [clang] Guard identifier reads in pragma handlers

---
 clang/docs/ReleaseNotes.md                    |  3 +
 clang/lib/Lex/Pragma.cpp                      | 43 +++++++---
 clang/lib/Parse/ParsePragma.cpp               | 62 ++++++++------
 clang/test/FixIt/fixit-pragma-attribute.cpp   |  5 ++
 clang/test/Parser/pragma-attribute.cpp        |  7 ++
 .../Parser/pragma-nested-annotation-target.c  | 31 +++++++
 clang/test/Parser/pragma-nested-annotation.c  | 85 +++++++++++++++++++
 clang/unittests/Lex/LexerTest.cpp             | 25 ++++++
 8 files changed, 224 insertions(+), 37 deletions(-)
 create mode 100644 clang/test/Parser/pragma-nested-annotation-target.c
 create mode 100644 clang/test/Parser/pragma-nested-annotation.c

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 77a1e73bc8af6..4867f40c51cae 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -947,6 +947,9 @@ features cannot lower the translation-unit ABI level;
 
 #### Miscellaneous Clang Crashes Fixed
 
+- Fixed crashes when nested `_Pragma` or Microsoft `__pragma` expressions
+  introduce annotation tokens where a pragma expects an identifier. (#GH225035)
+
 - Fixed a crash when Microsoft extensions were enabled and an unterminated
   `__identifier` expression reached the end of a preprocessing directive or
   source file. (#GH222310)
diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index 078842ab08c5e..e47bbc7402ef5 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -108,10 +108,11 @@ void PragmaNamespace::HandlePragma(Preprocessor &PP,
   PP.LexUnexpandedToken(Tok);
 
   // Get the handler for this token.  If there is no handler, ignore the 
pragma.
-  PragmaHandler *Handler
-    = FindHandler(Tok.getIdentifierInfo() ? Tok.getIdentifierInfo()->getName()
-                                          : StringRef(),
-                  /*IgnoreNull=*/false);
+  PragmaHandler *Handler = FindHandler(
+      Tok.is(tok::identifier) || tok::getKeywordSpelling(Tok.getKind())
+          ? Tok.getIdentifierInfo()->getName()
+          : StringRef(),
+      /*IgnoreNull=*/false);
   if (!Handler) {
     PP.Diag(Tok, diag::warn_pragma_ignored);
     return;
@@ -921,7 +922,7 @@ void Preprocessor::HandlePragmaSetPPState(PragmaIntroducer 
Introducer,
                                           Token &Tok) {
   // Lex the macro name we want to set.
   LexUnexpandedToken(Tok);
-  if (!Tok.getIdentifierInfo()) {
+  if (Tok.isNot(tok::identifier) && !tok::getKeywordSpelling(Tok.getKind())) {
     Diag(Tok.getLocation(), diag::err_pp_pragma_set_pp_state_expected_name);
     return;
   }
@@ -1149,7 +1150,10 @@ struct PragmaDebugHandler : public PragmaHandler {
     } else if (II->isStr("macro")) {
       Token MacroName;
       PP.LexUnexpandedToken(MacroName);
-      auto *MacroII = MacroName.getIdentifierInfo();
+      auto *MacroII = MacroName.is(tok::identifier) ||
+                              tok::getKeywordSpelling(MacroName.getKind())
+                          ? MacroName.getIdentifierInfo()
+                          : nullptr;
       if (MacroII)
         PP.dumpMacroInfo(MacroII);
       else
@@ -1174,7 +1178,10 @@ struct PragmaDebugHandler : public PragmaHandler {
     } else if (II->isStr("module_lookup")) {
       Token MName;
       PP.LexUnexpandedToken(MName);
-      auto *MNameII = MName.getIdentifierInfo();
+      auto *MNameII =
+          MName.is(tok::identifier) || tok::getKeywordSpelling(MName.getKind())
+              ? MName.getIdentifierInfo()
+              : nullptr;
       if (!MNameII) {
         PP.Diag(MName, diag::warn_pragma_debug_missing_argument)
             << II->getName();
@@ -1219,7 +1226,10 @@ struct PragmaDebugHandler : public PragmaHandler {
 
       Token Kind;
       PP.LexUnexpandedToken(Kind);
-      auto *DumpII = Kind.getIdentifierInfo();
+      auto *DumpII =
+          Kind.is(tok::identifier) || tok::getKeywordSpelling(Kind.getKind())
+              ? Kind.getIdentifierInfo()
+              : nullptr;
       if (!DumpII) {
         PP.Diag(Kind, diag::warn_pragma_debug_missing_argument)
             << II->getName();
@@ -1453,7 +1463,9 @@ struct PragmaWarningHandler : public PragmaHandler {
     }
 
     PP.Lex(Tok);
-    IdentifierInfo *II = Tok.getIdentifierInfo();
+    IdentifierInfo *II = Tok.isOneOf(tok::identifier, tok::kw_default)
+                             ? Tok.getIdentifierInfo()
+                             : nullptr;
 
     if (II && II->isStr("push")) {
       // #pragma warning( push[ ,n ] )
@@ -1484,7 +1496,9 @@ struct PragmaWarningHandler : public PragmaHandler {
       // #pragma warning( warning-specifier : warning-number-list
       //                  [; warning-specifier : warning-number-list...] )
       while (true) {
-        II = Tok.getIdentifierInfo();
+        II = Tok.isOneOf(tok::identifier, tok::kw_default)
+                 ? Tok.getIdentifierInfo()
+                 : nullptr;
         if (!II && !Tok.is(tok::numeric_constant)) {
           PP.Diag(Tok, diag::warn_pragma_warning_spec_invalid);
           return;
@@ -1601,7 +1615,8 @@ struct PragmaExecCharsetHandler : public PragmaHandler {
     }
 
     PP.Lex(Tok);
-    IdentifierInfo *II = Tok.getIdentifierInfo();
+    IdentifierInfo *II =
+        Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
 
     if (II && II->isStr("push")) {
       // #pragma execution_character_set( push[ , string ] )
@@ -1930,7 +1945,8 @@ struct PragmaARCCFCodeAuditedHandler : public 
PragmaHandler {
 
     // Lex the 'begin' or 'end'.
     PP.LexUnexpandedToken(Tok);
-    const IdentifierInfo *BeginEnd = Tok.getIdentifierInfo();
+    const IdentifierInfo *BeginEnd =
+        Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
     if (BeginEnd && BeginEnd->isStr("begin")) {
       IsBegin = true;
     } else if (BeginEnd && BeginEnd->isStr("end")) {
@@ -1985,7 +2001,8 @@ struct PragmaAssumeNonNullHandler : public PragmaHandler {
 
     // Lex the 'begin' or 'end'.
     PP.LexUnexpandedToken(Tok);
-    const IdentifierInfo *BeginEnd = Tok.getIdentifierInfo();
+    const IdentifierInfo *BeginEnd =
+        Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
     if (BeginEnd && BeginEnd->isStr("begin")) {
       IsBegin = true;
     } else if (BeginEnd && BeginEnd->isStr("end")) {
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 04e7bb5a9b7dd..77c2f3e0b200e 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -1310,7 +1310,8 @@ bool Parser::HandlePragmaMSStrictGuardStackCheck(
 
   bool Value = false;
   if (Action & Sema::PSK_Push || Action & Sema::PSK_Set) {
-    const IdentifierInfo *II = Tok.getIdentifierInfo();
+    const IdentifierInfo *II =
+        Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
     if (II && II->isStr("off")) {
       PP.Lex(Tok);
       Value = false;
@@ -1553,7 +1554,8 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
   if (StateOption) {
     ConsumeAnnotationToken();
     SourceLocation StateLoc = Toks[0].getLocation();
-    IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
+    IdentifierInfo *StateInfo =
+        Toks[0].is(tok::identifier) ? Toks[0].getIdentifierInfo() : nullptr;
 
     bool Valid =
         StateInfo &&
@@ -1583,7 +1585,8 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
     ConsumeAnnotationToken();
 
     SourceLocation StateLoc = Toks[0].getLocation();
-    IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
+    IdentifierInfo *StateInfo =
+        Toks[0].is(tok::identifier) ? Toks[0].getIdentifierInfo() : nullptr;
     StringRef IsScalableStr = StateInfo ? StateInfo->getName() : "";
 
     // Look for vectorize_width(fixed|scalable)
@@ -1612,7 +1615,7 @@ bool Parser::HandlePragmaLoopHint(LoopHint &Hint) {
       if (Tok.is(tok::comma)) {
         PP.Lex(Tok); // ,
 
-        StateInfo = Tok.getIdentifierInfo();
+        StateInfo = Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : 
nullptr;
         IsScalableStr = StateInfo ? StateInfo->getName() : "";
 
         if (IsScalableStr != "scalable" && IsScalableStr != "fixed") {
@@ -1860,7 +1863,8 @@ enum class MissingAttributeSubjectRulesRecoveryPoint {
 
 MissingAttributeSubjectRulesRecoveryPoint
 getAttributeSubjectRulesRecoveryPointForToken(const Token &Tok) {
-  if (const auto *II = Tok.getIdentifierInfo()) {
+  if (Tok.is(tok::identifier)) {
+    const auto *II = Tok.getIdentifierInfo();
     if (II->isStr("apply_to"))
       return MissingAttributeSubjectRulesRecoveryPoint::ApplyTo;
     if (II->isStr("any"))
@@ -2028,7 +2032,7 @@ void Parser::HandlePragmaAttribute() {
     ParseMicrosoftDeclSpecs(Attrs);
   } else {
     Diag(Tok, diag::err_pragma_attribute_expected_attribute_syntax);
-    if (Tok.getIdentifierInfo()) {
+    if (Tok.is(tok::identifier) || tok::getKeywordSpelling(Tok.getKind())) {
       // If we suspect that this is an attribute suggest the use of
       // '__attribute__'.
       if (ParsedAttr::getParsedKind(
@@ -2141,7 +2145,8 @@ void 
PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
   Token Tok;
   PP.LexUnexpandedToken(Tok);
 
-  const IdentifierInfo *PushPop = Tok.getIdentifierInfo();
+  const IdentifierInfo *PushPop =
+      Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
 
   const IdentifierInfo *VisType;
   if (PushPop && PushPop->isStr("pop")) {
@@ -2154,7 +2159,9 @@ void 
PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP,
       return;
     }
     PP.LexUnexpandedToken(Tok);
-    VisType = Tok.getIdentifierInfo();
+    VisType = Tok.isOneOf(tok::identifier, tok::kw_default, tok::kw_protected)
+                  ? Tok.getIdentifierInfo()
+                  : nullptr;
     if (!VisType) {
       PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
         << "visibility";
@@ -2842,7 +2849,8 @@ void PragmaMSPointersToMembers::HandlePragma(Preprocessor 
&PP,
     return;
   }
   PP.Lex(Tok);
-  const IdentifierInfo *Arg = Tok.getIdentifierInfo();
+  const IdentifierInfo *Arg =
+      Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
   if (!Arg) {
     PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
       << "pointers_to_members";
@@ -2858,7 +2866,7 @@ void PragmaMSPointersToMembers::HandlePragma(Preprocessor 
&PP,
       if (Tok.is(tok::comma)) {
         PP.Lex(Tok);
 
-        Arg = Tok.getIdentifierInfo();
+        Arg = Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
         if (!Arg) {
           PP.Diag(Tok.getLocation(),
                   diag::err_pragma_pointers_to_members_unknown_kind)
@@ -2937,7 +2945,8 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP,
   PP.Lex(Tok);
 
   Sema::PragmaMsStackAction Action = Sema::PSK_Set;
-  const IdentifierInfo *II = Tok.getIdentifierInfo();
+  const IdentifierInfo *II =
+      Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
   if (II) {
     if (II->isStr("push")) {
       // #pragma vtordisp(push, mode)
@@ -2965,7 +2974,8 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP,
 
   uint64_t Value = 0;
   if (Action & Sema::PSK_Push || Action & Sema::PSK_Set) {
-    const IdentifierInfo *II = Tok.getIdentifierInfo();
+    const IdentifierInfo *II =
+        Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
     if (II && II->isStr("off")) {
       PP.Lex(Tok);
       Value = 0;
@@ -3338,7 +3348,7 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
   }
   if (Tok.isNot(tok::identifier)) {
     PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_invalid_argument)
-      << PP.getSpelling(Tok);
+        << PP.getSpelling(Tok);
     return;
   }
   const IdentifierInfo *II = Tok.getIdentifierInfo();
@@ -3348,14 +3358,14 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor 
&PP,
     IsOn = true;
   } else if (!II->isStr("off")) {
     PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_invalid_argument)
-      << PP.getSpelling(Tok);
+        << PP.getSpelling(Tok);
     return;
   }
   PP.Lex(Tok);
 
   if (Tok.isNot(tok::eod)) {
     PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_extra_argument)
-      << PP.getSpelling(Tok);
+        << PP.getSpelling(Tok);
     return;
   }
 
@@ -3883,11 +3893,12 @@ bool Parser::HandlePragmaMSOptimize(StringRef 
PragmaName,
         << PragmaName << /*Expected=*/true << "'on' or 'off'";
     return false;
   }
-  IdentifierInfo *II = Tok.getIdentifierInfo();
+  IdentifierInfo *II =
+      Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
   if (!II || (!II->isStr("on") && !II->isStr("off"))) {
     PP.Diag(PragmaLocation, diag::warn_pragma_invalid_argument)
-        << PP.getSpelling(Tok) << PragmaName << /*Expected=*/true
-        << "'on' or 'off'";
+        << (Tok.isAnnotation() ? "" : PP.getSpelling(Tok)) << PragmaName
+        << /*Expected=*/true << "'on' or 'off'";
     return false;
   }
   bool IsOn = II->isStr("on");
@@ -3968,7 +3979,8 @@ void PragmaForceCUDAHostDeviceHandler::HandlePragma(
   Token FirstTok = Tok;
 
   PP.Lex(Tok);
-  IdentifierInfo *Info = Tok.getIdentifierInfo();
+  IdentifierInfo *Info =
+      Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
   if (!Info || (!Info->isStr("begin") && !Info->isStr("end"))) {
     PP.Diag(FirstTok.getLocation(),
             diag::warn_pragma_force_cuda_host_device_bad_arg);
@@ -4227,21 +4239,23 @@ void PragmaRISCVHandler::HandlePragma(Preprocessor &PP,
                                       Token &FirstToken) {
   Token Tok;
   PP.Lex(Tok);
-  IdentifierInfo *II = Tok.getIdentifierInfo();
+  IdentifierInfo *II =
+      Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
 
   if (!II || !II->isStr("intrinsic")) {
     PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
-        << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << 
"'intrinsic'";
+        << (Tok.isAnnotation() ? "" : PP.getSpelling(Tok)) << "riscv"
+        << /*Expected=*/true << "'intrinsic'";
     return;
   }
 
   PP.Lex(Tok);
-  II = Tok.getIdentifierInfo();
+  II = Tok.is(tok::identifier) ? Tok.getIdentifierInfo() : nullptr;
   if (!II || !(II->isStr("vector") || II->isStr("sifive_vector") ||
                II->isStr("andes_vector"))) {
     PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
-        << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true
-        << "'vector', 'sifive_vector' or 'andes_vector'";
+        << (Tok.isAnnotation() ? "" : PP.getSpelling(Tok)) << "riscv"
+        << /*Expected=*/true << "'vector', 'sifive_vector' or 'andes_vector'";
     return;
   }
 
diff --git a/clang/test/FixIt/fixit-pragma-attribute.cpp 
b/clang/test/FixIt/fixit-pragma-attribute.cpp
index 3824e45d8fca5..ac6e1b5a9041a 100644
--- a/clang/test/FixIt/fixit-pragma-attribute.cpp
+++ b/clang/test/FixIt/fixit-pragma-attribute.cpp
@@ -7,6 +7,11 @@
 // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:31-[[@LINE-1]]:31}:"__attribute__(("
 // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:49-[[@LINE-2]]:49}:"))"
 
+#pragma clang attribute push(const, apply_to=function)
+// CHECK: note: use the GNU '__attribute__' syntax
+// CHECK: fix-it:{{.*}}:{[[@LINE-2]]:30-[[@LINE-2]]:30}:"__attribute__(("
+// CHECK: fix-it:{{.*}}:{[[@LINE-3]]:36-[[@LINE-3]]:36}:"))"
+
 #pragma clang attribute push(__attribute__((annotate("test"))), apply_to = 
any( enum, function, function, namespace, function ))
 // CHECK: fix-it:{{.*}}:{[[@LINE-1]]:97-[[@LINE-1]]:107}:""
 // CHECK: fix-it:{{.*}}:{[[@LINE-2]]:118-[[@LINE-2]]:127}:""
diff --git a/clang/test/Parser/pragma-attribute.cpp 
b/clang/test/Parser/pragma-attribute.cpp
index 1f90a8990bb96..78699c06262cd 100644
--- a/clang/test/Parser/pragma-attribute.cpp
+++ b/clang/test/Parser/pragma-attribute.cpp
@@ -180,6 +180,13 @@ _Pragma("clang attribute pop");
 #pragma clang attribute push (annotate("test")) // expected-error {{expected 
an attribute that is specified using the GNU, C++11 or '__declspec' syntax}}
 // expected-note@-1 {{use the GNU '__attribute__' syntax}}
 
+// Nested pragmas must be diagnosed without crashing (GH225035).
+#pragma clang attribute (_Pragma("clang attribute push")) // expected-error 
{{expected an attribute that is specified using the GNU, C++11 or '__declspec' 
syntax}}
+#pragma clang attribute push (_Pragma("clang attribute push")) // 
expected-error {{expected an attribute that is specified using the GNU, C++11 
or '__declspec' syntax}}
+#pragma clang attribute push(__attribute__((annotate("test"))) _Pragma("clang 
attribute push")) // expected-error {{expected ','}}
+#pragma clang attribute push(__attribute__((annotate("test"))), _Pragma("clang 
attribute push")) // expected-error {{expected attribute subject set specifier 
'apply_to'}}
+#pragma clang attribute push(__attribute__((annotate("test"))), apply_to 
_Pragma("clang attribute push")) // expected-error {{expected '='}}
+
 #pragma clang attribute push([[clang::uninitialized]], apply_to = 
variable(is_local))
 #pragma clang attribute pop
 #pragma clang attribute push([[clang::uninitialized]], apply_to = function) // 
expected-error {{attribute 'clang::uninitialized' cannot be applied to 
'function'}}
diff --git a/clang/test/Parser/pragma-nested-annotation-target.c 
b/clang/test/Parser/pragma-nested-annotation-target.c
new file mode 100644
index 0000000000000..345a5b60ef7cc
--- /dev/null
+++ b/clang/test/Parser/pragma-nested-annotation-target.c
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -triple riscv64 -fsyntax-only -fms-extensions -DTEST_RISCV 
-verify=riscv %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x cuda -fsyntax-only 
-fms-extensions -DTEST_CUDA -verify=cuda %s
+
+// Existing recovery can leave inner pragma arguments in the token stream.
+// Use empty declarations to keep the invalid cases independent.
+
+#ifdef TEST_RISCV
+#pragma clang riscv _Pragma("weak foobar") intrinsic vector // riscv-warning 
{{unexpected argument '' to '#pragma riscv'; expected 'intrinsic'}}
+// riscv-error@-1 {{unknown type name 'foobar'}} riscv-error@-1 {{expected ';' 
after top level declarator}}
+;
+#pragma clang riscv intrinsic _Pragma("weak foobar") vector // riscv-warning 
{{unexpected argument '' to '#pragma riscv'; expected 'vector', 'sifive_vector' 
or 'andes_vector'}}
+// riscv-error@-1 {{unknown type name 'foobar'}} riscv-error@-1 {{expected ';' 
after top level declarator}}
+;
+
+// Invalid ordinary tokens keep their spelling.
+#pragma clang riscv 42 // riscv-warning {{unexpected argument '42' to '#pragma 
riscv'; expected 'intrinsic'}}
+#pragma clang riscv intrinsic wrong // riscv-warning {{unexpected argument 
'wrong' to '#pragma riscv'; expected 'vector', 'sifive_vector' or 
'andes_vector'}}
+#endif
+
+#ifdef TEST_CUDA
+#pragma clang force_cuda_host_device _Pragma("weak foobar") // cuda-warning 
{{incorrect use of #pragma clang force_cuda_host_device begin|end}}
+// cuda-error@-1 {{unknown type name 'foobar'}} cuda-error@-1 {{expected 
unqualified-id}}
+;
+
+#pragma clang force_cuda_host_device begin
+void host_device_function(void) {}
+#pragma clang force_cuda_host_device end
+#endif
+
+int after_pragmas;
+int use_after_pragmas(void) { return after_pragmas; }
diff --git a/clang/test/Parser/pragma-nested-annotation.c 
b/clang/test/Parser/pragma-nested-annotation.c
new file mode 100644
index 0000000000000..aef659ca0475d
--- /dev/null
+++ b/clang/test/Parser/pragma-nested-annotation.c
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -fsyntax-only -fms-extensions -verify=expected,c %s
+// RUN: %clang_cc1 -fsyntax-only -fms-extensions -fms-compatibility 
-verify=expected,c %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -fms-extensions -verify=expected,cxx %s
+
+// Nested _Pragma annotations must be rejected without querying identifier
+// information on the annotation token. Existing recovery can leave
+// inner pragma arguments in the token stream; expect the resulting errors and
+// use empty declarations to keep the cases independent.
+#pragma strict_gs_check(push, _Pragma("pack(1)")) // expected-warning 
{{unknown action for '#pragma strict_gs_check' - ignored}}
+#pragma optimize("", _Pragma("weak foobar")) // expected-warning {{unexpected 
argument '' to '#pragma optimize'; expected 'on' or 'off'}}
+#pragma optimize("", 42) // expected-warning {{unexpected argument '42' to 
'#pragma optimize'; expected 'on' or 'off'}}
+#pragma vtordisp(_Pragma("weak foobar")) // expected-warning {{unknown action 
for '#pragma vtordisp' - ignored}}
+// c-error@-1 {{type specifier missing}} c-error@-1 {{expected ';' after top 
level declarator}}
+// cxx-error@-2 {{unknown type name 'foobar'}} cxx-error@-2 {{expected 
unqualified-id}}
+;
+#pragma vtordisp(push, _Pragma("weak foobar")) // expected-warning {{unknown 
action for '#pragma vtordisp' - ignored}}
+// c-error@-1 {{type specifier missing}} c-error@-1 {{expected ';' after top 
level declarator}}
+// cxx-error@-2 {{unknown type name 'foobar'}} cxx-error@-2 {{expected 
unqualified-id}}
+;
+#pragma pointers_to_members(_Pragma("weak foobar")) // expected-warning 
{{expected identifier in '#pragma pointers_to_members' - ignored}}
+// c-error@-1 {{type specifier missing}} c-error@-1 {{expected ';' after top 
level declarator}}
+// cxx-error@-2 {{unknown type name 'foobar'}} cxx-error@-2 {{expected 
unqualified-id}}
+;
+#pragma pointers_to_members(full_generality, _Pragma("weak foobar")) // 
expected-error {{unexpected <annot_pragma_weak>, expected to see one of 
'single_inheritance', 'multiple_inheritance', or 'virtual_inheritance'}}
+// c-error@-1 {{type specifier missing}} c-error@-1 {{expected ';' after top 
level declarator}}
+// cxx-error@-2 {{unknown type name 'foobar'}} cxx-error@-2 {{expected 
unqualified-id}}
+;
+#pragma warning(_Pragma("weak foobar")) // expected-warning {{#pragma warning 
expected 'push', 'pop', 'default', 'disable', 'error', 'once', 'suppress', 1, 
2, 3, or 4}}
+// c-error@-1 {{type specifier missing}} c-error@-1 {{expected ';' after top 
level declarator}}
+// cxx-error@-2 {{unknown type name 'foobar'}} cxx-error@-2 {{expected 
unqualified-id}}
+;
+#pragma warning(disable : 1; _Pragma("weak foobar")) // expected-warning 
{{#pragma warning expected 'push', 'pop', 'default', 'disable', 'error', 
'once', 'suppress', 1, 2, 3, or 4}}
+// c-error@-1 {{type specifier missing}} c-error@-1 {{expected ';' after top 
level declarator}}
+// cxx-error@-2 {{unknown type name 'foobar'}} cxx-error@-2 {{expected 
unqualified-id}}
+;
+#pragma execution_character_set(_Pragma("weak foobar")) // expected-warning 
{{#pragma execution_character_set expected 'push' or 'pop'}}
+// c-error@-1 {{type specifier missing}} c-error@-1 {{expected ';' after top 
level declarator}}
+// cxx-error@-2 {{unknown type name 'foobar'}} cxx-error@-2 {{expected 
unqualified-id}}
+;
+
+void loop_state(void) {
+#pragma clang loop vectorize(_Pragma("weak foobar")) // expected-error 
{{invalid argument; expected 'enable', 'assume_safety' or 'disable'}}
+  for (int i = 0; i < 4; ++i) {}
+}
+
+void loop_width(void) {
+#pragma clang loop vectorize_width(_Pragma("weak foobar")) // expected-error 
{{expected expression}} expected-note {{vectorize_width loop hint malformed}} 
expected-warning {{extra tokens at end of '#pragma clang loop vectorize_width' 
- ignored}}
+  for (int i = 0; i < 4; ++i) {}
+}
+
+void loop_width_second_arg(void) {
+#pragma clang loop vectorize_width(4, _Pragma("weak foobar")) // 
expected-error {{vectorize_width loop hint malformed}} expected-warning {{extra 
tokens at end of '#pragma clang loop vectorize_width' - ignored}}
+  for (int i = 0; i < 4; ++i) {}
+}
+
+// Preserve the non-identifier alternatives in valid pragmas.
+#pragma vtordisp()
+#pragma vtordisp(2)
+#pragma vtordisp(push, 1)
+#pragma vtordisp(pop)
+#pragma warning(default : 1; 2 : 2)
+#pragma GCC visibility push(default)
+#pragma GCC visibility pop
+#pragma GCC visibility push(protected)
+#pragma GCC visibility pop
+
+// __pragma captures expanded tokens, so even LexUnexpandedToken can return
+// annotations to the namespace dispatch and pragma handlers.
+__pragma(GCC _Pragma("weak foobar") ivdep)
+__pragma(GCC visibility _Pragma("weak foobar")) // expected-warning {{expected 
identifier in '#pragma visibility' - ignored}}
+__pragma(GCC visibility push(_Pragma("weak foobar"))) // expected-warning 
{{expected identifier in '#pragma visibility' - ignored}}
+__pragma(clang arc_cf_code_audited _Pragma("weak foobar")) // expected-error 
{{expected 'begin' or 'end'}}
+__pragma(clang assume_nonnull _Pragma("weak foobar")) // expected-error 
{{expected 'begin' or 'end'}}
+__pragma(clang __set_pp_state _Pragma("weak foobar")) // expected-error 
{{expected identifier after '#pragma clang __set_pp_state'}}
+__pragma(clang __debug macro _Pragma("weak foobar")) // expected-warning 
{{missing argument to debug command 'macro'}}
+__pragma(clang __debug module_lookup _Pragma("weak foobar")) // 
expected-warning {{missing argument to debug command 'module_lookup'}}
+__pragma(clang __debug modules _Pragma("weak foobar")) // expected-warning 
{{missing argument to debug command 'modules'}}
+
+// Macro names may be keywords.
+#define int int
+__pragma(clang __debug macro int)
+#undef int
+
+int after_pragmas;
+int use_after_pragmas(void) { return after_pragmas; }
diff --git a/clang/unittests/Lex/LexerTest.cpp 
b/clang/unittests/Lex/LexerTest.cpp
index 8f632ccc5b931..6dd78d0d1ade8 100644
--- a/clang/unittests/Lex/LexerTest.cpp
+++ b/clang/unittests/Lex/LexerTest.cpp
@@ -22,6 +22,7 @@
 #include "clang/Lex/MacroArgs.h"
 #include "clang/Lex/MacroInfo.h"
 #include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/Pragma.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/PreprocessorOptions.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -135,6 +136,30 @@ class LexerTest : public ::testing::Test {
   std::string PreDefines;
 };
 
+TEST_F(LexerTest, PragmaKeywordAliasesKeepTheirNames) {
+  class RecordingPragmaHandler : public PragmaHandler {
+    std::vector<std::string> &Names;
+
+  public:
+    RecordingPragmaHandler(StringRef Name, std::vector<std::string> &Names)
+        : PragmaHandler(Name), Names(Names) {}
+
+    void HandlePragma(Preprocessor &, PragmaIntroducer, Token &) override {
+      Names.push_back(getName().str());
+    }
+  };
+
+  std::vector<std::string> Names;
+  for (StringRef Name : {"const", "__const__"})
+    PP->AddPragmaHandler(new RecordingPragmaHandler(Name, Names));
+  PP->AddPragmaHandler("test", new RecordingPragmaHandler("__const__", Names));
+
+  Lex("#pragma const\n"
+      "#pragma __const__\n"
+      "#pragma test __const__\n");
+  EXPECT_THAT(Names, ElementsAre("const", "__const__", "__const__"));
+}
+
 TEST_F(LexerTest, GetSourceTextExpandsToMaximumInMacroArgument) {
   std::vector<tok::TokenKind> ExpectedTokens;
   ExpectedTokens.push_back(tok::identifier);

>From d3f45ee062695b81146025a25785762f25927e4c Mon Sep 17 00:00:00 2001
From: Chen Miao <[email protected]>
Date: Sun, 18 Oct 2026 05:16:28 +0800
Subject: [PATCH 2/4] [clang] Preserve operator keyword names in pragma
 handlers

---
 clang/lib/Lex/Pragma.cpp                     | 34 +++++++++-----------
 clang/test/Parser/pragma-attribute.cpp       |  3 --
 clang/test/Parser/pragma-nested-annotation.c |  9 +++---
 clang/unittests/Lex/LexerTest.cpp            | 18 +++++++++--
 4 files changed, 35 insertions(+), 29 deletions(-)

diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index e47bbc7402ef5..6a2e209ff5510 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -101,6 +101,13 @@ void PragmaNamespace::RemovePragmaHandler(PragmaHandler 
*Handler) {
   Handlers.erase(I);
 }
 
+// Names may be C++ operator keywords, which have punctuator token kinds.
+static IdentifierInfo *getPragmaIdentifierInfo(const Token &Tok) {
+  if (Tok.isAnnotation() || Tok.is(tok::raw_identifier))
+    return nullptr;
+  return Tok.getIdentifierInfo();
+}
+
 void PragmaNamespace::HandlePragma(Preprocessor &PP,
                                    PragmaIntroducer Introducer, Token &Tok) {
   // Read the 'namespace' that the directive is in, e.g. STDC.  Do not macro
@@ -108,11 +115,9 @@ void PragmaNamespace::HandlePragma(Preprocessor &PP,
   PP.LexUnexpandedToken(Tok);
 
   // Get the handler for this token.  If there is no handler, ignore the 
pragma.
-  PragmaHandler *Handler = FindHandler(
-      Tok.is(tok::identifier) || tok::getKeywordSpelling(Tok.getKind())
-          ? Tok.getIdentifierInfo()->getName()
-          : StringRef(),
-      /*IgnoreNull=*/false);
+  IdentifierInfo *II = getPragmaIdentifierInfo(Tok);
+  PragmaHandler *Handler =
+      FindHandler(II ? II->getName() : StringRef(), /*IgnoreNull=*/false);
   if (!Handler) {
     PP.Diag(Tok, diag::warn_pragma_ignored);
     return;
@@ -922,12 +927,12 @@ void 
Preprocessor::HandlePragmaSetPPState(PragmaIntroducer Introducer,
                                           Token &Tok) {
   // Lex the macro name we want to set.
   LexUnexpandedToken(Tok);
-  if (Tok.isNot(tok::identifier) && !tok::getKeywordSpelling(Tok.getKind())) {
+  IdentifierInfo *MacroName = getPragmaIdentifierInfo(Tok);
+  if (!MacroName) {
     Diag(Tok.getLocation(), diag::err_pp_pragma_set_pp_state_expected_name);
     return;
   }
 
-  IdentifierInfo *MacroName = Tok.getIdentifierInfo();
   if (!isPragmaSetPPStateMacro(MacroName)) {
     Diag(Tok.getLocation(), diag::err_pp_pragma_set_pp_state_invalid_arg)
         << MacroName;
@@ -1150,10 +1155,7 @@ struct PragmaDebugHandler : public PragmaHandler {
     } else if (II->isStr("macro")) {
       Token MacroName;
       PP.LexUnexpandedToken(MacroName);
-      auto *MacroII = MacroName.is(tok::identifier) ||
-                              tok::getKeywordSpelling(MacroName.getKind())
-                          ? MacroName.getIdentifierInfo()
-                          : nullptr;
+      auto *MacroII = getPragmaIdentifierInfo(MacroName);
       if (MacroII)
         PP.dumpMacroInfo(MacroII);
       else
@@ -1178,10 +1180,7 @@ struct PragmaDebugHandler : public PragmaHandler {
     } else if (II->isStr("module_lookup")) {
       Token MName;
       PP.LexUnexpandedToken(MName);
-      auto *MNameII =
-          MName.is(tok::identifier) || tok::getKeywordSpelling(MName.getKind())
-              ? MName.getIdentifierInfo()
-              : nullptr;
+      auto *MNameII = getPragmaIdentifierInfo(MName);
       if (!MNameII) {
         PP.Diag(MName, diag::warn_pragma_debug_missing_argument)
             << II->getName();
@@ -1226,10 +1225,7 @@ struct PragmaDebugHandler : public PragmaHandler {
 
       Token Kind;
       PP.LexUnexpandedToken(Kind);
-      auto *DumpII =
-          Kind.is(tok::identifier) || tok::getKeywordSpelling(Kind.getKind())
-              ? Kind.getIdentifierInfo()
-              : nullptr;
+      auto *DumpII = getPragmaIdentifierInfo(Kind);
       if (!DumpII) {
         PP.Diag(Kind, diag::warn_pragma_debug_missing_argument)
             << II->getName();
diff --git a/clang/test/Parser/pragma-attribute.cpp 
b/clang/test/Parser/pragma-attribute.cpp
index 78699c06262cd..e2fb747d035b8 100644
--- a/clang/test/Parser/pragma-attribute.cpp
+++ b/clang/test/Parser/pragma-attribute.cpp
@@ -182,10 +182,7 @@ _Pragma("clang attribute pop");
 
 // Nested pragmas must be diagnosed without crashing (GH225035).
 #pragma clang attribute (_Pragma("clang attribute push")) // expected-error 
{{expected an attribute that is specified using the GNU, C++11 or '__declspec' 
syntax}}
-#pragma clang attribute push (_Pragma("clang attribute push")) // 
expected-error {{expected an attribute that is specified using the GNU, C++11 
or '__declspec' syntax}}
 #pragma clang attribute push(__attribute__((annotate("test"))) _Pragma("clang 
attribute push")) // expected-error {{expected ','}}
-#pragma clang attribute push(__attribute__((annotate("test"))), _Pragma("clang 
attribute push")) // expected-error {{expected attribute subject set specifier 
'apply_to'}}
-#pragma clang attribute push(__attribute__((annotate("test"))), apply_to 
_Pragma("clang attribute push")) // expected-error {{expected '='}}
 
 #pragma clang attribute push([[clang::uninitialized]], apply_to = 
variable(is_local))
 #pragma clang attribute pop
diff --git a/clang/test/Parser/pragma-nested-annotation.c 
b/clang/test/Parser/pragma-nested-annotation.c
index aef659ca0475d..7b4a517629295 100644
--- a/clang/test/Parser/pragma-nested-annotation.c
+++ b/clang/test/Parser/pragma-nested-annotation.c
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -fsyntax-only -fms-extensions -verify=expected,c %s
-// RUN: %clang_cc1 -fsyntax-only -fms-extensions -fms-compatibility 
-verify=expected,c %s
 // RUN: %clang_cc1 -x c++ -fsyntax-only -fms-extensions -verify=expected,cxx %s
 
 // Nested _Pragma annotations must be rejected without querying identifier
@@ -54,10 +53,7 @@ void loop_width_second_arg(void) {
 }
 
 // Preserve the non-identifier alternatives in valid pragmas.
-#pragma vtordisp()
 #pragma vtordisp(2)
-#pragma vtordisp(push, 1)
-#pragma vtordisp(pop)
 #pragma warning(default : 1; 2 : 2)
 #pragma GCC visibility push(default)
 #pragma GCC visibility pop
@@ -81,5 +77,10 @@ __pragma(clang __debug modules _Pragma("weak foobar")) // 
expected-warning {{mis
 __pragma(clang __debug macro int)
 #undef int
 
+// MS extensions also permit C++ operator names as macro names.
+#define and 1
+#pragma clang __debug macro and
+#undef and
+
 int after_pragmas;
 int use_after_pragmas(void) { return after_pragmas; }
diff --git a/clang/unittests/Lex/LexerTest.cpp 
b/clang/unittests/Lex/LexerTest.cpp
index 6dd78d0d1ade8..8d06ccf0222a7 100644
--- a/clang/unittests/Lex/LexerTest.cpp
+++ b/clang/unittests/Lex/LexerTest.cpp
@@ -137,6 +137,11 @@ class LexerTest : public ::testing::Test {
 };
 
 TEST_F(LexerTest, PragmaKeywordAliasesKeepTheirNames) {
+  LangOpts.CPlusPlus = true;
+  LangOpts.CXXOperatorNames = true;
+  PP = std::make_unique<Preprocessor>(PPOpts, Diags, LangOpts, SourceMgr,
+                                      HeaderInfo, ModLoader);
+
   class RecordingPragmaHandler : public PragmaHandler {
     std::vector<std::string> &Names;
 
@@ -150,14 +155,21 @@ TEST_F(LexerTest, PragmaKeywordAliasesKeepTheirNames) {
   };
 
   std::vector<std::string> Names;
-  for (StringRef Name : {"const", "__const__"})
+  for (StringRef Name : {"const", "__const__", "and", "or"})
     PP->AddPragmaHandler(new RecordingPragmaHandler(Name, Names));
   PP->AddPragmaHandler("test", new RecordingPragmaHandler("__const__", Names));
+  PP->AddPragmaHandler("test", new RecordingPragmaHandler("or", Names));
 
   Lex("#pragma const\n"
       "#pragma __const__\n"
-      "#pragma test __const__\n");
-  EXPECT_THAT(Names, ElementsAre("const", "__const__", "__const__"));
+      "#pragma test __const__\n"
+      "#pragma and\n"
+      "#pragma or\n"
+      "#pragma test or\n"
+      "#pragma &&\n"
+      "#pragma test ||\n");
+  EXPECT_THAT(
+      Names, ElementsAre("const", "__const__", "__const__", "and", "or", 
"or"));
 }
 
 TEST_F(LexerTest, GetSourceTextExpandsToMaximumInMacroArgument) {

>From 7d454b414929d3fe083b79434899bc7d51c947cd Mon Sep 17 00:00:00 2001
From: Chen Miao <[email protected]>
Date: Tue, 20 Oct 2026 02:32:51 +0800
Subject: [PATCH 3/4] [clang] Simplify release note for nested pragma crashes

---
 clang/docs/ReleaseNotes.md | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 4867f40c51cae..4dc911a9b3c3d 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -947,9 +947,7 @@ features cannot lower the translation-unit ABI level;
 
 #### Miscellaneous Clang Crashes Fixed
 
-- Fixed crashes when nested `_Pragma` or Microsoft `__pragma` expressions
-  introduce annotation tokens where a pragma expects an identifier. (#GH225035)
-
+- Fixed crashes when `_Pragma` is used inside another pragma. (#GH225035)
 - Fixed a crash when Microsoft extensions were enabled and an unterminated
   `__identifier` expression reached the end of a preprocessing directive or
   source file. (#GH222310)

>From fed61187157edd076b1e11d80ef8f57dcd89ae85 Mon Sep 17 00:00:00 2001
From: Chen Miao <[email protected]>
Date: Tue, 20 Oct 2026 03:27:45 +0800
Subject: [PATCH 4/4] [clang] Replace pragma keyword unit test with regression
 coverage

---
 clang/test/Parser/pragma-nested-annotation.c | 41 ++++++++++++++++----
 clang/unittests/Lex/LexerTest.cpp            | 37 ------------------
 2 files changed, 34 insertions(+), 44 deletions(-)

diff --git a/clang/test/Parser/pragma-nested-annotation.c 
b/clang/test/Parser/pragma-nested-annotation.c
index 7b4a517629295..78cfa7ede694b 100644
--- a/clang/test/Parser/pragma-nested-annotation.c
+++ b/clang/test/Parser/pragma-nested-annotation.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -fms-extensions -verify=expected,c %s
-// RUN: %clang_cc1 -x c++ -fsyntax-only -fms-extensions -verify=expected,cxx %s
+// RUN: %clang_cc1 -fsyntax-only -fms-extensions -verify=expected,c %s 2>&1 | 
FileCheck %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -fms-extensions -verify=expected,cxx 
%s 2>&1 | FileCheck %s
 
 // Nested _Pragma annotations must be rejected without querying identifier
 // information on the annotation token. Existing recovery can leave
@@ -72,15 +72,42 @@ __pragma(clang __debug macro _Pragma("weak foobar")) // 
expected-warning {{missi
 __pragma(clang __debug module_lookup _Pragma("weak foobar")) // 
expected-warning {{missing argument to debug command 'module_lookup'}}
 __pragma(clang __debug modules _Pragma("weak foobar")) // expected-warning 
{{missing argument to debug command 'modules'}}
 
-// Macro names may be keywords.
+// Keywords and aliases must retain their original macro names.
+#define const 1
+#pragma clang __debug macro const
+// CHECK-LABEL: MacroState {{.*}} const{{$}}
+// CHECK: #define <macro> 1{{$}}
+#undef const
+
+#define __const__ 2
+#pragma clang __debug macro __const__
+// CHECK-LABEL: MacroState {{.*}} __const__{{$}}
+// CHECK: #define <macro> 2{{$}}
+#undef __const__
+
+// C++ operator keywords carry identifier information despite punctuator kinds.
+#define and 3
+#pragma clang __debug macro and
+// CHECK-LABEL: MacroState {{.*}} and{{$}}
+// CHECK: #define <macro> 3{{$}}
+#undef and
+
+#define or 4
+#pragma clang __debug macro or
+// CHECK-LABEL: MacroState {{.*}} or{{$}}
+// CHECK: #define <macro> 4{{$}}
+#undef or
+
+// A self-referential macro preserves the keyword through __pragma expansion.
 #define int int
 __pragma(clang __debug macro int)
+// CHECK-LABEL: MacroState {{.*}} int{{$}}
+// CHECK: #define <macro> int{{$}}
 #undef int
 
-// MS extensions also permit C++ operator names as macro names.
-#define and 1
-#pragma clang __debug macro and
-#undef and
+// Punctuators must not be treated as operator keyword names.
+#pragma clang __debug macro && // expected-warning {{missing argument to debug 
command 'macro'}}
+#pragma clang __debug macro || // expected-warning {{missing argument to debug 
command 'macro'}}
 
 int after_pragmas;
 int use_after_pragmas(void) { return after_pragmas; }
diff --git a/clang/unittests/Lex/LexerTest.cpp 
b/clang/unittests/Lex/LexerTest.cpp
index 8d06ccf0222a7..8f632ccc5b931 100644
--- a/clang/unittests/Lex/LexerTest.cpp
+++ b/clang/unittests/Lex/LexerTest.cpp
@@ -22,7 +22,6 @@
 #include "clang/Lex/MacroArgs.h"
 #include "clang/Lex/MacroInfo.h"
 #include "clang/Lex/ModuleLoader.h"
-#include "clang/Lex/Pragma.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/PreprocessorOptions.h"
 #include "llvm/ADT/ArrayRef.h"
@@ -136,42 +135,6 @@ class LexerTest : public ::testing::Test {
   std::string PreDefines;
 };
 
-TEST_F(LexerTest, PragmaKeywordAliasesKeepTheirNames) {
-  LangOpts.CPlusPlus = true;
-  LangOpts.CXXOperatorNames = true;
-  PP = std::make_unique<Preprocessor>(PPOpts, Diags, LangOpts, SourceMgr,
-                                      HeaderInfo, ModLoader);
-
-  class RecordingPragmaHandler : public PragmaHandler {
-    std::vector<std::string> &Names;
-
-  public:
-    RecordingPragmaHandler(StringRef Name, std::vector<std::string> &Names)
-        : PragmaHandler(Name), Names(Names) {}
-
-    void HandlePragma(Preprocessor &, PragmaIntroducer, Token &) override {
-      Names.push_back(getName().str());
-    }
-  };
-
-  std::vector<std::string> Names;
-  for (StringRef Name : {"const", "__const__", "and", "or"})
-    PP->AddPragmaHandler(new RecordingPragmaHandler(Name, Names));
-  PP->AddPragmaHandler("test", new RecordingPragmaHandler("__const__", Names));
-  PP->AddPragmaHandler("test", new RecordingPragmaHandler("or", Names));
-
-  Lex("#pragma const\n"
-      "#pragma __const__\n"
-      "#pragma test __const__\n"
-      "#pragma and\n"
-      "#pragma or\n"
-      "#pragma test or\n"
-      "#pragma &&\n"
-      "#pragma test ||\n");
-  EXPECT_THAT(
-      Names, ElementsAre("const", "__const__", "__const__", "and", "or", 
"or"));
-}
-
 TEST_F(LexerTest, GetSourceTextExpandsToMaximumInMacroArgument) {
   std::vector<tok::TokenKind> ExpectedTokens;
   ExpectedTokens.push_back(tok::identifier);

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

Reply via email to