diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-01-07 22:00:24 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-01-09 23:45:46 +0100 |
commit | 7a103daef78a8f9fc9b2af7c28123f25e8fa7163 (patch) | |
tree | 39e4a1d02b2f424b4d77c4e0b0cdff875467e41d /gcc/d | |
parent | acae7b21bc026150c2c01465e4ab0eacb20bd44d (diff) | |
download | gcc-7a103daef78a8f9fc9b2af7c28123f25e8fa7163.zip gcc-7a103daef78a8f9fc9b2af7c28123f25e8fa7163.tar.gz gcc-7a103daef78a8f9fc9b2af7c28123f25e8fa7163.tar.bz2 |
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.
Diffstat (limited to 'gcc/d')
-rw-r--r-- | gcc/d/dmd/MERGE | 2 | ||||
-rw-r--r-- | gcc/d/dmd/declaration.c | 45 | ||||
-rw-r--r-- | gcc/d/dmd/declaration.h | 1 | ||||
-rw-r--r-- | gcc/d/dmd/denum.c | 34 | ||||
-rw-r--r-- | gcc/d/dmd/dsymbol.c | 23 | ||||
-rw-r--r-- | gcc/d/dmd/dsymbol.h | 2 | ||||
-rw-r--r-- | gcc/d/dmd/enum.h | 2 | ||||
-rw-r--r-- | gcc/d/dmd/expression.c | 26 | ||||
-rw-r--r-- | gcc/d/dmd/expression.h | 3 | ||||
-rw-r--r-- | gcc/d/dmd/expressionsem.c | 9 | ||||
-rw-r--r-- | gcc/d/dmd/mtype.c | 21 | ||||
-rw-r--r-- | gcc/d/dmd/parse.c | 132 | ||||
-rw-r--r-- | gcc/d/dmd/traits.c | 4 |
13 files changed, 245 insertions, 59 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index f6c8f6f..a34fd41 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 f196bc8..72a07d9b8 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 19e4d1a..a464f9b 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 b881fb6..d15d94a 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]); @@ -745,6 +767,14 @@ 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); return ::semantic(e, sc); } diff --git a/gcc/d/dmd/dsymbol.c b/gcc/d/dmd/dsymbol.c index d74fe6c..5b4fad4 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 5fa509b..6555f12 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 481ff0c..6d389ed 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 a3c3f72..395dc56 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 ccfaa65..d84878f 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 f519389..ecafd9d 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 42f90fa..ceee70a 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 80aaac0..2664af2 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 2f00c88..46b7d96 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) { |