Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]);
}
---
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps include an example of how to get the UDAs of a parameter from outside of a function. Or should that be left as an exercise for the reader 😃.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a bit more complicated and I think we will provide an interface in std.traits anyhow.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok.

8 changes: 5 additions & 3 deletions src/dmd/astbase.d
Original file line number Diff line number Diff line change
Expand Up @@ -1734,15 +1734,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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expression defaultArg, UserAttributeDeclaration userAttribDecl = null)

Giving this a default value would save on a lot of code edits that just add a null as the last parameter. Not sure if default values are being avoided here on purpose or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT is the prevalent coding style in the DMD source code to prefer explicitness.

{
this.storageClass = storageClass;
this.type = type;
this.ident = ident;
this.defaultArg = defaultArg;
this.userAttribDecl = userAttribDecl;
Copy link
Contributor Author

@wilzbach wilzbach Jan 2, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RazvanN7 do you have any plans on removing the giant code duplication in astbase?

}

static size_t dim(Parameters* parameters)
Expand Down Expand Up @@ -1809,7 +1811,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 @@ -3623,7 +3625,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 @@ -1263,6 +1263,7 @@ extern (C++) final class CompileDeclaration : AttribDeclaration

/***********************************************************
* User defined attributes look like:
* @foo(args, ...)
* @(args, ...)
*/
extern (C++) final class UserAttributeDeclaration : AttribDeclaration
Expand Down
18 changes: 9 additions & 9 deletions src/dmd/clone.d
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,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 @@ -504,7 +504,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 @@ -529,8 +529,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 @@ -574,7 +574,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 @@ -649,8 +649,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 @@ -757,7 +757,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 Expand Up @@ -1009,7 +1009,7 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
// // TODO: if (del) delete (char*)this;
// return (void*) this;
// }
Parameter delparam = new Parameter(STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32));
Parameter delparam = new Parameter(STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32), null);
Parameters* params = new Parameters;
params.push(delparam);
auto ftype = new TypeFunction(params, Type.tvoidptr, false, LINK.cpp, dtor.storage_class);
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 @@ -621,7 +621,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 @@ -3581,6 +3581,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 @@ -6684,7 +6684,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 @@ -1106,7 +1106,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 @@ -3934,7 +3934,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 @@ -3981,7 +3981,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 @@ -3114,6 +3114,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 @@ -20,6 +20,7 @@ import core.stdc.string;

import dmd.aggregate;
import dmd.arraytypes;
import dmd.attrib;
import dmd.gluelayer;
import dmd.dclass;
import dmd.declaration;
Expand Down Expand Up @@ -4615,7 +4616,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 @@ -6040,7 +6041,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 @@ -6066,15 +6067,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 @@ -6215,27 +6216,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 @@ -821,8 +821,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