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

>From 774f0176cad0716b4990f1c7290813e876735fa8 Mon Sep 17 00:00:00 2001
From: Chen Miao <[email protected]>
Date: Mon, 5 Oct 2026 15:12:50 +0800
Subject: [PATCH 1/2] [clang] Fix pragma attribute crashes caused by nested
 _Pragma

A nested `_Pragma` can produce an `annot_pragma_attribute` token during
preprocessing. After diagnosing invalid attribute syntax,
`HandlePragmaAttribute` calls `getIdentifierInfo()` to generate a fix-it
without checking whether the current token is an annotation.
`getAttributeSubjectRulesRecoveryPointForToken`, which handles recovery
for attribute subject rules, has the same problem.

For example, this input enters the attribute syntax error path:

```c
#pragma clang attribute (_Pragma("clang attribute push"))
```

In the following input, the attribute itself is valid, but a nested
`_Pragma` appears where `apply_to` is expected, entering the attribute
subject rule recovery path:

```c
#pragma clang attribute push(__attribute__((annotate("test"))), _Pragma("clang 
attribute push"))
```

Before this change, both inputs fail in assertion-enabled builds with:

```text
Assertion `!isAnnotation() && "getIdentifierInfo() on an annotation token!"' 
failed.
```

Check for annotation tokens before querying identifier information in
`HandlePragmaAttribute`. Return `None` for annotation tokens in
`getAttributeSubjectRulesRecoveryPointForToken` so that the existing
error recovery logic can handle them.

The two inputs now produce the following diagnostics, respectively:

```text
error: expected an attribute that is specified using the GNU, C++11 or 
'__declspec' syntax
error: expected attribute subject set specifier 'apply_to'
```

Fixes #225035
---
 clang/lib/Parse/ParsePragma.cpp        | 8 +++++++-
 clang/test/Parser/pragma-attribute.cpp | 7 +++++++
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index f58d2c70b7d980..34a9ed09fec8ed 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -1870,6 +1870,10 @@ enum class MissingAttributeSubjectRulesRecoveryPoint {
 
 MissingAttributeSubjectRulesRecoveryPoint
 getAttributeSubjectRulesRecoveryPointForToken(const Token &Tok) {
+  // Nested `_Pragma` annotations cannot name attribute subject rules.
+  // https://github.com/llvm/llvm-project/issues/225035
+  if (Tok.isAnnotation())
+    return MissingAttributeSubjectRulesRecoveryPoint::None;
   if (const auto *II = Tok.getIdentifierInfo()) {
     if (II->isStr("apply_to"))
       return MissingAttributeSubjectRulesRecoveryPoint::ApplyTo;
@@ -2038,7 +2042,9 @@ void Parser::HandlePragmaAttribute() {
     ParseMicrosoftDeclSpecs(Attrs);
   } else {
     Diag(Tok, diag::err_pragma_attribute_expected_attribute_syntax);
-    if (Tok.getIdentifierInfo()) {
+    // A nested `_Pragma` can produce an annotation token here.
+    // https://github.com/llvm/llvm-project/issues/225035
+    if (!Tok.isAnnotation() && Tok.getIdentifierInfo()) {
       // If we suspect that this is an attribute suggest the use of
       // '__attribute__'.
       if (ParsedAttr::getParsedKind(
diff --git a/clang/test/Parser/pragma-attribute.cpp 
b/clang/test/Parser/pragma-attribute.cpp
index 1f90a8990bb96e..78699c06262cd7 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'}}

>From f8c5fbe0def3e9863fe308b7d9f3effe9619d9f6 Mon Sep 17 00:00:00 2001
From: Chen Miao <[email protected]>
Date: Sat, 10 Oct 2026 07:04:51 +0800
Subject: [PATCH 2/2] [clang] Fix crashes and recovery for nested pragmas

Check token kinds before reading identifier information, and omit annotation
token spellings from diagnostics and dependency messages. Preserve valid
keyword arguments and aliases.

Track active pragma lexer boundaries so an inner end-of-directive token does
not terminate an enclosing pragma, including when arguments extend beyond a
macro expansion. Ignore captured __pragma(mark ...) arguments when no
character lexer is available.

Fixes #225035
---
 clang/docs/ReleaseNotes.md                    |   7 ++
 .../clang/Basic/DiagnosticParseKinds.td       |  10 +-
 clang/include/clang/Lex/Preprocessor.h        |   9 ++
 clang/include/clang/Lex/TokenLexer.h          |   7 ++
 clang/lib/Lex/Pragma.cpp                      |  84 ++++++++++---
 clang/lib/Lex/Preprocessor.cpp                |  14 ++-
 clang/lib/Lex/TokenLexer.cpp                  |   2 +
 clang/lib/Parse/ParsePragma.cpp               | 111 ++++++++++++------
 clang/test/FixIt/fixit-pragma-attribute.cpp   |   5 +
 clang/test/Lexer/pragma-mark.c                |  14 +++
 .../Parser/pragma-nested-annotation-target.c  |  22 ++++
 clang/test/Parser/pragma-nested-annotation.c  | 102 ++++++++++++++++
 .../pragma-dependency-nested-annotation.c     |  13 ++
 .../Preprocessor/print-pragma-microsoft.c     |  12 ++
 clang/unittests/Lex/LexerTest.cpp             |  25 ++++
 clang/unittests/Lex/PPCallbacksTest.cpp       |  16 +++
 16 files changed, 395 insertions(+), 58 deletions(-)
 create mode 100644 clang/test/Parser/pragma-nested-annotation-target.c
 create mode 100644 clang/test/Parser/pragma-nested-annotation.c
 create mode 100644 
clang/test/Preprocessor/pragma-dependency-nested-annotation.c

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 7ec126a065ae5a..f05a74b36a06e8 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -850,6 +850,13 @@ features cannot lower the translation-unit ABI level;
 
 #### Miscellaneous Clang Crashes Fixed
 
+- Fixed crashes when nested `_Pragma` or Microsoft `__pragma` expressions
+  introduce annotation tokens into pragma arguments. Invalid arguments are now
+  diagnosed without crashing.
+  Improved error recovery for nested pragmas, including those that start in a
+  macro expansion and end outside it, preventing premature termination of the
+  enclosing pragma and spurious errors in subsequent code.
+  Also fixed a separate crash in `__pragma(mark ...)`. (#GH225035)
 - Fixed a crash in CTAD for type alias templates when the aggregate deduction 
guide could not be resolved. (#GH206994)
 - Fixed a crash when instantiating an invalid dependent friend destructor 
declaration in a class template. (#GH210234)
 - Fixed an assertion failure in `-extract-api` when a documentation comment
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 594d158d25e928..df82177ebe4b5c 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1088,8 +1088,10 @@ def warn_pragma_expected_string : Warning<
   "expected string literal in '#pragma %0' - ignoring">, 
InGroup<IgnoredPragmas>;
 def warn_pragma_missing_argument : Warning<
   "missing argument to '#pragma %0'%select{|; expected %2}1">, 
InGroup<IgnoredPragmas>;
+// Annotation tokens have no source spelling; allow omitting it.
 def warn_pragma_invalid_argument : Warning<
-  "unexpected argument '%0' to '#pragma %1'%select{|; expected %3}2">, 
InGroup<IgnoredPragmas>;
+  "unexpected argument%select{ '%0'|}4 to '#pragma %1'"
+  "%select{|; expected %3}2">, InGroup<IgnoredPragmas>;
 
 def err_pragma_misplaced_in_decl : Error<"this pragma cannot appear in %0 
declaration">;
 
@@ -1217,10 +1219,10 @@ def err_pragma_pointers_to_members_unknown_kind : Error<
   "'single_inheritance', 'multiple_inheritance', or 'virtual_inheritance'">;
 // - #pragma clang optimize on/off
 def err_pragma_optimize_invalid_argument : Error<
-  "unexpected argument '%0' to '#pragma clang optimize'; "
+  "unexpected argument%select{ '%0'|}1 to '#pragma clang optimize'; "
   "expected 'on' or 'off'">;
 def err_pragma_optimize_extra_argument : Error<
-  "unexpected extra argument '%0' to '#pragma clang optimize'">;
+  "unexpected extra argument%select{ '%0'|}1 to '#pragma clang optimize'">;
 // - #pragma clang attribute
 def err_pragma_attribute_expected_push_pop_paren : Error<
   "expected 'push', 'pop', or '(' after '#pragma clang attribute'">;
@@ -1597,7 +1599,7 @@ def note_pragma_loop_invalid_vectorize_option : Note<
 def err_pragma_fp_invalid_option : Error<
   "%select{invalid|missing}0 option%select{ %1|}0; expected 'contract', 
'reassociate', 'reciprocal', or 'exceptions'">;
 def err_pragma_fp_invalid_argument : Error<
-  "unexpected argument '%0' to '#pragma clang fp %1'; expected "
+  "unexpected argument%select{ '%0'|}3 to '#pragma clang fp %1'; expected "
   "%select{"
   "'fast' or 'on' or 'off'|"
   "'on' or 'off'|"
diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index 31b68a0fd0670e..1f1b5253bfb3fc 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -883,6 +883,10 @@ class Preprocessor {
   };
   std::vector<IncludeStackInfo> IncludeMacroStack;
 
+  /// Stack depths of the pragmas whose arguments are being read. Track all
+  /// active scopes so that macro stack pops update enclosing boundaries too.
+  SmallVector<size_t, 4> PragmaLexerStackDepths;
+
   /// Actions invoked when some preprocessor activity is
   /// encountered (e.g. a file is \#included, etc).
   std::unique_ptr<PPCallbacks> Callbacks;
@@ -2655,6 +2659,11 @@ class Preprocessor {
     CurLexerSubmodule = IncludeMacroStack.back().TheSubmodule;
     CurLexerCallback = IncludeMacroStack.back().CurLexerCallback;
     IncludeMacroStack.pop_back();
+
+    // A __pragma can start in a macro and finish in its enclosing token 
stream.
+    // Keep all active pragma boundaries within the remaining lexer stack.
+    for (size_t &Depth : PragmaLexerStackDepths)
+      Depth = std::min(Depth, IncludeMacroStack.size());
   }
 
   void PropagateLineStartLeadingSpaceInfo(Token &Result);
diff --git a/clang/include/clang/Lex/TokenLexer.h 
b/clang/include/clang/Lex/TokenLexer.h
index 0c0c5742673648..df7b0bebc4c061 100644
--- a/clang/include/clang/Lex/TokenLexer.h
+++ b/clang/include/clang/Lex/TokenLexer.h
@@ -104,6 +104,9 @@ class TokenLexer {
   /// directive.
   bool LexingCXXModuleDirective : 1;
 
+  /// This lexer contains the captured tokens of a __pragma directive.
+  bool IsPragmaLexer : 1;
+
 public:
   /// Create a TokenLexer for the specified macro with the specified actual
   /// arguments.  Note that this ctor takes ownership of the ActualArgs 
pointer.
@@ -155,6 +158,10 @@ class TokenLexer {
   /// preprocessor directive.
   bool isParsingPreprocessorDirective() const;
 
+  /// Return true if this lexer contains the captured tokens of a __pragma
+  /// directive.
+  bool isPragmaLexer() const { return IsPragmaLexer; }
+
   /// setLexingCXXModuleDirective - This is set to true if this TokenLexer is
   /// created when handling a C++ module directive.
   void setLexingCXXModuleDirective(bool Val = true);
diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index 9e9f1d21980e37..15f07341a4465b 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -35,6 +35,7 @@
 #include "clang/Lex/TokenLexer.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Compiler.h"
@@ -108,10 +109,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;
@@ -170,6 +172,21 @@ void Preprocessor::HandlePragmaDirective(PragmaIntroducer 
Introducer) {
 
   ++NumPragma;
 
+  // Record this pragma's lexer stack depth so Lex() can distinguish its eod
+  // from an eod left by a nested pragma. For example:
+  //
+  //   #pragma vtordisp(_Pragma("clang __debug dump x"))
+  //   int after;
+  //
+  // The inner __debug dump leaves its arguments and eod for the parser:
+  //
+  //   annot_pragma_dump x <inner eod> ) <outer eod>
+  //
+  // Lex() must skip the inner eod so the outer handler's error recovery also
+  // consumes the trailing ')' and leaves the following declaration intact.
+  PragmaLexerStackDepths.push_back(IncludeMacroStack.size());
+  llvm::scope_exit PragmaScope([this] { PragmaLexerStackDepths.pop_back(); });
+
   // Invoke the first level of pragma handlers which reads the namespace id.
   Token Tok;
   PragmaHandlers->HandlePragma(*this, Introducer, Tok);
@@ -353,6 +370,16 @@ void clang::prepare_PragmaString(SmallVectorImpl<char> 
&StrVal) {
 /// HandleMicrosoft__pragma - Like Handle_Pragma except the pragma text
 /// is not enclosed within a string literal.
 void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
+  // Expanding the captured arguments can execute nested pragmas before the
+  // outer handler runs. For example:
+  //
+  //   __pragma(optimize("", _Pragma("clang __debug dump x")))
+  //
+  // Keep a boundary active during capture too, so Lex() skips the inner
+  // __debug dump's leftover eod rather than including it in PragmaToks.
+  PragmaLexerStackDepths.push_back(IncludeMacroStack.size());
+  llvm::scope_exit PragmaScope([this] { PragmaLexerStackDepths.pop_back(); });
+
   // During macro pre-expansion, check the syntax now but put the tokens back
   // into the token stream for later consumption. Same as Handle_Pragma.
   TokenCollector Toks = {*this, InMacroArgPreExpansion, {}, Tok};
@@ -402,6 +429,7 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) {
   // Push the tokens onto the stack.
   EnterTokenStream(TokArray, PragmaToks.size(), true, true,
                    /*IsReinject*/ false);
+  CurTokenLexer->IsPragmaLexer = true;
 
   // With everything set up, lex this as a #pragma directive.
   HandlePragmaDirective({PIK___pragma, PragmaLoc});
@@ -427,7 +455,12 @@ void Preprocessor::HandlePragmaOnce(Token &OnceTok) {
 }
 
 void Preprocessor::HandlePragmaMark(Token &MarkTok) {
-  assert(CurPPLexer && "No current lexer?");
+  // __pragma uses a captured token stream, so there is no lexer from which to
+  // read the uninterpreted text. Ignore the mark and consume its arguments.
+  if (!CurLexer) {
+    DiscardUntilEndOfDirective();
+    return;
+  }
 
   SmallString<64> Buffer;
   CurLexer->ReadToEndOfLine(&Buffer);
@@ -553,7 +586,8 @@ void Preprocessor::HandlePragmaDependency(Token 
&DependencyTok) {
     std::string Message;
     Lex(DependencyTok);
     while (DependencyTok.isNot(tok::eod)) {
-      Message += getSpelling(DependencyTok) + " ";
+      if (!DependencyTok.isAnnotation())
+        Message += getSpelling(DependencyTok) + " ";
       Lex(DependencyTok);
     }
 
@@ -921,7 +955,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;
   }
@@ -1153,7 +1187,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
@@ -1178,7 +1215,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();
@@ -1223,7 +1263,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();
@@ -1459,7 +1502,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 ] )
@@ -1490,9 +1535,13 @@ 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);
+          if (Tok.isAnnotation())
+            PP.DiscardUntilEndOfDirective();
           return;
         }
 
@@ -1607,7 +1656,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 ] )
@@ -1636,6 +1686,8 @@ struct PragmaExecCharsetHandler : public PragmaHandler {
         Callbacks->PragmaExecCharsetPop(DiagLoc);
     } else {
       PP.Diag(Tok, diag::warn_pragma_exec_charset_spec_invalid);
+      if (Tok.isAnnotation())
+        PP.DiscardUntilEndOfDirective();
       return;
     }
 
@@ -1936,7 +1988,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")) {
@@ -1991,7 +2044,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/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 84907adc5d744a..20626fa87466a5 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -981,8 +981,18 @@ void Preprocessor::Lex(Token &Result) {
   ++LexLevel;
 
   // We loop here until a lex function returns a token; this avoids recursion.
-  while (!CurLexerCallback(*this, Result))
-    ;
+  do {
+    while (!CurLexerCallback(*this, Result))
+      ;
+    // A nested pragma can defer parsing by injecting an annotation followed by
+    // its arguments and an eod. Its eod must not terminate the enclosing
+    // pragma. Only skip eod from actual pragma lexers; a token stream can also
+    // replay the enclosing pragma's own eod, for example when producing -E
+    // output.
+  } while (Result.is(tok::eod) && !PragmaLexerStackDepths.empty() &&
+           IncludeMacroStack.size() > PragmaLexerStackDepths.back() &&
+           ((CurLexer && CurLexer->isPragmaLexer()) ||
+            (CurTokenLexer && CurTokenLexer->isPragmaLexer())));
 
   if (Result.is(tok::unknown) && TheModuleLoader.HadFatalFailure)
     return;
diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp
index 9b18c31e19eb17..52608e0218c1e5 100644
--- a/clang/lib/Lex/TokenLexer.cpp
+++ b/clang/lib/Lex/TokenLexer.cpp
@@ -58,6 +58,7 @@ void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, 
MacroInfo *MI,
   NumTokens = Macro->tokens_end()-Macro->tokens_begin();
   MacroExpansionStart = SourceLocation();
   LexingCXXModuleDirective = false;
+  IsPragmaLexer = false;
 
   SourceManager &SM = PP.getSourceManager();
   MacroStartSLocOffset = SM.getNextLocalOffset();
@@ -115,6 +116,7 @@ void TokenLexer::Init(const Token *TokArray, unsigned 
NumToks,
   NextTokGetsSpace = false;
   MacroExpansionStart = SourceLocation();
   LexingCXXModuleDirective = false;
+  IsPragmaLexer = false;
 
   // Set HasLeadingSpace/AtStartOfLine so that the first token will be
   // returned unmodified.
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 34a9ed09fec8ed..f086a04a29e1f9 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -1320,7 +1320,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;
@@ -1563,7 +1564,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 &&
@@ -1593,7 +1595,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)
@@ -1622,7 +1625,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") {
@@ -1870,11 +1873,8 @@ enum class MissingAttributeSubjectRulesRecoveryPoint {
 
 MissingAttributeSubjectRulesRecoveryPoint
 getAttributeSubjectRulesRecoveryPointForToken(const Token &Tok) {
-  // Nested `_Pragma` annotations cannot name attribute subject rules.
-  // https://github.com/llvm/llvm-project/issues/225035
-  if (Tok.isAnnotation())
-    return MissingAttributeSubjectRulesRecoveryPoint::None;
-  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"))
@@ -2042,9 +2042,7 @@ void Parser::HandlePragmaAttribute() {
     ParseMicrosoftDeclSpecs(Attrs);
   } else {
     Diag(Tok, diag::err_pragma_attribute_expected_attribute_syntax);
-    // A nested `_Pragma` can produce an annotation token here.
-    // https://github.com/llvm/llvm-project/issues/225035
-    if (!Tok.isAnnotation() && 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(
@@ -2157,7 +2155,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")) {
@@ -2170,7 +2169,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";
@@ -2884,10 +2885,13 @@ 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";
+    if (Tok.isAnnotation())
+      PP.DiscardUntilEndOfDirective();
     return;
   }
   PP.Lex(Tok);
@@ -2900,11 +2904,13 @@ 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)
               << Tok.getKind() << /*OnlyInheritanceModels*/ 0;
+          if (Tok.isAnnotation())
+            PP.DiscardUntilEndOfDirective();
           return;
         }
         PP.Lex(Tok);
@@ -2982,7 +2988,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)
@@ -3010,7 +3017,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;
@@ -3027,6 +3035,8 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP,
     } else {
       PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action)
           << "vtordisp";
+      if (Tok.isAnnotation())
+        PP.DiscardUntilEndOfDirective();
       return;
     }
   }
@@ -3391,8 +3401,11 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor 
&PP,
     return;
   }
   if (Tok.isNot(tok::identifier)) {
+    bool IsAnnotation = Tok.isAnnotation();
     PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_invalid_argument)
-      << PP.getSpelling(Tok);
+        << (IsAnnotation ? "" : PP.getSpelling(Tok)) << IsAnnotation;
+    if (IsAnnotation)
+      PP.DiscardUntilEndOfDirective();
     return;
   }
   const IdentifierInfo *II = Tok.getIdentifierInfo();
@@ -3402,14 +3415,17 @@ 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) << /*OmitArgument=*/false;
     return;
   }
   PP.Lex(Tok);
 
   if (Tok.isNot(tok::eod)) {
+    bool IsAnnotation = Tok.isAnnotation();
     PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_extra_argument)
-      << PP.getSpelling(Tok);
+        << (IsAnnotation ? "" : PP.getSpelling(Tok)) << IsAnnotation;
+    if (IsAnnotation)
+      PP.DiscardUntilEndOfDirective();
     return;
   }
 
@@ -3472,9 +3488,12 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
 
     // Don't diagnose if we have an eval_metod pragma with "double" kind.
     if (Tok.isNot(tok::identifier) && !isEvalMethodDouble) {
+      bool IsAnnotation = Tok.isAnnotation();
       PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
-          << PP.getSpelling(Tok) << OptionInfo->getName()
-          << static_cast<int>(*FlagKind);
+          << (IsAnnotation ? "" : PP.getSpelling(Tok)) << OptionInfo->getName()
+          << static_cast<int>(*FlagKind) << IsAnnotation;
+      if (IsAnnotation)
+        PP.DiscardUntilEndOfDirective();
       return;
     }
     const IdentifierInfo *II = Tok.getIdentifierInfo();
@@ -3489,7 +3508,8 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
               .Default(std::nullopt);
       if (!AnnotValue->ContractValue) {
         PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
-            << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
+            << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind
+            << /*OmitArgument=*/false;
         return;
       }
     } else if (FlagKind == PFK_Reassociate || FlagKind == PFK_Reciprocal) {
@@ -3502,7 +3522,8 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
                   .Default(std::nullopt);
       if (!Value) {
         PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
-            << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
+            << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind
+            << /*OmitArgument=*/false;
         return;
       }
     } else if (FlagKind == PFK_Exceptions) {
@@ -3515,7 +3536,8 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
               .Default(std::nullopt);
       if (!AnnotValue->ExceptionsValue) {
         PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
-            << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
+            << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind
+            << /*OmitArgument=*/false;
         return;
       }
     } else if (FlagKind == PFK_EvalMethod) {
@@ -3528,7 +3550,8 @@ void PragmaFPHandler::HandlePragma(Preprocessor &PP,
               .Default(std::nullopt);
       if (!AnnotValue->EvalMethodValue) {
         PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument)
-            << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind;
+            << PP.getSpelling(Tok) << OptionInfo->getName() << *FlagKind
+            << /*OmitArgument=*/false;
         return;
       }
     }
@@ -3949,11 +3972,13 @@ 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"))) {
+    bool IsAnnotation = Tok.isAnnotation();
     PP.Diag(PragmaLocation, diag::warn_pragma_invalid_argument)
-        << PP.getSpelling(Tok) << PragmaName << /*Expected=*/true
-        << "'on' or 'off'";
+        << (IsAnnotation ? "" : PP.getSpelling(Tok)) << PragmaName
+        << /*Expected=*/true << "'on' or 'off'" << IsAnnotation;
     return false;
   }
   bool IsOn = II->isStr("on");
@@ -3967,7 +3992,7 @@ bool Parser::HandlePragmaMSOptimize(StringRef PragmaName,
   if (!OptimizationList->getString().empty()) {
     PP.Diag(PragmaLocation, diag::warn_pragma_invalid_argument)
         << OptimizationList->getString() << PragmaName << /*Expected=*/true
-        << "\"\"";
+        << "\"\"" << /*OmitArgument=*/false;
     return false;
   }
 
@@ -4034,10 +4059,13 @@ 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);
+    if (Tok.isAnnotation())
+      PP.DiscardUntilEndOfDirective();
     return;
   }
 
@@ -4305,21 +4333,30 @@ 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")) {
+    bool IsAnnotation = Tok.isAnnotation();
     PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
-        << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << 
"'intrinsic'";
+        << (IsAnnotation ? "" : PP.getSpelling(Tok)) << "riscv"
+        << /*Expected=*/true << "'intrinsic'" << IsAnnotation;
+    if (IsAnnotation)
+      PP.DiscardUntilEndOfDirective();
     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"))) {
+    bool IsAnnotation = Tok.isAnnotation();
     PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
-        << PP.getSpelling(Tok) << "riscv" << /*Expected=*/true
-        << "'vector', 'sifive_vector' or 'andes_vector'";
+        << (IsAnnotation ? "" : PP.getSpelling(Tok)) << "riscv"
+        << /*Expected=*/true << "'vector', 'sifive_vector' or 'andes_vector'"
+        << IsAnnotation;
+    if (IsAnnotation)
+      PP.DiscardUntilEndOfDirective();
     return;
   }
 
diff --git a/clang/test/FixIt/fixit-pragma-attribute.cpp 
b/clang/test/FixIt/fixit-pragma-attribute.cpp
index 3824e45d8fca54..ac6e1b5a9041a5 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/Lexer/pragma-mark.c b/clang/test/Lexer/pragma-mark.c
index e58b2267ddbceb..3f4f6f29fd89ac 100644
--- a/clang/test/Lexer/pragma-mark.c
+++ b/clang/test/Lexer/pragma-mark.c
@@ -1,4 +1,6 @@
 // RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -fsyntax-only -fms-extensions -DTEST_MS_PRAGMA -verify
+// RUN: %clang_cc1 %s -E -fms-extensions -DTEST_MS_PRAGMA -verify | FileCheck 
%s
 // expected-no-diagnostics
 
 // Lexer diagnostics shouldn't be included in #pragma mark.
@@ -10,3 +12,15 @@ X("mark foo ' bar")
 
 int i;
 
+#ifdef TEST_MS_PRAGMA
+// __pragma has already lexed and expanded its arguments. It must consume the
+// captured tokens without requiring a character lexer, including annotations
+// introduced by nested pragmas.
+__pragma(mark)
+__pragma(mark foo) int after_mark;
+__pragma(mark foo _Pragma("weak foobar")) int after_nested_mark;
+int use_after_marks(void) { return after_mark + after_nested_mark; }
+// CHECK: int after_mark;
+// CHECK: int after_nested_mark;
+// CHECK: int use_after_marks(void) { return after_mark + after_nested_mark; }
+#endif
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 00000000000000..49fd5e5a24eed7
--- /dev/null
+++ b/clang/test/Parser/pragma-nested-annotation-target.c
@@ -0,0 +1,22 @@
+// 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
+
+#ifdef TEST_RISCV
+#pragma clang riscv _Pragma("weak foobar") intrinsic vector // riscv-warning 
{{unexpected argument to '#pragma riscv'; expected 'intrinsic'}}
+#pragma clang riscv intrinsic _Pragma("weak foobar") vector // riscv-warning 
{{unexpected argument to '#pragma riscv'; expected 'vector', 'sifive_vector' or 
'andes_vector'}}
+
+// 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}}
+
+#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 00000000000000..7805abed8370f2
--- /dev/null
+++ b/clang/test/Parser/pragma-nested-annotation.c
@@ -0,0 +1,102 @@
+// RUN: %clang_cc1 -fsyntax-only -fms-extensions -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fms-extensions -fms-compatibility -verify %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -fms-extensions -verify %s
+
+// Nested _Pragma annotations must be rejected without querying identifier
+// information or spelling on the annotation token.
+#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 vtordisp(_Pragma("weak foobar")) // expected-warning {{unknown action 
for '#pragma vtordisp' - ignored}}
+#pragma vtordisp(push, _Pragma("weak foobar")) // expected-warning {{unknown 
action for '#pragma vtordisp' - ignored}}
+#pragma pointers_to_members(_Pragma("weak foobar")) // expected-warning 
{{expected identifier in '#pragma pointers_to_members' - ignored}}
+#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'}}
+#pragma warning(_Pragma("weak foobar")) // expected-warning {{#pragma warning 
expected 'push', 'pop', 'default', 'disable', 'error', 'once', 'suppress', 1, 
2, 3, or 4}}
+#pragma warning(disable : 1; _Pragma("weak foobar")) // expected-warning 
{{#pragma warning expected 'push', 'pop', 'default', 'disable', 'error', 
'once', 'suppress', 1, 2, 3, or 4}}
+#pragma execution_character_set(_Pragma("weak foobar")) // expected-warning 
{{#pragma execution_character_set expected 'push' or 'pop'}}
+
+#pragma clang optimize _Pragma("weak foobar") on // expected-error 
{{unexpected argument to '#pragma clang optimize'; expected 'on' or 'off'}}
+#pragma clang optimize on _Pragma("weak foobar") // expected-error 
{{unexpected extra argument to '#pragma clang optimize'}}
+#pragma clang fp contract(_Pragma("weak foobar")) // expected-error 
{{unexpected argument to '#pragma clang fp contract'; expected 'fast' or 'on' 
or 'off'}}
+
+// Ordinary invalid tokens retain their spelling in the diagnostics.
+#pragma clang optimize 42 // expected-error {{unexpected argument '42' to 
'#pragma clang optimize'; expected 'on' or 'off'}}
+#pragma clang optimize on 42 // expected-error {{unexpected extra argument 
'42' to '#pragma clang optimize'}}
+#pragma clang fp contract(42) // expected-error {{unexpected argument '42' to 
'#pragma clang fp contract'; expected 'fast' or 'on' or 'off'}}
+#pragma optimize("", 42) // expected-warning {{unexpected argument '42' to 
'#pragma optimize'; expected 'on' or 'off'}}
+
+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 clang fp eval_method(double)
+
+// __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
+
+// Unlike most pragma handlers, __debug dump leaves its arguments and eod for
+// the parser. That inner eod must not terminate the enclosing pragma, either
+// during error recovery or while saving arguments for later parsing.
+#pragma vtordisp(_Pragma("clang __debug dump x")) // expected-warning 
{{unknown action for '#pragma vtordisp' - ignored}}
+int after_vtordisp;
+#pragma optimize("", _Pragma("clang __debug dump x")) // expected-warning 
{{unexpected argument to '#pragma optimize'; expected 'on' or 'off'}}
+int after_ms_optimize;
+
+// __pragma expands the inner pragma while capturing its arguments, before the
+// outer handler runs. Capturing must also ignore the inner eod.
+__pragma(optimize("", _Pragma("clang __debug dump x"))) // expected-warning 
{{unexpected argument to '#pragma optimize'; expected 'on' or 'off'}}
+int after_ms_pragmas;
+
+// An inner __pragma can also defer parsing. Its captured token stream has a
+// separate eod which must not terminate the outer directive or argument 
capture.
+#pragma vtordisp(__pragma(clang __debug dump x)) // expected-warning {{unknown 
action for '#pragma vtordisp' - ignored}}
+int after_nested_ms_pragma;
+__pragma(optimize("", __pragma(clang __debug dump x))) // expected-warning 
{{unexpected argument to '#pragma optimize'; expected 'on' or 'off'}}
+int after_nested_ms_capture;
+
+// Both captures start in the same macro, but continue after it is popped.
+// Keep the outer boundary updated when the inner capture finishes.
+#define BEGIN_NESTED_PRAGMA __pragma(optimize("", __pragma(clang __debug dump
+BEGIN_NESTED_PRAGMA x))) // expected-warning {{unexpected argument to '#pragma 
optimize'; expected 'on' or 'off'}}
+#undef BEGIN_NESTED_PRAGMA
+int after_macro;
+
+int after_pragmas;
+int use_after_pragmas(void) {
+  return after_pragmas + after_vtordisp + after_ms_optimize + after_ms_pragmas 
+
+         after_nested_ms_pragma + after_nested_ms_capture + after_macro;
+}
diff --git a/clang/test/Preprocessor/pragma-dependency-nested-annotation.c 
b/clang/test/Preprocessor/pragma-dependency-nested-annotation.c
new file mode 100644
index 00000000000000..6b65d849fc6589
--- /dev/null
+++ b/clang/test/Preprocessor/pragma-dependency-nested-annotation.c
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: cp %s %t/test.c
+// RUN: echo "// dependency" > %t/header.h
+// RUN: %python -c "import os; ts = os.stat(r'%t/test.c').st_mtime + 60; 
os.utime(r'%t/header.h', (ts, ts))"
+// RUN: %clang_cc1 -fsyntax-only -verify %t/test.c
+
+// The message contains tokens injected by a nested pragma. Skip the annotation
+// while preserving surrounding ordinary tokens and the dependency warning.
+#pragma GCC dependency "header.h" before _Pragma("weak foobar") after // 
expected-warning {{current file is older than dependency before foobar after}}
+
+int after_pragmas;
+int use_after_pragmas(void) { return after_pragmas; }
diff --git a/clang/test/Preprocessor/print-pragma-microsoft.c 
b/clang/test/Preprocessor/print-pragma-microsoft.c
index d121d93f0d8577..20244db4f7aa4a 100644
--- a/clang/test/Preprocessor/print-pragma-microsoft.c
+++ b/clang/test/Preprocessor/print-pragma-microsoft.c
@@ -18,3 +18,15 @@
 #pragma pack(push, _CRT_PACKING)
 // CHECK: #pragma pack(push, 8)
 #pragma pack(pop)
+
+// Printing an unknown pragma replays its first token for macro expansion. In
+// the empty case that token is the outer pragma's eod, which must be 
preserved.
+__pragma()
+// CHECK: #pragma{{$}}
+int after_empty;
+// CHECK: int after_empty;
+
+__pragma(unknown argument)
+// CHECK: #pragma unknown argument
+int after_unknown;
+// CHECK: int after_unknown;
diff --git a/clang/unittests/Lex/LexerTest.cpp 
b/clang/unittests/Lex/LexerTest.cpp
index 8f632ccc5b9315..6dd78d0d1ade8e 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);
diff --git a/clang/unittests/Lex/PPCallbacksTest.cpp 
b/clang/unittests/Lex/PPCallbacksTest.cpp
index 169734f80df475..8a04fe9f78909f 100644
--- a/clang/unittests/Lex/PPCallbacksTest.cpp
+++ b/clang/unittests/Lex/PPCallbacksTest.cpp
@@ -554,6 +554,22 @@ TEST_F(PPCallbacksTest, CollectMarks) {
   ASSERT_EQ(" - trivia", Marks[3].Trivia);
 }
 
+TEST_F(PPCallbacksTest, CollectMarksWithMicrosoftPragmas) {
+  LangOpts.MicrosoftExt = 1;
+  const char *Source =
+      "#pragma mark - before\n"
+      "__pragma(mark ignored)\n"
+      "__pragma(mark _Pragma(\"mark inner's trivia\") ignored)\n"
+      "#pragma mark - after\n";
+
+  auto Marks = PragmaMarkCall(Source);
+
+  ASSERT_EQ(3u, Marks.size());
+  EXPECT_EQ(" - before", Marks[0].Trivia);
+  EXPECT_EQ(" inner's trivia", Marks[1].Trivia);
+  EXPECT_EQ(" - after", Marks[2].Trivia);
+}
+
 TEST_F(PPCallbacksTest, DirectiveExprRanges) {
   const auto &Results1 = DirectiveExprRange("#if FLUZZY_FLOOF\n#endif\n");
   EXPECT_EQ(Results1.size(), 1U);

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

Reply via email to