mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 13:10:12 +03:00
Allow multiple message arguments for static assert (#14611)
Allow multiple message arguments for static assert Signed-off-by: Razvan Nitu <razvan.nitu1305@gmail.com> Merged-on-behalf-of: Razvan Nitu <razvan.nitu1305@gmail.com>
This commit is contained in:
parent
5f2761d146
commit
8cc27077c5
11 changed files with 100 additions and 32 deletions
13
changelog/dmd.static-assert.dd
Normal file
13
changelog/dmd.static-assert.dd
Normal file
|
@ -0,0 +1,13 @@
|
|||
`static assert` now supports multiple message arguments
|
||||
|
||||
When the condition evaluates to false, any subsequent expressions will
|
||||
each be converted to string and then concatenated. The resulting string
|
||||
will be printed out along with the error diagnostic.
|
||||
---
|
||||
enum e = 3;
|
||||
static assert(false, "a = ", e);
|
||||
---
|
||||
Will print:
|
||||
$(CONSOLE
|
||||
file.d(2): Error: static assert: a = 3
|
||||
)
|
|
@ -452,12 +452,19 @@ struct ASTBase
|
|||
extern (C++) final class StaticAssert : Dsymbol
|
||||
{
|
||||
Expression exp;
|
||||
Expression msg;
|
||||
Expressions* msg;
|
||||
|
||||
extern (D) this(const ref Loc loc, Expression exp, Expression msg)
|
||||
{
|
||||
super(Id.empty);
|
||||
this.loc = loc;
|
||||
super(loc, Id.empty);
|
||||
this.exp = exp;
|
||||
this.msg = new Expressions(1);
|
||||
(*this.msg)[0] = msg;
|
||||
}
|
||||
|
||||
extern (D) this(const ref Loc loc, Expression exp, Expressions* msg)
|
||||
{
|
||||
super(loc, Id.empty);
|
||||
this.exp = exp;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
|
|
@ -4607,7 +4607,7 @@ class StaticAssert final : public Dsymbol
|
|||
{
|
||||
public:
|
||||
Expression* exp;
|
||||
Expression* msg;
|
||||
Array<Expression* >* msgs;
|
||||
StaticAssert* syntaxCopy(Dsymbol* s) override;
|
||||
void addMember(Scope* sc, ScopeDsymbol* sds) override;
|
||||
bool oneMember(Dsymbol** ps, Identifier* ident) override;
|
||||
|
|
|
@ -823,10 +823,13 @@ public:
|
|||
buf.writestring(s.kind());
|
||||
buf.writeByte('(');
|
||||
s.exp.expressionToBuffer(buf, hgs);
|
||||
if (s.msg)
|
||||
if (s.msgs)
|
||||
{
|
||||
buf.writestring(", ");
|
||||
s.msg.expressionToBuffer(buf, hgs);
|
||||
foreach (m; (*s.msgs)[])
|
||||
{
|
||||
buf.writestring(", ");
|
||||
m.expressionToBuffer(buf, hgs);
|
||||
}
|
||||
}
|
||||
buf.writestring(");");
|
||||
buf.writenl();
|
||||
|
|
|
@ -1982,7 +1982,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
{
|
||||
const loc = token.loc;
|
||||
AST.Expression exp;
|
||||
AST.Expression msg = null;
|
||||
AST.Expressions* msg = null;
|
||||
|
||||
//printf("parseStaticAssert()\n");
|
||||
nextToken();
|
||||
|
@ -1991,15 +1991,16 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
exp = parseAssignExp();
|
||||
if (token.value == TOK.comma)
|
||||
{
|
||||
nextToken();
|
||||
if (token.value != TOK.rightParenthesis)
|
||||
if (peekNext() == TOK.rightParenthesis)
|
||||
{
|
||||
msg = parseAssignExp();
|
||||
if (token.value == TOK.comma)
|
||||
nextToken();
|
||||
nextToken(); // consume `,`
|
||||
nextToken(); // consume `)`
|
||||
}
|
||||
else
|
||||
msg = parseArguments();
|
||||
}
|
||||
check(TOK.rightParenthesis);
|
||||
else
|
||||
check(TOK.rightParenthesis);
|
||||
check(TOK.semicolon, "static assert");
|
||||
return new AST.StaticAssert(loc, exp, msg);
|
||||
}
|
||||
|
|
|
@ -110,21 +110,36 @@ private extern(C++) final class Semantic2Visitor : Visitor
|
|||
else if (result)
|
||||
return;
|
||||
|
||||
if (sa.msg)
|
||||
if (sa.msgs)
|
||||
{
|
||||
sc = sc.startCTFE();
|
||||
sa.msg = sa.msg.expressionSemantic(sc);
|
||||
sa.msg = resolveProperties(sc, sa.msg);
|
||||
sc = sc.endCTFE();
|
||||
sa.msg = sa.msg.ctfeInterpret();
|
||||
if (StringExp se = sa.msg.toStringExp())
|
||||
OutBuffer msgbuf;
|
||||
for (size_t i = 0; i < sa.msgs.length; i++)
|
||||
{
|
||||
// same with pragma(msg)
|
||||
const slice = se.toUTF8(sc).peekString();
|
||||
error(sa.loc, "static assert: \"%.*s\"", cast(int)slice.length, slice.ptr);
|
||||
Expression e = (*sa.msgs)[i];
|
||||
sc = sc.startCTFE();
|
||||
e = e.expressionSemantic(sc);
|
||||
e = resolveProperties(sc, e);
|
||||
sc = sc.endCTFE();
|
||||
e = ctfeInterpretForPragmaMsg(e);
|
||||
if (e.op == EXP.error)
|
||||
{
|
||||
errorSupplemental(sa.loc, "while evaluating `static assert` argument `%s`", (*sa.msgs)[i].toChars());
|
||||
return;
|
||||
}
|
||||
StringExp se = e.toStringExp();
|
||||
if (se)
|
||||
{
|
||||
const slice = se.toUTF8(sc).peekString();
|
||||
// Hack to keep old formatting to avoid changing error messages everywhere
|
||||
if (sa.msgs.length == 1)
|
||||
msgbuf.printf("\"%.*s\"", cast(int)slice.length, slice.ptr);
|
||||
else
|
||||
msgbuf.printf("%.*s", cast(int)slice.length, slice.ptr);
|
||||
}
|
||||
else
|
||||
msgbuf.printf("%s", e.toChars());
|
||||
}
|
||||
else
|
||||
error(sa.loc, "static assert: %s", sa.msg.toChars());
|
||||
error(sa.loc, "static assert: %s", msgbuf.extractChars());
|
||||
}
|
||||
else
|
||||
error(sa.loc, "static assert: `%s` is false", sa.exp.toChars());
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
module dmd.staticassert;
|
||||
|
||||
import dmd.arraytypes;
|
||||
import dmd.dscope;
|
||||
import dmd.dsymbol;
|
||||
import dmd.expression;
|
||||
|
@ -27,19 +28,27 @@ import dmd.visitor;
|
|||
extern (C++) final class StaticAssert : Dsymbol
|
||||
{
|
||||
Expression exp;
|
||||
Expression msg;
|
||||
Expressions* msgs;
|
||||
|
||||
extern (D) this(const ref Loc loc, Expression exp, Expression msg)
|
||||
{
|
||||
super(loc, Id.empty);
|
||||
this.exp = exp;
|
||||
this.msg = msg;
|
||||
this.msgs = new Expressions(1);
|
||||
(*this.msgs)[0] = msg;
|
||||
}
|
||||
|
||||
extern (D) this(const ref Loc loc, Expression exp, Expressions* msgs)
|
||||
{
|
||||
super(loc, Id.empty);
|
||||
this.exp = exp;
|
||||
this.msgs = msgs;
|
||||
}
|
||||
|
||||
override StaticAssert syntaxCopy(Dsymbol s)
|
||||
{
|
||||
assert(!s);
|
||||
return new StaticAssert(loc, exp.syntaxCopy(), msg ? msg.syntaxCopy() : null);
|
||||
return new StaticAssert(loc, exp.syntaxCopy(), msgs ? Expression.arraySyntaxCopy(msgs) : null);
|
||||
}
|
||||
|
||||
override void addMember(Scope* sc, ScopeDsymbol sds)
|
||||
|
|
|
@ -18,7 +18,7 @@ class StaticAssert : public Dsymbol
|
|||
{
|
||||
public:
|
||||
Expression *exp;
|
||||
Expression *msg;
|
||||
Expressions *msg;
|
||||
|
||||
StaticAssert *syntaxCopy(Dsymbol *s) override;
|
||||
void addMember(Scope *sc, ScopeDsymbol *sds) override;
|
||||
|
|
|
@ -490,8 +490,9 @@ package mixin template ParseVisitMethods(AST)
|
|||
{
|
||||
//printf("Visiting StaticAssert\n");
|
||||
s.exp.accept(this);
|
||||
if (s.msg)
|
||||
s.msg.accept(this);
|
||||
if (s.msgs)
|
||||
foreach (m; (*s.msgs)[])
|
||||
m.accept(this);
|
||||
}
|
||||
|
||||
override void visit(AST.EnumMember em)
|
||||
|
|
9
compiler/test/fail_compilation/staticassertargs.d
Normal file
9
compiler/test/fail_compilation/staticassertargs.d
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/staticassertargs.d(9): Error: static assert: abcxe3!!
|
||||
---
|
||||
*/
|
||||
|
||||
enum e = "!!";
|
||||
static assert(false, "abc", ['x', 'e'], 3, e);
|
10
compiler/test/fail_compilation/staticassertargsfail.d
Normal file
10
compiler/test/fail_compilation/staticassertargsfail.d
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/staticassertargsfail.d(10): Error: incompatible types for `('x') : (new Object)`: `char` and `object.Object`
|
||||
fail_compilation/staticassertargsfail.d(10): while evaluating `static assert` argument `['x', new Object] ~ ""`
|
||||
---
|
||||
*/
|
||||
|
||||
|
||||
static assert(0, "abc", ['x', new Object] ~ "");
|
Loading…
Add table
Add a link
Reference in a new issue