@@ -69,7 +69,7 @@ public Statement gccAsmSemantic(GccAsmStatement s, Scope* sc)
6969 s.insn = semanticString(sc, s.insn, " asm instruction template" );
7070
7171 if (s.labels && s.outputargs)
72- error(s.loc, " extended asm statements with labels cannot have output constraints" );
72+ p.eSink. error(s.loc, " extended asm statements with labels cannot have output constraints" );
7373
7474 // Analyse all input and output operands.
7575 if (s.args)
@@ -143,6 +143,35 @@ public void gccAsmSemantic(CAsmDeclaration ad, Scope* sc)
143143
144144private :
145145
146+ /* **********************************
147+ * Parse an expression that evaluates to a string.
148+ * Grammar:
149+ * | AsmStringExpr:
150+ * | StringLiteral
151+ * | ( AssignExpression )
152+ * Params:
153+ * p = parser state
154+ * Returns:
155+ * the parsed string expression
156+ */
157+ Expression parseAsmString (Parser)(Parser p)
158+ {
159+ if (p.token.value == TOK .leftParenthesis)
160+ {
161+ p.nextToken();
162+ Expression insn = p.parseAssignExp();
163+ p.check(TOK .rightParenthesis);
164+ return insn;
165+ }
166+ else if (p.token.value != TOK .string_)
167+ {
168+ p.eSink.error(p.token.loc, " expected string literal or expression in parentheses" );
169+ return ErrorExp.get ();
170+ }
171+
172+ return p.parsePrimaryExp();
173+ }
174+
146175/* **********************************
147176 * Parse list of extended asm input or output operands.
148177 * Grammar:
@@ -202,7 +231,7 @@ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s)
202231 if (p.token.value != TOK .leftParenthesis)
203232 {
204233 arg = p.parseAssignExp();
205- error(arg.loc, " `%s` must be surrounded by parentheses" , arg.toChars());
234+ p.eSink. error(arg.loc, " `%s` must be surrounded by parentheses" , arg.toChars());
206235 }
207236 else
208237 {
@@ -352,13 +381,13 @@ Lerror:
352381 * | GotoAsmInstruction
353382 * |
354383 * | BasicAsmInstruction:
355- * | AssignExpression
384+ * | AsmStringExpr
356385 * |
357386 * | ExtAsmInstruction:
358- * | AssignExpression : Operands(opt) : Operands(opt) : Clobbers(opt)
387+ * | AsmStringExpr : Operands(opt) : Operands(opt) : Clobbers(opt)
359388 * |
360389 * | GotoAsmInstruction:
361- * | AssignExpression : : Operands(opt) : Clobbers(opt) : GotoLabels(opt)
390+ * | AsmStringExpr : : Operands(opt) : Clobbers(opt) : GotoLabels(opt)
362391 * Params:
363392 * p = parser state
364393 * s = asm statement to parse
@@ -367,7 +396,10 @@ Lerror:
367396 */
368397GccAsmStatement parseGccAsm (Parser)(Parser p, GccAsmStatement s)
369398{
370- s.insn = p.parseAssignExp();
399+ s.insn = p.parseAsmString();
400+ if (s.insn.isErrorExp())
401+ return s;
402+
371403 if (p.token.value == TOK .semicolon || p.token.value == TOK .endOfFile)
372404 goto Ldone;
373405
@@ -519,11 +551,11 @@ unittest
519551 } },
520552
521553 // Any CTFE-able string allowed as instruction template.
522- q{ asm { generateAsm( );
554+ q{ asm { (generateAsm );
523555 } },
524556
525557 // Likewise mixins, permissible so long as the result is a string.
526- q{ asm { mixin (` "repne"` , ` ~ "scasb"` );
558+ q{ asm { ( mixin (` "repne"` , ` ~ "scasb"` ) );
527559 } },
528560
529561 // :: token tests
@@ -557,6 +589,11 @@ unittest
557589
558590 // https://issues.dlang.org/show_bug.cgi?id=20593
559591 q{ asm { " instruction" : : " operand" 123 ; } },
592+
593+ // https://github.com/dlang/dmd/issues/21298
594+ q{ asm { 1 ; } },
595+ q{ asm { int ; } },
596+ q{ asm { : " =r" (i); } },
560597 ];
561598
562599 foreach (test; passAsmTests)
0 commit comments