@@ -392,6 +392,23 @@ final class Parser(AST) : Lexer
392392 return new AST .Dsymbols();
393393 }
394394
395+ private StorageClass parseDeprecatedAttribute (ref AST .Expression msg)
396+ {
397+ if (peek(&token).value != TOK .leftParentheses)
398+ return AST .STC .deprecated_;
399+
400+ nextToken();
401+ check(TOK .leftParentheses);
402+ AST .Expression e = parseAssignExp();
403+ check(TOK .rightParentheses);
404+ if (msg)
405+ {
406+ error(" conflicting storage class `deprecated(%s)` and `deprecated(%s)`" , msg.toChars(), e.toChars());
407+ }
408+ msg = e;
409+ return AST .STC .undefined_;
410+ }
411+
395412 AST .Dsymbols* parseDeclDefs (int once, AST .Dsymbol* pLastDecl = null , PrefixAttributes! AST * pAttrs = null )
396413 {
397414 AST .Dsymbol lastDecl = null ; // used to link unittest to its previous declaration
@@ -811,20 +828,12 @@ final class Parser(AST) : Lexer
811828
812829 case TOK .deprecated_:
813830 {
814- if (peek(&token).value != TOK .leftParentheses)
831+ AST .Expression e;
832+ if (StorageClass _stc = parseDeprecatedAttribute(pAttrs.depmsg))
815833 {
816- stc = AST . STC .deprecated_ ;
834+ stc = _stc ;
817835 goto Lstc;
818836 }
819- nextToken();
820- check(TOK .leftParentheses);
821- AST .Expression e = parseAssignExp();
822- check(TOK .rightParentheses);
823- if (pAttrs.depmsg)
824- {
825- error(" conflicting storage class `deprecated(%s)` and `deprecated(%s)`" , pAttrs.depmsg.toChars(), e.toChars());
826- }
827- pAttrs.depmsg = e;
828837 a = parseBlock(pLastDecl, pAttrs);
829838 if (pAttrs.depmsg)
830839 {
@@ -2950,7 +2959,7 @@ final class Parser(AST) : Lexer
29502959 AST .Type memtype;
29512960 auto loc = token.loc;
29522961
2953- // printf("Parser::parseEnum()\n");
2962+ // printf("Parser::parseEnum()\n");
29542963 nextToken();
29552964 if (token.value == TOK .identifier)
29562965 {
@@ -2977,34 +2986,93 @@ final class Parser(AST) : Lexer
29772986 nextToken();
29782987 else if (token.value == TOK .leftCurly)
29792988 {
2989+ bool isAnonymousEnum = ! id;
2990+
29802991 // printf("enum definition\n");
29812992 e.members = new AST .Dsymbols();
29822993 nextToken();
29832994 const (char )* comment = token.blockComment;
29842995 while (token.value != TOK .rightCurly)
29852996 {
2986- /* Can take the following forms:
2997+ /* Can take the following forms...
29872998 * 1. ident
29882999 * 2. ident = value
29893000 * 3. type ident = value
3001+ * ... prefixed by valid attributes
29903002 */
29913003 loc = token.loc;
29923004
29933005 AST .Type type = null ;
29943006 Identifier ident = null ;
2995- Token * tp = peek(&token);
2996- if (token.value == TOK .identifier && (tp.value == TOK .assign || tp.value == TOK .comma || tp.value == TOK .rightCurly))
3007+
3008+ AST .Expressions* udas;
3009+ StorageClass stc;
3010+ AST .Expression deprecationMessage;
3011+ enum attributeErrorMessage = " `%s` is not a valid attribute for enum members" ;
3012+ while (token.value != TOK .rightCurly
3013+ && token.value != TOK .comma
3014+ && token.value != TOK .assign)
29973015 {
2998- ident = token.ident;
2999- type = null ;
3000- nextToken();
3016+ switch (token.value)
3017+ {
3018+ case TOK .at:
3019+ if (StorageClass _stc = parseAttribute(&udas))
3020+ {
3021+ if (_stc == AST .STC .disable)
3022+ stc |= _stc;
3023+ else
3024+ {
3025+ OutBuffer buf;
3026+ AST .stcToBuffer(&buf, _stc);
3027+ error(attributeErrorMessage, buf.peekString());
3028+ }
3029+ nextToken();
3030+ }
3031+ break ;
3032+ case TOK .deprecated_:
3033+ if (StorageClass _stc = parseDeprecatedAttribute(deprecationMessage))
3034+ {
3035+ stc |= _stc;
3036+ nextToken();
3037+ }
3038+ break ;
3039+ case TOK .identifier:
3040+ Token * tp = peek(&token);
3041+ if (tp.value == TOK .assign || tp.value == TOK .comma || tp.value == TOK .rightCurly)
3042+ {
3043+ ident = token.ident;
3044+ type = null ;
3045+ nextToken();
3046+ }
3047+ else
3048+ {
3049+ goto default ;
3050+ }
3051+ break ;
3052+ default :
3053+ if (isAnonymousEnum)
3054+ {
3055+ type = parseType(&ident, null );
3056+ if (type == AST .Type.terror)
3057+ {
3058+ type = null ;
3059+ nextToken();
3060+ }
3061+ }
3062+ else
3063+ {
3064+ error(attributeErrorMessage, token.toChars());
3065+ nextToken();
3066+ }
3067+ break ;
3068+ }
30013069 }
3002- else
3070+
3071+ if (type && type != AST .Type.terror)
30033072 {
3004- type = parseType(&ident, null );
30053073 if (! ident)
30063074 error(" no identifier for declarator `%s`" , type.toChars());
3007- if (id || memtype )
3075+ if (! isAnonymousEnum )
30083076 error(" type only allowed if anonymous enum and no enum type" );
30093077 }
30103078
@@ -3017,11 +3085,22 @@ final class Parser(AST) : Lexer
30173085 else
30183086 {
30193087 value = null ;
3020- if (type)
3088+ if (type && type != AST .Type.terror && isAnonymousEnum )
30213089 error(" if type, there must be an initializer" );
30223090 }
30233091
3024- auto em = new AST .EnumMember(loc, ident, value, type);
3092+ AST .UserAttributeDeclaration uad;
3093+ if (udas)
3094+ uad = new AST .UserAttributeDeclaration(udas, null );
3095+
3096+ AST .DeprecatedDeclaration dd;
3097+ if (deprecationMessage)
3098+ {
3099+ dd = new AST .DeprecatedDeclaration(deprecationMessage, null );
3100+ stc |= AST .STC .deprecated_;
3101+ }
3102+
3103+ auto em = new AST .EnumMember(loc, ident, value, type, stc, uad, dd);
30253104 e.members.push(em);
30263105
30273106 if (token.value == TOK .rightCurly)
0 commit comments