llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Chen Miao (ChenMiaoi)

<details>
<summary>Changes</summary>

Nested `_Pragma` or Microsoft `__pragma` expressions can produce annotation 
tokens in an enclosing pragma's arguments. This patch fixes crashes when these 
tokens are processed as arguments or used to construct diagnostics, and 
improves error recovery for nested pragmas.

``` cc
#pragma vtordisp(push, _Pragma("weak foobar"))
```

After the inner `_Pragma` is processed, the enclosing pragma receives an 
annotation where it expects a mode argument. Similar cases occur when arguments 
are buffered and parsed later.

Previously, these paths called `getIdentifierInfo()` and then checked whether 
the result was null. The assertion occurs inside the getter, so checking its 
return value cannot prevent the crash.

This patch checks the token kind before calling the getter. Only identifiers or 
keywords permitted by the pragma's syntax are queried for identifier 
information; other tokens follow the existing diagnostic and recovery paths.

Split by #<!-- -->228990 



---

Patch is 25.72 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/230927.diff


8 Files Affected:

- (modified) clang/docs/ReleaseNotes.md (+3) 
- (modified) clang/lib/Lex/Pragma.cpp (+27-14) 
- (modified) clang/lib/Parse/ParsePragma.cpp (+38-24) 
- (modified) clang/test/FixIt/fixit-pragma-attribute.cpp (+5) 
- (modified) clang/test/Parser/pragma-attribute.cpp (+4) 
- (added) clang/test/Parser/pragma-nested-annotation-target.c (+31) 
- (added) clang/test/Parser/pragma-nested-annotation.c (+86) 
- (modified) clang/unittests/Lex/LexerTest.cpp (+37) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 77a1e73bc8af60..4867f40c51cae7 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 078842ab08c5ef..6a2e209ff5510f 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,10 +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.getIdentifierInfo() ? 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;
@@ -921,12 +927,12 @@ void 
Preprocessor::HandlePragmaSetPPState(PragmaIntroducer Introducer,
                                           Token &Tok) {
   // Lex the macro name we want to set.
   LexUnexpandedToken(Tok);
-  if (!Tok.getIdentifierInfo()) {
+  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;
@@ -1149,7 +1155,7 @@ struct PragmaDebugHandler : public PragmaHandler {
     } else if (II->isStr("macro")) {
       Token MacroName;
       PP.LexUnexpandedToken(MacroName);
-      auto *MacroII = MacroName.getIdentifierInfo();
+      auto *MacroII = getPragmaIdentifierInfo(MacroName);
       if (MacroII)
         PP.dumpMacroInfo(MacroII);
       else
@@ -1174,7 +1180,7 @@ struct PragmaDebugHandler : public PragmaHandler {
     } else if (II->isStr("module_lookup")) {
       Token MName;
       PP.LexUnexpandedToken(MName);
-      auto *MNameII = MName.getIdentifierInfo();
+      auto *MNameII = getPragmaIdentifierInfo(MName);
       if (!MNameII) {
         PP.Diag(MName, diag::warn_pragma_debug_missing_argument)
             << II->getName();
@@ -1219,7 +1225,7 @@ struct PragmaDebugHandler : public PragmaHandler {
 
       Token Kind;
       PP.LexUnexpandedToken(Kind);
-      auto *DumpII = Kind.getIdentifierInfo();
+      auto *DumpII = getPragmaIdentifierInfo(Kind);
       if (!DumpII) {
         PP.Diag(Kind, diag::warn_pragma_debug_missing_argument)
             << II->getName();
@@ -1453,7 +1459,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 +1492,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 +1611,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 +1941,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 +1997,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 04e7bb5a9b7dd9..77c2f3e0b200ea 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 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/Parser/pragma-attribute.cpp 
b/clang/test/Parser/pragma-attribute.cpp
index 1f90a8990bb96e..e2fb747d035b8f 100644
--- a/clang/test/Parser/pragma-attribute.cpp
+++ b/clang/test/Parser/pragma-attribute.cpp
@@ -180,6 +180,10 @@ _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(__attribute__((annotate("test"))) _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 00000000000000..345a5b60ef7cc7
--- /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 00000000000000..7b4a517629295a
--- /dev/null
+++ b/clang/test/Parser/pragma-nested-annotation.c
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -fsyntax-only -fms-extensions -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...
[truncated]

``````````

</details>


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

Reply via email to