From 7a103daef78a8f9fc9b2af7c28123f25e8fa7163 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Thu, 7 Jan 2021 22:00:24 +0100 Subject: [PATCH] d: Support deprecated, @disable, and user-defined attributes on enum members Reviewed-on: https://github.com/dlang/dmd/pull/12108 gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 9bba772fa. --- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/declaration.c | 45 ++++++ gcc/d/dmd/declaration.h | 1 + gcc/d/dmd/denum.c | 34 ++++- gcc/d/dmd/dsymbol.c | 23 +-- gcc/d/dmd/dsymbol.h | 2 +- gcc/d/dmd/enum.h | 2 + gcc/d/dmd/expression.c | 26 +++- gcc/d/dmd/expression.h | 3 +- gcc/d/dmd/expressionsem.c | 9 ++ gcc/d/dmd/mtype.c | 21 ++- gcc/d/dmd/parse.c | 132 ++++++++++++++---- gcc/d/dmd/traits.c | 4 +- gcc/testsuite/gdc.test/compilable/test17908.d | 17 +++ gcc/testsuite/gdc.test/compilable/test9701.d | 58 ++++++++ gcc/testsuite/gdc.test/compilable/vcg-ast.d | 43 ++++++ .../gdc.test/fail_compilation/disable.d | 26 ++-- .../gdc.test/fail_compilation/fail10968.d | 12 +- .../gdc.test/fail_compilation/fail11355.d | 2 +- .../gdc.test/fail_compilation/fail15044.d | 2 +- .../gdc.test/fail_compilation/fail341.d | 4 +- .../gdc.test/fail_compilation/fail9346.d | 4 +- .../fail_compilation/fail_contracts1.d | 8 ++ .../fail_compilation/fail_contracts2.d | 8 ++ .../fail_compilation/fail_contracts3.d | 14 ++ .../fail_compilation/fail_contracts4.d | 8 ++ .../gdc.test/fail_compilation/test17908a.d | 15 ++ .../gdc.test/fail_compilation/test17908b.d | 14 ++ .../gdc.test/fail_compilation/test9701.d | 63 +++++++++ .../gdc.test/fail_compilation/test9701b.d | 22 +++ .../gdc.test/fail_compilation/udaparams.d | 57 ++++++++ 31 files changed, 601 insertions(+), 80 deletions(-) create mode 100644 gcc/testsuite/gdc.test/compilable/test17908.d create mode 100644 gcc/testsuite/gdc.test/compilable/test9701.d create mode 100644 gcc/testsuite/gdc.test/compilable/vcg-ast.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_contracts1.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_contracts2.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_contracts3.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail_contracts4.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test17908a.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test17908b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test9701.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test9701b.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/udaparams.d diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index f6c8f6f02cf..a34fd4138d7 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -e598f69c0726ad1bf6b2e15e0b60d7cead737fad +9bba772fa67c6864e551bc87097402f691d947d4 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/declaration.c b/gcc/d/dmd/declaration.c index f196bc825a2..72a07d9b8f5 100644 --- a/gcc/d/dmd/declaration.c +++ b/gcc/d/dmd/declaration.c @@ -155,6 +155,51 @@ int Declaration::checkModify(Loc loc, Scope *sc, Type *, Expression *e1, int fla return 1; } +/** + * Issue an error if an attempt to call a disabled method is made + * + * If the declaration is disabled but inside a disabled function, + * returns `true` but do not issue an error message. + * + * Params: + * loc = Location information of the call + * sc = Scope in which the call occurs + * isAliasedDeclaration = if `true` searches overload set + * + * Returns: + * `true` if this `Declaration` is `@disable`d, `false` otherwise. + */ +bool Declaration::checkDisabled(Loc loc, Scope *sc, bool isAliasedDeclaration) +{ + if (!(storage_class & STCdisable)) + return false; + + if (sc->func && (sc->func->storage_class & STCdisable)) + return true; + + Dsymbol *p = toParent(); + if (p && isPostBlitDeclaration()) + { + p->error(loc, "is not copyable because it is annotated with `@disable`"); + return true; + } + + // if the function is @disabled, maybe there + // is an overload in the overload set that isn't + if (isAliasedDeclaration) + { + FuncDeclaration *fd = isFuncDeclaration(); + if (fd) + { + for (FuncDeclaration *ovl = fd; ovl; ovl = (FuncDeclaration *)ovl->overnext) + if (!(ovl->storage_class & STCdisable)) + return false; + } + } + error(loc, "cannot be used because it is annotated with `@disable`"); + return true; +} + Dsymbol *Declaration::search(const Loc &loc, Identifier *ident, int flags) { Dsymbol *s = Dsymbol::search(loc, ident, flags); diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 19e4d1a5aa8..a464f9beb71 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -139,6 +139,7 @@ public: void semantic(Scope *sc); const char *kind() const; d_uns64 size(Loc loc); + bool checkDisabled(Loc loc, Scope *sc, bool isAliasedDeclaration = false); int checkModify(Loc loc, Scope *sc, Type *t, Expression *e1, int flag); Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); diff --git a/gcc/d/dmd/denum.c b/gcc/d/dmd/denum.c index b881fb6df15..d15d94a3157 100644 --- a/gcc/d/dmd/denum.c +++ b/gcc/d/dmd/denum.c @@ -13,6 +13,7 @@ #include "errors.h" #include "enum.h" +#include "attrib.h" #include "mtype.h" #include "scope.h" #include "id.h" @@ -504,6 +505,18 @@ EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *origTyp this->origType = origType; } +EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *memType, + StorageClass stc, UserAttributeDeclaration *uad, DeprecatedDeclaration *dd) + : VarDeclaration(loc, NULL, id ? id : Id::empty, new ExpInitializer(loc, value)) +{ + this->ed = NULL; + this->origValue = value; + this->origType = memType; + this->storage_class = stc; + this->userAttribDecl = uad; + this->depdecl = dd; +} + Expression *&EnumMember::value() { return ((ExpInitializer*)_init)->exp; @@ -536,6 +549,7 @@ void EnumMember::semantic(Scope *sc) return; } assert(ed); + ed->semantic(sc); if (ed->errors) goto Lerrors; @@ -552,8 +566,16 @@ void EnumMember::semantic(Scope *sc) protection = ed->isAnonymous() ? ed->protection : Prot(Prot::public_); linkage = LINKd; - storage_class = STCmanifest; - userAttribDecl = ed->isAnonymous() ? ed->userAttribDecl : NULL; + storage_class |= STCmanifest; + + // https://issues.dlang.org/show_bug.cgi?id=9701 + if (ed->isAnonymous()) + { + if (userAttribDecl) + userAttribDecl->userAttribDecl = ed->userAttribDecl; + else + userAttribDecl = ed->userAttribDecl; + } // The first enum member is special bool first = (this == (*ed->members)[0]); @@ -743,6 +765,14 @@ void EnumMember::semantic(Scope *sc) Expression *EnumMember::getVarExp(Loc loc, Scope *sc) { semantic(sc); + if (errors) + return new ErrorExp(); + checkDisabled(loc, sc); + + if (depdecl && !depdecl->_scope) + depdecl->_scope = sc; + checkDeprecated(loc, sc); + if (errors) return new ErrorExp(); Expression *e = new VarExp(loc, this); diff --git a/gcc/d/dmd/dsymbol.c b/gcc/d/dmd/dsymbol.c index d74fe6cfdd5..5b4fad4ebb7 100644 --- a/gcc/d/dmd/dsymbol.c +++ b/gcc/d/dmd/dsymbol.c @@ -760,7 +760,7 @@ void Dsymbol::deprecation(const char *format, ...) va_end(ap); } -void Dsymbol::checkDeprecated(Loc loc, Scope *sc) +bool Dsymbol::checkDeprecated(Loc loc, Scope *sc) { if (global.params.useDeprecated != DIAGNOSTICoff && isDeprecated()) { @@ -768,17 +768,17 @@ void Dsymbol::checkDeprecated(Loc loc, Scope *sc) for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) { if (sp->isDeprecated()) - goto L1; + return false; } for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing) { if (sc2->scopesym && sc2->scopesym->isDeprecated()) - goto L1; + return false; // If inside a StorageClassDeclaration that is deprecated if (sc2->stc & STCdeprecated) - goto L1; + return false; } const char *message = NULL; @@ -793,20 +793,11 @@ void Dsymbol::checkDeprecated(Loc loc, Scope *sc) deprecation(loc, "is deprecated - %s", message); else deprecation(loc, "is deprecated"); - } - L1: - Declaration *d = isDeclaration(); - if (d && d->storage_class & STCdisable) - { - if (!(sc->func && sc->func->storage_class & STCdisable)) - { - if (d->toParent() && d->isPostBlitDeclaration()) - d->toParent()->error(loc, "is not copyable because it is annotated with @disable"); - else - error(loc, "is not callable because it is annotated with @disable"); - } + return true; } + + return false; } /********************************** diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 5fa509be9ca..6555f12e7b4 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -175,7 +175,7 @@ public: void error(const char *format, ...); void deprecation(Loc loc, const char *format, ...); void deprecation(const char *format, ...); - void checkDeprecated(Loc loc, Scope *sc); + bool checkDeprecated(Loc loc, Scope *sc); Module *getModule(); Module *getAccessModule(); Dsymbol *pastMixin(); diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h index 481ff0c1cd3..6d389ed76e0 100644 --- a/gcc/d/dmd/enum.h +++ b/gcc/d/dmd/enum.h @@ -85,6 +85,8 @@ public: EnumDeclaration *ed; EnumMember(Loc loc, Identifier *id, Expression *value, Type *origType); + EnumMember(Loc loc, Identifier *id, Expression *value, Type *memType, + StorageClass stc, UserAttributeDeclaration *uad, DeprecatedDeclaration *dd); Dsymbol *syntaxCopy(Dsymbol *s); const char *kind() const; void semantic(Scope *sc); diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c index a3c3f72d261..395dc56748c 100644 --- a/gcc/d/dmd/expression.c +++ b/gcc/d/dmd/expression.c @@ -2344,9 +2344,18 @@ bool Expression::checkArithmetic() return checkValue(); } -void Expression::checkDeprecated(Scope *sc, Dsymbol *s) +bool Expression::checkDeprecated(Scope *sc, Dsymbol *s) { - s->checkDeprecated(loc, sc); + return s->checkDeprecated(loc, sc); +} + +bool Expression::checkDisabled(Scope *sc, Dsymbol *s) +{ + if (Declaration *d = s->isDeclaration()) + { + return d->checkDisabled(loc, sc); + } + return false; } /********************************************* @@ -2661,11 +2670,8 @@ bool Expression::checkPostblit(Scope *sc, Type *t) StructDeclaration *sd = ((TypeStruct *)t)->sym; if (sd->postblit) { - if (sd->postblit->storage_class & STCdisable) - { - sd->error(loc, "is not copyable because it is annotated with @disable"); + if (sd->postblit->checkDisabled(loc, sc)) return true; - } //checkDeprecated(sc, sd->postblit); // necessary? checkPurity(sc, sd->postblit); checkSafety(sc, sd->postblit); @@ -3715,14 +3721,22 @@ Lagain: else { if (!s->isFuncDeclaration()) // functions are checked after overloading + { s->checkDeprecated(loc, sc); + if (d) + d->checkDisabled(loc, sc); + } // Bugzilla 12023: if 's' is a tuple variable, the tuple is returned. s = s->toAlias(); //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis()); if (s != olds && !s->isFuncDeclaration()) + { s->checkDeprecated(loc, sc); + if (d) + d->checkDisabled(loc, sc); + } } if (EnumMember *em = s->isEnumMember()) diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index ccfaa65f764..d84878f0d6e 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -181,7 +181,8 @@ public: bool checkNoBool(); bool checkIntegral(); bool checkArithmetic(); - void checkDeprecated(Scope *sc, Dsymbol *s); + bool checkDeprecated(Scope *sc, Dsymbol *s); + bool checkDisabled(Scope *sc, Dsymbol *s); bool checkPurity(Scope *sc, FuncDeclaration *f); bool checkPurity(Scope *sc, VarDeclaration *v); bool checkSafety(Scope *sc, FuncDeclaration *f); diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c index f519389571a..ecafd9d2066 100644 --- a/gcc/d/dmd/expressionsem.c +++ b/gcc/d/dmd/expressionsem.c @@ -1218,6 +1218,7 @@ public: if (!f || f->errors) return setError(); exp->checkDeprecated(sc, f); + exp->checkDisabled(sc, f); exp->checkPurity(sc, f); exp->checkSafety(sc, f); exp->checkNogc(sc, f); @@ -1246,6 +1247,7 @@ public: if (!f || f->errors) return setError(); exp->checkDeprecated(sc, f); + exp->checkDisabled(sc, f); exp->checkPurity(sc, f); exp->checkSafety(sc, f); exp->checkNogc(sc, f); @@ -1313,6 +1315,7 @@ public: if (!f || f->errors) return setError(); exp->checkDeprecated(sc, f); + exp->checkDisabled(sc, f); exp->checkPurity(sc, f); exp->checkSafety(sc, f); exp->checkNogc(sc, f); @@ -1341,6 +1344,7 @@ public: if (!f || f->errors) return setError(); exp->checkDeprecated(sc, f); + exp->checkDisabled(sc, f); exp->checkPurity(sc, f); exp->checkSafety(sc, f); exp->checkNogc(sc, f); @@ -3214,6 +3218,7 @@ public: } exp->checkDeprecated(sc, exp->f); + exp->checkDisabled(sc, exp->f); exp->checkPurity(sc, exp->f); exp->checkSafety(sc, exp->f); exp->checkNogc(sc, exp->f); @@ -3307,6 +3312,7 @@ public: if (!exp->f || exp->f->errors) return setError(); exp->checkDeprecated(sc, exp->f); + exp->checkDisabled(sc, exp->f); exp->checkPurity(sc, exp->f); exp->checkSafety(sc, exp->f); exp->checkNogc(sc, exp->f); @@ -3345,6 +3351,7 @@ public: if (!exp->f || exp->f->errors) return setError(); exp->checkDeprecated(sc, exp->f); + exp->checkDisabled(sc, exp->f); exp->checkPurity(sc, exp->f); exp->checkSafety(sc, exp->f); exp->checkNogc(sc, exp->f); @@ -3587,6 +3594,7 @@ public: } exp->checkDeprecated(sc, exp->f); + exp->checkDisabled(sc, exp->f); exp->checkPurity(sc, exp->f); exp->checkSafety(sc, exp->f); exp->checkNogc(sc, exp->f); @@ -8381,6 +8389,7 @@ Expression *semanticY(DotIdExp *exp, Scope *sc, int flag) s = s->toAlias(); exp->checkDeprecated(sc, s); + exp->checkDisabled(sc, s); EnumMember *em = s->isEnumMember(); if (em) diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c index 42f90fa9e04..ceee70ac7c3 100644 --- a/gcc/d/dmd/mtype.c +++ b/gcc/d/dmd/mtype.c @@ -1762,10 +1762,10 @@ bool Type::needsNested() void Type::checkDeprecated(Loc loc, Scope *sc) { - Dsymbol *s = toDsymbol(sc); - - if (s) + if (Dsymbol *s = toDsymbol(sc)) + { s->checkDeprecated(loc, sc); + } } @@ -6956,7 +6956,12 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, if (d && (d->storage_class & STCtemplateparameter)) s = s->toAlias(); else - s->checkDeprecated(loc, sc); // check for deprecated aliases + { + // check for deprecated aliases + s->checkDeprecated(loc, sc); + if (d) + d->checkDisabled(loc, sc, true); + } s = s->toAlias(); //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); @@ -8045,7 +8050,11 @@ L1: // return noMember(sc, e, ident, flag); } if (!s->isFuncDeclaration()) // because of overloading + { s->checkDeprecated(e->loc, sc); + if (Declaration *d = s->isDeclaration()) + d->checkDisabled(e->loc, sc); + } s = s->toAlias(); EnumMember *em = s->isEnumMember(); @@ -8749,7 +8758,11 @@ L1: // return noMember(sc, e, ident, flag); } if (!s->isFuncDeclaration()) // because of overloading + { s->checkDeprecated(e->loc, sc); + if (Declaration *d = s->isDeclaration()) + d->checkDisabled(e->loc, sc); + } s = s->toAlias(); EnumMember *em = s->isEnumMember(); diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c index 80aaac089ec..2664af2e706 100644 --- a/gcc/d/dmd/parse.c +++ b/gcc/d/dmd/parse.c @@ -216,6 +216,24 @@ Lerr: return new Dsymbols(); } +static StorageClass parseDeprecatedAttribute(Parser *p, Expression **msg) +{ + if (p->peekNext() != TOKlparen) + return STCdeprecated; + + p->nextToken(); + p->check(TOKlparen); + Expression *e = p->parseAssignExp(); + p->check(TOKrparen); + if (*msg) + { + p->error("conflicting storage class `deprecated(%s)` and `deprecated(%s)`", + (*msg)->toChars(), e->toChars()); + } + *msg = e; + return STCundefined; +} + struct PrefixAttributes { StorageClass storageClass; @@ -626,21 +644,12 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes case TOKdeprecated: { - if (peek(&token)->value != TOKlparen) + Expression *e = NULL; + if (StorageClass _stc = parseDeprecatedAttribute(this, &pAttrs->depmsg)) { - stc = STCdeprecated; + stc = _stc; goto Lstc; } - nextToken(); - check(TOKlparen); - Expression *e = parseAssignExp(); - check(TOKrparen); - if (pAttrs->depmsg) - { - error("conflicting storage class 'deprecated(%s)' and 'deprecated(%s)'", - pAttrs->depmsg->toChars(), e->toChars()); - } - pAttrs->depmsg = e; a = parseBlock(pLastDecl, pAttrs); if (pAttrs->depmsg) { @@ -2185,7 +2194,7 @@ EnumDeclaration *Parser::parseEnum() Type *memtype; Loc loc = token.loc; - //printf("Parser::parseEnum()\n"); + // printf("Parser::parseEnum()\n"); nextToken(); if (token.value == TOKidentifier) { @@ -2213,36 +2222,96 @@ EnumDeclaration *Parser::parseEnum() nextToken(); else if (token.value == TOKlcurly) { + bool isAnonymousEnum = !id; + //printf("enum definition\n"); e->members = new Dsymbols(); nextToken(); const utf8_t *comment = token.blockComment; while (token.value != TOKrcurly) { - /* Can take the following forms: + /* Can take the following forms... * 1. ident * 2. ident = value * 3. type ident = value + * ... prefixed by valid attributes */ - loc = token.loc; Type *type = NULL; Identifier *ident = NULL; - Token *tp = peek(&token); - if (token.value == TOKidentifier && - (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly)) + + Expressions *udas = NULL; + StorageClass stc = STCundefined; + Expression *deprecationMessage = NULL; + + while (token.value != TOKrcurly && + token.value != TOKcomma && + token.value != TOKassign) { - ident = token.ident; - type = NULL; - nextToken(); + switch (token.value) + { + case TOKat: + if (StorageClass _stc = parseAttribute(&udas)) + { + if (_stc == STCdisable) + stc |= _stc; + else + { + OutBuffer buf; + stcToBuffer(&buf, _stc); + error("`%s` is not a valid attribute for enum members", buf.peekChars()); + } + nextToken(); + } + break; + case TOKdeprecated: + if (StorageClass _stc = parseDeprecatedAttribute(this, &deprecationMessage)) + { + stc |= _stc; + nextToken(); + } + break; + case TOKidentifier: + { + Token *tp = peek(&token); + if (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly) + { + ident = token.ident; + type = NULL; + nextToken(); + } + else + { + goto Ldefault; + } + break; + } + default: + Ldefault: + if (isAnonymousEnum) + { + type = parseType(&ident, NULL); + if (type == Type::terror) + { + type = NULL; + nextToken(); + } + } + else + { + error("`%s` is not a valid attribute for enum members", token.toChars()); + nextToken(); + } + break; + } } - else + + if (type && type != Type::terror) { - type = parseType(&ident, NULL); if (!ident) error("no identifier for declarator %s", type->toChars()); - if (id || memtype) + if (!isAnonymousEnum) error("type only allowed if anonymous enum and no enum type"); } @@ -2255,11 +2324,22 @@ EnumDeclaration *Parser::parseEnum() else { value = NULL; - if (type) + if (type && type != Type::terror && isAnonymousEnum) error("if type, there must be an initializer"); } - EnumMember *em = new EnumMember(loc, ident, value, type); + UserAttributeDeclaration *uad = NULL; + if (udas) + uad = new UserAttributeDeclaration(udas, NULL); + + DeprecatedDeclaration *dd = NULL; + if (deprecationMessage) + { + dd = new DeprecatedDeclaration(deprecationMessage, NULL); + stc |= STCdeprecated; + } + + EnumMember *em = new EnumMember(loc, ident, value, type, stc, uad, dd); e->members->push(em); if (token.value == TOKrcurly) diff --git a/gcc/d/dmd/traits.c b/gcc/d/dmd/traits.c index 2f00c883706..46b7d968621 100644 --- a/gcc/d/dmd/traits.c +++ b/gcc/d/dmd/traits.c @@ -313,7 +313,6 @@ static Expression *isDsymX(TraitsExp *e, bool (*fp)(Dsymbol *s)) return True(e); } -static bool isFuncDisabled(FuncDeclaration *f) { return f->isDisabled(); } static bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); } static bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); } static bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); } @@ -337,6 +336,7 @@ static Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f)) return True(e); } +static bool isDeclDisabled(Declaration *d) { return d->isDisabled(); } static bool isDeclFuture(Declaration *d) { return d->isFuture(); } static bool isDeclRef(Declaration *d) { return d->isRef(); } static bool isDeclOut(Declaration *d) { return d->isOut(); } @@ -811,7 +811,7 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) if (dim != 1) return dimError(e, 1, dim); - return isFuncX(e, &isFuncDisabled); + return isDeclX(e, &isDeclDisabled); } else if (e->ident == Id::isAbstractFunction) { diff --git a/gcc/testsuite/gdc.test/compilable/test17908.d b/gcc/testsuite/gdc.test/compilable/test17908.d new file mode 100644 index 00000000000..3520b5f44ee --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test17908.d @@ -0,0 +1,17 @@ +// PERMUTE ARGS: + +@disable void foo() {} +void foo(int) {} +alias g = foo; + +// make sure the order of declaration +// doesn't change anything +void bar(int) {} +@disable void bar() {} +alias h = bar; + +void main() +{ + g(10); + h(10); +} diff --git a/gcc/testsuite/gdc.test/compilable/test9701.d b/gcc/testsuite/gdc.test/compilable/test9701.d new file mode 100644 index 00000000000..8f822add531 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test9701.d @@ -0,0 +1,58 @@ +// https://issues.dlang.org/show_bug.cgi?id=9701 + +template AliasSeq(TList...) +{ + alias AliasSeq = TList; +} + +enum +{ + uda4, + uda5, + uda6, + uda8, + uda9 +} + +enum Enum +{ + value0, + @("uda1") value1, + @("uda2", "uda3", 42) value2, + @uda4 value3, + @uda5 @uda6 value4, + @("uda7") @uda8 value5, + @uda9 @("uda10") value6, + deprecated value7, + deprecated("message") value8, +} + +@("uda0") +enum +{ + value0, + @("uda1") value1, + @("uda2") @("uda3") value2, + @uda4 value3, + @uda5 @uda6 value4, + @("uda7") @uda8 value5, + @uda9 @("uda10") value6 +} + +static assert(__traits(getAttributes, Enum.value0).length == 0); +static assert(__traits(getAttributes, Enum.value1) == AliasSeq!("uda1")); +static assert(__traits(getAttributes, Enum.value2) == AliasSeq!("uda2", "uda3", 42)); +static assert(__traits(getAttributes, Enum.value3) == AliasSeq!(uda4)); +static assert(__traits(getAttributes, Enum.value4) == AliasSeq!(uda5, uda6)); +static assert(__traits(getAttributes, Enum.value5) == AliasSeq!("uda7", uda8)); +static assert(__traits(getAttributes, Enum.value6) == AliasSeq!(uda9, "uda10")); +static assert(__traits(isDeprecated, Enum.value7)); +static assert(__traits(isDeprecated, Enum.value8)); + +static assert(__traits(getAttributes, value0) == AliasSeq!("uda0")); +static assert(__traits(getAttributes, value1) == AliasSeq!("uda0", "uda1")); +static assert(__traits(getAttributes, value2) == AliasSeq!("uda0", "uda2", "uda3")); +static assert(__traits(getAttributes, value3) == AliasSeq!("uda0", uda4)); +static assert(__traits(getAttributes, value4) == AliasSeq!("uda0", uda5, uda6)); +static assert(__traits(getAttributes, value5) == AliasSeq!("uda0", "uda7", uda8)); +static assert(__traits(getAttributes, value6) == AliasSeq!("uda0", uda9, "uda10")); diff --git a/gcc/testsuite/gdc.test/compilable/vcg-ast.d b/gcc/testsuite/gdc.test/compilable/vcg-ast.d new file mode 100644 index 00000000000..7cc376fbec5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/vcg-ast.d @@ -0,0 +1,43 @@ +module vcg; +// REQUIRED_ARGS: -vcg-ast -o- +// PERMUTE_ARGS: + +template Seq(A...) +{ + alias Seq = A; +} + +auto a = Seq!(1,2,3); + + +template R(T) +{ + struct _R { T elem; } +} + +typeof(R!int._R.elem) x; + + +static foreach(enum i; 0..3) +{ + mixin("int a" ~ i.stringof ~ " = 1;"); +} + +void foo() +{ + static foreach(enum i; 0..3) + { + mixin("int a" ~ i.stringof ~ " = 1;"); + } +} + +class C +{ + invariant {} + invariant (true); + + int foo() in{} out{} out(r){} in(true) out(; true) out(r; true) + { + return 2; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/disable.d b/gcc/testsuite/gdc.test/fail_compilation/disable.d index 517fddd9940..7e7d9c2d48d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/disable.d +++ b/gcc/testsuite/gdc.test/fail_compilation/disable.d @@ -1,15 +1,16 @@ /* TEST_OUTPUT: --- -fail_compilation/disable.d(50): Error: function disable.DisabledOpAssign.opAssign is not callable because it is annotated with @disable -fail_compilation/disable.d(53): Error: function disable.DisabledPostblit.opAssign is not callable because it is annotated with @disable -fail_compilation/disable.d(56): Error: function disable.HasDtor.opAssign is not callable because it is annotated with @disable -fail_compilation/disable.d(60): Error: generated function disable.Nested!(DisabledOpAssign).Nested.opAssign is not callable because it is annotated with @disable -fail_compilation/disable.d(63): Error: generated function disable.Nested!(DisabledPostblit).Nested.opAssign is not callable because it is annotated with @disable -fail_compilation/disable.d(66): Error: generated function disable.Nested!(HasDtor).Nested.opAssign is not callable because it is annotated with @disable -fail_compilation/disable.d(70): Error: generated function disable.NestedDtor!(DisabledOpAssign).NestedDtor.opAssign is not callable because it is annotated with @disable -fail_compilation/disable.d(73): Error: generated function disable.NestedDtor!(DisabledPostblit).NestedDtor.opAssign is not callable because it is annotated with @disable -fail_compilation/disable.d(76): Error: generated function disable.NestedDtor!(HasDtor).NestedDtor.opAssign is not callable because it is annotated with @disable +fail_compilation/disable.d(56): Error: function `disable.DisabledOpAssign.opAssign` cannot be used because it is annotated with `@disable` +fail_compilation/disable.d(59): Error: function `disable.DisabledPostblit.opAssign` cannot be used because it is annotated with `@disable` +fail_compilation/disable.d(62): Error: function `disable.HasDtor.opAssign` cannot be used because it is annotated with `@disable` +fail_compilation/disable.d(66): Error: generated function `disable.Nested!(DisabledOpAssign).Nested.opAssign` cannot be used because it is annotated with `@disable` +fail_compilation/disable.d(69): Error: generated function `disable.Nested!(DisabledPostblit).Nested.opAssign` cannot be used because it is annotated with `@disable` +fail_compilation/disable.d(72): Error: generated function `disable.Nested!(HasDtor).Nested.opAssign` cannot be used because it is annotated with `@disable` +fail_compilation/disable.d(76): Error: generated function `disable.NestedDtor!(DisabledOpAssign).NestedDtor.opAssign` cannot be used because it is annotated with `@disable` +fail_compilation/disable.d(79): Error: generated function `disable.NestedDtor!(DisabledPostblit).NestedDtor.opAssign` cannot be used because it is annotated with `@disable` +fail_compilation/disable.d(82): Error: generated function `disable.NestedDtor!(HasDtor).NestedDtor.opAssign` cannot be used because it is annotated with `@disable` +fail_compilation/disable.d(84): Error: enum member `disable.Enum1.value` cannot be used because it is annotated with `@disable` --- */ struct DisabledOpAssign { @@ -44,6 +45,11 @@ struct NestedDtor (T) ~this() {} } +enum Enum1 +{ + @disable value +} + void main () { DisabledOpAssign o; @@ -74,4 +80,6 @@ void main () NestedDtor!(HasDtor) ndd; ndd = NestedDtor!(HasDtor)(); + + auto v1 = Enum1.value; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d index ef75f910180..257d739bbd3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d @@ -43,12 +43,12 @@ void bar() pure @safe /* TEST_OUTPUT: --- -fail_compilation/fail10968.d(66): Error: struct fail10968.SD is not copyable because it is annotated with @disable -fail_compilation/fail10968.d(67): Error: struct fail10968.SD is not copyable because it is annotated with @disable -fail_compilation/fail10968.d(68): Error: struct fail10968.SD is not copyable because it is annotated with @disable -fail_compilation/fail10968.d(71): Error: struct fail10968.SD is not copyable because it is annotated with @disable -fail_compilation/fail10968.d(72): Error: struct fail10968.SD is not copyable because it is annotated with @disable -fail_compilation/fail10968.d(73): Error: struct fail10968.SD is not copyable because it is annotated with @disable +fail_compilation/fail10968.d(66): Error: struct fail10968.SD is not copyable because it is annotated with `@disable` +fail_compilation/fail10968.d(67): Error: struct fail10968.SD is not copyable because it is annotated with `@disable` +fail_compilation/fail10968.d(68): Error: struct fail10968.SD is not copyable because it is annotated with `@disable` +fail_compilation/fail10968.d(71): Error: struct fail10968.SD is not copyable because it is annotated with `@disable` +fail_compilation/fail10968.d(72): Error: struct fail10968.SD is not copyable because it is annotated with `@disable` +fail_compilation/fail10968.d(73): Error: struct fail10968.SD is not copyable because it is annotated with `@disable` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11355.d b/gcc/testsuite/gdc.test/fail_compilation/fail11355.d index 474d376794f..c41a4c492e3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail11355.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11355.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail11355.d(28): Error: struct fail11355.A is not copyable because it is annotated with @disable +fail_compilation/fail11355.d(28): Error: struct fail11355.A is not copyable because it is annotated with `@disable` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15044.d b/gcc/testsuite/gdc.test/fail_compilation/fail15044.d index 8674b8d08c6..964dcf913c2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail15044.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail15044.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail15044.d(30): Error: generated function fail15044.V.opAssign is not callable because it is annotated with @disable +fail_compilation/fail15044.d(30): Error: generated function `fail15044.V.opAssign` cannot be used because it is annotated with `@disable` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail341.d b/gcc/testsuite/gdc.test/fail_compilation/fail341.d index af78e8145b9..8677d485a40 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail341.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail341.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail341.d(26): Error: struct fail341.S is not copyable because it is annotated with @disable -fail_compilation/fail341.d(27): Error: function fail341.foo is not callable because it is annotated with @disable +fail_compilation/fail341.d(26): Error: struct fail341.S is not copyable because it is annotated with `@disable` +fail_compilation/fail341.d(27): Error: function `fail341.foo` cannot be used because it is annotated with `@disable` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9346.d b/gcc/testsuite/gdc.test/fail_compilation/fail9346.d index d3c7a593db2..57d420f76ef 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail9346.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail9346.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail9346.d(26): Error: struct fail9346.S is not copyable because it is annotated with @disable -fail_compilation/fail9346.d(27): Error: struct fail9346.S is not copyable because it is annotated with @disable +fail_compilation/fail9346.d(26): Error: struct fail9346.S is not copyable because it is annotated with `@disable` +fail_compilation/fail9346.d(27): Error: struct fail9346.S is not copyable because it is annotated with `@disable` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_contracts1.d b/gcc/testsuite/gdc.test/fail_compilation/fail_contracts1.d new file mode 100644 index 00000000000..572b821e982 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_contracts1.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail_contracts1.d(8): Error: `(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `)` +--- +*/ + +void foo() out()){} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_contracts2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_contracts2.d new file mode 100644 index 00000000000..2a07a60e5f3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_contracts2.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail_contracts2.d(8): Error: missing `do { ... }` after `in` or `out` +--- +*/ + +void foo()in{}{} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_contracts3.d b/gcc/testsuite/gdc.test/fail_compilation/fail_contracts3.d new file mode 100644 index 00000000000..de3e9bb7081 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_contracts3.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail_contracts3.d(13): Error: function `fail_contracts3.D.foo` cannot have an in contract when overridden function `fail_contracts3.C.foo` does not have an in contract +--- +*/ + +class C { + void foo(){} +} + +class D : C { + override void foo()in{}do{} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_contracts4.d b/gcc/testsuite/gdc.test/fail_compilation/fail_contracts4.d new file mode 100644 index 00000000000..f1b664477cc --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_contracts4.d @@ -0,0 +1,8 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail_contracts4.d(8): Error: missing `do { ... }` for function literal +--- +*/ + +enum x = delegate int()in(true) out(;true) out(r; true) in{} out(r){}; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17908a.d b/gcc/testsuite/gdc.test/fail_compilation/test17908a.d new file mode 100644 index 00000000000..907239734d4 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test17908a.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test17908a.d(10): Error: function `test17908a.foo` cannot be used because it is annotated with `@disable` +--- +*/ + +@disable void foo(); +@disable void foo(int) {} +alias g = foo; + +void main() +{ + g(10); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17908b.d b/gcc/testsuite/gdc.test/fail_compilation/test17908b.d new file mode 100644 index 00000000000..e2c4d84abed --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test17908b.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test17908b.d(13): Error: function `test17908b.foobar` cannot be used because it is annotated with `@disable` +--- +*/ +void foobar() {} +@disable void foobar(int) {} +alias i = foobar; + +void main() +{ + i(10); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test9701.d b/gcc/testsuite/gdc.test/fail_compilation/test9701.d new file mode 100644 index 00000000000..384c51444b1 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test9701.d @@ -0,0 +1,63 @@ +/* +TEST_OUTPUT +--- +fail_compilation/test9701.d(38): Error: `@safe` is not a valid attribute for enum members +fail_compilation/test9701.d(39): Error: `@system` is not a valid attribute for enum members +fail_compilation/test9701.d(40): Error: `@trusted` is not a valid attribute for enum members +fail_compilation/test9701.d(41): Error: `@nogc` is not a valid attribute for enum members +fail_compilation/test9701.d(42): Error: `pure` is not a valid attribute for enum members +fail_compilation/test9701.d(43): Error: `shared` is not a valid attribute for enum members +fail_compilation/test9701.d(44): Error: `inout` is not a valid attribute for enum members +fail_compilation/test9701.d(45): Error: `immutable` is not a valid attribute for enum members +fail_compilation/test9701.d(46): Error: `const` is not a valid attribute for enum members +fail_compilation/test9701.d(47): Error: `synchronized` is not a valid attribute for enum members +fail_compilation/test9701.d(48): Error: `scope` is not a valid attribute for enum members +fail_compilation/test9701.d(49): Error: `auto` is not a valid attribute for enum members +fail_compilation/test9701.d(50): Error: `ref` is not a valid attribute for enum members +fail_compilation/test9701.d(51): Error: `__gshared` is not a valid attribute for enum members +fail_compilation/test9701.d(52): Error: `final` is not a valid attribute for enum members +fail_compilation/test9701.d(53): Error: `extern` is not a valid attribute for enum members +fail_compilation/test9701.d(54): Error: `export` is not a valid attribute for enum members +fail_compilation/test9701.d(55): Error: `nothrow` is not a valid attribute for enum members +fail_compilation/test9701.d(56): Error: `public` is not a valid attribute for enum members +fail_compilation/test9701.d(57): Error: `private` is not a valid attribute for enum members +fail_compilation/test9701.d(58): Error: `package` is not a valid attribute for enum members +fail_compilation/test9701.d(59): Error: `static` is not a valid attribute for enum members +fail_compilation/test9701.d(60): Error: `static` is not a valid attribute for enum members +fail_compilation/test9701.d(61): Error: `static` is not a valid attribute for enum members +fail_compilation/test9701.d(62): Error: `static` is not a valid attribute for enum members +--- +*/ + +// This test exists to verify that parsing of enum member attributes rejects invalid attributes + +// https://issues.dlang.org/show_bug.cgi?id=9701 + +enum Enum +{ + @safe safe, + @system system, + @trusted trusted, + @nogc nogc, + pure pure_, + shared shared_, + inout inout_, + immutable immutable_, + const const_, + synchronized synchronized_, + scope scope_, + auto auto_, + ref ref_, + __gshared __gshared_, + final final_, + extern extern_, + export export_, + nothrow nothrow_, + public public_, + private private_, + package package_, + static static1, + @("a") static static2, + static @("a") static3, + @("a") static @("b") static3, +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test9701b.d b/gcc/testsuite/gdc.test/fail_compilation/test9701b.d new file mode 100644 index 00000000000..16c25413ecb --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test9701b.d @@ -0,0 +1,22 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT +--- +fail_compilation/test9701b.d(20): Deprecation: enum member `test9701b.Enum.e0` is deprecated +fail_compilation/test9701b.d(21): Deprecation: enum member `test9701b.Enum.e1` is deprecated - message +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=9701 + +enum Enum +{ + deprecated e0, + deprecated("message") e1, +} + +void main() +{ + auto value = Enum.e0; + auto value2 = Enum.e1; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/udaparams.d b/gcc/testsuite/gdc.test/fail_compilation/udaparams.d new file mode 100644 index 00000000000..ec760bd60b7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/udaparams.d @@ -0,0 +1,57 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/udaparams.d(31): Error: variadic parameter cannot have user-defined attributes +fail_compilation/udaparams.d(32): Error: variadic parameter cannot have user-defined attributes +fail_compilation/udaparams.d(34): Error: user-defined attributes cannot appear as postfixes +fail_compilation/udaparams.d(35): Error: user-defined attributes cannot appear as postfixes +fail_compilation/udaparams.d(36): Error: user-defined attributes cannot appear as postfixes +fail_compilation/udaparams.d(38): Error: `@safe` attribute for function parameter is not supported +fail_compilation/udaparams.d(39): Error: `@safe` attribute for function parameter is not supported +fail_compilation/udaparams.d(40): Error: `@safe` attribute for function parameter is not supported +fail_compilation/udaparams.d(43): Error: `@system` attribute for function parameter is not supported +fail_compilation/udaparams.d(44): Error: `@trusted` attribute for function parameter is not supported +fail_compilation/udaparams.d(45): Error: `@nogc` attribute for function parameter is not supported +fail_compilation/udaparams.d(51): Error: Cannot put a storage-class in an alias declaration. +fail_compilation/udaparams.d(52): Error: Cannot put a storage-class in an alias declaration. +fail_compilation/udaparams.d(53): Error: semicolon expected to close `alias` declaration +fail_compilation/udaparams.d(53): Error: declaration expected, not `=>` +fail_compilation/udaparams.d(54): Error: semicolon expected to close `alias` declaration +fail_compilation/udaparams.d(54): Error: declaration expected, not `=>` +fail_compilation/udaparams.d(57): Error: basic type expected, not `@` +fail_compilation/udaparams.d(57): Error: identifier expected for template value parameter +fail_compilation/udaparams.d(57): Error: found `@` when expecting `)` +fail_compilation/udaparams.d(57): Error: basic type expected, not `3` +fail_compilation/udaparams.d(57): Error: found `3` when expecting `)` +fail_compilation/udaparams.d(57): Error: semicolon expected following function declaration +fail_compilation/udaparams.d(57): Error: declaration expected, not `)` +--- +*/ + +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()); + + +void test16(A)(A a @system); +void test16(A)(A a @trusted); +void test16(A)(A a @nogc); + +// lambdas without parentheses +alias test19a = @safe b => 1 + 2; +alias test19b = @system b => 1 + 2; +alias test19c = @nogc b => 1 + 2; +alias test19d = @(2) @system b => 1 + 2; +alias test19e = @safe @(2) b => 1 + 2; +alias test19f = extern(C++) b => 1 + 2; +alias test19g = align(2) b => 1 + 2; + +// UDAs on Template parameter aren't supported +void test21(@(3) T)(T t) {} -- 2.30.2