From patchwork Thu Jan 7 17:26:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 1423396 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gcc.gnu.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=Jxg5/7ym; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4DBY7B5pcvz9sVw for ; Fri, 8 Jan 2021 04:26:29 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E8C62386EC62; Thu, 7 Jan 2021 17:26:26 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E8C62386EC62 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1610040387; bh=5UjgDflCE+9YQ9ktSSpECimsbzaVSMWUTRE4lpCt1KA=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=Jxg5/7ymdaIU78wuxt7mklYt1kmu/T0sv7Dfy5TeN0xOL2tWw0cn5bXw8L5Pi84wK vkZS3ZPe3hM6SH3eUVi5tdDO8Zyb+IycV+Ot3OLv4C0NoOFlaXfGJqOnfEkyyp/M81 BJB/hgBpFDLCNlmz3eXF8Jp6ETTIkS3eoa7qNAsI= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-202.mailbox.org (mout-p-202.mailbox.org [IPv6:2001:67c:2050::465:202]) by sourceware.org (Postfix) with ESMTPS id A5CAD3858039 for ; Thu, 7 Jan 2021 17:26:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org A5CAD3858039 Received: from smtp2.mailbox.org (smtp2.mailbox.org [80.241.60.241]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-202.mailbox.org (Postfix) with ESMTPS id 4DBY6y70VTzQlVR; Thu, 7 Jan 2021 18:26:18 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de Received: from smtp2.mailbox.org ([80.241.60.241]) by spamfilter06.heinlein-hosting.de (spamfilter06.heinlein-hosting.de [80.241.56.125]) (amavisd-new, port 10030) with ESMTP id wwzVTgWGod69; Thu, 7 Jan 2021 18:26:12 +0100 (CET) To: gcc-patches@gcc.gnu.org Subject: [committed] d: Merge upstream dmd 9038e64c5. Date: Thu, 7 Jan 2021 18:26:10 +0100 Message-Id: <20210107172610.677198-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-MBO-SPAM-Probability: * X-Rspamd-Score: 1.15 / 15.00 / 15.00 X-Rspamd-Queue-Id: E663917B7 X-Rspamd-UID: 37db2a X-Spam-Status: No, score=-15.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Iain Buclaw via Gcc-patches From: Iain Buclaw Reply-To: Iain Buclaw Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" Hi, This patch adds support for using user-defined attributes on function arguments and single-parameter alias declarations. These attributes behave analogous to existing UDAs. Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, and committed to mainline. Regards Iain. --- gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 9038e64c5. * d-builtins.cc (build_frontend_type): Update call to Parameter::create. --- gcc/d/d-builtins.cc | 2 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/arrayop.c | 8 +- gcc/d/dmd/clone.c | 16 +- gcc/d/dmd/cond.c | 2 +- gcc/d/dmd/declaration.c | 2 +- gcc/d/dmd/dtemplate.c | 2 +- gcc/d/dmd/expression.c | 2 +- gcc/d/dmd/expressionsem.c | 5 +- gcc/d/dmd/func.c | 24 ++- gcc/d/dmd/hdrgen.c | 12 ++ gcc/d/dmd/mtype.c | 30 +-- gcc/d/dmd/mtype.h | 7 +- gcc/d/dmd/parse.c | 113 ++++++++-- gcc/d/dmd/statementsem.c | 24 +-- gcc/d/dmd/traits.c | 39 +++- .../gdc.test/compilable/extra-files/header1.d | 18 ++ .../gdc.test/compilable/testheaderudamodule.d | 2 + .../gdc.test/fail_compilation/fail10207.d | 2 +- gcc/testsuite/gdc.test/runnable/uda.d | 194 ++++++++++++++++++ 20 files changed, 432 insertions(+), 74 deletions(-) diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 26ccd00c79a..3f1533b592f 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -311,7 +311,7 @@ build_frontend_type (tree type) return NULL; } - args->push (Parameter::create (sc, targ, NULL, NULL)); + args->push (Parameter::create (sc, targ, NULL, NULL, NULL)); } /* GCC generic and placeholder built-ins are marked as variadic, yet diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 1629b4535ee..25b2b3ac965 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -a5c86f5b92c4cd3afde910c89881ccaea11de554 +9038e64c5b67a10763d32893f53bb6c610df3595 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/arrayop.c b/gcc/d/dmd/arrayop.c index 72abd5e9b30..20cdb6fd184 100644 --- a/gcc/d/dmd/arrayop.c +++ b/gcc/d/dmd/arrayop.c @@ -51,7 +51,7 @@ FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc) 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), @@ -422,7 +422,7 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams) void visit(Expression *e) { Identifier *id = Identifier::generateId("c", fparams->length); - 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); } @@ -441,7 +441,7 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams) void visit(ArrayLiteralExp *e) { Identifier *id = Identifier::generateId("p", fparams->length); - 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); Expression *index = new IdentifierExp(Loc(), Id::p); @@ -451,7 +451,7 @@ Expression *buildArrayLoop(Expression *e, Parameters *fparams) void visit(SliceExp *e) { Identifier *id = Identifier::generateId("p", fparams->length); - 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); Expression *index = new IdentifierExp(Loc(), Id::p); diff --git a/gcc/d/dmd/clone.c b/gcc/d/dmd/clone.c index dd22fb340f5..73c4a660368 100644 --- a/gcc/d/dmd/clone.c +++ b/gcc/d/dmd/clone.c @@ -244,7 +244,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(ParameterList(fparams), sd->handleType(), LINKd, stc | STCref); FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf); @@ -503,7 +503,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(ParameterList(parameters), Type::tbool, LINKd); tfeqptr->mod = MODconst; tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), &scx); @@ -531,8 +531,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(ParameterList(parameters), Type::tbool, LINKd); Identifier *id = Id::xopEquals; @@ -583,7 +583,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(ParameterList(parameters), Type::tint32, LINKd); tfcmpptr->mod = MODconst; tfcmpptr = (TypeFunction *)tfcmpptr->semantic(Loc(), &scx); @@ -616,8 +616,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(ParameterList(parameters), Type::tint32, LINKd); Identifier *id = Id::xopCmp; @@ -738,7 +738,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(ParameterList(parameters), Type::thash_t, LINKd, STCnothrow | STCtrusted); diff --git a/gcc/d/dmd/cond.c b/gcc/d/dmd/cond.c index 9f76e83238e..2ea3d408155 100644 --- a/gcc/d/dmd/cond.c +++ b/gcc/d/dmd/cond.c @@ -257,7 +257,7 @@ static void lowerNonArrayAggregate(StaticForeach *sfe, Scope *sc) { Parameters *params = pparams[j]; Parameter *p = sfe->aggrfe ? (*sfe->aggrfe->parameters)[i] : sfe->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 *res[2]; diff --git a/gcc/d/dmd/declaration.c b/gcc/d/dmd/declaration.c index f490cc5a413..f196bc825a2 100644 --- a/gcc/d/dmd/declaration.c +++ b/gcc/d/dmd/declaration.c @@ -224,7 +224,7 @@ Type *TupleDeclaration::getType() { Type *t = (*types)[i]; //printf("type = %s\n", t->toChars()); - Parameter *arg = new Parameter(0, t, NULL, NULL); + Parameter *arg = new Parameter(0, t, NULL, NULL, NULL); (*args)[i] = arg; if (!t->deco) hasdeco = 0; diff --git a/gcc/d/dmd/dtemplate.c b/gcc/d/dmd/dtemplate.c index 1035f829e12..316f105b9e3 100644 --- a/gcc/d/dmd/dtemplate.c +++ b/gcc/d/dmd/dtemplate.c @@ -6805,7 +6805,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/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c index 78918320192..a3c3f72d261 100644 --- a/gcc/d/dmd/expression.c +++ b/gcc/d/dmd/expression.c @@ -1953,7 +1953,7 @@ bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf, args->setDim(arguments->length - nparams); for (size_t i = 0; i < arguments->length - 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; } diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c index 7dfe995b711..f519389571a 100644 --- a/gcc/d/dmd/expressionsem.c +++ b/gcc/d/dmd/expressionsem.c @@ -2051,7 +2051,7 @@ public: for (size_t i = 0; i < cd->baseclasses->length; 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); } @@ -2100,7 +2100,8 @@ public: return setError(); args->push(new Parameter(arg->storageClass, arg->type, (e->tok2 == TOKparameters) ? arg->ident : NULL, - (e->tok2 == TOKparameters) ? arg->defaultArg : NULL)); + (e->tok2 == TOKparameters) ? arg->defaultArg : NULL, + arg->userAttribDecl)); } tded = new TypeTuple(args); break; diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c index fe1ad1118e0..53621adcc41 100644 --- a/gcc/d/dmd/func.c +++ b/gcc/d/dmd/func.c @@ -1221,6 +1221,15 @@ Ldone: Compiler::genCmain(sc); assert(type->ty != Terror || errors); + + // semantic for parameters' UDAs + const size_t nparams = f->parameterList.length(); + for (size_t i = 0; i < nparams; i++) + { + Parameter *param = f->parameterList[i]; + if (param && param->userAttribDecl) + param->userAttribDecl->semantic(sc); + } } void FuncDeclaration::semantic2(Scope *sc) @@ -1237,6 +1246,17 @@ void FuncDeclaration::semantic2(Scope *sc) { objc()->checkLinkage(this); } + if (!type || type->ty != Tfunction) + return; + TypeFunction *f = type->toTypeFunction(); + const size_t nparams = f->parameterList.length(); + // semantic for parameters' UDAs + for (size_t i = 0; i < nparams; i++) + { + Parameter *param = f->parameterList[i]; + if (param && param->userAttribDecl) + param->userAttribDecl->semantic2(sc); + } } /**************************************************** @@ -1317,7 +1337,7 @@ static void buildEnsureRequire(FuncDeclaration *fdx) Parameter *p = NULL; if (fdx->outId) { - p = new Parameter(STCref | STCconst, f->nextOf(), fdx->outId, NULL); + p = new Parameter(STCref | STCconst, f->nextOf(), fdx->outId, NULL, NULL); fparams->push(p); } TypeFunction *tf = new TypeFunction(ParameterList(fparams), Type::tvoid, LINKd); @@ -1603,6 +1623,8 @@ void FuncDeclaration::semantic3(Scope *sc) parameters->push(v); localsymtab->insert(v); v->parent = this; + if (fparam->userAttribDecl) + v->userAttribDecl = fparam->userAttribDecl; } } diff --git a/gcc/d/dmd/hdrgen.c b/gcc/d/dmd/hdrgen.c index fd4d16241c4..a04a8c523a3 100644 --- a/gcc/d/dmd/hdrgen.c +++ b/gcc/d/dmd/hdrgen.c @@ -3097,6 +3097,18 @@ public: void visit(Parameter *p) { + if (p->userAttribDecl) + { + buf->writestring("@"); + bool isAnonymous = p->userAttribDecl->atts->length > 0 + && (*p->userAttribDecl->atts)[0]->op != TOKcall; + if (isAnonymous) + buf->writestring("("); + argsToBuffer(p->userAttribDecl->atts); + if (isAnonymous) + buf->writestring(")"); + buf->writestring(" "); + } if (p->storageClass & STCauto) buf->writestring("auto "); diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c index 94e2082f5b2..42f90fa9e04 100644 --- a/gcc/d/dmd/mtype.c +++ b/gcc/d/dmd/mtype.c @@ -1543,7 +1543,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) { @@ -1552,7 +1552,7 @@ Type *stripDefaultArgs(Type *t) for (size_t j = 0; j < params->length; j++) (*params)[j] = (*parameters)[j]; } - (*params)[i] = new Parameter(p->storageClass, ta, NULL, NULL); + (*params)[i] = new Parameter(p->storageClass, ta, NULL, NULL, NULL); } } } @@ -1996,7 +1996,7 @@ Type *TypeFunction::substWildTo(unsigned) continue; if (params == parameterList.parameters) params = parameterList.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 == parameterList.parameters) return this; @@ -4914,7 +4914,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 = fd_aaLen->type->toTypeFunction(); tf->purity = PUREconst; @@ -5821,7 +5821,7 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) } (*newparams)[j] = new Parameter( - stc, narg->type, narg->ident, narg->defaultArg); + stc, narg->type, narg->ident, narg->defaultArg, narg->userAttribDecl); } fparam->type = new TypeTuple(newparams); } @@ -9098,7 +9098,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; } } @@ -9124,15 +9124,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() @@ -9436,17 +9436,20 @@ size_t ParameterList::length() /***************************** 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() @@ -9454,7 +9457,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/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index b0878c8f730..28dba1c250a 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -623,9 +623,12 @@ public: 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/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c index be861fa92f6..e414a4d69c0 100644 --- a/gcc/d/dmd/parse.c +++ b/gcc/d/dmd/parse.c @@ -1110,7 +1110,7 @@ StorageClass Parser::parsePostfix(StorageClass storageClass, Expressions **pudas // Disallow: // void function() @uda fp; // () @uda { return 1; } - error("user defined attributes cannot appear as postfixes"); + error("user-defined attributes cannot appear as postfixes"); } continue; } @@ -1979,9 +1979,11 @@ Parameters *Parser::parseParameters(VarArg *pvarargs, TemplateParameters **tpl) StorageClass storageClass = 0; StorageClass stc; Expression *ae; + Expressions *udas = NULL; for (;1; nextToken()) { + L3: switch (token.value) { case TOKrparen: @@ -2016,6 +2018,28 @@ Parameters *Parser::parseParameters(VarArg *pvarargs, TemplateParameters **tpl) 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 have user-defined attributes"); + 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; @@ -2068,6 +2092,30 @@ Parameters *Parser::parseParameters(VarArg *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 ... @@ -2076,11 +2124,11 @@ Parameters *Parser::parseParameters(VarArg *pvarargs, TemplateParameters **tpl) if (storageClass & (STCout | STCref)) error("variadic argument cannot be out or ref"); varargs = VARARGtypesafe; - 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; @@ -3779,6 +3827,21 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con tpl = parseTemplateParameterList(); check(TOKassign); + bool hasParsedAttributes = false; + if (token.value == TOKat) + { + if (!hasParsedAttributes) + { + hasParsedAttributes = true; + storage_class = STCundefined; + link = linkage; + setAlignment = false; + ealign = NULL; + udas = NULL; + parseStorageClasses(storage_class, link, setAlignment, ealign, udas); + } + } + Declaration *v; if (token.value == TOKfunction || token.value == TOKdelegate || @@ -3796,21 +3859,39 @@ Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con // identifier => expression Dsymbol *s = parseFunctionLiteral(); + + if (udas != NULL) + { + if (storage_class != 0) + error("Cannot put a storage-class in an alias declaration."); + // shouldn't have set these variables + assert(link == linkage && !setAlignment && ealign == NULL); + TemplateDeclaration *tpl_ = (TemplateDeclaration *) s; + assert(tpl_ != NULL && tpl_->members->length == 1); + FuncLiteralDeclaration *fd = (FuncLiteralDeclaration *) (*tpl_->members)[0]; + TypeFunction *tf = (TypeFunction *) fd->type; + assert(tf->parameterList.length() > 0); + Dsymbols *as = new Dsymbols(); + (*tf->parameterList.parameters)[0]->userAttribDecl = new UserAttributeDeclaration(udas, as); + } v = new AliasDeclaration(loc, ident, s); } else { // StorageClasses type - - storage_class = STCundefined; - link = linkage; - setAlignment = false; - ealign = NULL; - udas = NULL; - parseStorageClasses(storage_class, link, setAlignment, ealign, udas); + if (!hasParsedAttributes) + { + hasParsedAttributes = true; + storage_class = STCundefined; + link = linkage; + setAlignment = false; + ealign = NULL; + udas = NULL; + parseStorageClasses(storage_class, link, setAlignment, ealign, udas); + } if (udas) - error("user defined attributes not allowed for %s declarations", Token::toChars(tok)); + error("user-defined attributes not allowed for %s declarations", Token::toChars(tok)); t = parseType(); v = new AliasDeclaration(loc, ident, t); @@ -3991,7 +4072,7 @@ L2: */ if (udas) - error("user defined attributes not allowed for %s declarations", Token::toChars(tok)); + error("user-defined attributes not allowed for %s declarations", Token::toChars(tok)); if (token.value == TOKassign) { @@ -4221,7 +4302,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); @@ -4811,7 +4892,7 @@ Statement *Parser::parseForeach(Loc loc, bool *isRange, bool isDecl) 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(); @@ -5335,14 +5416,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/gcc/d/dmd/statementsem.c b/gcc/d/dmd/statementsem.c index 4ff07f6f2eb..2fe0d9efeea 100644 --- a/gcc/d/dmd/statementsem.c +++ b/gcc/d/dmd/statementsem.c @@ -1494,7 +1494,7 @@ public: s = new ExpStatement(Loc(), v); fs->_body = new CompoundStatement(loc, s, fs->_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, fs->func); @@ -1570,15 +1570,15 @@ public: 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(ParameterList(dgparams), Type::tint32, 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]); } @@ -1637,14 +1637,14 @@ public: 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(ParameterList(dgparams), Type::tint32, 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) @@ -3192,7 +3192,7 @@ public: cs->push(new ExpStatement(ss->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(ss->loc, new VarExp(ss->loc, fdenter, false), new VarExp(ss->loc, tmp)); @@ -3234,7 +3234,7 @@ public: cs->push(new ExpStatement(ss->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 AddrExp(ss->loc, tmpExp); diff --git a/gcc/d/dmd/traits.c b/gcc/d/dmd/traits.c index 658529943ea..2f00c883706 100644 --- a/gcc/d/dmd/traits.c +++ b/gcc/d/dmd/traits.c @@ -658,7 +658,8 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) if (e->ident != Id::compiles && e->ident != Id::isSame && e->ident != Id::identifier && - e->ident != Id::getProtection && e->ident != Id::getVisibility) + e->ident != Id::getProtection && e->ident != Id::getVisibility && + e->ident != Id::getAttributes) { // Pretend we're in a deprecated scope so that deprecation messages // aren't triggered when checking if a symbol is deprecated @@ -905,8 +906,12 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) Identifier *id = NULL; if (Parameter *po = isParameter(o)) { + if (!po->ident) + { + e->error("argument `%s` has no identifier", po->type->toChars()); + return new ErrorExp(); + } id = po->ident; - assert(id); } else { @@ -1245,23 +1250,39 @@ 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) return dimError(e, 1, dim); RootObject *o = (*e->args)[0]; + Parameter *po = isParameter(o); Dsymbol *s = getDsymbolWithoutExpCtx(o); - if (!s) + UserAttributeDeclaration *udad = NULL; + if (po) { - e->error("first argument is not a symbol"); - return new ErrorExp(); + udad = po->userAttribDecl; } - if (Import *imp = s->isImport()) + else if (s) { - s = imp->mod; + if (Import *imp = s->isImport()) + { + s = imp->mod; + } + //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope); + udad = s->userAttribDecl; + } + else + { + e->error("first argument is not a symbol"); + return new ErrorExp(); } - //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope); - UserAttributeDeclaration *udad = s->userAttribDecl; Expressions *exps = udad ? udad->getAttributes() : new Expressions(); TupleExp *tup = new TupleExp(e->loc, exps); return semantic(tup, sc); diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d index a746a2aac06..d8221eb882a 100644 --- a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d +++ b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d @@ -519,3 +519,21 @@ struct Foo3A(T) @disable this(this); @disable this(); } + +void test13x(@(10) int a, @(20) int, @(30) @(40) int[] arr...) {} + +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 test15x(@(20) void delegate(int) @safe dg){} diff --git a/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d b/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d index 1a7d6506669..5ee94868993 100644 --- a/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d +++ b/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d @@ -11,3 +11,5 @@ struct UDA } void main() {} + +void foo(@(1) int bar, @UDA(2) string bebe); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10207.d b/gcc/testsuite/gdc.test/fail_compilation/fail10207.d index ac8b4eef11a..3f09a27541a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10207.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10207.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail10207.d(7): Error: user defined attributes not allowed for `alias` declarations +fail_compilation/fail10207.d(7): Error: user-defined attributes not allowed for `alias` declarations --- */ alias @Safe int __externC; diff --git a/gcc/testsuite/gdc.test/runnable/uda.d b/gcc/testsuite/gdc.test/runnable/uda.d index c1782c90a7b..38f84e5971d 100644 --- a/gcc/testsuite/gdc.test/runnable/uda.d +++ b/gcc/testsuite/gdc.test/runnable/uda.d @@ -467,6 +467,193 @@ static assert(__traits(getAttributes, FileData11844.member)[0](new FileData11844 /************************************************/ +template AliasSeq(T...) +{ + alias AliasSeq = 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 = AliasSeq!(__traits(getAttributes, PT[i..i+1])); + } + else + { + alias Get = AliasSeq!(); + } + } + } + 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 = AliasSeq!(); } + alias PT = AliasSeq!(); + } + + 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)); +} + +template MinimalFunctionTypeOf(func...) +if (func.length == 1) +{ + static if (is(func[0] T) || is(typeof(func[0]) T) && is(T Fdlg == delegate)) + alias MinimalFunctionTypeOf = Fdlg; // HIT: delegate + else + static assert(0); +} + +template Parameters(func...) +if (func.length == 1) +{ + static if (is(MinimalFunctionTypeOf!func P == function)) + alias Parameters = P; + else + static assert(0, "argument has no parameters"); +} + +void test15y(@(20) void delegate(@Test14UDA2("2") @("test15yUDA") int) @safe dg) +{ + static assert([__traits(getAttributes, dg)] == [20]); + static assert(is(typeof(dg) == void delegate(int) @safe)); + auto foo = (@("myUDA") int x){ + static assert([__traits(getAttributes, x)] == ["myUDA"]); + }; + static assert(__traits(getAttributes, Parameters!dg)[0] == Test14UDA2("2")); + static assert(__traits(getAttributes, Parameters!dg)[1] == "test15yUDA"); +} + +void test15z() +{ + test15y((@(15) @(16) int x){ + static assert([__traits(getAttributes, x)] == [15, 16]); + }); +} + +void test16x(A)(@(22) A a) +{ + static assert([__traits(getAttributes, a)] == [22]); +} + +void test16() +{ + static assert([ParameterUDA!(0, test16x!int)] == [22]); +} + +void test17() +{ + void test17x(A)(@(23) A a) + { + static assert([__traits(getAttributes, a)] == [23]); + } + static assert([ParameterUDA!(0, test17x!int)] == [23]); +} + +void test18() +{ + void test18a(@(Tuple!(18, "a")) int a) + { + static assert(__traits(getAttributes, a) == Tuple!(18, "a")); + } + void test18b(@Tuple!(18, "b") int a) + { + static assert(__traits(getAttributes, a) == Tuple!(18, "b")); + } + + static assert(ParameterUDA!(0, test18a) == Tuple!(18, "a")); + static assert(ParameterUDA!(0, test18b) == Tuple!(18, "b")); +} + +// Lambdas with parentheses: +void test19() +{ + // lambdas without parentheses + alias test19a = @(3) b => 1 + 2; + alias test19b = @(3) @(4) b => 1 + 2; + + alias test19c = (@(3) c, @(5) d) => 1 + 2; + alias test19d = (@(3) @(4) c, @(5) d) => 1 + 2; + auto test19e = (@(3) int c, @(5) int d) => 1 + 2; + + // still allow alias function declarations + alias FuncType = @safe void function(); + alias FuncType2 = @safe nothrow void function(); + alias FuncType3 = nothrow void function(); + alias FuncType4 = nothrow @safe void function(); +} + +void test20() +{ + // Using a delegate with inferred parameter type + void test20a(int delegate(int) t){ t(1); } + test20a((@(19) a) { + static assert([__traits(getAttributes, a)] == [19]); + return a + 2; + }); +} + +/************************************************/ + + int main() { test1(); @@ -482,6 +669,13 @@ int main() test11(); test12(); test9178(); + test13(); + test14(); + test16(); + test17(); + test18(); + test19(); + test20(); printf("Success\n"); return 0;