diff --git a/src/arrayop.c b/src/arrayop.c index 8f93e5ab458a..da9dc6c9e2ed 100644 --- a/src/arrayop.c +++ b/src/arrayop.c @@ -54,7 +54,7 @@ FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc, Loc loc Parameter *p = (*fparams)[0]; // foreach (i; 0 .. p.length) Statement *s1 = new ForeachRangeStatement(Loc(), TOKforeach, - new Parameter(0, NULL, Id::p, NULL), + new Parameter(0, NULL, Id::p, NULL, NULL), new IntegerExp(Loc(), 0, Type::tsize_t), new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p->ident)), new ExpStatement(Loc(), loopbody), @@ -425,7 +425,7 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams) void visit(Expression *e) { Identifier *id = Identifier::generateId("c", fparams->dim); - Parameter *param = new Parameter(0, e->type, id, NULL); + Parameter *param = new Parameter(0, e->type, id, NULL, NULL); fparams->shift(param); result = new IdentifierExp(Loc(), id); } @@ -444,7 +444,7 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams) void visit(ArrayLiteralExp *e) { Identifier *id = Identifier::generateId("p", fparams->dim); - Parameter *param = new Parameter(STCconst, e->type, id, NULL); + Parameter *param = new Parameter(STCconst, e->type, id, NULL, NULL); fparams->shift(param); Expression *ie = new IdentifierExp(Loc(), id); Expressions *arguments = new Expressions(); @@ -456,7 +456,7 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams) void visit(SliceExp *e) { Identifier *id = Identifier::generateId("p", fparams->dim); - Parameter *param = new Parameter(STCconst, e->type, id, NULL); + Parameter *param = new Parameter(STCconst, e->type, id, NULL, NULL); fparams->shift(param); Expression *ie = new IdentifierExp(Loc(), id); Expressions *arguments = new Expressions(); diff --git a/src/clone.c b/src/clone.c index 5d057fc7f351..eb74f2ff3d4e 100644 --- a/src/clone.c +++ b/src/clone.c @@ -231,7 +231,7 @@ FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc) } Parameters *fparams = new Parameters; - fparams->push(new Parameter(STCnodtor, sd->type, Id::p, NULL)); + fparams->push(new Parameter(STCnodtor, sd->type, Id::p, NULL, NULL)); TypeFunction *tf = new TypeFunction(fparams, sd->handleType(), 0, LINKd, stc | STCref); FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf); @@ -477,7 +477,7 @@ FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc) /* const bool opEquals(ref const S s); */ Parameters *parameters = new Parameters; - parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL)); + parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL, NULL)); tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd); tfeqptr->mod = MODconst; tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), &scx); @@ -510,8 +510,8 @@ FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc) Loc loc = Loc(); // loc is unnecessary so errors are gagged Parameters *parameters = new Parameters; - parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL)); - parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL)); + parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL, NULL)); + parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL, NULL)); TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd); Identifier *id = Id::xopEquals; @@ -562,7 +562,7 @@ FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc) /* const int opCmp(ref const S s); */ Parameters *parameters = new Parameters; - parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL)); + parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL, NULL)); tfcmpptr = new TypeFunction(parameters, Type::tint32, 0, LINKd); tfcmpptr->mod = MODconst; tfcmpptr = (TypeFunction *)tfcmpptr->semantic(Loc(), &scx); @@ -635,8 +635,8 @@ FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc) Loc loc = Loc(); // loc is unnecessary so errors are gagged Parameters *parameters = new Parameters; - parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL)); - parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL)); + parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL, NULL)); + parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL, NULL)); TypeFunction *tf = new TypeFunction(parameters, Type::tint32, 0, LINKd); Identifier *id = Id::xopCmp; @@ -748,7 +748,7 @@ FuncDeclaration *buildXtoHash(StructDeclaration *sd, Scope *sc) Loc loc = Loc(); // internal code should have no loc to prevent coverage Parameters *parameters = new Parameters(); - parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL)); + parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL, NULL)); TypeFunction *tf = new TypeFunction(parameters, Type::thash_t, 0, LINKd, STCnothrow | STCtrusted); Identifier *id = Id::xtoHash; diff --git a/src/declaration.c b/src/declaration.c index 3bdec1e11e99..7ef02959ee70 100644 --- a/src/declaration.c +++ b/src/declaration.c @@ -243,7 +243,7 @@ Type *TupleDeclaration::getType() Identifier *id = new Identifier(name, TOKidentifier); Parameter *arg = new Parameter(STCin, t, id, NULL); #else - Parameter *arg = new Parameter(0, t, NULL, NULL); + Parameter *arg = new Parameter(0, t, NULL, NULL, NULL); #endif (*args)[i] = arg; if (!t->deco) diff --git a/src/expression.c b/src/expression.c index 29075ec07edc..7989c19498e2 100644 --- a/src/expression.c +++ b/src/expression.c @@ -1917,7 +1917,7 @@ bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf, args->setDim(arguments->dim - nparams); for (size_t i = 0; i < arguments->dim - nparams; i++) { - Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL); + Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL, NULL); (*args)[i] = arg; } @@ -6295,7 +6295,7 @@ Expression *IsExp::semantic(Scope *sc) for (size_t i = 0; i < cd->baseclasses->dim; i++) { BaseClass *b = (*cd->baseclasses)[i]; - args->push(new Parameter(STCin, b->type, NULL, NULL)); + args->push(new Parameter(STCin, b->type, NULL, NULL, NULL)); } tded = new TypeTuple(args); } @@ -6343,8 +6343,9 @@ Expression *IsExp::semantic(Scope *sc) arg->defaultArg->op == TOKerror) return new ErrorExp(); args->push(new Parameter(arg->storageClass, arg->type, - (tok2 == TOKparameters) ? arg->ident : NULL, - (tok2 == TOKparameters) ? arg->defaultArg : NULL)); + (tok2 == TOKparameters) ? arg->ident : NULL, + (tok2 == TOKparameters) ? arg->defaultArg : NULL, + arg->userAttribDecl)); } tded = new TypeTuple(args); break; diff --git a/src/func.c b/src/func.c index a15d4d9aac71..9cff29f0089c 100644 --- a/src/func.c +++ b/src/func.c @@ -1138,7 +1138,7 @@ void FuncDeclaration::semantic(Scope *sc) Parameter *p = NULL; if (outId) { - p = new Parameter(STCref | STCconst, f->nextOf(), outId, NULL); + p = new Parameter(STCref | STCconst, f->nextOf(), outId, NULL, NULL); fparams->push(p); } TypeFunction *tf = new TypeFunction(fparams, Type::tvoid, 0, LINKd); @@ -1214,10 +1214,37 @@ void FuncDeclaration::semantic(Scope *sc) genCmain(sc); assert(type->ty != Terror || errors); + + //semantic for parameters' UDAs + for (size_t i = 0; i < nparams; i++) + { + Parameter *param = Parameter::getNth(f->parameters, i); + if (param && param->userAttribDecl) + param->userAttribDecl->semantic(sc); + } } void FuncDeclaration::semantic2(Scope *sc) { +#if 0 + printf("FuncDeclaration::semantic2('%s')\n", toPrettyChars()); +#endif + if (semanticRun >= PASSsemantic2) + return; + assert(semanticRun <= PASSsemantic2); + semanticRun = PASSsemantic2; + + if (!type || type->ty != Tfunction) return; + TypeFunction *f = (TypeFunction *)type; + if (!f->parameters) return; + size_t nparams = Parameter::dim(f->parameters); + //semantic for parameters' UDAs + for (size_t i = 0; i < nparams; i++) + { + Parameter *param = Parameter::getNth(f->parameters, i); + if (param && param->userAttribDecl) + param->userAttribDecl->semantic2(sc); + } } // Do the semantic analysis on the internals of the function. @@ -1428,6 +1455,8 @@ void FuncDeclaration::semantic3(Scope *sc) parameters->push(v); localsymtab->insert(v); v->parent = this; + if (fparam->userAttribDecl) + v->userAttribDecl = fparam->userAttribDecl; } } @@ -2188,10 +2217,22 @@ void FuncDeclaration::semantic3(Scope *sc) * done by TemplateInstance::semantic. * Otherwise, error gagging should be temporarily ungagged by functionSemantic3. */ - semanticRun = PASSsemantic3done; - semantic3Errors = (global.errors != nerrors) || (fbody && fbody->isErrorStatement()); if (type->ty == Terror) errors = true; + + if (!errors) + { + assert(f); + size_t nparams = f->parameters ? Parameter::dim(f->parameters) : 0; + for (size_t i = 0; i < nparams; i++) + { + Parameter *param = Parameter::getNth(f->parameters, i); + if (param && param->userAttribDecl) + param->userAttribDecl->semantic3(sc); + } + } + semanticRun = PASSsemantic3done; + semantic3Errors = (global.errors != nerrors) || (fbody && fbody->isErrorStatement()); //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); //fflush(stdout); } diff --git a/src/hdrgen.c b/src/hdrgen.c index caf8e929dc1c..ff9e4d767939 100644 --- a/src/hdrgen.c +++ b/src/hdrgen.c @@ -2913,6 +2913,12 @@ class PrettyPrintVisitor : public Visitor void visit(Parameter *p) { + if (p->userAttribDecl) + { + buf->writestring("@("); + argsToBuffer(p->userAttribDecl->atts); + buf->writestring(") "); + } if (p->storageClass & STCauto) buf->writestring("auto "); diff --git a/src/mtype.c b/src/mtype.c index 72a79026a205..ec602d522e32 100644 --- a/src/mtype.c +++ b/src/mtype.c @@ -1573,7 +1573,7 @@ Type *stripDefaultArgs(Type *t) { Parameter *p = (*params)[i]; Type *ta = stripDefaultArgs(p->type); - if (ta != p->type || p->defaultArg || p->ident) + if (ta != p->type || p->defaultArg || p->ident || p->userAttribDecl) { if (params == parameters) { @@ -1583,7 +1583,7 @@ Type *stripDefaultArgs(Type *t) (*params)[j] = (*parameters)[j]; } StorageClass stc = p->storageClass & (~STCauto); // issue 14656 - (*params)[i] = new Parameter(stc, ta, NULL, NULL); + (*params)[i] = new Parameter(stc, ta, NULL, NULL, NULL); } } } @@ -2037,7 +2037,7 @@ Type *TypeFunction::substWildTo(unsigned) 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; @@ -3706,7 +3706,7 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f Parameters *params = new Parameters; Type *next = n->ty == Twchar ? Type::twchar : Type::tchar; Type *arrty = next->arrayOf(); - params->push(new Parameter(0, arrty, NULL, NULL)); + params->push(new Parameter(0, arrty, NULL, NULL, NULL)); reverseFd[i] = FuncDeclaration::genCfunc(params, arrty, reverseName[i]); } @@ -3729,7 +3729,7 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f Parameters *params = new Parameters; Type *next = n->ty == Twchar ? Type::twchar : Type::tchar; Type *arrty = next->arrayOf(); - params->push(new Parameter(0, arrty, NULL, NULL)); + params->push(new Parameter(0, arrty, NULL, NULL, NULL)); sortFd[i] = FuncDeclaration::genCfunc(params, arrty, sortName[i]); } @@ -3754,8 +3754,8 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f if (!adReverse_fd) { Parameters *params = new Parameters; - params->push(new Parameter(0, Type::tvoid->arrayOf(), NULL, NULL)); - params->push(new Parameter(0, Type::tsize_t, NULL, NULL)); + params->push(new Parameter(0, Type::tvoid->arrayOf(), NULL, NULL, NULL)); + params->push(new Parameter(0, Type::tsize_t, NULL, NULL, NULL)); adReverse_fd = FuncDeclaration::genCfunc(params, Type::tvoid->arrayOf(), Id::adReverse); } fd = adReverse_fd; @@ -3778,8 +3778,8 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int f if (!fd) { Parameters *params = new Parameters; - params->push(new Parameter(0, Type::tvoid->arrayOf(), NULL, NULL)); - params->push(new Parameter(0, Type::dtypeinfo->type, NULL, NULL)); + params->push(new Parameter(0, Type::tvoid->arrayOf(), NULL, NULL, NULL)); + params->push(new Parameter(0, Type::dtypeinfo->type, NULL, NULL, NULL)); fd = FuncDeclaration::genCfunc(params, Type::tvoid->arrayOf(), "_adSort"); } ec = new VarExp(Loc(), fd); @@ -4786,7 +4786,7 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int if (fd_aaLen == NULL) { Parameters *fparams = new Parameters(); - fparams->push(new Parameter(STCin, this, NULL, NULL)); + fparams->push(new Parameter(STCin, this, NULL, NULL, NULL)); fd_aaLen = FuncDeclaration::genCfunc(fparams, Type::tsize_t, Id::aaLen); TypeFunction *tf = (TypeFunction *)fd_aaLen->type; tf->purity = PUREconst; @@ -5608,7 +5608,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) { Parameter *narg = (*tt->arguments)[j]; (*newparams)[j] = new Parameter(narg->storageClass | fparam->storageClass, - narg->type, narg->ident, narg->defaultArg); + narg->type, narg->ident, narg->defaultArg, narg->userAttribDecl); } fparam->type = new TypeTuple(newparams); } @@ -8685,7 +8685,7 @@ TypeTuple::TypeTuple(Expressions *exps) { Expression *e = (*exps)[i]; if (e->type->ty == Ttuple) e->error("cannot form tuple of tuples"); - Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL); + Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL, NULL); (*arguments)[i] = arg; } } @@ -8711,15 +8711,15 @@ TypeTuple::TypeTuple(Type *t1) : Type(Ttuple) { arguments = new Parameters(); - arguments->push(new Parameter(0, t1, NULL, NULL)); + arguments->push(new Parameter(0, t1, NULL, NULL, NULL)); } TypeTuple::TypeTuple(Type *t1, Type *t2) : Type(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)); } const char *TypeTuple::kind() @@ -9016,17 +9016,18 @@ Expression *TypeNull::defaultInit(Loc loc) { return new NullExp(Loc(), Type::tnu /***************************** Parameter *****************************/ -Parameter::Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg) +Parameter::Parameter(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; } -Parameter *Parameter::create(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg) +Parameter *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 *Parameter::syntaxCopy() @@ -9034,7 +9035,8 @@ Parameter *Parameter::syntaxCopy() return new Parameter(storageClass, type ? type->syntaxCopy() : NULL, ident, - defaultArg ? defaultArg->syntaxCopy() : NULL); + defaultArg ? defaultArg->syntaxCopy() : NULL, + userAttribDecl ? (UserAttributeDeclaration *)userAttribDecl->syntaxCopy(NULL) : NULL); } Parameters *Parameter::arraySyntaxCopy(Parameters *parameters) diff --git a/src/mtype.h b/src/mtype.h index e0848b184f5c..fd64e16d81d9 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -911,9 +911,12 @@ class Parameter : public RootObject Type *type; Identifier *ident; Expression *defaultArg; + UserAttributeDeclaration *userAttribDecl; // user defined attributes - Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg); - static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg); + Parameter(StorageClass storageClass, Type *type, Identifier *ident, + Expression *defaultArg, UserAttributeDeclaration *userAttribDecl); + static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident, + Expression *defaultArg, UserAttributeDeclaration *userAttribDecl); Parameter *syntaxCopy(); Type *isLazyArray(); // kludge for template.isType() diff --git a/src/parse.c b/src/parse.c index dd03b42e3773..03e9c5664341 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1904,9 +1904,11 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) StorageClass storageClass = 0; StorageClass stc; Expression *ae; + Expressions *udas = NULL; for (;1; nextToken()) { + L3: switch (token.value) { case TOKrparen: @@ -1940,7 +1942,27 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) goto Ldefault; stc = STCwild; goto L2; + case TOKat: + { + Expressions *exps = NULL; + StorageClass stc2 = parseAttribute(&exps); + + if (stc2 == STCproperty || stc2 == STCnogc || stc2 == STCdisable || + stc2 == STCsafe || stc2 == STCtrusted || stc2 == STCsystem) + { + error("@%s attribute for function parameter is not supported", token.toChars()); + } + else + { + udas = UserAttributeDeclaration::concat(udas, exps); + } + if (token.value == TOKdotdotdot) + error("variadic parameter cannot has UDAs"); + if (stc2) + nextToken(); + goto L3; // Don't call nextToken again. + } case TOKin: stc = STCin; goto L2; case TOKout: stc = STCout; goto L2; case TOKref: stc = STCref; goto L2; @@ -2020,6 +2042,32 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) error("default argument expected for %s", ai ? ai->toChars() : at->toChars()); } + Parameter *param = new Parameter(storageClass, at, ai, ae, NULL); + if (udas) + { + Dsymbols *a = new Dsymbols(); + UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a); + param->userAttribDecl = udad; + } + + if (token.value == TOKat) + { + Expressions *exps = NULL; + StorageClass stc2 = parseAttribute(&exps); + + if (stc2 == STCproperty || stc2 == STCnogc || stc2 == STCdisable || + stc2 == STCsafe || stc2 == STCtrusted || stc2 == STCsystem) + { + error("@%s attribute for function parameter is not supported", token.toChars()); + } + else + { + error("user defined attributes cannot appear as postfixes", token.toChars()); + } + if (stc2) + nextToken(); + } + if (token.value == TOKdotdotdot) { /* This is: * at ai ... @@ -2028,11 +2076,12 @@ Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) if (storageClass & (STCout | STCref)) error("variadic argument cannot be out or ref"); varargs = 2; - parameters->push(new Parameter(storageClass, at, ai, ae)); + parameters->push(param); nextToken(); break; } - parameters->push(new Parameter(storageClass, at, ai, ae)); + parameters->push(param); + if (token.value == TOKcomma) { nextToken(); goto L1; @@ -4144,7 +4193,7 @@ Dsymbol *Parser::parseFunctionLiteral() parameters = new Parameters(); Identifier *id = Identifier::generateId("__T"); Type *t = new TypeIdentifier(loc, id); - parameters->push(new Parameter(0, t, token.ident, NULL)); + parameters->push(new Parameter(0, t, token.ident, NULL, NULL)); tpl = new TemplateParameters(); TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL); @@ -5097,7 +5146,7 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc if (!ai) error("no identifier for declarator %s", at->toChars()); Larg: - Parameter *p = new Parameter(storageClass, at, ai, NULL); + Parameter *p = new Parameter(storageClass, at, ai, NULL, NULL); parameters->push(p); if (token.value == TOKcomma) { nextToken(); @@ -5193,14 +5242,14 @@ Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc Type *at = NULL; // infer parameter type nextToken(); check(TOKassign); - param = new Parameter(storageClass, at, ai, NULL); + param = new Parameter(storageClass, at, ai, NULL, NULL); } else if (isDeclaration(&token, 2, TOKassign, NULL)) { Identifier *ai; Type *at = parseType(&ai); check(TOKassign); - param = new Parameter(storageClass, at, ai, NULL); + param = new Parameter(storageClass, at, ai, NULL, NULL); } condition = parseExpression(); diff --git a/src/statement.c b/src/statement.c index 9618dda266e5..7d74a64fb05b 100644 --- a/src/statement.c +++ b/src/statement.c @@ -2458,7 +2458,7 @@ Statement *ForeachStatement::semantic(Scope *sc) s = new ExpStatement(Loc(), v); body = new CompoundStatement(loc, s, body); } - params->push(new Parameter(stc, p->type, id, NULL)); + params->push(new Parameter(stc, p->type, id, NULL, NULL)); } // Bugzilla 13840: Throwable nested function inside nothrow function is acceptable. StorageClass stc = mergeFuncAttrs(STCsafe | STCpure | STCnogc, func); @@ -2533,14 +2533,14 @@ Statement *ForeachStatement::semantic(Scope *sc) if (!fdapply[i]) { params = new Parameters(); - params->push(new Parameter(0, Type::tvoid->pointerTo(), NULL, NULL)); - params->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); + params->push(new Parameter(0, Type::tvoid->pointerTo(), NULL, NULL, NULL)); + params->push(new Parameter(STCin, Type::tsize_t, NULL, NULL, NULL)); Parameters* dgparams = new Parameters; - dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL)); + dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL)); if (dim == 2) - dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL)); + dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL)); fldeTy[i] = new TypeDelegate(new TypeFunction(dgparams, Type::tint32, 0, LINKd)); - params->push(new Parameter(0, fldeTy[i], NULL, NULL)); + params->push(new Parameter(0, fldeTy[i], NULL, NULL, NULL)); fdapply[i] = FuncDeclaration::genCfunc(params, Type::tint32, name[i]); } @@ -2596,13 +2596,13 @@ Statement *ForeachStatement::semantic(Scope *sc) FuncDeclaration *fdapply; TypeDelegate *dgty; params = new Parameters(); - params->push(new Parameter(STCin, tn->arrayOf(), NULL, NULL)); + params->push(new Parameter(STCin, tn->arrayOf(), NULL, NULL, NULL)); Parameters* dgparams = new Parameters; - dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL)); + dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL)); if (dim == 2) - dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL)); + dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL)); dgty = new TypeDelegate(new TypeFunction(dgparams, Type::tint32, 0, LINKd)); - params->push(new Parameter(0, dgty, NULL, NULL)); + params->push(new Parameter(0, dgty, NULL, NULL, NULL)); fdapply = FuncDeclaration::genCfunc(params, Type::tint32, fdname); if (tab->ty == Tsarray) @@ -4406,7 +4406,7 @@ Statement *SynchronizedStatement::semantic(Scope *sc) cs->push(new ExpStatement(loc, tmp)); Parameters* args = new Parameters; - args->push(new Parameter(0, ClassDeclaration::object->type, NULL, NULL)); + args->push(new Parameter(0, ClassDeclaration::object->type, NULL, NULL, NULL)); FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter); Expression *e = new CallExp(loc, new VarExp(loc, fdenter), new VarExp(loc, tmp)); @@ -4447,7 +4447,7 @@ Statement *SynchronizedStatement::semantic(Scope *sc) cs->push(new ExpStatement(loc, v)); Parameters* args = new Parameters; - args->push(new Parameter(0, t->pointerTo(), NULL, NULL)); + args->push(new Parameter(0, t->pointerTo(), NULL, NULL, NULL)); FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter, STCnothrow); Expression *e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); diff --git a/src/template.c b/src/template.c index c65159e744d2..918a5f7997a1 100644 --- a/src/template.c +++ b/src/template.c @@ -6637,7 +6637,7 @@ bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f 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); diff --git a/src/traits.c b/src/traits.c index cf6ecd9abaa7..03b8ab050ed7 100644 --- a/src/traits.c +++ b/src/traits.c @@ -472,7 +472,8 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) printf("TraitsExp::semantic() %s\n", e->toChars()); #endif if (e->ident != Id::compiles && e->ident != Id::isSame && - e->ident != Id::identifier && e->ident != Id::getProtection) + e->ident != Id::identifier && e->ident != Id::getProtection && + e->ident != Id::getAttributes) { if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1)) return new ErrorExp(); @@ -623,8 +624,12 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) Identifier *id; if (po) { + if (!po->ident) + { + e->error("argument %s has no identifier", po->type->toChars()); + goto Lfalse; + } id = po->ident; - assert(id); } else { @@ -871,11 +876,33 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) } else if (e->ident == Id::getAttributes) { + /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that + * a symbol should not be folded to a constant. + * Bit 1 means don't convert Parameter to Type if Parameter has an identifier + */ + if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 3)) + return new ErrorExp(); + if (dim != 1) goto Ldimerror; RootObject *o = (*e->args)[0]; + Parameter *po = isParameter(o); Dsymbol *s = getDsymbol(o); - if (!s) + UserAttributeDeclaration *udad = NULL; + if (po) + { + udad = po->userAttribDecl; + } + else if (s) + { + if (s->isImport()) + { + s = s->isImport()->mod; + } + //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->scope); + udad = s->userAttribDecl; + } + else { #if 0 Expression *x = isExpression(o); @@ -886,12 +913,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) e->error("first argument is not a symbol"); goto Lfalse; } - if (s->isImport()) - { - s = s->isImport()->mod; - } - //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->scope); - UserAttributeDeclaration *udad = s->userAttribDecl; + TupleExp *tup = new TupleExp(e->loc, udad ? udad->getAttributes() : new Expressions()); return tup->semantic(sc); } diff --git a/test/fail_compilation/udaparams.d b/test/fail_compilation/udaparams.d new file mode 100644 index 000000000000..a2409d341bad --- /dev/null +++ b/test/fail_compilation/udaparams.d @@ -0,0 +1,24 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/udaparams.d(15): Error: variadic parameter cannot has UDAs +fail_compilation/udaparams.d(16): Error: variadic parameter cannot has UDAs +fail_compilation/udaparams.d(18): Error: user defined attributes cannot appear as postfixes +fail_compilation/udaparams.d(19): Error: user defined attributes cannot appear as postfixes +fail_compilation/udaparams.d(20): Error: user defined attributes cannot appear as postfixes +fail_compilation/udaparams.d(22): Error: @safe attribute for function parameter is not supported +fail_compilation/udaparams.d(23): Error: @safe attribute for function parameter is not supported +fail_compilation/udaparams.d(24): Error: @safe attribute for function parameter is not supported +--- +*/ + +void vararg1(int a, @(10) ...); +extern(C) void vararg2(int a, @(10) ...); + +void rhsuda(int a @(10)); +void rhsuda2(int @(10)); +void rhsuda3(int[] arr @(10) ...); + +void wrongAttr1(@safe int); +void wrongAttr2(@safe void function()); +void wrongAttr3(@safe void delegate()); diff --git a/test/runnable/uda.d b/test/runnable/uda.d index ee8920bd2f56..7f5e94a7b80a 100644 --- a/test/runnable/uda.d +++ b/test/runnable/uda.d @@ -467,6 +467,94 @@ static assert(__traits(getAttributes, FileData11844.member)[0](new FileData11844 /************************************************/ +template TypeTuple(T...) +{ + alias TypeTuple = T; +} + +template ParameterUDA(size_t p_num, func...) + if (func.length == 1 && is(typeof(func[0]) PT == __parameters) && PT.length > p_num) +{ + static if (is(typeof(func[0]) PT == __parameters)) + { + template Get(size_t i) + { + static if (//!isFunctionPointer!func && !isDelegate!func + // Parameters without UDA may yield CT error. + /*&&*/ is(typeof(__traits(getAttributes, PT[i..i+1]))x)) + { + alias Get = TypeTuple!(__traits(getAttributes, PT[i..i+1])); + } + else + { + alias Get = TypeTuple!(); + } + } + } + else + { + static assert(0, func[0].stringof ~ "is not a function"); + + // Define dummy entities to avoid pointless errors + template Get(size_t i) { alias Get = TypeTuple!(); } + alias PT = TypeTuple!(); + } + + alias ParameterUDA = Get!p_num; +} + +void test13x(@(10) int a, @(20) int, @(30) @(40) int[] arr...) {} + +void test13() +{ + static assert([ParameterUDA!(0, test13x)] == [10]); + static assert([ParameterUDA!(1, test13x)] == [20]); + static assert([ParameterUDA!(2, test13x)] == [30, 40]); +} + +template Test13t(F) +{ + static assert(!__traits(compiles, ParameterUDA!(0, F))); + static assert(!__traits(compiles, ParameterUDA!(1, F))); + static assert(!__traits(compiles, ParameterUDA!(2, F))); + enum Test13t = true; +} + +alias test13t = Test13t!(typeof(test13x)); + +enum Test14UDA1; + +struct Test14UDA2 +{ + string str; +} + +Test14UDA2 test14uda3(string name) +{ + return Test14UDA2(name); +} + +struct Test14UDA4(string v) +{ +} + +void test14x(@Test14UDA1 int, @Test14UDA2("1") int, @test14uda3("2") int, @Test14UDA4!"3" int) {} +void test14() +{ + static assert(is(ParameterUDA!(0, test14x)[0] == Test14UDA1)); + static assert(ParameterUDA!(1, test14x)[0] == Test14UDA2("1")); + static assert(ParameterUDA!(2, test14x)[0] == test14uda3("2")); + static assert(is(ParameterUDA!(3, test14x)[0] == Test14UDA4!"3")); +} + +void test15x(@(20) void delegate(int) @safe dg) +{ + static assert([__traits(getAttributes, dg)] == [20]); + static assert(is(typeof(dg) == void delegate(int) @safe)); +} + +/************************************************/ + int main() { test1(); @@ -482,6 +570,8 @@ int main() test11(); test12(); test9178(); + test13(); + test14(); printf("Success\n"); return 0;