d: Support deprecated, @disable, and user-defined attributes on enum members
authorIain Buclaw <ibuclaw@gdcproject.org>
Thu, 7 Jan 2021 21:00:24 +0000 (22:00 +0100)
committerIain Buclaw <ibuclaw@gdcproject.org>
Sat, 9 Jan 2021 22:45:46 +0000 (23:45 +0100)
Reviewed-on: https://github.com/dlang/dmd/pull/12108

gcc/d/ChangeLog:

* dmd/MERGE: Merge upstream dmd 9bba772fa.

31 files changed:
gcc/d/dmd/MERGE
gcc/d/dmd/declaration.c
gcc/d/dmd/declaration.h
gcc/d/dmd/denum.c
gcc/d/dmd/dsymbol.c
gcc/d/dmd/dsymbol.h
gcc/d/dmd/enum.h
gcc/d/dmd/expression.c
gcc/d/dmd/expression.h
gcc/d/dmd/expressionsem.c
gcc/d/dmd/mtype.c
gcc/d/dmd/parse.c
gcc/d/dmd/traits.c
gcc/testsuite/gdc.test/compilable/test17908.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test9701.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/vcg-ast.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/disable.d
gcc/testsuite/gdc.test/fail_compilation/fail10968.d
gcc/testsuite/gdc.test/fail_compilation/fail11355.d
gcc/testsuite/gdc.test/fail_compilation/fail15044.d
gcc/testsuite/gdc.test/fail_compilation/fail341.d
gcc/testsuite/gdc.test/fail_compilation/fail9346.d
gcc/testsuite/gdc.test/fail_compilation/fail_contracts1.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/fail_contracts2.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/fail_contracts3.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/fail_contracts4.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test17908a.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test17908b.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test9701.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test9701b.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/udaparams.d [new file with mode: 0644]

index f6c8f6f02cf2ac2e65c4fe368e8fa4d28ebaf2fa..a34fd4138d740e5d31e9a66a31c5c55863c74ebf 100644 (file)
@@ -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.
index f196bc825a2edc0409d8cce523216a90c0e9119a..72a07d9b8f5096fdacaa21668a2fc1156caa66f4 100644 (file)
@@ -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);
index 19e4d1a5aa84e51d78fb4bab2da9fe42a934ae78..a464f9beb71fad919122f89e0adbc9244f684457 100644 (file)
@@ -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);
index b881fb6df156d2d772eb58f622b133c6c693613c..d15d94a31572a572c25af1cbd1fcb7d5f4a21e27 100644 (file)
@@ -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);
index d74fe6cfdd5ef88d0d4d32fc5e408023085e5203..5b4fad4ebb7f2afe17d5cb7d15fb282859a39622 100644 (file)
@@ -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;
 }
 
 /**********************************
index 5fa509be9ca5e3df0e0d13719b3c8bf54408a592..6555f12e7b4bb75df707aed6f883b27a07ad32f1 100644 (file)
@@ -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();
index 481ff0c1cd3845a93ca48377295545de7eb50b51..6d389ed76e01249cf7415744d4f55a4c71b29f49 100644 (file)
@@ -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);
index a3c3f72d2619bae96c64370baacfc70144425fe9..395dc56748cf35cddcaf4cb8a9e5eab2e31a6703 100644 (file)
@@ -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())
index ccfaa65f7643e903b6a4e93e35591151da07da96..d84878f0d6ebfed66b39b7ef8252c76d69fd9f16 100644 (file)
@@ -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);
index f519389571a523a8aa53b64390fdee8d0672b9d8..ecafd9d20662002ac8954f10a269497f8418294f 100644 (file)
@@ -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)
index 42f90fa9e04e222bdac9d3bfe3ca5ffdf0675227..ceee70ac7c3900842bcbf2f72fb373487bf70903 100644 (file)
@@ -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();
index 80aaac089eccfd2c0b6163b21e64cf13708d4359..2664af2e706896726b58f5bdc253c3dcf0dccc67 100644 (file)
@@ -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)
index 2f00c8837068454fdb669686c724eb52bd8b2175..46b7d9686214e4502ded5f557214f3d294bc437c 100644 (file)
@@ -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 (file)
index 0000000..3520b5f
--- /dev/null
@@ -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 (file)
index 0000000..8f822ad
--- /dev/null
@@ -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 (file)
index 0000000..7cc376f
--- /dev/null
@@ -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;
+    }
+}
index 517fddd9940b3971d1de1cbc1b6db09629c4c161..7e7d9c2d48d541808b8745a0063d5a7dff8ec067 100644 (file)
@@ -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;
 }
index ef75f9101803f32419bc92110d4e5e55bce8334e..257d739bbd33b1a92a711f83b7707338d7779c07 100644 (file)
@@ -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`
 ---
 */
 
index 474d376794f4959807d57ae815b4fdf583022ac6..c41a4c492e3f39e4b7c6168582cbaf72de6ecc51 100644 (file)
@@ -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`
 ---
 */
 
index 8674b8d08c6663f9bec0fc6a579d369d51676fc7..964dcf913c2af3d6a0b0044c8df23113f3eac213 100644 (file)
@@ -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`
 ---
 */
 
index af78e8145b92709a09477596fc3b15485a8ec3f6..8677d485a406a6f8a75a57f3c044741e7f7d606b 100644 (file)
@@ -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`
 ---
 */
 
index d3c7a593db27d0698d168afc59976e18538f8534..57d420f76ef524c88c74e84dc59546b20c751f50 100644 (file)
@@ -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 (file)
index 0000000..572b821
--- /dev/null
@@ -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 (file)
index 0000000..2a07a60
--- /dev/null
@@ -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 (file)
index 0000000..de3e9bb
--- /dev/null
@@ -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 (file)
index 0000000..f1b6644
--- /dev/null
@@ -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 (file)
index 0000000..9072397
--- /dev/null
@@ -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 (file)
index 0000000..e2c4d84
--- /dev/null
@@ -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 (file)
index 0000000..384c514
--- /dev/null
@@ -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 (file)
index 0000000..16c2541
--- /dev/null
@@ -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 (file)
index 0000000..ec760bd
--- /dev/null
@@ -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) {}