[clang] [clang][Sema] Diagnose nested assembler dialect alternatives in inline `asm` strings (PR #225306)
Akash Manna via cfe-commits
cfe-commits at lists.llvm.org
Sun Sep 27 04:22:39 PDT 2026
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 <akash.manna.mymail at gmail.com>
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) {
More information about the cfe-commits
mailing list