Skip to content

Commit

Permalink
UDAs for function arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
wilzbach committed May 7, 2018
1 parent f94107e commit 4679f23
Show file tree
Hide file tree
Showing 24 changed files with 347 additions and 67 deletions.
10 changes: 10 additions & 0 deletions changelog/uda-function-arguments.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
UDAs on function arguments are now supported

User-defined attributes on function arguments behave analogous to existing UDAs:

---
void test(A)(@(22) A a)
{
static assert([__traits(getAttributes, a)] == [22]);
}
---
8 changes: 5 additions & 3 deletions src/dmd/astbase.d
Original file line number Diff line number Diff line change
Expand Up @@ -1727,15 +1727,17 @@ struct ASTBase
Type type;
Identifier ident;
Expression defaultArg;
UserAttributeDeclaration userAttribDecl; // user defined attributes

extern (D) alias ForeachDg = int delegate(size_t idx, Parameter param);

final extern (D) this(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg)
final extern (D) this(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl)
{
this.storageClass = storageClass;
this.type = type;
this.ident = ident;
this.defaultArg = defaultArg;
this.userAttribDecl = userAttribDecl;
}

static size_t dim(Parameters* parameters)
Expand Down Expand Up @@ -1802,7 +1804,7 @@ struct ASTBase

Parameter syntaxCopy()
{
return new Parameter(storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null);
return new Parameter(storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null, userAttribDecl ? cast(UserAttributeDeclaration) userAttribDecl.syntaxCopy(null) : null);
}

void accept(Visitor v)
Expand Down Expand Up @@ -3616,7 +3618,7 @@ struct ASTBase
Expression e = (*exps)[i];
if (e.type.ty == Ttuple)
e.error("cannot form tuple of tuples");
auto arg = new Parameter(STC.undefined_, e.type, null, null);
auto arg = new Parameter(STC.undefined_, e.type, null, null, null);
(*arguments)[i] = arg;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/dmd/attrib.d
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,7 @@ extern (C++) final class CompileDeclaration : AttribDeclaration

/***********************************************************
* User defined attributes look like:
* @foo(args, ...)
* @(args, ...)
*/
extern (C++) final class UserAttributeDeclaration : AttribDeclaration
Expand Down
16 changes: 8 additions & 8 deletions src/dmd/clone.d
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ extern (C++) FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
}

auto fparams = new Parameters();
fparams.push(new Parameter(STC.nodtor, sd.type, Id.p, null));
fparams.push(new Parameter(STC.nodtor, sd.type, Id.p, null, null));
auto tf = new TypeFunction(fparams, sd.handleType(), 0, LINK.d, stc | STC.ref_);
auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.assign, stc, tf);
fop.storage_class |= STC.inference;
Expand Down Expand Up @@ -498,7 +498,7 @@ extern (C++) FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
/* const bool opEquals(ref const S s);
*/
auto parameters = new Parameters();
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, null, null));
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, null, null, null));
tfeqptr = new TypeFunction(parameters, Type.tbool, 0, LINK.d);
tfeqptr.mod = MODFlags.const_;
tfeqptr = cast(TypeFunction)tfeqptr.typeSemantic(Loc.initial, &scx);
Expand All @@ -523,8 +523,8 @@ extern (C++) FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
Loc declLoc; // loc is unnecessary so __xopEquals is never called directly
Loc loc; // loc is unnecessary so errors are gagged
auto parameters = new Parameters();
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null));
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null));
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null));
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null));
auto tf = new TypeFunction(parameters, Type.tbool, 0, LINK.d);
Identifier id = Id.xopEquals;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
Expand Down Expand Up @@ -568,7 +568,7 @@ extern (C++) FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
/* const int opCmp(ref const S s);
*/
auto parameters = new Parameters();
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, null, null));
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, null, null, null));
tfcmpptr = new TypeFunction(parameters, Type.tint32, 0, LINK.d);
tfcmpptr.mod = MODFlags.const_;
tfcmpptr = cast(TypeFunction)tfcmpptr.typeSemantic(Loc.initial, &scx);
Expand Down Expand Up @@ -643,8 +643,8 @@ extern (C++) FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
Loc declLoc; // loc is unnecessary so __xopCmp is never called directly
Loc loc; // loc is unnecessary so errors are gagged
auto parameters = new Parameters();
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null));
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null));
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null));
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null));
auto tf = new TypeFunction(parameters, Type.tint32, 0, LINK.d);
Identifier id = Id.xopCmp;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
Expand Down Expand Up @@ -751,7 +751,7 @@ extern (C++) FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
Loc declLoc; // loc is unnecessary so __xtoHash is never called directly
Loc loc; // internal code should have no loc to prevent coverage
auto parameters = new Parameters();
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null));
parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null));
auto tf = new TypeFunction(parameters, Type.thash_t, 0, LINK.d, STC.nothrow_ | STC.trusted);
Identifier id = Id.xtoHash;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/cond.d
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ extern (C++) final class StaticForeach : RootObject
foreach (params; pparams)
{
auto p = aggrfe ? (*aggrfe.parameters)[i] : rangefe.prm;
params.push(new Parameter(p.storageClass, p.type, p.ident, null));
params.push(new Parameter(p.storageClass, p.type, p.ident, null, null));
}
}
Expression[2] res;
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ extern (C++) final class TupleDeclaration : Declaration
}
else
{
auto arg = new Parameter(0, t, null, null);
auto arg = new Parameter(0, t, null, null, null);
}
(*args)[i] = arg;
if (!t.deco)
Expand Down
8 changes: 8 additions & 0 deletions src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -3574,6 +3574,14 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
genCmain(sc);

assert(funcdecl.type.ty != Terror || funcdecl.errors);

// semantic for parameters' UDAs
foreach (i; 0 .. Parameter.dim(f.parameters))
{
Parameter param = Parameter.getNth(f.parameters, i);
if (param && param.userAttribDecl)
param.userAttribDecl.dsymbolSemantic(sc);
}
}

/// Do the semantic analysis on the external interface to the function.
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -6692,7 +6692,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
for (size_t i = 0; i < dim; i++)
{
Parameter arg = (*tt.arguments)[i];
if (flags & 2 && arg.ident)
if (flags & 2 && (arg.ident || arg.userAttribDecl))
tiargs.insert(j + i, arg);
else
tiargs.insert(j + i, arg.type);
Expand Down
6 changes: 3 additions & 3 deletions src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -1098,7 +1098,7 @@ private bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type tthis,
args.setDim(arguments.dim - nparams);
for (size_t i = 0; i < arguments.dim - nparams; i++)
{
auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null);
auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null, null);
(*args)[i] = arg;
}
auto tup = new TypeTuple(args);
Expand Down Expand Up @@ -3888,7 +3888,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
for (size_t i = 0; i < cd.baseclasses.dim; i++)
{
BaseClass* b = (*cd.baseclasses)[i];
args.push(new Parameter(STC.in_, b.type, null, null));
args.push(new Parameter(STC.in_, b.type, null, null, null));
}
tded = new TypeTuple(args);
}
Expand Down Expand Up @@ -3935,7 +3935,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == TOK.error)
return setError();
args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null));
args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl));
}
tded = new TypeTuple(args);
break;
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -2170,7 +2170,7 @@ extern (C++) class FuncDeclaration : Declaration
Parameter p = null;
if (canBuildResultVar())
{
p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null);
p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
fparams.push(p);
}
auto tf = new TypeFunction(fparams, Type.tvoid, 0, LINK.d);
Expand Down
12 changes: 12 additions & 0 deletions src/dmd/hdrgen.d
Original file line number Diff line number Diff line change
Expand Up @@ -3103,6 +3103,18 @@ public:
////////////////////////////////////////////////////////////////////////////
override void visit(Parameter p)
{
if (p.userAttribDecl)
{
buf.writestring("@");
scope(exit) buf.writestring(" ");

bool isAnonymous = p.userAttribDecl.atts.dim > 0 && (*p.userAttribDecl.atts)[0].op != TOK.call;
if (isAnonymous)
buf.writestring("(");
argsToBuffer(p.userAttribDecl.atts);
if (isAnonymous)
buf.writestring(")");
}
if (p.storageClass & STC.auto_)
buf.writestring("auto ");
if (p.storageClass & STC.return_)
Expand Down
23 changes: 14 additions & 9 deletions src/dmd/mtype.d
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import core.stdc.string;
import dmd.access;
import dmd.aggregate;
import dmd.arraytypes;
import dmd.attrib;
import dmd.gluelayer;
import dmd.complex;
import dmd.dclass;
Expand Down Expand Up @@ -4757,7 +4758,7 @@ extern (C++) final class TypeFunction : TypeNext
continue;
if (params == parameters)
params = parameters.copy();
(*params)[i] = new Parameter(p.storageClass, t, null, null);
(*params)[i] = new Parameter(p.storageClass, t, null, null, null);
}
if (next == tret && params == parameters)
return this;
Expand Down Expand Up @@ -6555,7 +6556,7 @@ extern (C++) final class TypeTuple : Type
Expression e = (*exps)[i];
if (e.type.ty == Ttuple)
e.error("cannot form tuple of tuples");
auto arg = new Parameter(STC.undefined_, e.type, null, null);
auto arg = new Parameter(STC.undefined_, e.type, null, null, null);
(*arguments)[i] = arg;
}
}
Expand All @@ -6581,15 +6582,15 @@ extern (C++) final class TypeTuple : Type
{
super(Ttuple);
arguments = new Parameters();
arguments.push(new Parameter(0, t1, null, null));
arguments.push(new Parameter(0, t1, null, null, null));
}

extern (D) this(Type t1, Type t2)
{
super(Ttuple);
arguments = new Parameters();
arguments.push(new Parameter(0, t1, null, null));
arguments.push(new Parameter(0, t2, null, null));
arguments.push(new Parameter(0, t1, null, null, null));
arguments.push(new Parameter(0, t2, null, null, null));
}

override const(char)* kind() const
Expand Down Expand Up @@ -6751,27 +6752,31 @@ extern (C++) final class TypeNull : Type
*/
extern (C++) final class Parameter : RootObject
{
import dmd.attrib : UserAttributeDeclaration;

StorageClass storageClass;
Type type;
Identifier ident;
Expression defaultArg;
UserAttributeDeclaration userAttribDecl; // user defined attributes

extern (D) this(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg)
extern (D) this(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl)
{
this.type = type;
this.ident = ident;
this.storageClass = storageClass;
this.defaultArg = defaultArg;
this.userAttribDecl = userAttribDecl;
}

static Parameter create(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg)
static Parameter create(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl)
{
return new Parameter(storageClass, type, ident, defaultArg);
return new Parameter(storageClass, type, ident, defaultArg, userAttribDecl);
}

Parameter syntaxCopy()
{
return new Parameter(storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null);
return new Parameter(storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null, userAttribDecl ? cast(UserAttributeDeclaration) userAttribDecl.syntaxCopy(null) : null);
}

/****************************************************
Expand Down
4 changes: 3 additions & 1 deletion src/dmd/mtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -842,8 +842,10 @@ class Parameter : public RootObject
Type *type;
Identifier *ident;
Expression *defaultArg;
UserAttributeDeclaration *userAttribDecl; // user defined attributes

static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg);
static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident,
Expression *defaultArg, UserAttributeDeclaration *userAttribDecl);
Parameter *syntaxCopy();
Type *isLazyArray();
// kludge for template.isType()
Expand Down
Loading

0 comments on commit 4679f23

Please sign in to comment.