https://github.com/akash-manna-sky updated 
https://github.com/llvm/llvm-project/pull/225306

>From 055bce5fd8fe4a0a22b0f3f546be7ba9d003cce8 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Tue, 22 Sep 2026 11:51:38 +0530
Subject: [PATCH] [clang][Sema] Diagnose nested assembler dialect alternatives
 in inline asm strings

GCCAsmStmt::AnalyzeAsmString rewrote {, | and } into the backend's
$(, $| and $) markers without checking their structure, so a nested
{a{b}} alternative reached the AsmPrinter and was reported with
report_fatal_error. Track the open alternative while scanning and
report nested or unterminated alternatives as regular Sema errors at
their location in the string, matching GCC, which rejects both.

Fixes #204773
---
 clang/docs/ReleaseNotes.md                    |  4 +++
 .../include/clang/Basic/DiagnosticASTKinds.td |  4 +++
 clang/lib/AST/Stmt.cpp                        | 29 +++++++++++++++++--
 clang/test/Sema/asm.c                         | 13 +++++++++
 clang/test/Sema/inline-asm-validate-aarch64.c |  4 +++
 5 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index f4a34a37aff52..61dacc99a9f2b 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -451,6 +451,10 @@ features cannot lower the translation-unit ABI level;
 - Clang now rejects inline asm constraints and clobbers that contain an
   embedded null character, instead of silently truncating them. (#GH173900)
 
+- Clang now rejects nested or unterminated assembler dialect alternatives
+  (`{att|intel}`) in an inline asm string, instead of producing a backend fatal
+  error or silently emitting the wrong dialect. (#GH204773)
+
 - Added `-Wstringop-overread` to warn when `memcpy`, `memmove`, `memcmp`,
   and related builtins read more bytes than the source buffer size (#GH83728).
 
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td 
b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 0aca1f75428f8..ac8e7ed7c2f6d 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -461,6 +461,10 @@ let CategoryName = "Inline Assembly Issue" in {
     "empty symbolic operand name in inline assembly string">;
   def err_asm_invalid_operand_number : Error<
     "invalid operand number in inline asm string">;
+  def err_asm_nested_dialect_alternatives : Error<
+    "nested assembler dialect alternatives in inline assembly string">;
+  def err_asm_unterminated_dialect_alternative : Error<
+    "unterminated assembler dialect alternative in inline assembly string">;
 }
 
 // vtable related.
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 15d0e6435aaf3..4513e8d6f665f 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -699,12 +699,19 @@ unsigned 
GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
 
   bool HasVariants = !C.getTargetInfo().hasNoAsmVariants();
 
+  // Offset of the '{' opening the current {a|b|c} dialect alternative, if any.
+  std::optional<unsigned> VariantStartOffs;
+
   unsigned LastAsmStringToken = 0;
   unsigned LastAsmStringOffset = 0;
 
   while (true) {
     // Done with the string?
     if (CurPtr == StrEnd) {
+      if (VariantStartOffs) {
+        DiagOffs = *VariantStartOffs;
+        return diag::err_asm_unterminated_dialect_alternative;
+      }
       if (!CurStringPiece.empty())
         Pieces.push_back(AsmStringPiece(CurStringPiece));
       return 0;
@@ -713,9 +720,27 @@ unsigned 
GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
     char CurChar = *CurPtr++;
     switch (CurChar) {
     case '$': CurStringPiece += "$$"; continue;
-    case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue;
+    case '{':
+      if (!HasVariants) {
+        CurStringPiece += '{';
+        continue;
+      }
+      if (VariantStartOffs) {
+        DiagOffs = CurPtr - StrStart - 1;
+        return diag::err_asm_nested_dialect_alternatives;
+      }
+      VariantStartOffs = CurPtr - StrStart - 1;
+      CurStringPiece += "$(";
+      continue;
     case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue;
-    case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue;
+    case '}':
+      if (!HasVariants) {
+        CurStringPiece += '}';
+        continue;
+      }
+      VariantStartOffs.reset();
+      CurStringPiece += "$)";
+      continue;
     case '%':
       break;
     default:
diff --git a/clang/test/Sema/asm.c b/clang/test/Sema/asm.c
index cc9acac1e169d..4434adfeee5e7 100644
--- a/clang/test/Sema/asm.c
+++ b/clang/test/Sema/asm.c
@@ -404,3 +404,16 @@ void test20(char x) {
   asm ("fabs" : "=t" (d): "0" (v)); // expected-error {{unsupported inline 
asm: input with type 'int2' (vector of 2 'int' values) matching output with 
type 'double'}}
   asm ("fabs" : "=t" (v): "0" (d)); // expected-error {{unsupported inline 
asm: input with type 'double' matching output with type 'int2' (vector of 2 
'int' values)}}
 }
+
+// GH204773
+void test21(int x) {
+  asm ("{cmpl{l}\t$d,%c0;je\t1f;addw{l}\t$d,%c0;jmp\t2f;1:decl\t%c0;2:}" : : 
"g"(x)); // expected-error {{nested assembler dialect alternatives in inline 
assembly string}}
+  asm ("{addl %0, %0|add %0, %0}" : : "r"(x)); // ok
+  asm ("{a|b}{c|d}" : : "r"(x)); // ok
+  asm ("{a|b" : : "r"(x)); // expected-error {{unterminated assembler dialect 
alternative in inline assembly string}}
+  asm ("{" : : "r"(x)); // expected-error {{unterminated assembler dialect 
alternative in inline assembly string}}
+  asm ("a}b|c" : : "r"(x)); // ok
+  asm ("%{%{%}%}" : : "r"(x)); // ok, escaped braces
+  asm ("{%{a%}|b}" : : "r"(x)); // ok
+  asm ("{{"); // ok, simple asm
+}
diff --git a/clang/test/Sema/inline-asm-validate-aarch64.c 
b/clang/test/Sema/inline-asm-validate-aarch64.c
index 1e753d40d8ca0..da4e59859743d 100644
--- a/clang/test/Sema/inline-asm-validate-aarch64.c
+++ b/clang/test/Sema/inline-asm-validate-aarch64.c
@@ -10,6 +10,10 @@ void test_s(int i) {
   /// Codegen error
   asm("" :: "S"(i));
   asm("" :: "S"(test_s(i))); // expected-error{{invalid type 'void' in asm 
input for constraint 'S'}}
+
+  // GH204773: braces are ordinary characters on this target.
+  asm("{a{b}}" :: "r"(i));
+  asm("{" :: "r"(i));
 }
 #else
 uint8_t constraint_r(uint8_t *addr) {

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

Reply via email to