1 /**
2  * Takes a token stream from the lexer, and parses it into an abstract syntax tree.
3  *
4  * Specification: $(LINK2 https://dlang.org/spec/grammar.html, D Grammar)
5  *
6  * Copyright:   Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/parse.d, _parse.d)
10  * Documentation:  https://dlang.org/phobos/dmd_parse.html
11  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/parse.d
12  */
13 
14 module dmd.parse;
15 
16 import core.stdc.stdio;
17 import core.stdc.string;
18 
19 import dmd.astenums;
20 import dmd.errorsink;
21 import dmd.id;
22 import dmd.identifier;
23 import dmd.lexer;
24 import dmd.location;
25 import dmd.root.filename;
26 import dmd.common.outbuffer;
27 import dmd.root.rmem;
28 import dmd.rootobject;
29 import dmd.root.string;
30 import dmd.tokens;
31 
32 alias CompileEnv = dmd.lexer.CompileEnv;
33 
34 /***********************************************************
35  */
36 class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
37 {
38     AST.ModuleDeclaration* md;
39 
40     protected
41     {
42         AST.Module mod;
43         LINK linkage;
44         Loc linkLoc;
45         CPPMANGLE cppmangle;
46         Loc endloc; // set to location of last right curly
47         int inBrackets; // inside [] of array index or slice
48         Loc lookingForElse; // location of lonely if looking for an else
49         bool doUnittests; // parse unittest blocks
50     }
51 
52     bool transitionIn = false; /// `-transition=in` is active, `in` parameters are listed
53 
54     /*********************
55      * Use this constructor for string mixins.
56      * Input:
57      *      loc = location in source file of mixin
58      */
59     extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment,
60         ErrorSink errorSink, const CompileEnv* compileEnv, const bool doUnittests) scope
61     {
62         //printf("Parser::Parser()1 %d\n", doUnittests);
63         this(_module, input, doDocComment, errorSink, compileEnv, doUnittests);
64         scanloc = loc;
65     }
66 
67     /**************************************************
68      * Main Parser constructor.
69      */
70     extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment, ErrorSink errorSink,
71         const CompileEnv* compileEnv, const bool doUnittests) scope
72     {
73         super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false,
74               errorSink,
75               compileEnv);
76 
77         //printf("Parser::Parser()2 %d\n", doUnittests);
78         this.mod = _module;
79         this.linkage = LINK.d;
80         this.doUnittests = doUnittests;
81     }
82 
83     /++
84      + Parse a module, i.e. the optional `module x.y.z` declaration and all declarations
85      + found in the current file.
86      +
87      + Returns: the list of declarations or an empty list in case of malformed declarations,
88      +          the module declaration will be stored as `this.md` if found
89      +/
90     AST.Dsymbols* parseModule()
91     {
92         if (!parseModuleDeclaration())
93             return errorReturn();
94 
95         return parseModuleContent();
96     }
97 
98     /++
99      + Parse the optional module declaration
100      +
101      + Returns: false if a malformed module declaration was found
102      +/
103     final bool parseModuleDeclaration()
104     {
105         const comment = token.blockComment;
106         bool isdeprecated = false;
107         AST.Expression msg = null;
108 
109         // Parse optional module attributes
110         parseModuleAttributes(msg, isdeprecated);
111 
112         // ModuleDeclaration leads off
113         if (token.value == TOK.module_)
114         {
115             const loc = token.loc;
116             nextToken();
117 
118             /* parse ModuleFullyQualifiedName
119              * https://dlang.org/spec/module.html#ModuleFullyQualifiedName
120              */
121 
122             if (token.value != TOK.identifier)
123             {
124                 error("identifier expected following `module`");
125                 return false;
126             }
127 
128             Identifier[] a;
129             Identifier id = token.ident;
130 
131             while (nextToken() == TOK.dot)
132             {
133                 a ~= id;
134                 nextToken();
135                 if (token.value != TOK.identifier)
136                 {
137                     error("identifier expected following `package`");
138                     return false;
139                 }
140                 id = token.ident;
141             }
142 
143             md = new AST.ModuleDeclaration(loc, a, id, msg, isdeprecated);
144 
145             if (token.value != TOK.semicolon)
146                 error("`;` expected following module declaration instead of `%s`", token.toChars());
147             nextToken();
148             addComment(mod, comment);
149         }
150         return true;
151     }
152 
153     /++
154      + Parse the content of a module, i.e. all declarations found until the end of file.
155      +
156      + Returns: the list of declarations or an empty list in case of malformed declarations
157      +/
158     final AST.Dsymbols* parseModuleContent()
159     {
160         AST.Dsymbol lastDecl = mod;
161         AST.Dsymbols* decldefs = parseDeclDefs(0, &lastDecl);
162 
163         if (token.value == TOK.rightCurly)
164         {
165             error("unmatched closing brace");
166             return errorReturn();
167         }
168 
169         if (token.value != TOK.endOfFile)
170         {
171             error("unrecognized declaration");
172             return errorReturn();
173         }
174         return decldefs;
175     }
176 
177     /++
178      + Skips to the end of the current declaration - denoted by either `;` or EOF
179      +
180      + Returns: An empty list of Dsymbols
181      +/
182     private AST.Dsymbols* errorReturn()
183     {
184         while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
185             nextToken();
186         nextToken();
187         return new AST.Dsymbols();
188     }
189 
190     /**********************************
191      * Parse the ModuleAttributes preceding a module declaration.
192      * ModuleDeclaration:
193      *    ModuleAttributes(opt) module ModuleFullyQualifiedName ;
194      * https://dlang.org/spec/module.html#ModuleAttributes
195      * Params:
196      *  msg = set to the AssignExpression from DeprecatedAttribute https://dlang.org/spec/module.html#DeprecatedAttribute
197      *  isdeprecated = set to true if a DeprecatedAttribute is seen
198      */
199     private
200     void parseModuleAttributes(out AST.Expression msg, out bool isdeprecated)
201     {
202         Token* tk;
203         if (!(skipAttributes(&token, &tk) && tk.value == TOK.module_))
204             return;             // no module attributes
205 
206         AST.Expressions* udas = null;
207         while (token.value != TOK.module_)
208         {
209             switch (token.value)
210             {
211             case TOK.deprecated_:
212                 {
213                     // deprecated (...) module ...
214                     if (isdeprecated)
215                         error("there is only one deprecation attribute allowed for module declaration");
216                     isdeprecated = true;
217                     nextToken();
218                     if (token.value == TOK.leftParenthesis)
219                     {
220                         check(TOK.leftParenthesis);
221                         msg = parseAssignExp();
222                         check(TOK.rightParenthesis);
223                     }
224                     break;
225                 }
226             case TOK.at:
227                 {
228                     AST.Expressions* exps = null;
229                     const stc = parseAttribute(exps);
230                     if (stc & atAttrGroup)
231                     {
232                         error("`@%s` attribute for module declaration is not supported", token.toChars());
233                     }
234                     else
235                     {
236                         udas = AST.UserAttributeDeclaration.concat(udas, exps);
237                     }
238                     if (stc)
239                         nextToken();
240                     break;
241                 }
242             default:
243                 {
244                     error("`module` expected instead of `%s`", token.toChars());
245                     nextToken();
246                     break;
247                 }
248             }
249         }
250 
251         if (udas)
252         {
253             auto a = new AST.Dsymbols();
254             auto udad = new AST.UserAttributeDeclaration(udas, a);
255             mod.userAttribDecl = udad;
256         }
257     }
258 
259   final:
260 
261     /**
262      * Parses a `deprecated` declaration
263      *
264      * Params:
265      *   msg = Deprecated message, if any.
266      *         Used to support overriding a deprecated storage class with
267      *         a deprecated declaration with a message, but to error
268      *         if both declaration have a message.
269      *
270      * Returns:
271      *   Whether the deprecated declaration has a message
272      */
273     private bool parseDeprecatedAttribute(ref AST.Expression msg)
274     {
275         if (peekNext() != TOK.leftParenthesis)
276             return false;
277 
278         nextToken();
279         check(TOK.leftParenthesis);
280         AST.Expression e = parseAssignExp();
281         check(TOK.rightParenthesis);
282         if (msg)
283         {
284             error(token.loc, "conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg.toChars(), e.toChars());
285         }
286         msg = e;
287         return true;
288     }
289 
290     /************************************
291      * Parse declarations and definitions
292      * Params:
293      *  once = !=0 means parse exactly one decl or def
294      *  pLastDecl = set to last decl or def parsed
295      *  pAttrs = keep track of attributes
296      * Returns:
297      *  array of declared symbols
298      */
299     AST.Dsymbols* parseDeclDefs(int once, AST.Dsymbol* pLastDecl = null, PrefixAttributes!AST* pAttrs = null)
300     {
301         AST.Dsymbol lastDecl = null; // used to link unittest to its previous declaration
302         if (!pLastDecl)
303             pLastDecl = &lastDecl;
304 
305         const linksave = linkage; // save global state
306 
307         //printf("Parser::parseDeclDefs()\n");
308         auto decldefs = new AST.Dsymbols();
309         do
310         {
311             // parse result
312             AST.Dsymbol s = null;
313             AST.Dsymbols* a = null;
314 
315             PrefixAttributes!AST attrs;
316             if (!once || !pAttrs)
317             {
318                 pAttrs = &attrs;
319                 pAttrs.comment = token.blockComment.ptr;
320             }
321             AST.Visibility.Kind prot;
322             StorageClass stc;
323             AST.Condition condition;
324 
325             linkage = linksave;
326 
327             Loc startloc;
328             Loc scdLoc;
329 
330             switch (token.value)
331             {
332             case TOK.enum_:
333                 {
334                     /* Determine if this is a manifest constant declaration,
335                      * or a conventional enum.
336                      */
337                     const tv = peekNext();
338                     if (tv == TOK.leftCurly || tv == TOK.colon)
339                         s = parseEnum();
340                     else if (tv != TOK.identifier)
341                         goto Ldeclaration;
342                     else
343                     {
344                         const nextv = peekNext2();
345                         if (nextv == TOK.leftCurly || nextv == TOK.colon || nextv == TOK.semicolon)
346                             s = parseEnum();
347                         else
348                             goto Ldeclaration;
349                     }
350                     break;
351                 }
352             case TOK.import_:
353                 a = parseImport();
354                 // keep pLastDecl
355                 break;
356 
357             case TOK.template_:
358                 s = cast(AST.Dsymbol)parseTemplateDeclaration();
359                 break;
360 
361             case TOK.mixin_:
362                 {
363                     const loc = token.loc;
364                     switch (peekNext())
365                     {
366                     case TOK.leftParenthesis:
367                         {
368                             // MixinType
369                             if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
370                                 goto Ldeclaration;
371                             // mixin(string)
372                             nextToken();
373                             auto exps = parseArguments();
374                             check(TOK.semicolon);
375                             s = new AST.MixinDeclaration(loc, exps);
376                             break;
377                         }
378                     case TOK.template_:
379                         // mixin template
380                         nextToken();
381                         s = cast(AST.Dsymbol)parseTemplateDeclaration(true);
382                         break;
383 
384                     default:
385                         s = parseMixin();
386                         break;
387                     }
388                     break;
389                 }
390             case TOK.wchar_:
391             case TOK.dchar_:
392             case TOK.bool_:
393             case TOK.char_:
394             case TOK.int8:
395             case TOK.uns8:
396             case TOK.int16:
397             case TOK.uns16:
398             case TOK.int32:
399             case TOK.uns32:
400             case TOK.int64:
401             case TOK.uns64:
402             case TOK.int128:
403             case TOK.uns128:
404             case TOK.float32:
405             case TOK.float64:
406             case TOK.float80:
407             case TOK.imaginary32:
408             case TOK.imaginary64:
409             case TOK.imaginary80:
410             case TOK.complex32:
411             case TOK.complex64:
412             case TOK.complex80:
413             case TOK.void_:
414             case TOK.alias_:
415             case TOK.identifier:
416             case TOK.super_:
417             case TOK.typeof_:
418             case TOK.dot:
419             case TOK.vector:
420             case TOK.struct_:
421             case TOK.union_:
422             case TOK.class_:
423             case TOK.interface_:
424             case TOK.traits:
425             Ldeclaration:
426                 a = parseDeclarations(false, pAttrs, pAttrs.comment);
427                 if (a && a.length)
428                     *pLastDecl = (*a)[a.length - 1];
429                 break;
430 
431             case TOK.this_:
432                 if (peekNext() == TOK.dot)
433                     goto Ldeclaration;
434                 s = parseCtor(pAttrs);
435                 break;
436 
437             case TOK.tilde:
438                 s = parseDtor(pAttrs);
439                 break;
440 
441             case TOK.invariant_:
442                 const tv = peekNext();
443                 if (tv == TOK.leftParenthesis || tv == TOK.leftCurly)
444                 {
445                     // invariant { statements... }
446                     // invariant() { statements... }
447                     // invariant (expression);
448                     s = parseInvariant(pAttrs);
449                     break;
450                 }
451                 error("invariant body expected, not `%s`", token.toChars());
452                 goto Lerror;
453 
454             case TOK.unittest_:
455                 /**
456                  * Ignore unittests in non-root modules.
457                  *
458                  * This mainly means that unittests *inside templates* are only
459                  * ever instantiated if the module lexically declaring the
460                  * template is one of the root modules.
461                  *
462                  * E.g., compiling some project with `-unittest` does NOT
463                  * compile and later run any unittests in instantiations of
464                  * templates declared in other libraries.
465                  *
466                  * Declaring unittests *inside* templates is considered an anti-
467                  * pattern. In almost all cases, the unittests don't depend on
468                  * the template parameters, but instantiate the template with
469                  * fixed arguments (e.g., Nullable!T unittests instantiating
470                  * Nullable!int), so compiling and running identical tests for
471                  * each template instantiation is hardly desirable.
472                  * But adding a unittest right below some function being tested
473                  * is arguably good for locality, so unittests end up inside
474                  * templates.
475                  * To make sure a template's unittests are run, it should be
476                  * instantiated in the same module, e.g., some module-level
477                  * unittest.
478                  *
479                  * Another reason for ignoring unittests in templates from non-
480                  * root modules is for template codegen culling via
481                  * TemplateInstance.needsCodegen(). If the compiler decides not
482                  * to emit some Nullable!bool because there's an existing
483                  * instantiation in some non-root module, it has no idea whether
484                  * that module was compiled with -unittest too, and so whether
485                  * Nullable!int (instantiated in some unittest inside the
486                  * Nullable template) can be culled too. By ignoring unittests
487                  * in non-root modules, the compiler won't consider any
488                  * template instantiations in these unittests as candidates for
489                  * further codegen culling.
490                  */
491                 // The isRoot check is here because it can change after parsing begins (see dmodule.d)
492                 if (doUnittests && mod.isRoot())
493                 {
494                     linkage = LINK.d; // unittests have D linkage
495                     s = parseUnitTest(pAttrs);
496                     if (*pLastDecl)
497                         (*pLastDecl).ddocUnittest = cast(AST.UnitTestDeclaration)s;
498                 }
499                 else
500                 {
501                     // Skip over unittest block by counting { }
502                     Loc loc = token.loc;
503                     int braces = 0;
504                     while (1)
505                     {
506                         nextToken();
507                         switch (token.value)
508                         {
509                         case TOK.leftCurly:
510                             ++braces;
511                             continue;
512 
513                         case TOK.rightCurly:
514                             if (--braces)
515                                 continue;
516                             nextToken();
517                             break;
518 
519                         case TOK.endOfFile:
520                             /* { */
521                             error(loc, "closing `}` of unittest not found before end of file");
522                             goto Lerror;
523 
524                         default:
525                             continue;
526                         }
527                         break;
528                     }
529                     // Workaround 14894. Add an empty unittest declaration to keep
530                     // the number of symbols in this scope independent of -unittest.
531                     s = new AST.UnitTestDeclaration(loc, token.loc, STC.undefined_, null);
532                 }
533                 break;
534 
535             case TOK.new_:
536                 s = parseNew(pAttrs);
537                 break;
538 
539             case TOK.colon:
540             case TOK.leftCurly:
541                 error("declaration expected, not `%s`", token.toChars());
542                 goto Lerror;
543 
544             case TOK.rightCurly:
545             case TOK.endOfFile:
546                 if (once)
547                     error("declaration expected, not `%s`", token.toChars());
548                 return decldefs;
549 
550             case TOK.static_:
551                 {
552                     const next = peekNext();
553                     if (next == TOK.this_)
554                         s = parseStaticCtor(pAttrs);
555                     else if (next == TOK.tilde)
556                         s = parseStaticDtor(pAttrs);
557                     else if (next == TOK.assert_)
558                         s = parseStaticAssert();
559                     else if (next == TOK.if_)
560                     {
561                         const Loc loc = token.loc;
562                         condition = parseStaticIfCondition();
563                         AST.Dsymbols* athen;
564                         if (token.value == TOK.colon)
565                             athen = parseBlock(pLastDecl);
566                         else
567                         {
568                             const lookingForElseSave = lookingForElse;
569                             lookingForElse = token.loc;
570                             athen = parseBlock(pLastDecl);
571                             lookingForElse = lookingForElseSave;
572                         }
573                         AST.Dsymbols* aelse = null;
574                         if (token.value == TOK.else_)
575                         {
576                             const elseloc = token.loc;
577                             nextToken();
578                             aelse = parseBlock(pLastDecl);
579                             checkDanglingElse(elseloc);
580                         }
581                         s = new AST.StaticIfDeclaration(loc, condition, athen, aelse);
582                     }
583                     else if (next == TOK.import_)
584                     {
585                         a = parseImport();
586                         // keep pLastDecl
587                     }
588                     else if (next == TOK.foreach_ || next == TOK.foreach_reverse_)
589                     {
590                         s = parseForeach!(AST.StaticForeachDeclaration)(token.loc, pLastDecl);
591                     }
592                     else
593                     {
594                         stc = STC.static_;
595                         goto Lstc;
596                     }
597                     break;
598                 }
599             case TOK.const_:
600                 if (peekNext() == TOK.leftParenthesis)
601                     goto Ldeclaration;
602                 stc = STC.const_;
603                 goto Lstc;
604 
605             case TOK.immutable_:
606                 if (peekNext() == TOK.leftParenthesis)
607                     goto Ldeclaration;
608                 stc = STC.immutable_;
609                 goto Lstc;
610 
611             case TOK.shared_:
612                 {
613                     const next = peekNext();
614                     if (next == TOK.leftParenthesis)
615                         goto Ldeclaration;
616                     if (next == TOK.static_)
617                     {
618                         TOK next2 = peekNext2();
619                         if (next2 == TOK.this_)
620                         {
621                             s = parseSharedStaticCtor(pAttrs);
622                             break;
623                         }
624                         if (next2 == TOK.tilde)
625                         {
626                             s = parseSharedStaticDtor(pAttrs);
627                             break;
628                         }
629                     }
630                     stc = STC.shared_;
631                     goto Lstc;
632                 }
633             case TOK.inout_:
634                 if (peekNext() == TOK.leftParenthesis)
635                     goto Ldeclaration;
636                 stc = STC.wild;
637                 goto Lstc;
638 
639             case TOK.final_:
640                 stc = STC.final_;
641                 goto Lstc;
642 
643             case TOK.auto_:
644                 stc = STC.auto_;
645                 goto Lstc;
646 
647             case TOK.scope_:
648                 stc = STC.scope_;
649                 goto Lstc;
650 
651             case TOK.override_:
652                 stc = STC.override_;
653                 goto Lstc;
654 
655             case TOK.abstract_:
656                 stc = STC.abstract_;
657                 goto Lstc;
658 
659             case TOK.synchronized_:
660                 stc = STC.synchronized_;
661                 goto Lstc;
662 
663             case TOK.nothrow_:
664                 stc = STC.nothrow_;
665                 goto Lstc;
666 
667             case TOK.pure_:
668                 stc = STC.pure_;
669                 goto Lstc;
670 
671             case TOK.ref_:
672                 stc = STC.ref_;
673                 goto Lstc;
674 
675             case TOK.gshared:
676                 stc = STC.gshared;
677                 goto Lstc;
678 
679             case TOK.at:
680                 {
681                     AST.Expressions* exps = null;
682                     stc = parseAttribute(exps);
683                     if (stc)
684                         goto Lstc; // it's a predefined attribute
685                     // no redundant/conflicting check for UDAs
686                     pAttrs.udas = AST.UserAttributeDeclaration.concat(pAttrs.udas, exps);
687                     goto Lautodecl;
688                 }
689             Lstc:
690                 pAttrs.storageClass = appendStorageClass(pAttrs.storageClass, stc);
691                 scdLoc = token.loc;
692                 nextToken();
693 
694             Lautodecl:
695 
696                 /* Look for auto initializers:
697                  *      storage_class identifier = initializer;
698                  *      storage_class identifier(...) = initializer;
699                  */
700                 if (token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign))
701                 {
702                     a = parseAutoDeclarations(getStorageClass!AST(pAttrs), pAttrs.comment);
703                     if (a && a.length)
704                         *pLastDecl = (*a)[a.length - 1];
705                     if (pAttrs.udas)
706                     {
707                         s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
708                         pAttrs.udas = null;
709                     }
710                     break;
711                 }
712 
713                 /* Look for return type inference for template functions.
714                  */
715                 Token* tk;
716                 if (token.value == TOK.identifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) &&
717                     (tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ ||
718                      tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.goesTo ||
719                      tk.value == TOK.identifier && tk.ident == Id._body))
720                 {
721                     if (tk.value == TOK.identifier && tk.ident == Id._body)
722                         usageOfBodyKeyword();
723 
724                     a = parseDeclarations(true, pAttrs, pAttrs.comment);
725                     if (a && a.length)
726                         *pLastDecl = (*a)[a.length - 1];
727                     if (pAttrs.udas)
728                     {
729                         s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
730                         pAttrs.udas = null;
731                     }
732                     break;
733                 }
734 
735                 a = parseBlock(pLastDecl, pAttrs);
736                 auto stc2 = getStorageClass!AST(pAttrs);
737                 if (stc2 != STC.undefined_)
738                 {
739                     s = new AST.StorageClassDeclaration(scdLoc, stc2, a);
740                 }
741                 if (pAttrs.udas)
742                 {
743                     if (s)
744                     {
745                         a = new AST.Dsymbols();
746                         a.push(s);
747                     }
748                     s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
749                     pAttrs.udas = null;
750                 }
751                 break;
752 
753             case TOK.deprecated_:
754                 {
755                     stc |= STC.deprecated_;
756                     if (!parseDeprecatedAttribute(pAttrs.depmsg))
757                         goto Lstc;
758 
759                     a = parseBlock(pLastDecl, pAttrs);
760                     s = new AST.DeprecatedDeclaration(pAttrs.depmsg, a);
761                     pAttrs.depmsg = null;
762                     break;
763                 }
764             case TOK.leftBracket:
765                 {
766                     if (peekNext() == TOK.rightBracket)
767                         error("empty attribute list is not allowed");
768                     error("use `@(attributes)` instead of `[attributes]`");
769                     AST.Expressions* exps = parseArguments();
770                     // no redundant/conflicting check for UDAs
771 
772                     pAttrs.udas = AST.UserAttributeDeclaration.concat(pAttrs.udas, exps);
773                     a = parseBlock(pLastDecl, pAttrs);
774                     if (pAttrs.udas)
775                     {
776                         s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
777                         pAttrs.udas = null;
778                     }
779                     break;
780                 }
781             case TOK.extern_:
782                 {
783                     if (peekNext() != TOK.leftParenthesis)
784                     {
785                         stc = STC.extern_;
786                         goto Lstc;
787                     }
788 
789                     const linkLoc = token.loc;
790                     auto res = parseLinkage();
791                     if (pAttrs.link != LINK.default_)
792                     {
793                         if (pAttrs.link != res.link)
794                         {
795                             error(token.loc, "conflicting linkage `extern (%s)` and `extern (%s)`", AST.linkageToChars(pAttrs.link), AST.linkageToChars(res.link));
796                         }
797                         else if (res.idents || res.identExps || res.cppmangle != CPPMANGLE.def)
798                         {
799                             // Allow:
800                             //      extern(C++, foo) extern(C++, bar) void foo();
801                             // to be equivalent with:
802                             //      extern(C++, foo.bar) void foo();
803                             // Allow also:
804                             //      extern(C++, "ns") extern(C++, class) struct test {}
805                             //      extern(C++, class) extern(C++, "ns") struct test {}
806                         }
807                         else
808                             error("redundant linkage `extern (%s)`", AST.linkageToChars(pAttrs.link));
809                     }
810                     pAttrs.link = res.link;
811                     this.linkage = res.link;
812                     this.linkLoc = linkLoc;
813                     a = parseBlock(pLastDecl, pAttrs);
814                     if (res.idents)
815                     {
816                         assert(res.link == LINK.cpp);
817                         assert(res.idents.length);
818                         for (size_t i = res.idents.length; i;)
819                         {
820                             Identifier id = (*res.idents)[--i];
821                             if (s)
822                             {
823                                 a = new AST.Dsymbols();
824                                 a.push(s);
825                             }
826                             s = new AST.Nspace(linkLoc, id, null, a);
827                         }
828                         pAttrs.link = LINK.default_;
829                     }
830                     else if (res.identExps)
831                     {
832                         assert(res.link == LINK.cpp);
833                         assert(res.identExps.length);
834                         for (size_t i = res.identExps.length; i;)
835                         {
836                             AST.Expression exp = (*res.identExps)[--i];
837                             if (s)
838                             {
839                                 a = new AST.Dsymbols();
840                                 a.push(s);
841                             }
842                             s = new AST.CPPNamespaceDeclaration(linkLoc, exp, a);
843                         }
844                         pAttrs.link = LINK.default_;
845                     }
846                     else if (res.cppmangle != CPPMANGLE.def)
847                     {
848                         assert(res.link == LINK.cpp);
849                         s = new AST.CPPMangleDeclaration(linkLoc, res.cppmangle, a);
850                     }
851                     else if (pAttrs.link != LINK.default_)
852                     {
853                         s = new AST.LinkDeclaration(linkLoc, pAttrs.link, a);
854                         pAttrs.link = LINK.default_;
855                     }
856                     break;
857                 }
858 
859             case TOK.private_:
860                 prot = AST.Visibility.Kind.private_;
861                 goto Lprot;
862 
863             case TOK.package_:
864                 prot = AST.Visibility.Kind.package_;
865                 goto Lprot;
866 
867             case TOK.protected_:
868                 prot = AST.Visibility.Kind.protected_;
869                 goto Lprot;
870 
871             case TOK.public_:
872                 prot = AST.Visibility.Kind.public_;
873                 goto Lprot;
874 
875             case TOK.export_:
876                 prot = AST.Visibility.Kind.export_;
877                 goto Lprot;
878             Lprot:
879                 {
880                     if (pAttrs.visibility.kind != AST.Visibility.Kind.undefined)
881                     {
882                         if (pAttrs.visibility.kind != prot)
883                             error(token.loc, "conflicting visibility attribute `%s` and `%s`", AST.visibilityToChars(pAttrs.visibility.kind), AST.visibilityToChars(prot));
884                         else
885                             error("redundant visibility attribute `%s`", AST.visibilityToChars(prot));
886                     }
887                     pAttrs.visibility.kind = prot;
888                     const attrloc = token.loc;
889 
890                     nextToken();
891 
892                     // optional qualified package identifier to bind
893                     // visibility to
894                     Identifier[] pkg_prot_idents;
895                     if (pAttrs.visibility.kind == AST.Visibility.Kind.package_ && token.value == TOK.leftParenthesis)
896                     {
897                         pkg_prot_idents = parseQualifiedIdentifier("protection package");
898                         if (pkg_prot_idents)
899                             check(TOK.rightParenthesis);
900                         else
901                         {
902                             while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
903                                 nextToken();
904                             nextToken();
905                             break;
906                         }
907                     }
908 
909                     a = parseBlock(pLastDecl, pAttrs);
910                     if (pAttrs.visibility.kind != AST.Visibility.Kind.undefined)
911                     {
912                         if (pAttrs.visibility.kind == AST.Visibility.Kind.package_ && pkg_prot_idents)
913                             s = new AST.VisibilityDeclaration(attrloc, pkg_prot_idents, a);
914                         else
915                             s = new AST.VisibilityDeclaration(attrloc, pAttrs.visibility, a);
916 
917                         pAttrs.visibility = AST.Visibility(AST.Visibility.Kind.undefined);
918                     }
919                     break;
920                 }
921             case TOK.align_:
922                 {
923                     const attrLoc = token.loc;
924 
925                     nextToken();
926 
927                     AST.Expression e = null; // default
928                     if (token.value == TOK.leftParenthesis)
929                     {
930                         nextToken();
931                         e = parseAssignExp();
932                         check(TOK.rightParenthesis);
933                     }
934 
935                     if (pAttrs.setAlignment)
936                     {
937                         if (e)
938                             error("redundant alignment attribute `align(%s)`", e.toChars());
939                         else
940                             error("redundant alignment attribute `align`");
941                     }
942 
943                     pAttrs.setAlignment = true;
944                     pAttrs.ealign = e;
945                     a = parseBlock(pLastDecl, pAttrs);
946                     if (pAttrs.setAlignment)
947                     {
948                         s = new AST.AlignDeclaration(attrLoc, pAttrs.ealign, a);
949                         pAttrs.setAlignment = false;
950                         pAttrs.ealign = null;
951                     }
952                     break;
953                 }
954             case TOK.pragma_:
955                 {
956                     AST.Expressions* args = null;
957                     const loc = token.loc;
958 
959                     nextToken();
960                     check(TOK.leftParenthesis);
961                     if (token.value != TOK.identifier)
962                     {
963                         error("`pragma(identifier)` expected");
964                         goto Lerror;
965                     }
966                     Identifier ident = token.ident;
967                     nextToken();
968                     if (token.value == TOK.comma && peekNext() != TOK.rightParenthesis)
969                         args = parseArguments(); // pragma(identifier, args...)
970                     else
971                         check(TOK.rightParenthesis); // pragma(identifier)
972 
973                     AST.Dsymbols* a2 = null;
974                     if (token.value == TOK.semicolon)
975                     {
976                         /* https://issues.dlang.org/show_bug.cgi?id=2354
977                          * Accept single semicolon as an empty
978                          * DeclarationBlock following attribute.
979                          *
980                          * Attribute DeclarationBlock
981                          * Pragma    DeclDef
982                          *           ;
983                          */
984                         nextToken();
985                     }
986                     else
987                         a2 = parseBlock(pLastDecl);
988                     s = new AST.PragmaDeclaration(loc, ident, args, a2);
989                     break;
990                 }
991             case TOK.debug_:
992                 startloc = token.loc;
993                 nextToken();
994                 if (token.value == TOK.assign)
995                 {
996                     s = parseDebugSpecification();
997                     break;
998                 }
999                 condition = parseDebugCondition();
1000                 goto Lcondition;
1001 
1002             case TOK.version_:
1003                 startloc = token.loc;
1004                 nextToken();
1005                 if (token.value == TOK.assign)
1006                 {
1007                     s = parseVersionSpecification();
1008                     break;
1009                 }
1010                 condition = parseVersionCondition();
1011                 goto Lcondition;
1012 
1013             Lcondition:
1014                 {
1015                     AST.Dsymbols* athen;
1016                     if (token.value == TOK.colon)
1017                         athen = parseBlock(pLastDecl);
1018                     else
1019                     {
1020                         const lookingForElseSave = lookingForElse;
1021                         lookingForElse = token.loc;
1022                         athen = parseBlock(pLastDecl);
1023                         lookingForElse = lookingForElseSave;
1024                     }
1025                     AST.Dsymbols* aelse = null;
1026                     if (token.value == TOK.else_)
1027                     {
1028                         const elseloc = token.loc;
1029                         nextToken();
1030                         aelse = parseBlock(pLastDecl);
1031                         checkDanglingElse(elseloc);
1032                     }
1033                     s = new AST.ConditionalDeclaration(startloc, condition, athen, aelse);
1034                     break;
1035                 }
1036             case TOK.semicolon:
1037                 // empty declaration
1038                 //error("empty declaration");
1039                 nextToken();
1040                 continue;
1041 
1042             default:
1043                 error("declaration expected, not `%s`", token.toChars());
1044             Lerror:
1045                 while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
1046                     nextToken();
1047                 nextToken();
1048                 s = null;
1049                 continue;
1050             }
1051 
1052             if (s)
1053             {
1054                 if (!s.isAttribDeclaration())
1055                     *pLastDecl = s;
1056                 decldefs.push(s);
1057                 addComment(s, pAttrs.comment);
1058             }
1059             else if (a && a.length)
1060             {
1061                 decldefs.append(a);
1062             }
1063         }
1064         while (!once);
1065 
1066         linkage = linksave;
1067 
1068         return decldefs;
1069     }
1070 
1071     /*****************************************
1072      * Parse auto declarations of the form:
1073      *   storageClass ident = init, ident = init, ... ;
1074      * and return the array of them.
1075      * Starts with token on the first ident.
1076      * Ends with scanner past closing ';'
1077      */
1078     private AST.Dsymbols* parseAutoDeclarations(StorageClass storageClass, const(char)* comment)
1079     {
1080         //printf("parseAutoDeclarations\n");
1081         auto a = new AST.Dsymbols();
1082 
1083         while (1)
1084         {
1085             const loc = token.loc;
1086             Identifier ident = token.ident;
1087             nextToken(); // skip over ident
1088 
1089             AST.TemplateParameters* tpl = null;
1090             if (token.value == TOK.leftParenthesis)
1091                 tpl = parseTemplateParameterList();
1092 
1093             check(TOK.assign);   // skip over '='
1094             AST.Initializer _init = parseInitializer();
1095             auto v = new AST.VarDeclaration(loc, null, ident, _init, storageClass);
1096 
1097             AST.Dsymbol s = v;
1098             if (tpl)
1099             {
1100                 auto a2 = new AST.Dsymbols();
1101                 a2.push(v);
1102                 auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2, 0);
1103                 s = tempdecl;
1104             }
1105             a.push(s);
1106             switch (token.value)
1107             {
1108             case TOK.semicolon:
1109                 nextToken();
1110                 addComment(s, comment);
1111                 break;
1112 
1113             case TOK.comma:
1114                 nextToken();
1115                 if (!(token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign)))
1116                 {
1117                     error("identifier expected following comma");
1118                     break;
1119                 }
1120                 addComment(s, comment);
1121                 continue;
1122 
1123             default:
1124                 error("semicolon expected following auto declaration, not `%s`", token.toChars());
1125                 break;
1126             }
1127             break;
1128         }
1129         return a;
1130     }
1131 
1132     /********************************************
1133      * Parse declarations after an align, visibility, or extern decl.
1134      */
1135     private AST.Dsymbols* parseBlock(AST.Dsymbol* pLastDecl, PrefixAttributes!AST* pAttrs = null)
1136     {
1137         AST.Dsymbols* a = null;
1138 
1139         //printf("parseBlock()\n");
1140         switch (token.value)
1141         {
1142         case TOK.semicolon:
1143             error("declaration expected following attribute, not `;`");
1144             nextToken();
1145             break;
1146 
1147         case TOK.endOfFile:
1148             error("declaration expected following attribute, not end of file");
1149             break;
1150 
1151         case TOK.leftCurly:
1152             {
1153                 const lcLoc = token.loc;
1154                 const lookingForElseSave = lookingForElse;
1155                 lookingForElse = Loc();
1156 
1157                 nextToken();
1158                 a = parseDeclDefs(0, pLastDecl);
1159                 if (token.value != TOK.rightCurly)
1160                 {
1161                     /* left curly brace */
1162                     error("matching `}` expected, not `%s`", token.toChars());
1163                     eSink.errorSupplemental(lcLoc, "unmatched `{`");
1164                 }
1165                 else
1166                     nextToken();
1167                 lookingForElse = lookingForElseSave;
1168                 break;
1169             }
1170         case TOK.colon:
1171             nextToken();
1172             a = parseDeclDefs(0, pLastDecl); // grab declarations up to closing curly bracket
1173             break;
1174 
1175         default:
1176             a = parseDeclDefs(1, pLastDecl, pAttrs);
1177             break;
1178         }
1179         return a;
1180     }
1181 
1182     /**
1183      * Provide an error message if `added` contains storage classes which are
1184      * redundant with those in `orig`; otherwise, return the combination.
1185      *
1186      * Params:
1187      *   orig = The already applied storage class.
1188      *   added = The new storage class to add to `orig`.
1189      *
1190      * Returns:
1191      *   The combination of both storage classes (`orig | added`).
1192      */
1193     private StorageClass appendStorageClass(StorageClass orig, StorageClass added)
1194     {
1195         void checkConflictSTCGroup(bool at = false)(StorageClass group)
1196         {
1197             if (added & group && orig & group & ((orig & group) - 1))
1198                 error(
1199                     at ? "conflicting attribute `@%s`"
1200                        : "conflicting attribute `%s`",
1201                     token.toChars());
1202         }
1203 
1204         if (orig & added)
1205         {
1206             OutBuffer buf;
1207             AST.stcToBuffer(buf, added);
1208             error("redundant attribute `%s`", buf.peekChars());
1209             return orig | added;
1210         }
1211 
1212         const Redundant = (STC.const_ | STC.scope_ | STC.ref_);
1213         orig |= added;
1214 
1215         if ((orig & STC.in_) && (added & Redundant))
1216         {
1217             if (added & STC.const_)
1218                 error("attribute `const` is redundant with previously-applied `in`");
1219             else if (compileEnv.previewIn)
1220             {
1221                 error("attribute `%s` is redundant with previously-applied `in`",
1222                       (orig & STC.scope_) ? "scope".ptr : "ref".ptr);
1223             }
1224             else if (added & STC.ref_)
1225             {
1226                 // accept using `in ref` for legacy compatibility
1227             }
1228             else
1229             {
1230                 version (IN_GCC)
1231                     error("attribute `scope` cannot be applied with `in`, use `-fpreview=in` instead");
1232                 else
1233                     error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead");
1234             }
1235             return orig;
1236         }
1237 
1238         if ((added & STC.in_) && (orig & Redundant))
1239         {
1240             if (orig & STC.const_)
1241                 error("attribute `in` cannot be added after `const`: remove `const`");
1242             else if (compileEnv.previewIn)
1243             {
1244                 // Windows `printf` does not support `%1$s`
1245                 const(char*) stc_str = (orig & STC.scope_) ? "scope".ptr : "ref".ptr;
1246                 error(token.loc, "attribute `in` cannot be added after `%s`: remove `%s`",
1247                       stc_str, stc_str);
1248             }
1249             else if (orig & STC.ref_)
1250             {
1251                 // accept using `in ref` for legacy compatibility
1252             }
1253             else
1254             {
1255                 version (IN_GCC)
1256                     error("attribute `in` cannot be added after `scope`: remove `scope` and use `-fpreview=in`");
1257                 else
1258                     error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`");
1259             }
1260             return orig;
1261         }
1262 
1263         checkConflictSTCGroup(STC.const_ | STC.immutable_ | STC.manifest);
1264         checkConflictSTCGroup(STC.gshared | STC.shared_);
1265         checkConflictSTCGroup!true(STC.safeGroup);
1266 
1267         return orig;
1268     }
1269 
1270     /***********************************************
1271      * Parse attribute(s), lexer is on '@'.
1272      *
1273      * Attributes can be builtin (e.g. `@safe`, `@nogc`, etc...),
1274      * or be user-defined (UDAs). In the former case, we return the storage
1275      * class via the return value, while in thelater case we return `0`
1276      * and set `pudas`.
1277      *
1278      * Params:
1279      *   pudas = An array of UDAs to append to
1280      *
1281      * Returns:
1282      *   If the attribute is builtin, the return value will be non-zero.
1283      *   Otherwise, 0 is returned, and `pudas` will be appended to.
1284      */
1285     private StorageClass parseAttribute(ref AST.Expressions* udas)
1286     {
1287         nextToken();
1288         if (token.value == TOK.identifier)
1289         {
1290             // If we find a builtin attribute, we're done, return immediately.
1291             if (StorageClass stc = isBuiltinAtAttribute(token.ident))
1292                 return stc;
1293 
1294             // Allow identifier, template instantiation, or function call
1295             // for `@Argument` (single UDA) form.
1296             AST.Expression exp = parsePrimaryExp();
1297             if (token.value == TOK.leftParenthesis)
1298             {
1299                 const loc = token.loc;
1300                 AST.Expressions* args = new AST.Expressions();
1301                 AST.Identifiers* names = new AST.Identifiers();
1302                 parseNamedArguments(args, names);
1303                 exp = new AST.CallExp(loc, exp, args, names);
1304             }
1305 
1306             if (udas is null)
1307                 udas = new AST.Expressions();
1308             udas.push(exp);
1309             return 0;
1310         }
1311 
1312         AST.Expression templateArgToExp(RootObject o, const ref Loc loc)
1313         {
1314             switch (o.dyncast)
1315             {
1316                 case DYNCAST.expression:
1317                     return cast(AST.Expression) o;
1318                 case DYNCAST.type:
1319                     return new AST.TypeExp(loc, cast(AST.Type)o);
1320                 default:
1321                     assert(0);
1322             }
1323         }
1324 
1325         if (token.value == TOK.leftParenthesis)
1326         {
1327             // Multi-UDAs ( `@( ArgumentList )`) form, concatenate with existing
1328             if (peekNext() == TOK.rightParenthesis)
1329                 error("empty attribute list is not allowed");
1330 
1331             if (udas is null)
1332                 udas = new AST.Expressions();
1333             auto args = parseTemplateArgumentList();
1334             foreach (arg; *args)
1335                 udas.push(templateArgToExp(arg, token.loc));
1336             return 0;
1337         }
1338 
1339         if (auto o = parseTemplateSingleArgument())
1340         {
1341             if (udas is null)
1342                 udas = new AST.Expressions();
1343             udas.push(templateArgToExp(o, token.loc));
1344             return 0;
1345         }
1346 
1347         if (token.isKeyword())
1348             error("`%s` is a keyword, not an `@` attribute", token.toChars());
1349         else
1350             error("`@identifier` or `@(ArgumentList)` expected, not `@%s`", token.toChars());
1351 
1352         return 0;
1353     }
1354 
1355     /***********************************************
1356      * Parse const/immutable/shared/inout/nothrow/pure postfix
1357      */
1358     private StorageClass parsePostfix(StorageClass storageClass, AST.Expressions** pudas)
1359     {
1360         while (1)
1361         {
1362             StorageClass stc;
1363             switch (token.value)
1364             {
1365             case TOK.const_:
1366                 stc = STC.const_;
1367                 break;
1368 
1369             case TOK.immutable_:
1370                 stc = STC.immutable_;
1371                 break;
1372 
1373             case TOK.shared_:
1374                 stc = STC.shared_;
1375                 break;
1376 
1377             case TOK.inout_:
1378                 stc = STC.wild;
1379                 break;
1380 
1381             case TOK.nothrow_:
1382                 stc = STC.nothrow_;
1383                 break;
1384 
1385             case TOK.pure_:
1386                 stc = STC.pure_;
1387                 break;
1388 
1389             case TOK.return_:
1390                 stc = STC.return_;
1391                 if (peekNext() == TOK.scope_)
1392                     stc |= STC.returnScope;     // recognize `return scope`
1393                 break;
1394 
1395             case TOK.scope_:
1396                 stc = STC.scope_;
1397                 break;
1398 
1399             case TOK.at:
1400                 {
1401                     AST.Expressions* udas = null;
1402                     stc = parseAttribute(udas);
1403                     if (udas)
1404                     {
1405                         if (pudas)
1406                             *pudas = AST.UserAttributeDeclaration.concat(*pudas, udas);
1407                         else
1408                         {
1409                             // Disallow:
1410                             //      void function() @uda fp;
1411                             //      () @uda { return 1; }
1412                             error("user-defined attributes cannot appear as postfixes");
1413                         }
1414                         continue;
1415                     }
1416                     break;
1417                 }
1418             default:
1419                 Token* tk;
1420                 if (skipAttributes(&token, &tk) && tk.ptr != token.ptr ||
1421                     token.value == TOK.static_ || token.value == TOK.extern_)
1422                 {
1423                     error("`%s` token is not allowed in postfix position",
1424                         Token.toChars(token.value));
1425                     nextToken();
1426                     continue;
1427                 }
1428                 return storageClass;
1429             }
1430             storageClass = appendStorageClass(storageClass, stc);
1431             nextToken();
1432         }
1433     }
1434 
1435     private StorageClass parseTypeCtor()
1436     {
1437         StorageClass storageClass = STC.undefined_;
1438 
1439         while (1)
1440         {
1441             if (peekNext() == TOK.leftParenthesis)
1442                 return storageClass;
1443 
1444             StorageClass stc;
1445             switch (token.value)
1446             {
1447             case TOK.const_:
1448                 stc = STC.const_;
1449                 break;
1450 
1451             case TOK.immutable_:
1452                 stc = STC.immutable_;
1453                 break;
1454 
1455             case TOK.shared_:
1456                 stc = STC.shared_;
1457                 break;
1458 
1459             case TOK.inout_:
1460                 stc = STC.wild;
1461                 break;
1462 
1463             default:
1464                 return storageClass;
1465             }
1466             storageClass = appendStorageClass(storageClass, stc);
1467             nextToken();
1468         }
1469     }
1470 
1471     /**************************************
1472      * Parse constraint.
1473      * Constraint is of the form:
1474      *      if ( ConstraintExpression )
1475      */
1476     private AST.Expression parseConstraint()
1477     {
1478         AST.Expression e = null;
1479         if (token.value == TOK.if_)
1480         {
1481             nextToken(); // skip over 'if'
1482             check(TOK.leftParenthesis);
1483             e = parseExpression();
1484             check(TOK.rightParenthesis);
1485         }
1486         return e;
1487     }
1488 
1489     /**************************************
1490      * Parse a TemplateDeclaration.
1491      */
1492     private AST.TemplateDeclaration parseTemplateDeclaration(bool ismixin = false)
1493     {
1494         AST.TemplateDeclaration tempdecl;
1495         Identifier id;
1496         AST.TemplateParameters* tpl;
1497         AST.Dsymbols* decldefs;
1498         AST.Expression constraint = null;
1499         const loc = token.loc;
1500 
1501         nextToken();
1502         if (token.value != TOK.identifier)
1503         {
1504             error("identifier expected following `template`");
1505             goto Lerr;
1506         }
1507         id = token.ident;
1508         nextToken();
1509         tpl = parseTemplateParameterList();
1510         if (!tpl)
1511             goto Lerr;
1512 
1513         constraint = parseConstraint();
1514 
1515         if (token.value != TOK.leftCurly)
1516         {
1517             error("`{` expected after template parameter list, not `%s`", token.toChars()); /* } */
1518             goto Lerr;
1519         }
1520         decldefs = parseBlock(null);
1521 
1522         tempdecl = new AST.TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
1523         return tempdecl;
1524 
1525     Lerr:
1526         return null;
1527     }
1528 
1529     /******************************************
1530      * Parse template parameter list.
1531      * Input:
1532      *      flag    0: parsing "( list )"
1533      *              1: parsing non-empty "list $(RPAREN)"
1534      */
1535     private AST.TemplateParameters* parseTemplateParameterList(int flag = 0)
1536     {
1537         auto tpl = new AST.TemplateParameters();
1538 
1539         if (!flag && token.value != TOK.leftParenthesis)
1540         {
1541             error("parenthesized template parameter list expected following template identifier");
1542             goto Lerr;
1543         }
1544         nextToken();
1545 
1546         // Get array of TemplateParameters
1547         if (flag || token.value != TOK.rightParenthesis)
1548         {
1549             while (token.value != TOK.rightParenthesis)
1550             {
1551                 AST.TemplateParameter tp;
1552                 Loc loc;
1553                 Identifier tp_ident = null;
1554                 AST.Type tp_spectype = null;
1555                 AST.Type tp_valtype = null;
1556                 AST.Type tp_defaulttype = null;
1557                 AST.Expression tp_specvalue = null;
1558                 AST.Expression tp_defaultvalue = null;
1559 
1560                 // Get TemplateParameter
1561 
1562                 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1563                 const tv = peekNext();
1564                 if (token.value == TOK.alias_)
1565                 {
1566                     // AliasParameter
1567                     nextToken();
1568                     loc = token.loc; // todo
1569                     AST.Type spectype = null;
1570                     if (isDeclaration(&token, NeedDeclaratorId.must, TOK.reserved, null))
1571                     {
1572                         spectype = parseType(&tp_ident);
1573                     }
1574                     else
1575                     {
1576                         if (token.value != TOK.identifier)
1577                         {
1578                             error("identifier expected for template `alias` parameter");
1579                             goto Lerr;
1580                         }
1581                         tp_ident = token.ident;
1582                         nextToken();
1583                     }
1584                     RootObject spec = null;
1585                     if (token.value == TOK.colon) // : Type
1586                     {
1587                         nextToken();
1588                         if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null))
1589                             spec = parseType();
1590                         else
1591                             spec = parseCondExp();
1592                     }
1593                     RootObject def = null;
1594                     if (token.value == TOK.assign) // = Type
1595                     {
1596                         nextToken();
1597                         if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null))
1598                             def = parseType();
1599                         else
1600                             def = parseCondExp();
1601                     }
1602                     tp = new AST.TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
1603                 }
1604                 else if (tv == TOK.colon || tv == TOK.assign || tv == TOK.comma || tv == TOK.rightParenthesis)
1605                 {
1606                     // TypeParameter
1607                     if (token.value != TOK.identifier)
1608                     {
1609                         error("identifier expected for template type parameter");
1610                         goto Lerr;
1611                     }
1612                     loc = token.loc;
1613                     tp_ident = token.ident;
1614                     nextToken();
1615                     if (token.value == TOK.colon) // : Type
1616                     {
1617                         nextToken();
1618                         tp_spectype = parseType();
1619                     }
1620                     if (token.value == TOK.assign) // = Type
1621                     {
1622                         nextToken();
1623                         tp_defaulttype = parseType();
1624                     }
1625                     tp = new AST.TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1626                 }
1627                 else if (token.value == TOK.identifier && tv == TOK.dotDotDot)
1628                 {
1629                     // ident...
1630                     loc = token.loc;
1631                     tp_ident = token.ident;
1632                     nextToken();
1633                     nextToken();
1634                     tp = new AST.TemplateTupleParameter(loc, tp_ident);
1635                 }
1636                 else if (token.value == TOK.this_)
1637                 {
1638                     // ThisParameter
1639                     nextToken();
1640                     if (token.value != TOK.identifier)
1641                     {
1642                         error("identifier expected for template `this` parameter");
1643                         goto Lerr;
1644                     }
1645                     loc = token.loc;
1646                     tp_ident = token.ident;
1647                     nextToken();
1648                     if (token.value == TOK.colon) // : Type
1649                     {
1650                         nextToken();
1651                         tp_spectype = parseType();
1652                     }
1653                     if (token.value == TOK.assign) // = Type
1654                     {
1655                         nextToken();
1656                         tp_defaulttype = parseType();
1657                     }
1658                     tp = new AST.TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1659                 }
1660                 else
1661                 {
1662                     // ValueParameter
1663                     loc = token.loc; // todo
1664                     tp_valtype = parseType(&tp_ident);
1665                     if (!tp_ident)
1666                     {
1667                         error("identifier expected for template value parameter");
1668                         tp_ident = Identifier.idPool("error");
1669                     }
1670                     if (token.value == TOK.colon) // : CondExpression
1671                     {
1672                         nextToken();
1673                         tp_specvalue = parseCondExp();
1674                     }
1675                     if (token.value == TOK.assign) // = CondExpression
1676                     {
1677                         nextToken();
1678                         tp_defaultvalue = parseDefaultInitExp();
1679                     }
1680                     tp = new AST.TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1681                 }
1682                 tpl.push(tp);
1683                 if (token.value != TOK.comma)
1684                     break;
1685                 nextToken();
1686             }
1687         }
1688         check(TOK.rightParenthesis);
1689 
1690     Lerr:
1691         return tpl;
1692     }
1693 
1694     /******************************************
1695      * Parse template mixin.
1696      *      mixin Foo;
1697      *      mixin Foo!(args);
1698      *      mixin a.b.c!(args).Foo!(args);
1699      *      mixin Foo!(args) identifier;
1700      *      mixin typeof(expr).identifier!(args);
1701      */
1702     private AST.Dsymbol parseMixin()
1703     {
1704         AST.TemplateMixin tm;
1705         Identifier id;
1706         AST.Objects* tiargs;
1707 
1708         //printf("parseMixin()\n");
1709         const locMixin = token.loc;
1710         nextToken(); // skip 'mixin'
1711 
1712         auto loc = token.loc;
1713         AST.TypeQualified tqual = null;
1714         if (token.value == TOK.dot)
1715         {
1716             id = Id.empty;
1717         }
1718         else
1719         {
1720             if (token.value == TOK.typeof_)
1721             {
1722                 tqual = parseTypeof();
1723                 check(TOK.dot);
1724             }
1725             if (token.value != TOK.identifier)
1726             {
1727                 error("identifier expected, not `%s`", token.toChars());
1728                 id = Id.empty;
1729             }
1730             else
1731                 id = token.ident;
1732             nextToken();
1733         }
1734 
1735         while (1)
1736         {
1737             tiargs = null;
1738             if (token.value == TOK.not)
1739             {
1740                 tiargs = parseTemplateArguments();
1741             }
1742 
1743             if (tiargs && token.value == TOK.dot)
1744             {
1745                 auto tempinst = new AST.TemplateInstance(loc, id, tiargs);
1746                 if (!tqual)
1747                     tqual = new AST.TypeInstance(loc, tempinst);
1748                 else
1749                     tqual.addInst(tempinst);
1750                 tiargs = null;
1751             }
1752             else
1753             {
1754                 if (!tqual)
1755                     tqual = new AST.TypeIdentifier(loc, id);
1756                 else
1757                     tqual.addIdent(id);
1758             }
1759 
1760             if (token.value != TOK.dot)
1761                 break;
1762 
1763             nextToken();
1764             if (token.value != TOK.identifier)
1765             {
1766                 error("identifier expected following `.` instead of `%s`", token.toChars());
1767                 break;
1768             }
1769             loc = token.loc;
1770             id = token.ident;
1771             nextToken();
1772         }
1773 
1774         id = null;
1775         if (token.value == TOK.identifier)
1776         {
1777             id = token.ident;
1778             nextToken();
1779         }
1780 
1781         tm = new AST.TemplateMixin(locMixin, id, tqual, tiargs);
1782         if (token.value != TOK.semicolon)
1783             error("`;` expected after `mixin`");
1784         nextToken();
1785 
1786         return tm;
1787     }
1788 
1789     /******************************************
1790      * Parse template arguments.
1791      * Input:
1792      *      current token is opening '!'
1793      * Output:
1794      *      current token is one after closing '$(RPAREN)'
1795      */
1796     private AST.Objects* parseTemplateArguments()
1797     {
1798         AST.Objects* tiargs;
1799 
1800         nextToken();
1801         if (token.value == TOK.leftParenthesis)
1802         {
1803             // ident!(template_arguments)
1804             tiargs = parseTemplateArgumentList();
1805         }
1806         else
1807         {
1808             // ident!template_argument
1809             RootObject o = parseTemplateSingleArgument();
1810             if (!o)
1811             {
1812                 error("template argument expected following `!`");
1813             }
1814             else
1815             {
1816                 tiargs = new AST.Objects();
1817                 tiargs.push(o);
1818             }
1819         }
1820         if (token.value == TOK.not)
1821         {
1822             TOK tok = peekNext();
1823             if (tok != TOK.is_ && tok != TOK.in_)
1824             {
1825                 error("multiple ! arguments are not allowed");
1826             Lagain:
1827                 nextToken();
1828                 if (token.value == TOK.leftParenthesis)
1829                     parseTemplateArgumentList();
1830                 else
1831                     parseTemplateSingleArgument();
1832                 if (token.value == TOK.not && (tok = peekNext()) != TOK.is_ && tok != TOK.in_)
1833                     goto Lagain;
1834             }
1835         }
1836         return tiargs;
1837     }
1838 
1839     /******************************************
1840      * Parse template argument list.
1841      * Input:
1842      *      current token is opening '$(LPAREN)',
1843      *          or ',' for __traits
1844      * Output:
1845      *      current token is one after closing '$(RPAREN)'
1846      */
1847     private AST.Objects* parseTemplateArgumentList()
1848     {
1849         //printf("Parser::parseTemplateArgumentList()\n");
1850         auto tiargs = new AST.Objects();
1851         TOK endtok = TOK.rightParenthesis;
1852         assert(token.value == TOK.leftParenthesis || token.value == TOK.comma);
1853         nextToken();
1854 
1855         // Get TemplateArgumentList
1856         while (token.value != endtok)
1857         {
1858             tiargs.push(parseTypeOrAssignExp());
1859             if (token.value != TOK.comma)
1860                 break;
1861             nextToken();
1862         }
1863         check(endtok, "template argument list");
1864         return tiargs;
1865     }
1866 
1867     /***************************************
1868      * Parse a Type or an Expression
1869      * Returns:
1870      *  RootObject representing the AST
1871      */
1872     RootObject parseTypeOrAssignExp(TOK endtoken = TOK.reserved)
1873     {
1874         return isDeclaration(&token, NeedDeclaratorId.no, endtoken, null)
1875             ? parseType()           // argument is a type
1876             : parseAssignExp();     // argument is an expression
1877     }
1878 
1879     /*****************************
1880      * Parse single template argument, to support the syntax:
1881      *      foo!arg
1882      * Input:
1883      *      current token is the arg
1884      * Returns: An AST.Type, AST.Expression, or `null` on error
1885      */
1886     private RootObject parseTemplateSingleArgument()
1887     {
1888         //printf("parseTemplateSingleArgument()\n");
1889         AST.Type ta;
1890         switch (token.value)
1891         {
1892         case TOK.identifier:
1893             ta = new AST.TypeIdentifier(token.loc, token.ident);
1894             goto LabelX;
1895 
1896         case TOK.vector:
1897             ta = parseVector();
1898             goto LabelX;
1899 
1900         case TOK.void_:
1901             ta = AST.Type.tvoid;
1902             goto LabelX;
1903 
1904         case TOK.int8:
1905             ta = AST.Type.tint8;
1906             goto LabelX;
1907 
1908         case TOK.uns8:
1909             ta = AST.Type.tuns8;
1910             goto LabelX;
1911 
1912         case TOK.int16:
1913             ta = AST.Type.tint16;
1914             goto LabelX;
1915 
1916         case TOK.uns16:
1917             ta = AST.Type.tuns16;
1918             goto LabelX;
1919 
1920         case TOK.int32:
1921             ta = AST.Type.tint32;
1922             goto LabelX;
1923 
1924         case TOK.uns32:
1925             ta = AST.Type.tuns32;
1926             goto LabelX;
1927 
1928         case TOK.int64:
1929             ta = AST.Type.tint64;
1930             goto LabelX;
1931 
1932         case TOK.uns64:
1933             ta = AST.Type.tuns64;
1934             goto LabelX;
1935 
1936         case TOK.int128:
1937             ta = AST.Type.tint128;
1938             goto LabelX;
1939 
1940         case TOK.uns128:
1941             ta = AST.Type.tuns128;
1942             goto LabelX;
1943 
1944         case TOK.float32:
1945             ta = AST.Type.tfloat32;
1946             goto LabelX;
1947 
1948         case TOK.float64:
1949             ta = AST.Type.tfloat64;
1950             goto LabelX;
1951 
1952         case TOK.float80:
1953             ta = AST.Type.tfloat80;
1954             goto LabelX;
1955 
1956         case TOK.imaginary32:
1957             ta = AST.Type.timaginary32;
1958             goto LabelX;
1959 
1960         case TOK.imaginary64:
1961             ta = AST.Type.timaginary64;
1962             goto LabelX;
1963 
1964         case TOK.imaginary80:
1965             ta = AST.Type.timaginary80;
1966             goto LabelX;
1967 
1968         case TOK.complex32:
1969             ta = AST.Type.tcomplex32;
1970             goto LabelX;
1971 
1972         case TOK.complex64:
1973             ta = AST.Type.tcomplex64;
1974             goto LabelX;
1975 
1976         case TOK.complex80:
1977             ta = AST.Type.tcomplex80;
1978             goto LabelX;
1979 
1980         case TOK.bool_:
1981             ta = AST.Type.tbool;
1982             goto LabelX;
1983 
1984         case TOK.char_:
1985             ta = AST.Type.tchar;
1986             goto LabelX;
1987 
1988         case TOK.wchar_:
1989             ta = AST.Type.twchar;
1990             goto LabelX;
1991 
1992         case TOK.dchar_:
1993             ta = AST.Type.tdchar;
1994             goto LabelX;
1995         LabelX:
1996             nextToken();
1997             return ta;
1998 
1999         case TOK.int32Literal:
2000         case TOK.uns32Literal:
2001         case TOK.int64Literal:
2002         case TOK.uns64Literal:
2003         case TOK.int128Literal:
2004         case TOK.uns128Literal:
2005         case TOK.float32Literal:
2006         case TOK.float64Literal:
2007         case TOK.float80Literal:
2008         case TOK.imaginary32Literal:
2009         case TOK.imaginary64Literal:
2010         case TOK.imaginary80Literal:
2011         case TOK.null_:
2012         case TOK.true_:
2013         case TOK.false_:
2014         case TOK.charLiteral:
2015         case TOK.wcharLiteral:
2016         case TOK.dcharLiteral:
2017         case TOK.string_:
2018         case TOK.hexadecimalString:
2019         case TOK.file:
2020         case TOK.fileFullPath:
2021         case TOK.line:
2022         case TOK.moduleString:
2023         case TOK.functionString:
2024         case TOK.prettyFunction:
2025         case TOK.this_:
2026             {
2027                 // Template argument is an expression
2028                 return parsePrimaryExp();
2029             }
2030         default:
2031             return null;
2032         }
2033     }
2034 
2035     /**********************************
2036      * Parse a static assertion.
2037      * Current token is 'static'.
2038      */
2039     private AST.StaticAssert parseStaticAssert()
2040     {
2041         const loc = token.loc;
2042         AST.Expression exp;
2043         AST.Expressions* msg = null;
2044 
2045         //printf("parseStaticAssert()\n");
2046         nextToken();
2047         nextToken();
2048         check(TOK.leftParenthesis);
2049         exp = parseAssignExp();
2050         if (token.value == TOK.comma)
2051         {
2052             if (peekNext() == TOK.rightParenthesis)
2053             {
2054                 nextToken(); // consume `,`
2055                 nextToken(); // consume `)`
2056             }
2057             else
2058                 msg = parseArguments();
2059         }
2060         else
2061             check(TOK.rightParenthesis);
2062         check(TOK.semicolon, "static assert");
2063         return new AST.StaticAssert(loc, exp, msg);
2064     }
2065 
2066     /***********************************
2067      * Parse typeof(expression).
2068      * Current token is on the 'typeof'.
2069      */
2070     private AST.TypeQualified parseTypeof()
2071     {
2072         AST.TypeQualified t;
2073         const loc = token.loc;
2074 
2075         nextToken();
2076         check(TOK.leftParenthesis);
2077         if (token.value == TOK.return_) // typeof(return)
2078         {
2079             nextToken();
2080             t = new AST.TypeReturn(loc);
2081         }
2082         else
2083         {
2084             AST.Expression exp = parseExpression(); // typeof(expression)
2085             t = new AST.TypeTypeof(loc, exp);
2086         }
2087         check(TOK.rightParenthesis);
2088         return t;
2089     }
2090 
2091     /***********************************
2092      * Parse __vector(type).
2093      * Current token is on the '__vector'.
2094      */
2095     private AST.Type parseVector()
2096     {
2097         nextToken();
2098         check(TOK.leftParenthesis);
2099         AST.Type tb = parseType();
2100         check(TOK.rightParenthesis);
2101         return new AST.TypeVector(tb);
2102     }
2103 
2104     /***********************************
2105      * Parse:
2106      *      extern (linkage)
2107      *      extern (C++, namespaces)
2108      *      extern (C++, "namespace", "namespaces", ...)
2109      *      extern (C++, (StringExp))
2110      * The parser is on the 'extern' token.
2111      */
2112     private ParsedLinkage!(AST) parseLinkage()
2113     {
2114         ParsedLinkage!(AST) result;
2115         nextToken();
2116         assert(token.value == TOK.leftParenthesis);
2117         nextToken();
2118         ParsedLinkage!(AST) returnLinkage(LINK link)
2119         {
2120             check(TOK.rightParenthesis);
2121             result.link = link;
2122             return result;
2123         }
2124         ParsedLinkage!(AST) invalidLinkage()
2125         {
2126             error("valid linkage identifiers are `D`, `C`, `C++`, `Objective-C`, `Windows`, `System`");
2127             return returnLinkage(LINK.d);
2128         }
2129 
2130         if (token.value != TOK.identifier)
2131             return returnLinkage(LINK.d);
2132 
2133         Identifier id = token.ident;
2134         nextToken();
2135         if (id == Id.Windows)
2136             return returnLinkage(LINK.windows);
2137         else if (id == Id.D)
2138             return returnLinkage(LINK.d);
2139         else if (id == Id.System)
2140             return returnLinkage(LINK.system);
2141         else if (id == Id.Objective) // Looking for tokens "Objective-C"
2142         {
2143             if (token.value != TOK.min)
2144                 return invalidLinkage();
2145 
2146             nextToken();
2147             if (token.ident != Id.C)
2148                 return invalidLinkage();
2149 
2150             nextToken();
2151             return returnLinkage(LINK.objc);
2152         }
2153         else if (id != Id.C)
2154             return invalidLinkage();
2155 
2156         if (token.value != TOK.plusPlus)
2157             return returnLinkage(LINK.c);
2158 
2159         nextToken();
2160         if (token.value != TOK.comma) // , namespaces or class or struct
2161             return returnLinkage(LINK.cpp);
2162 
2163         nextToken();
2164 
2165         if (token.value == TOK.rightParenthesis)
2166             return returnLinkage(LINK.cpp); // extern(C++,)
2167 
2168         if (token.value == TOK.class_ || token.value == TOK.struct_)
2169         {
2170             result.cppmangle = token.value == TOK.class_ ? CPPMANGLE.asClass : CPPMANGLE.asStruct;
2171             nextToken();
2172         }
2173         else if (token.value == TOK.identifier) // named scope namespace
2174         {
2175             result.idents = new AST.Identifiers();
2176             while (1)
2177             {
2178                 Identifier idn = token.ident;
2179                 result.idents.push(idn);
2180                 nextToken();
2181                 if (token.value == TOK.dot)
2182                 {
2183                     nextToken();
2184                     if (token.value == TOK.identifier)
2185                         continue;
2186                     error("identifier expected for C++ namespace");
2187                     result.idents = null;  // error occurred, invalidate list of elements.
2188                 }
2189                 break;
2190             }
2191         }
2192         else // non-scoped StringExp namespace
2193         {
2194             result.identExps = new AST.Expressions();
2195             while (1)
2196             {
2197                 result.identExps.push(parseCondExp());
2198                 if (token.value != TOK.comma)
2199                     break;
2200                 nextToken();
2201                 // Allow trailing commas as done for argument lists, arrays, ...
2202                 if (token.value == TOK.rightParenthesis)
2203                     break;
2204             }
2205         }
2206         return returnLinkage(LINK.cpp);
2207     }
2208 
2209     /***********************************
2210      * Parse ident1.ident2.ident3
2211      *
2212      * Params:
2213      *  entity = what qualified identifier is expected to resolve into.
2214      *     Used only for better error message
2215      *
2216      * Returns:
2217      *     array of identifiers with actual qualified one stored last
2218      */
2219     private Identifier[] parseQualifiedIdentifier(const(char)* entity)
2220     {
2221         Identifier[] qualified;
2222 
2223         do
2224         {
2225             nextToken();
2226             if (token.value != TOK.identifier)
2227             {
2228                 error(token.loc, "`%s` expected as dot-separated identifiers, got `%s`", entity, token.toChars());
2229                 return qualified;
2230             }
2231 
2232             Identifier id = token.ident;
2233             qualified ~= id;
2234 
2235             nextToken();
2236         }
2237         while (token.value == TOK.dot);
2238 
2239         return qualified;
2240     }
2241 
2242     private AST.DebugSymbol parseDebugSpecification()
2243     {
2244         AST.DebugSymbol s;
2245         nextToken();
2246         if (token.value == TOK.identifier)
2247             s = new AST.DebugSymbol(token.loc, token.ident);
2248         else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
2249         {
2250             // @@@DEPRECATED_2.111@@@
2251             // Deprecated in 2.101, remove in 2.111
2252             deprecation("`debug = <integer>` is deprecated, use debug identifiers instead");
2253 
2254             s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
2255         }
2256         else
2257         {
2258             error("identifier or integer expected, not `%s`", token.toChars());
2259             s = null;
2260         }
2261         nextToken();
2262         if (token.value != TOK.semicolon)
2263             error("semicolon expected");
2264         nextToken();
2265         return s;
2266     }
2267 
2268     /**************************************
2269      * Parse a debug conditional
2270      */
2271     private AST.Condition parseDebugCondition()
2272     {
2273         uint level = 1;
2274         Identifier id = null;
2275         Loc loc = token.loc;
2276 
2277         if (token.value == TOK.leftParenthesis)
2278         {
2279             nextToken();
2280 
2281             if (token.value == TOK.identifier)
2282                 id = token.ident;
2283             else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
2284             {
2285                 // @@@DEPRECATED_2.111@@@
2286                 // Deprecated in 2.101, remove in 2.111
2287                 deprecation("`debug( <integer> )` is deprecated, use debug identifiers instead");
2288 
2289                 level = cast(uint)token.unsvalue;
2290             }
2291             else
2292                 error("identifier or integer expected inside `debug(...)`, not `%s`", token.toChars());
2293             loc = token.loc;
2294             nextToken();
2295             check(TOK.rightParenthesis);
2296         }
2297         return new AST.DebugCondition(loc, mod, level, id);
2298     }
2299 
2300     /**************************************
2301      * Parse a version specification
2302      */
2303     private AST.VersionSymbol parseVersionSpecification()
2304     {
2305         AST.VersionSymbol s;
2306         nextToken();
2307         if (token.value == TOK.identifier)
2308             s = new AST.VersionSymbol(token.loc, token.ident);
2309         else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
2310         {
2311             // @@@DEPRECATED_2.111@@@
2312             // Deprecated in 2.101, remove in 2.111
2313             deprecation("`version = <integer>` is deprecated, use version identifiers instead");
2314             s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
2315         }
2316         else
2317         {
2318             error("identifier or integer expected, not `%s`", token.toChars());
2319             s = null;
2320         }
2321         nextToken();
2322         if (token.value != TOK.semicolon)
2323             error("semicolon expected");
2324         nextToken();
2325         return s;
2326     }
2327 
2328     /**************************************
2329      * Parse a version conditional
2330      */
2331     private AST.Condition parseVersionCondition()
2332     {
2333         uint level = 1;
2334         Identifier id = null;
2335         Loc loc;
2336 
2337         if (token.value == TOK.leftParenthesis)
2338         {
2339             nextToken();
2340             /* Allow:
2341              *    version (unittest)
2342              *    version (assert)
2343              * even though they are keywords
2344              */
2345             loc = token.loc;
2346             if (token.value == TOK.identifier)
2347                 id = token.ident;
2348             else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
2349             {
2350                 // @@@DEPRECATED_2.111@@@
2351                 // Deprecated in 2.101, remove in 2.111
2352                 deprecation("`version( <integer> )` is deprecated, use version identifiers instead");
2353 
2354                 level = cast(uint)token.unsvalue;
2355             }
2356             else if (token.value == TOK.unittest_)
2357                 id = Identifier.idPool(Token.toString(TOK.unittest_));
2358             else if (token.value == TOK.assert_)
2359                 id = Identifier.idPool(Token.toString(TOK.assert_));
2360             else
2361                 error("identifier or integer expected inside `version(...)`, not `%s`", token.toChars());
2362             nextToken();
2363             check(TOK.rightParenthesis);
2364         }
2365         else
2366             error("(condition) expected following `version`");
2367         return new AST.VersionCondition(loc, mod, level, id);
2368     }
2369 
2370     /***********************************************
2371      *      static if (expression)
2372      *          body
2373      *      else
2374      *          body
2375      * Current token is 'static'.
2376      */
2377     private AST.Condition parseStaticIfCondition()
2378     {
2379         AST.Expression exp;
2380         AST.Condition condition;
2381         const loc = token.loc;
2382 
2383         nextToken();
2384         nextToken();
2385         if (token.value == TOK.leftParenthesis)
2386         {
2387             nextToken();
2388             exp = parseAssignExp();
2389             check(TOK.rightParenthesis);
2390         }
2391         else
2392         {
2393             error("(expression) expected following `static if`");
2394             exp = null;
2395         }
2396         condition = new AST.StaticIfCondition(loc, exp);
2397         return condition;
2398     }
2399 
2400     /*****************************************
2401      * Parse a constructor definition:
2402      *      this(parameters) { body }
2403      * or postblit:
2404      *      this(this) { body }
2405      * or constructor template:
2406      *      this(templateparameters)(parameters) { body }
2407      * Current token is 'this'.
2408      */
2409     private AST.Dsymbol parseCtor(PrefixAttributes!AST* pAttrs)
2410     {
2411         AST.Expressions* udas = null;
2412         const loc = token.loc;
2413         StorageClass stc = getStorageClass!AST(pAttrs);
2414 
2415         nextToken();
2416         if (token.value == TOK.leftParenthesis && peekNext() == TOK.this_ && peekNext2() == TOK.rightParenthesis)
2417         {
2418             // this(this) { ... }
2419             nextToken();
2420             nextToken();
2421             check(TOK.rightParenthesis);
2422 
2423             stc = parsePostfix(stc, &udas);
2424             if (stc & STC.immutable_)
2425                 deprecation("`immutable` postblit is deprecated. Please use an unqualified postblit.");
2426             if (stc & STC.shared_)
2427                 deprecation("`shared` postblit is deprecated. Please use an unqualified postblit.");
2428             if (stc & STC.const_)
2429                 deprecation("`const` postblit is deprecated. Please use an unqualified postblit.");
2430             if (stc & STC.static_)
2431                 error(loc, "postblit cannot be `static`");
2432 
2433             auto f = new AST.PostBlitDeclaration(loc, Loc.initial, stc, Id.postblit);
2434             AST.Dsymbol s = parseContracts(f);
2435             if (udas)
2436             {
2437                 auto a = new AST.Dsymbols();
2438                 a.push(f);
2439                 s = new AST.UserAttributeDeclaration(udas, a);
2440             }
2441             return s;
2442         }
2443 
2444         /* Look ahead to see if:
2445          *   this(...)(...)
2446          * which is a constructor template
2447          */
2448         AST.TemplateParameters* tpl = null;
2449         if (token.value == TOK.leftParenthesis && peekPastParen(&token).value == TOK.leftParenthesis)
2450         {
2451             tpl = parseTemplateParameterList();
2452         }
2453 
2454         /* Just a regular constructor
2455          */
2456         auto parameterList = parseParameterList(null);
2457         stc = parsePostfix(stc, &udas);
2458 
2459         if (parameterList.varargs != VarArg.none || AST.Parameter.dim(parameterList.parameters) != 0)
2460         {
2461             if (stc & STC.static_)
2462                 error(loc, "constructor cannot be static");
2463         }
2464         else if (StorageClass ss = stc & (STC.shared_ | STC.static_)) // this()
2465         {
2466             if (ss == STC.static_)
2467                 error(loc, "use `static this()` to declare a static constructor");
2468             else if (ss == (STC.shared_ | STC.static_))
2469                 error(loc, "use `shared static this()` to declare a shared static constructor");
2470         }
2471 
2472         AST.Expression constraint = tpl ? parseConstraint() : null;
2473 
2474         AST.Type tf = new AST.TypeFunction(parameterList, null, linkage, stc); // RetrunType -> auto
2475         tf = tf.addSTC(stc);
2476 
2477         auto f = new AST.CtorDeclaration(loc, Loc.initial, stc, tf);
2478         AST.Dsymbol s = parseContracts(f, !!tpl);
2479         if (udas)
2480         {
2481             auto a = new AST.Dsymbols();
2482             a.push(f);
2483             s = new AST.UserAttributeDeclaration(udas, a);
2484         }
2485 
2486         if (tpl)
2487         {
2488             // Wrap a template around it
2489             auto decldefs = new AST.Dsymbols();
2490             decldefs.push(s);
2491             s = new AST.TemplateDeclaration(loc, f.ident, tpl, constraint, decldefs);
2492         }
2493 
2494         return s;
2495     }
2496 
2497     /*****************************************
2498      * Parse a destructor definition:
2499      *      ~this() { body }
2500      * Current token is '~'.
2501      */
2502     private AST.Dsymbol parseDtor(PrefixAttributes!AST* pAttrs)
2503     {
2504         AST.Expressions* udas = null;
2505         const loc = token.loc;
2506         StorageClass stc = getStorageClass!AST(pAttrs);
2507 
2508         nextToken();
2509         check(TOK.this_);
2510         check(TOK.leftParenthesis);
2511         check(TOK.rightParenthesis);
2512 
2513         stc = parsePostfix(stc, &udas);
2514         if (StorageClass ss = stc & (STC.shared_ | STC.static_))
2515         {
2516             if (ss == STC.static_)
2517                 error(loc, "use `static ~this()` to declare a static destructor");
2518             else if (ss == (STC.shared_ | STC.static_))
2519                 error(loc, "use `shared static ~this()` to declare a shared static destructor");
2520         }
2521 
2522         auto f = new AST.DtorDeclaration(loc, Loc.initial, stc, Id.dtor);
2523         AST.Dsymbol s = parseContracts(f);
2524         if (udas)
2525         {
2526             auto a = new AST.Dsymbols();
2527             a.push(f);
2528             s = new AST.UserAttributeDeclaration(udas, a);
2529         }
2530         return s;
2531     }
2532 
2533     /*****************************************
2534      * Parse a static constructor definition:
2535      *      static this() { body }
2536      * Current token is 'static'.
2537      */
2538     private AST.Dsymbol parseStaticCtor(PrefixAttributes!AST* pAttrs)
2539     {
2540         //Expressions *udas = NULL;
2541         const loc = token.loc;
2542         StorageClass stc = getStorageClass!AST(pAttrs);
2543 
2544         nextToken();
2545         nextToken();
2546         check(TOK.leftParenthesis);
2547         check(TOK.rightParenthesis);
2548 
2549         stc = parsePostfix(stc & ~STC.TYPECTOR, null) | stc;
2550         if (stc & STC.shared_)
2551             error(loc, "use `shared static this()` to declare a shared static constructor");
2552         else if (stc & STC.static_)
2553             appendStorageClass(stc, STC.static_); // complaint for the redundancy
2554         else if (StorageClass modStc = stc & STC.TYPECTOR)
2555         {
2556             OutBuffer buf;
2557             AST.stcToBuffer(buf, modStc);
2558             error(loc, "static constructor cannot be `%s`", buf.peekChars());
2559         }
2560         stc &= ~(STC.static_ | STC.TYPECTOR);
2561 
2562         auto f = new AST.StaticCtorDeclaration(loc, Loc.initial, stc);
2563         AST.Dsymbol s = parseContracts(f);
2564         return s;
2565     }
2566 
2567     /*****************************************
2568      * Parse a static destructor definition:
2569      *      static ~this() { body }
2570      * Current token is 'static'.
2571      */
2572     private AST.Dsymbol parseStaticDtor(PrefixAttributes!AST* pAttrs)
2573     {
2574         AST.Expressions* udas = null;
2575         const loc = token.loc;
2576         StorageClass stc = getStorageClass!AST(pAttrs);
2577 
2578         nextToken();
2579         nextToken();
2580         check(TOK.this_);
2581         check(TOK.leftParenthesis);
2582         check(TOK.rightParenthesis);
2583 
2584         stc = parsePostfix(stc & ~STC.TYPECTOR, &udas) | stc;
2585         if (stc & STC.shared_)
2586             error(loc, "use `shared static ~this()` to declare a shared static destructor");
2587         else if (stc & STC.static_)
2588             appendStorageClass(stc, STC.static_); // complaint for the redundancy
2589         else if (StorageClass modStc = stc & STC.TYPECTOR)
2590         {
2591             OutBuffer buf;
2592             AST.stcToBuffer(buf, modStc);
2593             error(loc, "static destructor cannot be `%s`", buf.peekChars());
2594         }
2595         stc &= ~(STC.static_ | STC.TYPECTOR);
2596 
2597         auto f = new AST.StaticDtorDeclaration(loc, Loc.initial, stc);
2598         AST.Dsymbol s = parseContracts(f);
2599         if (udas)
2600         {
2601             auto a = new AST.Dsymbols();
2602             a.push(f);
2603             s = new AST.UserAttributeDeclaration(udas, a);
2604         }
2605         return s;
2606     }
2607 
2608     /*****************************************
2609      * Parse a shared static constructor definition:
2610      *      shared static this() { body }
2611      * Current token is 'shared'.
2612      */
2613     private AST.Dsymbol parseSharedStaticCtor(PrefixAttributes!AST* pAttrs)
2614     {
2615         //Expressions *udas = NULL;
2616         const loc = token.loc;
2617         StorageClass stc = getStorageClass!AST(pAttrs);
2618 
2619         nextToken();
2620         nextToken();
2621         nextToken();
2622         check(TOK.leftParenthesis);
2623         check(TOK.rightParenthesis);
2624 
2625         stc = parsePostfix(stc & ~STC.TYPECTOR, null) | stc;
2626         if (StorageClass ss = stc & (STC.shared_ | STC.static_))
2627             appendStorageClass(stc, ss); // complaint for the redundancy
2628         else if (StorageClass modStc = stc & STC.TYPECTOR)
2629         {
2630             OutBuffer buf;
2631             AST.stcToBuffer(buf, modStc);
2632             error(loc, "shared static constructor cannot be `%s`", buf.peekChars());
2633         }
2634         stc &= ~(STC.static_ | STC.TYPECTOR);
2635 
2636         auto f = new AST.SharedStaticCtorDeclaration(loc, Loc.initial, stc);
2637         AST.Dsymbol s = parseContracts(f);
2638         return s;
2639     }
2640 
2641     /*****************************************
2642      * Parse a shared static destructor definition:
2643      *      shared static ~this() { body }
2644      * Current token is 'shared'.
2645      */
2646     private AST.Dsymbol parseSharedStaticDtor(PrefixAttributes!AST* pAttrs)
2647     {
2648         AST.Expressions* udas = null;
2649         const loc = token.loc;
2650         StorageClass stc = getStorageClass!AST(pAttrs);
2651 
2652         nextToken();
2653         nextToken();
2654         nextToken();
2655         check(TOK.this_);
2656         check(TOK.leftParenthesis);
2657         check(TOK.rightParenthesis);
2658 
2659         stc = parsePostfix(stc & ~STC.TYPECTOR, &udas) | stc;
2660         if (StorageClass ss = stc & (STC.shared_ | STC.static_))
2661             appendStorageClass(stc, ss); // complaint for the redundancy
2662         else if (StorageClass modStc = stc & STC.TYPECTOR)
2663         {
2664             OutBuffer buf;
2665             AST.stcToBuffer(buf, modStc);
2666             error(loc, "shared static destructor cannot be `%s`", buf.peekChars());
2667         }
2668         stc &= ~(STC.static_ | STC.TYPECTOR);
2669 
2670         auto f = new AST.SharedStaticDtorDeclaration(loc, Loc.initial, stc);
2671         AST.Dsymbol s = parseContracts(f);
2672         if (udas)
2673         {
2674             auto a = new AST.Dsymbols();
2675             a.push(f);
2676             s = new AST.UserAttributeDeclaration(udas, a);
2677         }
2678         return s;
2679     }
2680 
2681     /*****************************************
2682      * Parse an invariant definition:
2683      *      invariant { statements... }
2684      *      invariant() { statements... }
2685      *      invariant (expression);
2686      * Current token is 'invariant'.
2687      */
2688     private AST.Dsymbol parseInvariant(PrefixAttributes!AST* pAttrs)
2689     {
2690         const loc = token.loc;
2691         StorageClass stc = getStorageClass!AST(pAttrs);
2692 
2693         nextToken();
2694         if (token.value == TOK.leftParenthesis) // optional () or invariant (expression);
2695         {
2696             nextToken();
2697             if (token.value != TOK.rightParenthesis) // invariant (expression);
2698             {
2699                 AST.Expression e = parseAssignExp(), msg = null;
2700                 if (token.value == TOK.comma)
2701                 {
2702                     nextToken();
2703                     if (token.value != TOK.rightParenthesis)
2704                     {
2705                         msg = parseAssignExp();
2706                         if (token.value == TOK.comma)
2707                             nextToken();
2708                     }
2709                 }
2710                 check(TOK.rightParenthesis);
2711                 check(TOK.semicolon, "invariant");
2712                 e = new AST.AssertExp(loc, e, msg);
2713                 auto fbody = new AST.ExpStatement(loc, e);
2714                 auto f = new AST.InvariantDeclaration(loc, token.loc, stc, null, fbody);
2715                 return f;
2716             }
2717             nextToken();
2718         }
2719 
2720         auto fbody = parseStatement(ParseStatementFlags.curly);
2721         auto f = new AST.InvariantDeclaration(loc, token.loc, stc, null, fbody);
2722         return f;
2723     }
2724 
2725     /*****************************************
2726      * Parse a unittest definition:
2727      *      unittest { body }
2728      * Current token is 'unittest'.
2729      */
2730     private AST.Dsymbol parseUnitTest(PrefixAttributes!AST* pAttrs)
2731     {
2732         const loc = token.loc;
2733         StorageClass stc = getStorageClass!AST(pAttrs);
2734 
2735         nextToken();
2736 
2737         const(char)* begPtr = token.ptr + 1; // skip left curly brace
2738         const(char)* endPtr = null;
2739         AST.Statement sbody = parseStatement(ParseStatementFlags.curly, &endPtr);
2740 
2741         /** Extract unittest body as a string. Must be done eagerly since memory
2742          will be released by the lexer before doc gen. */
2743         char* docline = null;
2744         if (compileEnv.ddocOutput && endPtr > begPtr)
2745         {
2746             /* Remove trailing whitespaces */
2747             for (const(char)* p = endPtr - 1; begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p)
2748             {
2749                 endPtr = p;
2750             }
2751 
2752             size_t len = endPtr - begPtr;
2753             if (len > 0)
2754             {
2755                 docline = cast(char*)mem.xmalloc_noscan(len + 2);
2756                 memcpy(docline, begPtr, len);
2757                 docline[len] = '\n'; // Terminate all lines by LF
2758                 docline[len + 1] = '\0';
2759             }
2760         }
2761 
2762         auto f = new AST.UnitTestDeclaration(loc, token.loc, stc, docline);
2763         f.fbody = sbody;
2764         return f;
2765     }
2766 
2767     /*****************************************
2768      * Parse a new definition:
2769      *      @disable new();
2770      * Current token is 'new'.
2771      */
2772     private AST.Dsymbol parseNew(PrefixAttributes!AST* pAttrs)
2773     {
2774         const loc = token.loc;
2775         StorageClass stc = getStorageClass!AST(pAttrs);
2776         if (!(stc & STC.disable))
2777         {
2778             error("`new` allocator must be annotated with `@disabled`");
2779         }
2780         nextToken();
2781 
2782         /* @@@DEPRECATED_2.108@@@
2783          * After deprecation period (2.108), remove all code in the version(all) block.
2784          */
2785         version (all)
2786         {
2787             auto parameterList = parseParameterList(null);  // parameterList ignored
2788             if (parameterList.parameters.length > 0 || parameterList.varargs != VarArg.none)
2789                 deprecation("`new` allocator with non-empty parameter list is deprecated");
2790             auto f = new AST.NewDeclaration(loc, stc);
2791             if (token.value != TOK.semicolon)
2792             {
2793                 deprecation("`new` allocator with function definition is deprecated");
2794                 parseContracts(f);  // body ignored
2795                 f.fbody = null;
2796                 f.fensures = null;
2797                 f.frequires = null;
2798             }
2799             else
2800                 nextToken();
2801             return f;
2802         }
2803         else
2804         {
2805             check(TOK.leftParenthesis);
2806             check(TOK.rightParenthesis);
2807             check(TOK.semicolon);
2808             return new AST.NewDeclaration(loc, stc);
2809         }
2810     }
2811 
2812     /**********************************************
2813      * Parse parameter list.
2814      */
2815     private AST.ParameterList parseParameterList(AST.TemplateParameters** tpl)
2816     {
2817         auto parameters = new AST.Parameters();
2818         VarArg varargs = VarArg.none;
2819         StorageClass varargsStc;
2820 
2821         // Attributes allowed for ...
2822         enum VarArgsStc = STC.const_ | STC.immutable_ | STC.shared_ | STC.scope_ | STC.return_ | STC.returnScope;
2823 
2824         check(TOK.leftParenthesis);
2825         while (1)
2826         {
2827             Identifier ai = null;
2828             AST.Type at;
2829             StorageClass storageClass = 0;
2830             StorageClass stc;
2831             AST.Expression ae;
2832             AST.Expressions* udas = null;
2833             for (; 1; nextToken())
2834             {
2835             L3:
2836                 switch (token.value)
2837                 {
2838                 case TOK.rightParenthesis:
2839                     if (storageClass != 0 || udas !is null)
2840                         error("basic type expected, not `)`");
2841                     break;
2842 
2843                 case TOK.dotDotDot:
2844                     varargs = VarArg.variadic;
2845                     varargsStc = storageClass;
2846                     if (varargsStc & ~VarArgsStc)
2847                     {
2848                         OutBuffer buf;
2849                         AST.stcToBuffer(buf, varargsStc & ~VarArgsStc);
2850                         error("variadic parameter cannot have attributes `%s`", buf.peekChars());
2851                         varargsStc &= VarArgsStc;
2852                     }
2853                     nextToken();
2854                     break;
2855 
2856                 case TOK.const_:
2857                     if (peekNext() == TOK.leftParenthesis)
2858                         goto default;
2859                     stc = STC.const_;
2860                     goto L2;
2861 
2862                 case TOK.immutable_:
2863                     if (peekNext() == TOK.leftParenthesis)
2864                         goto default;
2865                     stc = STC.immutable_;
2866                     goto L2;
2867 
2868                 case TOK.shared_:
2869                     if (peekNext() == TOK.leftParenthesis)
2870                         goto default;
2871                     stc = STC.shared_;
2872                     goto L2;
2873 
2874                 case TOK.inout_:
2875                     if (peekNext() == TOK.leftParenthesis)
2876                         goto default;
2877                     stc = STC.wild;
2878                     goto L2;
2879                 case TOK.at:
2880                     {
2881                         AST.Expressions* exps = null;
2882                         StorageClass stc2 = parseAttribute(exps);
2883                         if (stc2 & atAttrGroup)
2884                         {
2885                             error("`@%s` attribute for function parameter is not supported", token.toChars());
2886                         }
2887                         else
2888                         {
2889                             udas = AST.UserAttributeDeclaration.concat(udas, exps);
2890                         }
2891                         if (token.value == TOK.dotDotDot)
2892                             error("variadic parameter cannot have user-defined attributes");
2893                         if (stc2)
2894                             nextToken();
2895                         goto L3;
2896                         // Don't call nextToken again.
2897                     }
2898                 case TOK.in_:
2899                     if (transitionIn)
2900                         eSink.message(scanloc, "Usage of 'in' on parameter");
2901                     stc = STC.in_;
2902                     goto L2;
2903 
2904                 case TOK.out_:
2905                     stc = STC.out_;
2906                     goto L2;
2907 
2908                 case TOK.ref_:
2909                     stc = STC.ref_;
2910                     goto L2;
2911 
2912                 case TOK.lazy_:
2913                     stc = STC.lazy_;
2914                     goto L2;
2915 
2916                 case TOK.scope_:
2917                     stc = STC.scope_;
2918                     goto L2;
2919 
2920                 case TOK.final_:
2921                     stc = STC.final_;
2922                     goto L2;
2923 
2924                 case TOK.auto_:
2925                     stc = STC.auto_;
2926                     goto L2;
2927 
2928                 case TOK.return_:
2929                     stc = STC.return_;
2930                     if (peekNext() == TOK.scope_)
2931                         stc |= STC.returnScope;
2932                     goto L2;
2933                 L2:
2934                     storageClass = appendStorageClass(storageClass, stc);
2935                     continue;
2936 
2937                 default:
2938                     {
2939                         stc = storageClass & (STC.IOR | STC.lazy_);
2940                         // if stc is not a power of 2
2941                         if (stc & (stc - 1) && !(stc == (STC.in_ | STC.ref_)))
2942                             error("incompatible parameter storage classes");
2943                         //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_)))
2944                             //error("scope cannot be ref or out");
2945 
2946                         const tv = peekNext();
2947                         Loc loc;
2948                         if (tpl && token.value == TOK.identifier &&
2949                             (tv == TOK.comma || tv == TOK.rightParenthesis || tv == TOK.dotDotDot))
2950                         {
2951                             Identifier id = Identifier.generateId("__T");
2952                             loc = token.loc;
2953                             at = new AST.TypeIdentifier(loc, id);
2954                             if (!*tpl)
2955                                 *tpl = new AST.TemplateParameters();
2956                             AST.TemplateParameter tp = new AST.TemplateTypeParameter(loc, id, null, null);
2957                             (*tpl).push(tp);
2958 
2959                             ai = token.ident;
2960                             nextToken();
2961                         }
2962                         else
2963                         {
2964                             at = parseType(&ai, null, &loc);
2965                         }
2966                         ae = null;
2967                         if (token.value == TOK.assign) // = defaultArg
2968                         {
2969                             nextToken();
2970                             ae = parseDefaultInitExp();
2971                         }
2972                         auto param = new AST.Parameter(loc, storageClass | STC.parameter, at, ai, ae, null);
2973                         if (udas)
2974                         {
2975                             auto a = new AST.Dsymbols();
2976                             auto udad = new AST.UserAttributeDeclaration(udas, a);
2977                             param.userAttribDecl = udad;
2978                         }
2979                         if (token.value == TOK.at)
2980                         {
2981                             AST.Expressions* exps = null;
2982                             StorageClass stc2 = parseAttribute(exps);
2983                             if (stc2 & atAttrGroup)
2984                             {
2985                                 error("`@%s` attribute for function parameter is not supported", token.toChars());
2986                             }
2987                             else
2988                             {
2989                                 error("user-defined attributes cannot appear as postfixes", token.toChars());
2990                             }
2991                             if (stc2)
2992                                 nextToken();
2993                         }
2994                         if (token.value == TOK.dotDotDot)
2995                         {
2996                             /* This is:
2997                              *      at ai ...
2998                              */
2999                             if (storageClass & (STC.out_ | STC.ref_))
3000                                 error("variadic argument cannot be `out` or `ref`");
3001                             varargs = VarArg.typesafe;
3002                             parameters.push(param);
3003                             nextToken();
3004                             break;
3005                         }
3006                         parameters.push(param);
3007                         if (token.value == TOK.comma)
3008                         {
3009                             nextToken();
3010                             goto L1;
3011                         }
3012                         break;
3013                     }
3014                 }
3015                 break;
3016             }
3017             break;
3018 
3019         L1:
3020         }
3021         check(TOK.rightParenthesis);
3022         return AST.ParameterList(parameters, varargs, varargsStc);
3023     }
3024 
3025     /*************************************
3026      */
3027     private AST.EnumDeclaration parseEnum()
3028     {
3029         AST.EnumDeclaration e;
3030         Identifier id;
3031         AST.Type memtype;
3032         auto loc = token.loc;
3033 
3034         // printf("Parser::parseEnum()\n");
3035         nextToken();
3036         id = null;
3037         if (token.value == TOK.identifier)
3038         {
3039             id = token.ident;
3040             nextToken();
3041         }
3042 
3043         memtype = null;
3044         if (token.value == TOK.colon)
3045         {
3046             nextToken();
3047             int alt = 0;
3048             const typeLoc = token.loc;
3049             memtype = parseBasicType();
3050             memtype = parseDeclarator(memtype, alt, null);
3051             checkCstyleTypeSyntax(typeLoc, memtype, alt, null);
3052         }
3053 
3054         e = new AST.EnumDeclaration(loc, id, memtype);
3055         // opaque type
3056         if (token.value == TOK.semicolon && id)
3057             nextToken();
3058         else if (token.value == TOK.leftCurly)
3059         {
3060             bool isAnonymousEnum = !id;
3061 
3062             //printf("enum definition\n");
3063             e.members = new AST.Dsymbols();
3064             nextToken();
3065             const(char)[] comment = token.blockComment;
3066             while (token.value != TOK.rightCurly)
3067             {
3068                 /* Can take the following forms...
3069                  *  1. ident
3070                  *  2. ident = value
3071                  *  3. type ident = value
3072                  *  ... prefixed by valid attributes
3073                  */
3074                 loc = token.loc;
3075 
3076                 AST.Type type = null;
3077                 Identifier ident = null;
3078 
3079                 AST.Expressions* udas;
3080                 StorageClass stc;
3081                 AST.Expression deprecationMessage;
3082                 enum attributeErrorMessage = "`%s` is not a valid attribute for enum members";
3083             Lattrs:
3084                 while (1)
3085                 {
3086                     switch (token.value)
3087                     {
3088                         case TOK.at:
3089                             if (StorageClass _stc = parseAttribute(udas))
3090                             {
3091                                 if (_stc == STC.disable)
3092                                     stc |= _stc;
3093                                 else
3094                                 {
3095                                     OutBuffer buf;
3096                                     AST.stcToBuffer(buf, _stc);
3097                                     error(attributeErrorMessage, buf.peekChars());
3098                                 }
3099                                 nextToken();
3100                             }
3101                             break;
3102                         case TOK.deprecated_:
3103                             stc |= STC.deprecated_;
3104                             if (!parseDeprecatedAttribute(deprecationMessage))
3105                             {
3106                                 nextToken();
3107                             }
3108                             break;
3109                         default:
3110                             break Lattrs;
3111                     }
3112                 }
3113                 if (token.value == TOK.identifier)
3114                 {
3115                     const tv = peekNext();
3116                     if (tv == TOK.assign || tv == TOK.comma || tv == TOK.rightCurly)
3117                     {
3118                         ident = token.ident;
3119                         type = null;
3120                         nextToken();
3121                     }
3122                     else
3123                     {
3124                         if (isAnonymousEnum)
3125                             goto Ltype;
3126 
3127                         nextToken();
3128                         error("expected `,` or `=` after identifier, not `%s`", token.toChars());
3129                     }
3130                 }
3131                 else
3132                 {
3133                     if (isAnonymousEnum)
3134                     {
3135                     Ltype:
3136                         // Type identifier
3137                         type = parseType(&ident, null);
3138                         if (type == AST.Type.terror)
3139                         {
3140                             type = null;
3141                             nextToken();
3142                         }
3143                         else if (!ident)
3144                         {
3145                             error("no identifier for declarator `%s`", type.toChars());
3146                             type = null;
3147                         }
3148                         else
3149                         {
3150                             const tv = token.value;
3151                             if (tv != TOK.assign && tv != TOK.comma && tv != TOK.rightCurly)
3152                             {
3153                                 error("expected `,` or `=` after identifier, not `%s`", token.toChars());
3154                                 nextToken();
3155                             }
3156                         }
3157                     }
3158                     else
3159                     {
3160                         Token* t = &token;
3161                         if (isBasicType(&t))
3162                         {
3163                             error("named enum cannot declare member with type", (*t).toChars());
3164                             nextToken();
3165                         }
3166                         else
3167                             check(TOK.identifier);
3168 
3169                         // avoid extra error messages
3170                         const tv = token.value;
3171                         if (tv != TOK.assign && tv != TOK.comma && tv != TOK.rightCurly && tv != TOK.endOfFile)
3172                             continue;
3173                     }
3174                 }
3175 
3176                 AST.Expression value;
3177                 if (token.value == TOK.assign)
3178                 {
3179                     nextToken();
3180                     value = parseAssignExp();
3181                 }
3182                 else
3183                 {
3184                     value = null;
3185                     if (type && isAnonymousEnum)
3186                         error("initializer required after `%s` when type is specified", ident.toChars());
3187                 }
3188 
3189                 AST.DeprecatedDeclaration dd;
3190                 if (deprecationMessage)
3191                 {
3192                     dd = new AST.DeprecatedDeclaration(deprecationMessage, null);
3193                     stc |= STC.deprecated_;
3194                 }
3195 
3196                 auto em = new AST.EnumMember(loc, ident, value, type, stc, null, dd);
3197                 e.members.push(em);
3198 
3199                 if (udas)
3200                 {
3201                     auto uad = new AST.UserAttributeDeclaration(udas, new AST.Dsymbols());
3202                     em.userAttribDecl = uad;
3203                 }
3204 
3205                 if (token.value != TOK.rightCurly)
3206                 {
3207                     addComment(em, comment);
3208                     comment = null;
3209                     check(TOK.comma);
3210                 }
3211                 addComment(em, comment);
3212                 comment = token.blockComment;
3213 
3214                 if (token.value == TOK.endOfFile)
3215                 {
3216                     error("premature end of file");
3217                     break;
3218                 }
3219             }
3220             nextToken();
3221         }
3222         else
3223         {
3224             nextToken();
3225             error("expected `{`, not `%s` for enum declaration", token.toChars());
3226         }
3227         //printf("-parseEnum() %s\n", e.toChars());
3228         return e;
3229     }
3230 
3231     /********************************
3232      * Parse struct, union, interface, class.
3233      */
3234     private AST.Dsymbol parseAggregate()
3235     {
3236         AST.TemplateParameters* tpl = null;
3237         AST.Expression constraint;
3238         const loc = token.loc;
3239         TOK tok = token.value;
3240 
3241         //printf("Parser::parseAggregate()\n");
3242         nextToken();
3243         Identifier id;
3244         if (token.value != TOK.identifier)
3245         {
3246             id = null;
3247         }
3248         else
3249         {
3250             id = token.ident;
3251             nextToken();
3252 
3253             if (token.value == TOK.leftParenthesis)
3254             {
3255                 // struct/class template declaration.
3256                 tpl = parseTemplateParameterList();
3257                 constraint = parseConstraint();
3258             }
3259         }
3260 
3261         // Collect base class(es)
3262         AST.BaseClasses* baseclasses = null;
3263         if (token.value == TOK.colon)
3264         {
3265             if (tok != TOK.interface_ && tok != TOK.class_)
3266                 error("base classes are not allowed for `%s`, did you mean `;`?", Token.toChars(tok));
3267             nextToken();
3268             baseclasses = parseBaseClasses();
3269         }
3270 
3271         if (token.value == TOK.if_)
3272         {
3273             if (constraint)
3274                 error("template constraints appear both before and after BaseClassList, put them before");
3275             constraint = parseConstraint();
3276         }
3277         if (constraint)
3278         {
3279             if (!id)
3280                 error("template constraints not allowed for anonymous `%s`", Token.toChars(tok));
3281             if (!tpl)
3282                 error("template constraints only allowed for templates");
3283         }
3284 
3285         AST.Dsymbols* members = null;
3286         if (token.value == TOK.leftCurly)
3287         {
3288             //printf("aggregate definition\n");
3289             const lookingForElseSave = lookingForElse;
3290             lookingForElse = Loc();
3291             nextToken();
3292             members = parseDeclDefs(0);
3293             lookingForElse = lookingForElseSave;
3294             if (token.value != TOK.rightCurly)
3295             {
3296                 /* { */
3297                 error(token.loc, "`}` expected following members in `%s` declaration",
3298                     Token.toChars(tok));
3299                 if (id)
3300                     eSink.errorSupplemental(loc, "%s `%s` starts here",
3301                         Token.toChars(tok), id.toChars());
3302                 else
3303                     eSink.errorSupplemental(loc, "%s starts here",
3304                         Token.toChars(tok));
3305             }
3306             nextToken();
3307         }
3308         else if (token.value == TOK.semicolon && id)
3309         {
3310             if (baseclasses || constraint)
3311                 error("members expected");
3312             nextToken();
3313         }
3314         else
3315         {
3316             error(token.loc, "{ } expected following `%s` declaration", Token.toChars(tok));
3317         }
3318 
3319         AST.AggregateDeclaration a;
3320         switch (tok)
3321         {
3322         case TOK.interface_:
3323             if (!id)
3324                 error(loc, "anonymous interfaces not allowed");
3325             a = new AST.InterfaceDeclaration(loc, id, baseclasses);
3326             a.members = members;
3327             break;
3328 
3329         case TOK.class_:
3330             if (!id)
3331                 error(loc, "anonymous classes not allowed");
3332             bool inObject = md && !md.packages && md.id == Id.object;
3333             a = new AST.ClassDeclaration(loc, id, baseclasses, members, inObject);
3334             break;
3335 
3336         case TOK.struct_:
3337             if (id)
3338             {
3339                 bool inObject = md && !md.packages && md.id == Id.object;
3340                 a = new AST.StructDeclaration(loc, id, inObject);
3341                 a.members = members;
3342             }
3343             else
3344             {
3345                 /* Anonymous structs/unions are more like attributes.
3346                  */
3347                 assert(!tpl);
3348                 return new AST.AnonDeclaration(loc, false, members);
3349             }
3350             break;
3351 
3352         case TOK.union_:
3353             if (id)
3354             {
3355                 a = new AST.UnionDeclaration(loc, id);
3356                 a.members = members;
3357             }
3358             else
3359             {
3360                 /* Anonymous structs/unions are more like attributes.
3361                  */
3362                 assert(!tpl);
3363                 return new AST.AnonDeclaration(loc, true, members);
3364             }
3365             break;
3366 
3367         default:
3368             assert(0);
3369         }
3370 
3371         if (tpl)
3372         {
3373             // Wrap a template around the aggregate declaration
3374             auto decldefs = new AST.Dsymbols();
3375             decldefs.push(a);
3376             auto tempdecl = new AST.TemplateDeclaration(loc, id, tpl, constraint, decldefs);
3377             return tempdecl;
3378         }
3379         return a;
3380     }
3381 
3382     /*******************************************
3383      */
3384     private AST.BaseClasses* parseBaseClasses()
3385     {
3386         auto baseclasses = new AST.BaseClasses();
3387 
3388         for (; 1; nextToken())
3389         {
3390             auto b = new AST.BaseClass(parseBasicType());
3391             baseclasses.push(b);
3392             if (token.value != TOK.comma)
3393                 break;
3394         }
3395         return baseclasses;
3396     }
3397 
3398     AST.Dsymbols* parseImport()
3399     {
3400         auto decldefs = new AST.Dsymbols();
3401         Identifier aliasid = null;
3402 
3403         int isstatic = token.value == TOK.static_;
3404         if (isstatic)
3405             nextToken();
3406 
3407         //printf("Parser::parseImport()\n");
3408         do
3409         {
3410         L1:
3411             nextToken();
3412             if (token.value != TOK.identifier)
3413             {
3414                 error("identifier expected following `import`");
3415                 break;
3416             }
3417 
3418             const loc = token.loc;
3419             Identifier id = token.ident;
3420             Identifier[] a;
3421             nextToken();
3422             if (!aliasid && token.value == TOK.assign)
3423             {
3424                 aliasid = id;
3425                 goto L1;
3426             }
3427             while (token.value == TOK.dot)
3428             {
3429                 a ~= id;
3430                 nextToken();
3431                 if (token.value != TOK.identifier)
3432                 {
3433                     error("identifier expected following `package`");
3434                     break;
3435                 }
3436                 id = token.ident;
3437                 nextToken();
3438             }
3439 
3440             auto s = new AST.Import(loc, a, id, aliasid, isstatic);
3441             decldefs.push(s);
3442 
3443             /* Look for
3444              *      : alias=name, alias=name;
3445              * syntax.
3446              */
3447             if (token.value == TOK.colon)
3448             {
3449                 do
3450                 {
3451                     nextToken();
3452                     if (token.value != TOK.identifier)
3453                     {
3454                         error("identifier expected following `:`");
3455                         break;
3456                     }
3457                     Identifier _alias = token.ident;
3458                     Identifier name;
3459                     nextToken();
3460                     if (token.value == TOK.assign)
3461                     {
3462                         nextToken();
3463                         if (token.value != TOK.identifier)
3464                         {
3465                             error("identifier expected following `%s=`", _alias.toChars());
3466                             break;
3467                         }
3468                         name = token.ident;
3469                         nextToken();
3470                     }
3471                     else
3472                     {
3473                         name = _alias;
3474                         _alias = null;
3475                     }
3476                     s.addAlias(name, _alias);
3477                 }
3478                 while (token.value == TOK.comma);
3479                 break; // no comma-separated imports of this form
3480             }
3481             aliasid = null;
3482         }
3483         while (token.value == TOK.comma);
3484 
3485         if (token.value == TOK.semicolon)
3486             nextToken();
3487         else
3488         {
3489             error("`;` expected");
3490             nextToken();
3491         }
3492 
3493         return decldefs;
3494     }
3495 
3496     /* Parse a type and optional identifier
3497      * Params:
3498      *  pident       = set to Identifier if there is one, null if not
3499      *  ptpl         = if !null, then set to TemplateParameterList
3500      *  pdeclLoc     = if !null, then set to location of the declarator
3501      */
3502     AST.Type parseType(Identifier* pident = null, AST.TemplateParameters** ptpl = null, Loc* pdeclLoc = null)
3503     {
3504         /* Take care of the storage class prefixes that
3505          * serve as type attributes:
3506          *               const type
3507          *           immutable type
3508          *              shared type
3509          *               inout type
3510          *         inout const type
3511          *        shared const type
3512          *        shared inout type
3513          *  shared inout const type
3514          */
3515         StorageClass stc = 0;
3516         while (1)
3517         {
3518             switch (token.value)
3519             {
3520             case TOK.const_:
3521                 if (peekNext() == TOK.leftParenthesis)
3522                     break; // const as type constructor
3523                 stc |= STC.const_; // const as storage class
3524                 nextToken();
3525                 continue;
3526 
3527             case TOK.immutable_:
3528                 if (peekNext() == TOK.leftParenthesis)
3529                     break;
3530                 stc |= STC.immutable_;
3531                 nextToken();
3532                 continue;
3533 
3534             case TOK.shared_:
3535                 if (peekNext() == TOK.leftParenthesis)
3536                     break;
3537                 stc |= STC.shared_;
3538                 nextToken();
3539                 continue;
3540 
3541             case TOK.inout_:
3542                 if (peekNext() == TOK.leftParenthesis)
3543                     break;
3544                 stc |= STC.wild;
3545                 nextToken();
3546                 continue;
3547 
3548             default:
3549                 break;
3550             }
3551             break;
3552         }
3553 
3554         const typeLoc = token.loc;
3555 
3556         AST.Type t;
3557         t = parseBasicType();
3558 
3559         if (pdeclLoc)
3560             *pdeclLoc = token.loc;
3561         int alt = 0;
3562         t = parseDeclarator(t, alt, pident, ptpl);
3563         checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : null);
3564 
3565         t = t.addSTC(stc);
3566         return t;
3567     }
3568 
3569     private AST.Type parseBasicType(bool dontLookDotIdents = false)
3570     {
3571         AST.Type t;
3572         Loc loc;
3573         Identifier id;
3574         //printf("parseBasicType()\n");
3575         switch (token.value)
3576         {
3577         case TOK.void_:
3578             t = AST.Type.tvoid;
3579             goto LabelX;
3580 
3581         case TOK.int8:
3582             t = AST.Type.tint8;
3583             goto LabelX;
3584 
3585         case TOK.uns8:
3586             t = AST.Type.tuns8;
3587             goto LabelX;
3588 
3589         case TOK.int16:
3590             t = AST.Type.tint16;
3591             goto LabelX;
3592 
3593         case TOK.uns16:
3594             t = AST.Type.tuns16;
3595             goto LabelX;
3596 
3597         case TOK.int32:
3598             t = AST.Type.tint32;
3599             goto LabelX;
3600 
3601         case TOK.uns32:
3602             t = AST.Type.tuns32;
3603             goto LabelX;
3604 
3605         case TOK.int64:
3606             t = AST.Type.tint64;
3607             nextToken();
3608             if (token.value == TOK.int64)   // if `long long`
3609             {
3610                 error("use `long` for a 64 bit integer instead of `long long`");
3611                 nextToken();
3612             }
3613             else if (token.value == TOK.float64)   // if `long double`
3614             {
3615                 error("use `real` instead of `long double`");
3616                 t = AST.Type.tfloat80;
3617                 nextToken();
3618             }
3619             break;
3620 
3621         case TOK.uns64:
3622             t = AST.Type.tuns64;
3623             goto LabelX;
3624 
3625         case TOK.int128:
3626             t = AST.Type.tint128;
3627             goto LabelX;
3628 
3629         case TOK.uns128:
3630             t = AST.Type.tuns128;
3631             goto LabelX;
3632 
3633         case TOK.float32:
3634             t = AST.Type.tfloat32;
3635             goto LabelX;
3636 
3637         case TOK.float64:
3638             t = AST.Type.tfloat64;
3639             goto LabelX;
3640 
3641         case TOK.float80:
3642             t = AST.Type.tfloat80;
3643             goto LabelX;
3644 
3645         case TOK.imaginary32:
3646             t = AST.Type.timaginary32;
3647             goto LabelX;
3648 
3649         case TOK.imaginary64:
3650             t = AST.Type.timaginary64;
3651             goto LabelX;
3652 
3653         case TOK.imaginary80:
3654             t = AST.Type.timaginary80;
3655             goto LabelX;
3656 
3657         case TOK.complex32:
3658             t = AST.Type.tcomplex32;
3659             goto LabelX;
3660 
3661         case TOK.complex64:
3662             t = AST.Type.tcomplex64;
3663             goto LabelX;
3664 
3665         case TOK.complex80:
3666             t = AST.Type.tcomplex80;
3667             goto LabelX;
3668 
3669         case TOK.bool_:
3670             t = AST.Type.tbool;
3671             goto LabelX;
3672 
3673         case TOK.char_:
3674             t = AST.Type.tchar;
3675             goto LabelX;
3676 
3677         case TOK.wchar_:
3678             t = AST.Type.twchar;
3679             goto LabelX;
3680 
3681         case TOK.dchar_:
3682             t = AST.Type.tdchar;
3683             goto LabelX;
3684         LabelX:
3685             nextToken();
3686             break;
3687 
3688         case TOK.this_:
3689         case TOK.super_:
3690         case TOK.identifier:
3691             loc = token.loc;
3692             id = token.ident;
3693             nextToken();
3694             if (token.value == TOK.not)
3695             {
3696                 // ident!(template_arguments)
3697                 auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments());
3698                 t = parseBasicTypeStartingAt(new AST.TypeInstance(loc, tempinst), dontLookDotIdents);
3699             }
3700             else
3701             {
3702                 t = parseBasicTypeStartingAt(new AST.TypeIdentifier(loc, id), dontLookDotIdents);
3703             }
3704             break;
3705 
3706         case TOK.mixin_:
3707             // https://dlang.org/spec/expression.html#mixin_types
3708             loc = token.loc;
3709             nextToken();
3710             if (token.value != TOK.leftParenthesis)
3711                 error(token.loc, "found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis));
3712             auto exps = parseArguments();
3713             t = new AST.TypeMixin(loc, exps);
3714             break;
3715 
3716         case TOK.dot:
3717             // Leading . as in .foo
3718             t = parseBasicTypeStartingAt(new AST.TypeIdentifier(token.loc, Id.empty), dontLookDotIdents);
3719             break;
3720 
3721         case TOK.typeof_:
3722             // typeof(expression)
3723             t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents);
3724             break;
3725 
3726         case TOK.vector:
3727             t = parseVector();
3728             break;
3729 
3730         case TOK.traits:
3731             if (AST.TraitsExp te = cast(AST.TraitsExp) parsePrimaryExp())
3732                 if (te.ident)
3733                 {
3734                     t = new AST.TypeTraits(token.loc, te);
3735                     break;
3736                 }
3737             t = new AST.TypeError;
3738             break;
3739 
3740         case TOK.const_:
3741             // const(type)
3742             nextToken();
3743             check(TOK.leftParenthesis);
3744             t = parseType().addSTC(STC.const_);
3745             check(TOK.rightParenthesis);
3746             break;
3747 
3748         case TOK.immutable_:
3749             // immutable(type)
3750             nextToken();
3751             check(TOK.leftParenthesis);
3752             t = parseType().addSTC(STC.immutable_);
3753             check(TOK.rightParenthesis);
3754             break;
3755 
3756         case TOK.shared_:
3757             // shared(type)
3758             nextToken();
3759             check(TOK.leftParenthesis);
3760             t = parseType().addSTC(STC.shared_);
3761             check(TOK.rightParenthesis);
3762             break;
3763 
3764         case TOK.inout_:
3765             // wild(type)
3766             nextToken();
3767             check(TOK.leftParenthesis);
3768             t = parseType().addSTC(STC.wild);
3769             check(TOK.rightParenthesis);
3770             break;
3771 
3772         default:
3773             error("basic type expected, not `%s`", token.toChars());
3774             if (token.value == TOK.else_)
3775                 eSink.errorSupplemental(token.loc, "There's no `static else`, use `else` instead.");
3776             t = AST.Type.terror;
3777             break;
3778         }
3779         return t;
3780     }
3781 
3782     private AST.Type parseBasicTypeStartingAt(AST.TypeQualified tid, bool dontLookDotIdents)
3783     {
3784         AST.Type maybeArray = null;
3785         // See https://issues.dlang.org/show_bug.cgi?id=1215
3786         // A basic type can look like MyType (typical case), but also:
3787         //  MyType.T -> A type
3788         //  MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
3789         //  MyType[expr].T -> A type.
3790         //  MyType[expr].T[expr] ->  Either a static array of MyType[expr].T or a type
3791         //                           (iif MyType[expr].T is a Ttuple)
3792         while (1)
3793         {
3794             switch (token.value)
3795             {
3796             case TOK.dot:
3797                 {
3798                     nextToken();
3799                     if (token.value != TOK.identifier)
3800                     {
3801                         error("identifier expected following `.` instead of `%s`", token.toChars());
3802                         break;
3803                     }
3804                     if (maybeArray)
3805                     {
3806                         // This is actually a TypeTuple index, not an {a/s}array.
3807                         // We need to have a while loop to unwind all index taking:
3808                         // T[e1][e2].U   ->  T, addIndex(e1), addIndex(e2)
3809                         AST.Objects dimStack;
3810                         AST.Type t = maybeArray;
3811                         while (true)
3812                         {
3813                             if (t.ty == Tsarray)
3814                             {
3815                                 // The index expression is an Expression.
3816                                 AST.TypeSArray a = cast(AST.TypeSArray)t;
3817                                 dimStack.push(a.dim.syntaxCopy());
3818                                 t = a.next.syntaxCopy();
3819                             }
3820                             else if (t.ty == Taarray)
3821                             {
3822                                 // The index expression is a Type. It will be interpreted as an expression at semantic time.
3823                                 AST.TypeAArray a = cast(AST.TypeAArray)t;
3824                                 dimStack.push(a.index.syntaxCopy());
3825                                 t = a.next.syntaxCopy();
3826                             }
3827                             else
3828                             {
3829                                 break;
3830                             }
3831                         }
3832                         assert(dimStack.length > 0);
3833                         // We're good. Replay indices in the reverse order.
3834                         tid = cast(AST.TypeQualified)t;
3835                         while (dimStack.length)
3836                         {
3837                             tid.addIndex(dimStack.pop());
3838                         }
3839                         maybeArray = null;
3840                     }
3841                     const loc = token.loc;
3842                     Identifier id = token.ident;
3843                     nextToken();
3844                     if (token.value == TOK.not)
3845                     {
3846                         auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments());
3847                         tid.addInst(tempinst);
3848                     }
3849                     else
3850                         tid.addIdent(id);
3851                     continue;
3852                 }
3853             case TOK.leftBracket:
3854                 {
3855                     if (dontLookDotIdents) // workaround for https://issues.dlang.org/show_bug.cgi?id=14911
3856                         goto Lend;
3857 
3858                     nextToken();
3859                     AST.Type t = maybeArray ? maybeArray : cast(AST.Type)tid;
3860                     if (token.value == TOK.rightBracket)
3861                     {
3862                         // It's a dynamic array, and we're done:
3863                         // T[].U does not make sense.
3864                         t = new AST.TypeDArray(t);
3865                         nextToken();
3866                         return t;
3867                     }
3868                     else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null))
3869                     {
3870                         // This can be one of two things:
3871                         //  1 - an associative array declaration, T[type]
3872                         //  2 - an associative array declaration, T[expr]
3873                         // These  can only be disambiguated later.
3874                         AST.Type index = parseType(); // [ type ]
3875                         maybeArray = new AST.TypeAArray(t, index);
3876                         check(TOK.rightBracket);
3877                     }
3878                     else
3879                     {
3880                         // This can be one of three things:
3881                         //  1 - an static array declaration, T[expr]
3882                         //  2 - a slice, T[expr .. expr]
3883                         //  3 - a template parameter pack index expression, T[expr].U
3884                         // 1 and 3 can only be disambiguated later.
3885                         //printf("it's type[expression]\n");
3886                         inBrackets++;
3887                         AST.Expression e = parseAssignExp(); // [ expression ]
3888                         if (token.value == TOK.slice)
3889                         {
3890                             // It's a slice, and we're done.
3891                             nextToken();
3892                             AST.Expression e2 = parseAssignExp(); // [ exp .. exp ]
3893                             t = new AST.TypeSlice(t, e, e2);
3894                             inBrackets--;
3895                             check(TOK.rightBracket);
3896                             return t;
3897                         }
3898                         else
3899                         {
3900                             maybeArray = new AST.TypeSArray(t, e);
3901                             inBrackets--;
3902                             check(TOK.rightBracket);
3903                             continue;
3904                         }
3905                     }
3906                     break;
3907                 }
3908             default:
3909                 goto Lend;
3910             }
3911         }
3912     Lend:
3913         return maybeArray ? maybeArray : cast(AST.Type)tid;
3914     }
3915 
3916     /******************************************
3917      * Parse suffixes to type t.
3918      *      *
3919      *      []
3920      *      [AssignExpression]
3921      *      [AssignExpression .. AssignExpression]
3922      *      [Type]
3923      *      delegate Parameters MemberFunctionAttributes(opt)
3924      *      function Parameters FunctionAttributes(opt)
3925      * Params:
3926      *      t = the already parsed type
3927      * Returns:
3928      *      t with the suffixes added
3929      * See_Also:
3930      *      https://dlang.org/spec/declaration.html#TypeSuffixes
3931      */
3932     private AST.Type parseTypeSuffixes(AST.Type t)
3933     {
3934         //printf("parseTypeSuffixes()\n");
3935         while (1)
3936         {
3937             switch (token.value)
3938             {
3939             case TOK.mul:
3940                 t = new AST.TypePointer(t);
3941                 nextToken();
3942                 continue;
3943 
3944             case TOK.leftBracket:
3945                 // Handle []. Make sure things like
3946                 //     int[3][1] a;
3947                 // is (array[1] of array[3] of int)
3948                 nextToken();
3949                 if (token.value == TOK.rightBracket)
3950                 {
3951                     t = new AST.TypeDArray(t); // []
3952                     nextToken();
3953                 }
3954                 else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null))
3955                 {
3956                     // It's an associative array declaration
3957                     //printf("it's an associative array\n");
3958                     AST.Type index = parseType(); // [ type ]
3959                     t = new AST.TypeAArray(t, index);
3960                     check(TOK.rightBracket);
3961                 }
3962                 else
3963                 {
3964                     //printf("it's type[expression]\n");
3965                     inBrackets++;
3966                     AST.Expression e = parseAssignExp(); // [ expression ]
3967                     if (!e)
3968                     {
3969                         inBrackets--;
3970                         check(TOK.rightBracket);
3971                         continue;
3972                     }
3973                     if (token.value == TOK.slice)
3974                     {
3975                         nextToken();
3976                         AST.Expression e2 = parseAssignExp(); // [ exp .. exp ]
3977                         t = new AST.TypeSlice(t, e, e2);
3978                     }
3979                     else
3980                     {
3981                         t = new AST.TypeSArray(t, e);
3982                     }
3983                     inBrackets--;
3984                     check(TOK.rightBracket);
3985                 }
3986                 continue;
3987 
3988             case TOK.delegate_:
3989             case TOK.function_:
3990                 {
3991                     // Handle delegate declaration:
3992                     //      t delegate(parameter list) nothrow pure
3993                     //      t function(parameter list) nothrow pure
3994                     const save = token.value;
3995                     nextToken();
3996 
3997                     auto parameterList = parseParameterList(null);
3998 
3999                     StorageClass stc = parsePostfix(STC.undefined_, null);
4000                     auto tf = new AST.TypeFunction(parameterList, t, linkage, stc);
4001                     if (stc & (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild | STC.return_))
4002                     {
4003                         if (save == TOK.function_)
4004                             error("`const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions");
4005                         else
4006                             tf = cast(AST.TypeFunction)tf.addSTC(stc);
4007                     }
4008                     t = save == TOK.delegate_ ? new AST.TypeDelegate(tf) : new AST.TypePointer(tf); // pointer to function
4009                     continue;
4010                 }
4011             default:
4012                 return t;
4013             }
4014             assert(0);
4015         }
4016         assert(0);
4017     }
4018 
4019     /**********************
4020      * Parse Declarator
4021      * Params:
4022      *  t            = base type to start with
4023      *  palt         = OR in 1 for C-style function pointer declaration syntax,
4024      *                 2 for C-style array declaration syntax, otherwise don't modify
4025      *  pident       = set to Identifier if there is one, null if not
4026      *  tpl          = if !null, then set to TemplateParameterList
4027      *  storageClass = any storage classes seen so far
4028      *  pdisable     = set to true if @disable seen
4029      *  pudas        = any user defined attributes seen so far. Merged with any more found
4030      * Returns:
4031      *  type declared
4032      * Reference: https://dlang.org/spec/declaration.html#Declarator
4033      */
4034     private AST.Type parseDeclarator(AST.Type t, ref int palt, Identifier* pident,
4035         AST.TemplateParameters** tpl = null, StorageClass storageClass = 0,
4036         bool* pdisable = null, AST.Expressions** pudas = null)
4037     {
4038         //printf("parseDeclarator(tpl = %p)\n", tpl);
4039         t = parseTypeSuffixes(t);
4040         AST.Type ts;
4041         switch (token.value)
4042         {
4043         case TOK.identifier:
4044             if (pident)
4045                 *pident = token.ident;
4046             else
4047                 error("unexpected identifier `%s` in declarator", token.ident.toChars());
4048             ts = t;
4049             nextToken();
4050             break;
4051 
4052         case TOK.leftParenthesis:
4053             {
4054                 // like: T (*fp)();
4055                 // like: T ((*fp))();
4056                 if (peekNext() == TOK.mul || peekNext() == TOK.leftParenthesis)
4057                 {
4058                     /* Parse things with parentheses around the identifier, like:
4059                      *  int (*ident[3])[]
4060                      * although the D style would be:
4061                      *  int[]*[3] ident
4062                      */
4063                     palt |= 1;
4064                     nextToken();
4065                     ts = parseDeclarator(t, palt, pident);
4066                     check(TOK.rightParenthesis);
4067                     break;
4068                 }
4069                 ts = t;
4070 
4071                 Token* peekt = &token;
4072                 /* Completely disallow C-style things like:
4073                  *   T (a);
4074                  * Improve error messages for the common bug of a missing return type
4075                  * by looking to see if (a) looks like a parameter list.
4076                  */
4077                 if (isParameters(&peekt))
4078                 {
4079                     error("function declaration without return type. (Note that constructors are always named `this`)");
4080                 }
4081                 else
4082                     error("unexpected `(` in declarator");
4083                 break;
4084             }
4085         default:
4086             ts = t;
4087             break;
4088         }
4089 
4090         // parse DeclaratorSuffixes
4091         while (1)
4092         {
4093             switch (token.value)
4094             {
4095                 static if (CARRAYDECL)
4096                 {
4097                     /* Support C style array syntax:
4098                      *   int ident[]
4099                      * as opposed to D-style:
4100                      *   int[] ident
4101                      */
4102                 case TOK.leftBracket:
4103                     {
4104                         // This is the old C-style post [] syntax.
4105                         AST.TypeNext ta;
4106                         nextToken();
4107                         if (token.value == TOK.rightBracket)
4108                         {
4109                             // It's a dynamic array
4110                             ta = new AST.TypeDArray(t); // []
4111                             nextToken();
4112                             palt |= 2;
4113                         }
4114                         else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null))
4115                         {
4116                             // It's an associative array
4117                             //printf("it's an associative array\n");
4118                             AST.Type index = parseType(); // [ type ]
4119                             check(TOK.rightBracket);
4120                             ta = new AST.TypeAArray(t, index);
4121                             palt |= 2;
4122                         }
4123                         else
4124                         {
4125                             //printf("It's a static array\n");
4126                             AST.Expression e = parseAssignExp(); // [ expression ]
4127                             ta = new AST.TypeSArray(t, e);
4128                             check(TOK.rightBracket);
4129                             palt |= 2;
4130                         }
4131 
4132                         /* Insert ta into
4133                          *   ts -> ... -> t
4134                          * so that
4135                          *   ts -> ... -> ta -> t
4136                          */
4137                         AST.Type* pt;
4138                         for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next)
4139                         {
4140                         }
4141                         *pt = ta;
4142                         continue;
4143                     }
4144                 }
4145             case TOK.leftParenthesis:
4146                 {
4147                     if (tpl)
4148                     {
4149                         Token* tk = peekPastParen(&token);
4150                         if (tk.value == TOK.leftParenthesis)
4151                         {
4152                             /* Look ahead to see if this is (...)(...),
4153                              * i.e. a function template declaration
4154                              */
4155                             //printf("function template declaration\n");
4156 
4157                             // Gather template parameter list
4158                             *tpl = parseTemplateParameterList();
4159                         }
4160                         else if (tk.value == TOK.assign)
4161                         {
4162                             /* or (...) =,
4163                              * i.e. a variable template declaration
4164                              */
4165                             //printf("variable template declaration\n");
4166                             *tpl = parseTemplateParameterList();
4167                             break;
4168                         }
4169                     }
4170 
4171                     auto parameterList = parseParameterList(null);
4172 
4173                     /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
4174                      */
4175                     // merge prefix storage classes
4176                     StorageClass stc = parsePostfix(storageClass, pudas);
4177 
4178                     AST.Type tf = new AST.TypeFunction(parameterList, t, linkage, stc);
4179                     tf = tf.addSTC(stc);
4180                     if (pdisable)
4181                         *pdisable = stc & STC.disable ? true : false;
4182 
4183                     /* Insert tf into
4184                      *   ts -> ... -> t
4185                      * so that
4186                      *   ts -> ... -> tf -> t
4187                      */
4188                     AST.Type* pt;
4189                     for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next)
4190                     {
4191                     }
4192                     *pt = tf;
4193                     break;
4194                 }
4195             default:
4196                 break;
4197             }
4198             break;
4199         }
4200         return ts;
4201     }
4202 
4203     private void parseStorageClasses(ref StorageClass storage_class, ref LINK link,
4204         ref bool setAlignment, ref AST.Expression ealign, ref AST.Expressions* udas,
4205         out Loc linkloc)
4206     {
4207         StorageClass stc;
4208         bool sawLinkage = false; // seen a linkage declaration
4209 
4210         linkloc = Loc.initial;
4211 
4212         while (1)
4213         {
4214             switch (token.value)
4215             {
4216             case TOK.const_:
4217                 if (peekNext() == TOK.leftParenthesis)
4218                     break; // const as type constructor
4219                 stc = STC.const_; // const as storage class
4220                 goto L1;
4221 
4222             case TOK.immutable_:
4223                 if (peekNext() == TOK.leftParenthesis)
4224                     break;
4225                 stc = STC.immutable_;
4226                 goto L1;
4227 
4228             case TOK.shared_:
4229                 if (peekNext() == TOK.leftParenthesis)
4230                     break;
4231                 stc = STC.shared_;
4232                 goto L1;
4233 
4234             case TOK.inout_:
4235                 if (peekNext() == TOK.leftParenthesis)
4236                     break;
4237                 stc = STC.wild;
4238                 goto L1;
4239 
4240             case TOK.static_:
4241                 stc = STC.static_;
4242                 goto L1;
4243 
4244             case TOK.final_:
4245                 stc = STC.final_;
4246                 goto L1;
4247 
4248             case TOK.auto_:
4249                 stc = STC.auto_;
4250                 goto L1;
4251 
4252             case TOK.scope_:
4253                 stc = STC.scope_;
4254                 goto L1;
4255 
4256             case TOK.override_:
4257                 stc = STC.override_;
4258                 goto L1;
4259 
4260             case TOK.abstract_:
4261                 stc = STC.abstract_;
4262                 goto L1;
4263 
4264             case TOK.synchronized_:
4265                 stc = STC.synchronized_;
4266                 goto L1;
4267 
4268             case TOK.deprecated_:
4269                 stc = STC.deprecated_;
4270                 goto L1;
4271 
4272             case TOK.nothrow_:
4273                 stc = STC.nothrow_;
4274                 goto L1;
4275 
4276             case TOK.pure_:
4277                 stc = STC.pure_;
4278                 goto L1;
4279 
4280             case TOK.ref_:
4281                 stc = STC.ref_;
4282                 goto L1;
4283 
4284             case TOK.gshared:
4285                 stc = STC.gshared;
4286                 goto L1;
4287 
4288             case TOK.enum_:
4289                 {
4290                     const tv = peekNext();
4291                     if (tv == TOK.leftCurly || tv == TOK.colon)
4292                         break;
4293                     if (tv == TOK.identifier)
4294                     {
4295                         const nextv = peekNext2();
4296                         if (nextv == TOK.leftCurly || nextv == TOK.colon || nextv == TOK.semicolon)
4297                             break;
4298                     }
4299                     stc = STC.manifest;
4300                     goto L1;
4301                 }
4302 
4303             case TOK.at:
4304                 {
4305                     stc = parseAttribute(udas);
4306                     if (stc)
4307                         goto L1;
4308                     continue;
4309                 }
4310             L1:
4311                 storage_class = appendStorageClass(storage_class, stc);
4312                 nextToken();
4313                 continue;
4314 
4315             case TOK.extern_:
4316                 {
4317                     if (peekNext() != TOK.leftParenthesis)
4318                     {
4319                         stc = STC.extern_;
4320                         goto L1;
4321                     }
4322 
4323                     if (sawLinkage)
4324                         error("redundant linkage declaration");
4325                     sawLinkage = true;
4326                     linkloc = token.loc;
4327                     auto res = parseLinkage();
4328                     link = res.link;
4329                     if (res.idents || res.identExps)
4330                     {
4331                         error("C++ name spaces not allowed here");
4332                     }
4333                     if (res.cppmangle != CPPMANGLE.def)
4334                     {
4335                         error("C++ mangle declaration not allowed here");
4336                     }
4337                     continue;
4338                 }
4339             case TOK.align_:
4340                 {
4341                     nextToken();
4342                     setAlignment = true;
4343                     if (token.value == TOK.leftParenthesis)
4344                     {
4345                         nextToken();
4346                         ealign = parseExpression();
4347                         check(TOK.rightParenthesis);
4348                     }
4349                     continue;
4350                 }
4351             default:
4352                 break;
4353             }
4354             break;
4355         }
4356     }
4357 
4358     /**********************************
4359      * Parse Declarations.
4360      * These can be:
4361      *      1. declarations at global/class level
4362      *      2. declarations at statement level
4363      * Returns:
4364      *  array of Declarations.
4365      */
4366     private AST.Dsymbols* parseDeclarations(bool autodecl, PrefixAttributes!AST* pAttrs, const(char)* comment)
4367     {
4368         StorageClass storage_class = STC.undefined_;
4369         LINK link = linkage;
4370         Loc linkloc = this.linkLoc;
4371         bool setAlignment = false;
4372         AST.Expression ealign;
4373         AST.Expressions* udas = null;
4374 
4375         //printf("parseDeclarations() %s\n", token.toChars());
4376         if (!comment)
4377             comment = token.blockComment.ptr;
4378 
4379         /* Look for AliasReassignment
4380          */
4381         if (token.value == TOK.identifier && peekNext() == TOK.assign)
4382             return parseAliasReassignment(comment);
4383 
4384         /* Declarations that start with `alias`
4385          */
4386         bool isAliasDeclaration = false;
4387         auto aliasLoc = token.loc;
4388         if (token.value == TOK.alias_)
4389         {
4390             if (auto a = parseAliasDeclarations(comment))
4391                 return a;
4392             /* Handle these later:
4393              *   alias StorageClasses type ident;
4394              */
4395             isAliasDeclaration = true;
4396         }
4397 
4398         AST.Type ts;
4399 
4400         if (!autodecl)
4401         {
4402             parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc);
4403 
4404             if (token.value == TOK.enum_)
4405             {
4406                 AST.Dsymbol d = parseEnum();
4407                 auto a = new AST.Dsymbols();
4408                 a.push(d);
4409 
4410                 if (udas)
4411                 {
4412                     d = new AST.UserAttributeDeclaration(udas, a);
4413                     a = new AST.Dsymbols();
4414                     a.push(d);
4415                 }
4416 
4417                 addComment(d, comment);
4418                 return a;
4419             }
4420             if (token.value == TOK.struct_ ||
4421                      token.value == TOK.union_ ||
4422                      token.value == TOK.class_ ||
4423                      token.value == TOK.interface_)
4424             {
4425                 AST.Dsymbol s = parseAggregate();
4426                 auto a = new AST.Dsymbols();
4427                 a.push(s);
4428 
4429                 if (storage_class)
4430                 {
4431                     s = new AST.StorageClassDeclaration(storage_class, a);
4432                     a = new AST.Dsymbols();
4433                     a.push(s);
4434                 }
4435                 if (setAlignment)
4436                 {
4437                     s = new AST.AlignDeclaration(s.loc, ealign, a);
4438                     a = new AST.Dsymbols();
4439                     a.push(s);
4440                 }
4441                 if (link != linkage)
4442                 {
4443                     s = new AST.LinkDeclaration(linkloc, link, a);
4444                     a = new AST.Dsymbols();
4445                     a.push(s);
4446                 }
4447                 if (udas)
4448                 {
4449                     s = new AST.UserAttributeDeclaration(udas, a);
4450                     a = new AST.Dsymbols();
4451                     a.push(s);
4452                 }
4453 
4454                 addComment(s, comment);
4455                 return a;
4456             }
4457 
4458             /* Look for auto initializers:
4459              *  storage_class identifier = initializer;
4460              *  storage_class identifier(...) = initializer;
4461              */
4462             if ((storage_class || udas) && token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign))
4463             {
4464                 AST.Dsymbols* a = parseAutoDeclarations(storage_class, comment);
4465                 if (udas)
4466                 {
4467                     AST.Dsymbol s = new AST.UserAttributeDeclaration(udas, a);
4468                     a = new AST.Dsymbols();
4469                     a.push(s);
4470                 }
4471                 return a;
4472             }
4473 
4474             /* Look for return type inference for template functions.
4475              */
4476             {
4477                 Token* tk;
4478                 if ((storage_class || udas) && token.value == TOK.identifier && skipParens(peek(&token), &tk) &&
4479                     skipAttributes(tk, &tk) &&
4480                     (tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.goesTo ||
4481                      tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body))
4482                 {
4483                     if (tk.value == TOK.identifier && tk.ident == Id._body)
4484                         usageOfBodyKeyword();
4485 
4486                     ts = null;
4487                 }
4488                 else
4489                 {
4490                     ts = parseBasicType();
4491                     ts = parseTypeSuffixes(ts);
4492                 }
4493             }
4494         }
4495 
4496         if (pAttrs)
4497         {
4498             storage_class |= pAttrs.storageClass;
4499             //pAttrs.storageClass = STC.undefined_;
4500         }
4501 
4502         AST.Type tfirst = null;
4503         auto a = new AST.Dsymbols();
4504 
4505         while (1)
4506         {
4507             AST.TemplateParameters* tpl = null;
4508             bool disable;
4509             int alt = 0;
4510 
4511             const loc = token.loc;
4512             Identifier ident;
4513             auto t = parseDeclarator(ts, alt, &ident, &tpl, storage_class, &disable, &udas);
4514             assert(t);
4515             if (!tfirst)
4516                 tfirst = t;
4517             else if (t != tfirst)
4518                 error(token.loc, "multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars());
4519 
4520             if (token.value == TOK.colon && !ident && t.ty != Tfunction)
4521             {
4522                 // Unnamed bit field
4523                 ident = Identifier.generateAnonymousId("BitField");
4524             }
4525 
4526             bool isThis = (t.ty == Tident && (cast(AST.TypeIdentifier)t).ident == Id.This && token.value == TOK.assign);
4527             if (ident)
4528                 checkCstyleTypeSyntax(loc, t, alt, ident);
4529             else if (!isThis && (t != AST.Type.terror))
4530                 noIdentifierForDeclarator(t);
4531 
4532             if (isAliasDeclaration)
4533             {
4534                 AST.Declaration v;
4535                 AST.Initializer _init = null;
4536 
4537                 /* Aliases can no longer have multiple declarators, storage classes,
4538                  * linkages, or auto declarations.
4539                  * These never made any sense, anyway.
4540                  * The code below needs to be fixed to reject them.
4541                  * The grammar has already been fixed to preclude them.
4542                  */
4543 
4544                 if (udas)
4545                     error("user-defined attributes not allowed for `alias` declarations");
4546 
4547                 if (token.value == TOK.assign)
4548                 {
4549                     nextToken();
4550                     _init = parseInitializer();
4551                 }
4552                 if (_init)
4553                 {
4554                     error("alias cannot have initializer");
4555                 }
4556                 v = new AST.AliasDeclaration(aliasLoc, ident, t);
4557 
4558                 v.storage_class = storage_class;
4559                 if (pAttrs)
4560                 {
4561                     /* AliasDeclaration distinguish @safe, @system, @trusted attributes
4562                      * on prefix and postfix.
4563                      *   @safe alias void function() FP1;
4564                      *   alias @safe void function() FP2;    // FP2 is not @safe
4565                      *   alias void function() @safe FP3;
4566                      */
4567                     pAttrs.storageClass &= STC.safeGroup;
4568                 }
4569                 AST.Dsymbol s = v;
4570 
4571                 if (link != linkage)
4572                 {
4573                     auto ax = new AST.Dsymbols();
4574                     ax.push(v);
4575                     s = new AST.LinkDeclaration(linkloc, link, ax);
4576                 }
4577                 a.push(s);
4578                 switch (token.value)
4579                 {
4580                 case TOK.semicolon:
4581                     nextToken();
4582                     addComment(s, comment);
4583                     break;
4584 
4585                 case TOK.comma:
4586                     nextToken();
4587                     addComment(s, comment);
4588                     continue;
4589 
4590                 default:
4591                     error("semicolon expected to close `alias` declaration, not `%s`", token.toChars());
4592                     break;
4593                 }
4594             }
4595             else if (t.ty == Tfunction)
4596             {
4597                 /* @@@DEPRECATED_2.115@@@
4598                  * change to error, deprecated in 2.105.1 */
4599                 if (storage_class & STC.manifest)
4600                     deprecation("function cannot have enum storage class");
4601 
4602                 AST.Expression constraint = null;
4603                 //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class);
4604                 auto f = new AST.FuncDeclaration(loc, Loc.initial, ident, storage_class | (disable ? STC.disable : 0), t);
4605                 if (pAttrs)
4606                     pAttrs.storageClass = STC.undefined_;
4607                 if (tpl)
4608                     constraint = parseConstraint();
4609                 AST.Dsymbol s = parseContracts(f, !!tpl);
4610                 auto tplIdent = s.ident;
4611 
4612                 if (link != linkage)
4613                 {
4614                     auto ax = new AST.Dsymbols();
4615                     ax.push(s);
4616                     s = new AST.LinkDeclaration(linkloc, link, ax);
4617                 }
4618                 if (udas)
4619                 {
4620                     auto ax = new AST.Dsymbols();
4621                     ax.push(s);
4622                     s = new AST.UserAttributeDeclaration(udas, ax);
4623                 }
4624 
4625                 /* A template parameter list means it's a function template
4626                  */
4627                 if (tpl)
4628                 {
4629                     // @@@DEPRECATED_2.114@@@
4630                     // Both deprecated in 2.104, change to error
4631                     if (storage_class & STC.override_)
4632                         deprecation(loc, "a function template is not virtual so cannot be marked `override`");
4633                     else if (storage_class & STC.abstract_)
4634                         deprecation(loc, "a function template is not virtual so cannot be marked `abstract`");
4635 
4636                     // Wrap a template around the function declaration
4637                     auto decldefs = new AST.Dsymbols();
4638                     decldefs.push(s);
4639                     auto tempdecl = new AST.TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs);
4640                     s = tempdecl;
4641 
4642                     StorageClass stc2 = STC.undefined_;
4643                     if (storage_class & STC.static_)
4644                     {
4645                         assert(f.storage_class & STC.static_);
4646                         f.storage_class &= ~STC.static_;
4647                         stc2 |= STC.static_;
4648                     }
4649                     if (storage_class & STC.deprecated_)
4650                     {
4651                         assert(f.storage_class & STC.deprecated_);
4652                         f.storage_class &= ~STC.deprecated_;
4653                         stc2 |= STC.deprecated_;
4654                     }
4655                     if (stc2 != STC.undefined_)
4656                     {
4657                         auto ax = new AST.Dsymbols();
4658                         ax.push(s);
4659                         s = new AST.StorageClassDeclaration(stc2, ax);
4660                     }
4661                 }
4662                 a.push(s);
4663                 addComment(s, comment);
4664             }
4665             else if (ident)
4666             {
4667                 AST.Expression width;
4668                 if (token.value == TOK.colon)
4669                 {
4670                     nextToken();
4671                     width = parseCondExp();
4672                 }
4673 
4674                 AST.Initializer _init = null;
4675                 if (token.value == TOK.assign)
4676                 {
4677                     nextToken();
4678                     _init = parseInitializer();
4679                 }
4680 
4681                 AST.Dsymbol s;
4682                 if (width)
4683                 {
4684                     if (_init)
4685                         error("initializer not allowed for bit-field declaration");
4686                     if (storage_class)
4687                         error("storage class not allowed for bit-field declaration");
4688                     s = new AST.BitFieldDeclaration(width.loc, t, ident, width);
4689                 }
4690                 else
4691                 {
4692                     auto v = new AST.VarDeclaration(loc, t, ident, _init);
4693                     v.storage_class = storage_class;
4694                     if (pAttrs)
4695                         pAttrs.storageClass = STC.undefined_;
4696                     s = v;
4697                 }
4698 
4699                 if (tpl && _init)
4700                 {
4701                     auto a2 = new AST.Dsymbols();
4702                     a2.push(s);
4703                     auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2, 0);
4704                     s = tempdecl;
4705                 }
4706                 if (setAlignment)
4707                 {
4708                     auto ax = new AST.Dsymbols();
4709                     ax.push(s);
4710                     s = new AST.AlignDeclaration(s.loc, ealign, ax);
4711                 }
4712                 if (link != linkage)
4713                 {
4714                     auto ax = new AST.Dsymbols();
4715                     ax.push(s);
4716                     s = new AST.LinkDeclaration(linkloc, link, ax);
4717                 }
4718                 if (udas)
4719                 {
4720                     auto ax = new AST.Dsymbols();
4721                     ax.push(s);
4722                     s = new AST.UserAttributeDeclaration(udas, ax);
4723                 }
4724                 a.push(s);
4725                 switch (token.value)
4726                 {
4727                 case TOK.semicolon:
4728                     nextToken();
4729                     addComment(s, comment);
4730                     break;
4731 
4732                 case TOK.comma:
4733                     nextToken();
4734                     addComment(s, comment);
4735                     continue;
4736 
4737                 default:
4738                     if (loc.linnum != token.loc.linnum)
4739                     {
4740                         error(token.loc, "semicolon needed to end declaration of `%s`, instead of `%s`", s.toChars(), token.toChars());
4741                         eSink.errorSupplemental(loc, "`%s` declared here", s.toChars());
4742                     }
4743                     else
4744                     {
4745                         error(token.loc, "semicolon needed to end declaration of `%s` instead of `%s`", s.toChars(), token.toChars());
4746                     }
4747                     break;
4748                 }
4749             }
4750             break;
4751         }
4752         return a;
4753     }
4754 
4755     /// Report an error that a declaration of type `t` is missing an identifier
4756     /// The parser is expected to sit on the next token after the type.
4757     private void noIdentifierForDeclarator(AST.Type t)
4758     {
4759         error("no identifier for declarator `%s`", t.toChars());
4760         // A common mistake is to use a reserved keyword as an identifier, e.g. `in` or `out`
4761         if (token.isKeyword)
4762         {
4763             eSink.errorSupplemental(token.loc, "`%s` is a keyword, perhaps append `_` to make it an identifier", token.toChars());
4764             nextToken();
4765         }
4766     }
4767 
4768     /********************************
4769      * Parse AliasReassignment:
4770      *   identifier = type;
4771      * Parser is sitting on the identifier.
4772      * https://dlang.org/spec/declaration.html#alias-reassignment
4773      * Params:
4774      *  comment = if not null, comment to attach to symbol
4775      * Returns:
4776      *  array of symbols
4777      */
4778     private AST.Dsymbols* parseAliasReassignment(const(char)* comment)
4779     {
4780         const loc = token.loc;
4781         auto ident = token.ident;
4782         nextToken();
4783         nextToken();        // advance past =
4784         auto t = parseType();
4785         AST.Dsymbol s = new AST.AliasAssign(loc, ident, t, null);
4786         check(TOK.semicolon, "alias reassignment");
4787         addComment(s, comment);
4788         auto a = new AST.Dsymbols();
4789         a.push(s);
4790         return a;
4791     }
4792 
4793     /********************************
4794      * Parse declarations that start with `alias`
4795      * Parser is sitting on the `alias`.
4796      * https://dlang.org/spec/declaration.html#alias
4797      * Params:
4798      *  comment = if not null, comment to attach to symbol
4799      * Returns:
4800      *  array of symbols
4801      */
4802     private AST.Dsymbols* parseAliasDeclarations(const(char)* comment)
4803     {
4804         const loc = token.loc;
4805         nextToken();
4806         Loc linkloc = this.linkLoc;
4807         AST.Expressions* udas;
4808         LINK link = linkage;
4809         StorageClass storage_class = STC.undefined_;
4810         AST.Expression ealign;
4811         bool setAlignment = false;
4812 
4813         /* Look for:
4814          *   alias Identifier this;
4815          * https://dlang.org/spec/class.html#alias-this
4816          */
4817         if (token.value == TOK.identifier && peekNext() == TOK.this_)
4818         {
4819             auto s = new AST.AliasThis(loc, token.ident);
4820             nextToken();
4821             check(TOK.this_);
4822             check(TOK.semicolon, "`alias Identifier this`");
4823             auto a = new AST.Dsymbols();
4824             a.push(s);
4825             addComment(s, comment);
4826             return a;
4827         }
4828         /* Look for:
4829          *  alias this = identifier;
4830          */
4831         if (token.value == TOK.this_ && peekNext() == TOK.assign && peekNext2() == TOK.identifier)
4832         {
4833             check(TOK.this_);
4834             check(TOK.assign);
4835             auto s = new AST.AliasThis(loc, token.ident);
4836             nextToken();
4837             check(TOK.semicolon, "`alias this = Identifier`");
4838             auto a = new AST.Dsymbols();
4839             a.push(s);
4840             addComment(s, comment);
4841             return a;
4842         }
4843         /* Look for:
4844          *  alias identifier = type;
4845          *  alias identifier(...) = type;
4846          * https://dlang.org/spec/declaration.html#alias
4847          */
4848         if (token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign))
4849         {
4850             auto a = new AST.Dsymbols();
4851             while (1)
4852             {
4853                 auto ident = token.ident;
4854                 nextToken();
4855                 AST.TemplateParameters* tpl = null;
4856                 if (token.value == TOK.leftParenthesis)
4857                     tpl = parseTemplateParameterList();
4858                 check(TOK.assign);
4859 
4860                 bool hasParsedAttributes;
4861                 void parseAttributes()
4862                 {
4863                     if (hasParsedAttributes) // only parse once
4864                         return;
4865                     hasParsedAttributes = true;
4866                     udas = null;
4867                     storage_class = STC.undefined_;
4868                     link = linkage;
4869                     linkloc = this.linkLoc;
4870                     setAlignment = false;
4871                     ealign = null;
4872                     parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc);
4873                 }
4874 
4875                 if (token.value == TOK.at)
4876                     parseAttributes;
4877 
4878                 AST.Declaration v;
4879                 AST.Dsymbol s;
4880 
4881                 // try to parse function type:
4882                 // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
4883                 bool attributesAppended;
4884                 const StorageClass funcStc = parseTypeCtor();
4885                 Token* tlu = &token;
4886                 Token* tk;
4887                 if (token.value != TOK.function_ &&
4888                     token.value != TOK.delegate_ &&
4889                     isBasicType(&tlu) && tlu &&
4890                     tlu.value == TOK.leftParenthesis)
4891                 {
4892                     AST.Type tret = parseBasicType();
4893                     auto parameterList = parseParameterList(null);
4894 
4895                     parseAttributes();
4896                     if (udas)
4897                         error("user-defined attributes not allowed for `alias` declarations");
4898 
4899                     attributesAppended = true;
4900                     storage_class = appendStorageClass(storage_class, funcStc);
4901                     AST.Type tf = new AST.TypeFunction(parameterList, tret, link, storage_class);
4902                     v = new AST.AliasDeclaration(loc, ident, tf);
4903                 }
4904                 else if (token.value == TOK.function_ ||
4905                     token.value == TOK.delegate_ ||
4906                     token.value == TOK.leftParenthesis &&
4907                         skipAttributes(peekPastParen(&token), &tk) &&
4908                         (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) ||
4909                     token.value == TOK.leftCurly ||
4910                     token.value == TOK.identifier && peekNext() == TOK.goesTo ||
4911                     token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis &&
4912                         skipAttributes(peekPastParen(peek(&token)), &tk) &&
4913                         (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) ||
4914                     token.value == TOK.auto_ && peekNext() == TOK.ref_ &&
4915                         peekNext2() == TOK.leftParenthesis &&
4916                         skipAttributes(peekPastParen(peek(peek(&token))), &tk) &&
4917                         (tk.value == TOK.goesTo || tk.value == TOK.leftCurly)
4918                    )
4919                 {
4920                     // function (parameters) { statements... }
4921                     // delegate (parameters) { statements... }
4922                     // (parameters) { statements... }
4923                     // (parameters) => expression
4924                     // { statements... }
4925                     // identifier => expression
4926                     // ref (parameters) { statements... }
4927                     // ref (parameters) => expression
4928                     // auto ref (parameters) { statements... }
4929                     // auto ref (parameters) => expression
4930 
4931                     s = parseFunctionLiteral();
4932 
4933                     if (udas !is null)
4934                     {
4935                         if (storage_class != 0)
4936                             error("cannot put a storage-class in an `alias` declaration.");
4937                         // parseAttributes shouldn't have set these variables
4938                         assert(link == linkage && !setAlignment && ealign is null);
4939                         auto tpl_ = cast(AST.TemplateDeclaration) s;
4940                         if (tpl_ is null || tpl_.members.length != 1)
4941                         {
4942                             error("user-defined attributes are not allowed on `alias` declarations");
4943                         }
4944                         else
4945                         {
4946                             auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0];
4947                             auto tf = cast(AST.TypeFunction) fd.type;
4948                             assert(tf.parameterList.parameters.length > 0);
4949                             auto as = new AST.Dsymbols();
4950                             (*tf.parameterList.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as);
4951                         }
4952                     }
4953 
4954                     v = new AST.AliasDeclaration(loc, ident, s);
4955                 }
4956                 else
4957                 {
4958                     parseAttributes();
4959                     // type
4960                     if (udas)
4961                         error("user-defined attributes not allowed for `alias` declarations");
4962 
4963                     auto t = parseType();
4964 
4965                     // Disallow meaningless storage classes on type aliases
4966                     if (storage_class)
4967                     {
4968                         // Don't raise errors for STC that are part of a function/delegate type, e.g.
4969                         // `alias F = ref pure nothrow @nogc @safe int function();`
4970                         auto tp = t.isTypePointer;
4971                         const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate;
4972                         const remStc = isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class;
4973 
4974                         if (remStc)
4975                         {
4976                             OutBuffer buf;
4977                             AST.stcToBuffer(buf, remStc);
4978                             // @@@DEPRECATED_2.103@@@
4979                             // Deprecated in 2020-07, can be made an error in 2.103
4980                             eSink.deprecation(token.loc, "storage class `%s` has no effect in type aliases", buf.peekChars());
4981                         }
4982                     }
4983 
4984                     v = new AST.AliasDeclaration(loc, ident, t);
4985                 }
4986                 if (!attributesAppended)
4987                     storage_class = appendStorageClass(storage_class, funcStc);
4988                 v.storage_class = storage_class;
4989 
4990                 s = v;
4991                 if (tpl)
4992                 {
4993                     auto a2 = new AST.Dsymbols();
4994                     a2.push(s);
4995                     auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2);
4996                     s = tempdecl;
4997                 }
4998                 if (link != linkage)
4999                 {
5000                     auto a2 = new AST.Dsymbols();
5001                     a2.push(s);
5002                     s = new AST.LinkDeclaration(linkloc, link, a2);
5003                 }
5004                 a.push(s);
5005 
5006                 switch (token.value)
5007                 {
5008                 case TOK.semicolon:
5009                     nextToken();
5010                     addComment(s, comment);
5011                     break;
5012 
5013                 case TOK.comma:
5014                     nextToken();
5015                     addComment(s, comment);
5016                     if (token.value != TOK.identifier)
5017                     {
5018                         error("identifier expected following comma, not `%s`", token.toChars());
5019                         break;
5020                     }
5021                     if (peekNext() != TOK.assign && peekNext() != TOK.leftParenthesis)
5022                     {
5023                         error("`=` expected following identifier");
5024                         nextToken();
5025                         break;
5026                     }
5027                     continue;
5028 
5029                 default:
5030                     error("semicolon expected to close `alias` declaration, not `%s`", token.toChars());
5031                     break;
5032                 }
5033                 break;
5034             }
5035             return a;
5036         }
5037 
5038         // alias StorageClasses type ident;
5039         return null;
5040     }
5041 
5042     private AST.Dsymbol parseFunctionLiteral()
5043     {
5044         const loc = token.loc;
5045         AST.TemplateParameters* tpl = null;
5046         AST.ParameterList parameterList;
5047         AST.Type tret = null;
5048         StorageClass stc = 0;
5049         TOK save = TOK.reserved;
5050 
5051         switch (token.value)
5052         {
5053         case TOK.function_:
5054         case TOK.delegate_:
5055             save = token.value;
5056             nextToken();
5057             if (token.value == TOK.auto_)
5058             {
5059                 nextToken();
5060                 if (token.value == TOK.ref_)
5061                 {
5062                     // function auto ref (parameters) { statements... }
5063                     // delegate auto ref (parameters) { statements... }
5064                     stc = STC.auto_ | STC.ref_;
5065                     nextToken();
5066                 }
5067                 else
5068                     error("`auto` can only be used as part of `auto ref` for function literal return values");
5069             }
5070             else if (token.value == TOK.ref_)
5071             {
5072                 // function ref (parameters) { statements... }
5073                 // delegate ref (parameters) { statements... }
5074                 stc = STC.ref_;
5075                 nextToken();
5076             }
5077             if (token.value != TOK.leftParenthesis && token.value != TOK.leftCurly &&
5078                 token.value != TOK.goesTo)
5079             {
5080                 // function type (parameters) { statements... }
5081                 // delegate type (parameters) { statements... }
5082                 tret = parseBasicType();
5083                 tret = parseTypeSuffixes(tret); // function return type
5084             }
5085 
5086             if (token.value == TOK.leftParenthesis)
5087             {
5088                 // function (parameters) { statements... }
5089                 // delegate (parameters) { statements... }
5090             }
5091             else
5092             {
5093                 // function { statements... }
5094                 // delegate { statements... }
5095                 break;
5096             }
5097             goto case TOK.leftParenthesis;
5098 
5099         case TOK.auto_:
5100             {
5101                 nextToken();
5102                 if (token.value == TOK.ref_)
5103                 {
5104                     // auto ref (parameters) => expression
5105                     // auto ref (parameters) { statements... }
5106                     stc = STC.auto_ | STC.ref_;
5107                     nextToken();
5108                 }
5109                 else
5110                     error("`auto` can only be used as part of `auto ref` for function literal return values");
5111                 goto case TOK.leftParenthesis;
5112             }
5113         case TOK.ref_:
5114             {
5115                 // ref (parameters) => expression
5116                 // ref (parameters) { statements... }
5117                 stc = STC.ref_;
5118                 nextToken();
5119                 goto case TOK.leftParenthesis;
5120             }
5121         case TOK.leftParenthesis:
5122             {
5123                 // (parameters) => expression
5124                 // (parameters) { statements... }
5125                 parameterList = parseParameterList(&tpl);
5126                 stc = parsePostfix(stc, null);
5127                 if (StorageClass modStc = stc & STC.TYPECTOR)
5128                 {
5129                     if (save == TOK.function_)
5130                     {
5131                         OutBuffer buf;
5132                         AST.stcToBuffer(buf, modStc);
5133                         error("function literal cannot be `%s`", buf.peekChars());
5134                     }
5135                     else
5136                         save = TOK.delegate_;
5137                 }
5138                 break;
5139             }
5140         case TOK.leftCurly:
5141             // { statements... }
5142             break;
5143 
5144         case TOK.identifier:
5145             {
5146                 // identifier => expression
5147                 parameterList.parameters = new AST.Parameters();
5148                 Identifier id = Identifier.generateId("__T");
5149                 AST.Type t = new AST.TypeIdentifier(loc, id);
5150                 parameterList.parameters.push(new AST.Parameter(loc, STC.parameter, t, token.ident, null, null));
5151 
5152                 tpl = new AST.TemplateParameters();
5153                 AST.TemplateParameter tp = new AST.TemplateTypeParameter(loc, id, null, null);
5154                 tpl.push(tp);
5155 
5156                 nextToken();
5157                 break;
5158             }
5159         default:
5160             assert(0);
5161         }
5162 
5163         auto tf = new AST.TypeFunction(parameterList, tret, linkage, stc);
5164         tf = cast(AST.TypeFunction)tf.addSTC(stc);
5165         auto fd = new AST.FuncLiteralDeclaration(loc, Loc.initial, tf, save, null, null, stc & STC.auto_);
5166 
5167         if (token.value == TOK.goesTo)
5168         {
5169             check(TOK.goesTo);
5170             if (token.value == TOK.leftCurly)
5171             {
5172                 deprecation("using `(args) => { ... }` to create a delegate that returns a delegate is error-prone.");
5173                 deprecationSupplemental("Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate.");
5174             }
5175             const returnloc = token.loc;
5176             AST.Expression ae = parseAssignExp();
5177             fd.fbody = new AST.ReturnStatement(returnloc, ae);
5178             fd.endloc = token.loc;
5179         }
5180         else
5181         {
5182             parseContracts(fd);
5183         }
5184 
5185         if (tpl)
5186         {
5187             // Wrap a template around function fd
5188             auto decldefs = new AST.Dsymbols();
5189             decldefs.push(fd);
5190             return new AST.TemplateDeclaration(fd.loc, fd.ident, tpl, null, decldefs, false, true);
5191         }
5192         return fd;
5193     }
5194 
5195     /*****************************************
5196      * Parse contracts following function declaration.
5197      */
5198     private AST.FuncDeclaration parseContracts(AST.FuncDeclaration f, bool isTemplateFunction = false)
5199     {
5200         LINK linksave = linkage;
5201 
5202         bool literal = f.isFuncLiteralDeclaration() !is null;
5203 
5204         // The following is irrelevant, as it is overridden by sc.linkage in
5205         // TypeFunction::semantic
5206         linkage = LINK.d; // nested functions have D linkage
5207         bool requireDo = false;
5208     L1:
5209         switch (token.value)
5210         {
5211         case TOK.goesTo:
5212             if (requireDo)
5213                 error("missing `do { ... }` after `in` or `out`");
5214             const returnloc = token.loc;
5215             nextToken();
5216             f.fbody = new AST.ReturnStatement(returnloc, parseExpression());
5217             f.endloc = token.loc;
5218             check(TOK.semicolon);
5219             break;
5220 
5221         case TOK.leftCurly:
5222             if (requireDo)
5223                 error("missing `do { ... }` after `in` or `out`");
5224             f.fbody = parseStatement(0);
5225             f.endloc = endloc;
5226             break;
5227 
5228         case TOK.identifier:
5229             if (token.ident == Id._body)
5230             {
5231                 usageOfBodyKeyword();
5232                 goto case TOK.do_;
5233             }
5234             goto default;
5235 
5236         case TOK.do_:
5237             nextToken();
5238             f.fbody = parseStatement(ParseStatementFlags.curly);
5239             f.endloc = endloc;
5240             break;
5241 
5242             version (none)
5243             {
5244                 // Do we want this for function declarations, so we can do:
5245                 // int x, y, foo(), z;
5246             case TOK.comma:
5247                 nextToken();
5248                 continue;
5249             }
5250 
5251         case TOK.in_:
5252             // in { statements... }
5253             // in (expression)
5254             auto loc = token.loc;
5255             nextToken();
5256             if (!f.frequires)
5257             {
5258                 f.frequires = new AST.Statements;
5259             }
5260             if (token.value == TOK.leftParenthesis)
5261             {
5262                 nextToken();
5263                 AST.Expression e = parseAssignExp(), msg = null;
5264                 if (token.value == TOK.comma)
5265                 {
5266                     nextToken();
5267                     if (token.value != TOK.rightParenthesis)
5268                     {
5269                         msg = parseAssignExp();
5270                         if (token.value == TOK.comma)
5271                             nextToken();
5272                     }
5273                 }
5274                 check(TOK.rightParenthesis);
5275                 e = new AST.AssertExp(loc, e, msg);
5276                 f.frequires.push(new AST.ExpStatement(loc, e));
5277                 requireDo = false;
5278             }
5279             else
5280             {
5281                 auto ret = parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_);
5282                 assert(ret);
5283                 f.frequires.push(ret);
5284                 requireDo = true;
5285             }
5286             goto L1;
5287 
5288         case TOK.out_:
5289             // out { statements... }
5290             // out (; expression)
5291             // out (identifier) { statements... }
5292             // out (identifier; expression)
5293             auto loc = token.loc;
5294             nextToken();
5295             if (!f.fensures)
5296             {
5297                 f.fensures = new AST.Ensures;
5298             }
5299             Identifier id = null;
5300             if (token.value != TOK.leftCurly)
5301             {
5302                 check(TOK.leftParenthesis);
5303                 if (token.value != TOK.identifier && token.value != TOK.semicolon)
5304                     error("`(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `%s`", token.toChars());
5305                 if (token.value != TOK.semicolon)
5306                 {
5307                     id = token.ident;
5308                     nextToken();
5309                 }
5310                 if (token.value == TOK.semicolon)
5311                 {
5312                     nextToken();
5313                     AST.Expression e = parseAssignExp(), msg = null;
5314                     if (token.value == TOK.comma)
5315                     {
5316                         nextToken();
5317                         if (token.value != TOK.rightParenthesis)
5318                         {
5319                             msg = parseAssignExp();
5320                             if (token.value == TOK.comma)
5321                                 nextToken();
5322                         }
5323                     }
5324                     check(TOK.rightParenthesis);
5325                     e = new AST.AssertExp(loc, e, msg);
5326                     f.fensures.push(AST.Ensure(id, new AST.ExpStatement(loc, e)));
5327                     requireDo = false;
5328                     goto L1;
5329                 }
5330                 check(TOK.rightParenthesis);
5331             }
5332             f.fensures.push(AST.Ensure(id, parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_)));
5333             requireDo = true;
5334             goto L1;
5335 
5336         case TOK.semicolon:
5337             if (!literal)
5338             {
5339                 // https://issues.dlang.org/show_bug.cgi?id=15799
5340                 // Semicolon becomes a part of function declaration
5341                 // only when 'do' is not required
5342                 if (!requireDo)
5343                     nextToken();
5344                 break;
5345             }
5346             goto default;
5347 
5348         default:
5349             if (literal)
5350             {
5351                 const(char)* sbody = requireDo ? "do " : "";
5352                 error("missing `%s{ ... }` for function literal", sbody);
5353             }
5354             else if (!requireDo) // allow contracts even with no body
5355             {
5356                 TOK t = token.value;
5357                 if (t == TOK.const_ || t == TOK.immutable_ || t == TOK.inout_ || t == TOK.return_ ||
5358                         t == TOK.shared_ || t == TOK.nothrow_ || t == TOK.pure_)
5359                     error("'%s' cannot be placed after a template constraint", token.toChars);
5360                 else if (t == TOK.at)
5361                     error("attributes cannot be placed after a template constraint");
5362                 else if (t == TOK.if_)
5363                 {
5364                     if (isTemplateFunction)
5365                         error("template constraint must follow parameter lists and attributes");
5366                     else
5367                         error("cannot use function constraints for non-template functions. Use `static if` instead");
5368                 }
5369                 else
5370                     error("semicolon expected following function declaration, not `%s`", token.toChars());
5371             }
5372             break;
5373         }
5374         if (literal && !f.fbody)
5375         {
5376             // Set empty function body for error recovery
5377             f.fbody = new AST.CompoundStatement(Loc.initial, cast(AST.Statement)null);
5378         }
5379 
5380         linkage = linksave;
5381 
5382         return f;
5383     }
5384 
5385     /*****************************************
5386      */
5387     private void checkDanglingElse(Loc elseloc)
5388     {
5389         if (token.value != TOK.else_ && token.value != TOK.catch_ && token.value != TOK.finally_ && lookingForElse.linnum != 0)
5390         {
5391             eSink.warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
5392         }
5393     }
5394 
5395     /* *************************
5396      * Issue errors if C-style syntax
5397      * Params:
5398      *  alt = !=0 for C-style syntax
5399      */
5400     private void checkCstyleTypeSyntax(Loc loc, AST.Type t, int alt, Identifier ident)
5401     {
5402         if (!alt)
5403             return;
5404 
5405         const(char)* sp = !ident ? "" : " ";
5406         const(char)* s = !ident ? "" : ident.toChars();
5407         error(loc, "instead of C-style syntax, use D-style `%s%s%s`", t.toChars(), sp, s);
5408     }
5409 
5410     /*****************************
5411      * Ad-hoc error message for missing or extra parens that close a condition.
5412      * Params:
5413      *  start = "if", "while", etc. Must be 0 terminated.
5414      *  param = if the condition is a declaration, this will be non-null
5415      *  condition = if param is null, then this is the conditional Expression. If condition is null,
5416      *      then an error in the condition was already reported.
5417      */
5418     private void closeCondition(string start, AST.Parameter param, AST.Expression condition)
5419     {
5420         string format;
5421         if (token.value != TOK.rightParenthesis && condition)
5422         {
5423             format = "missing closing `)` after `%s (%s`";
5424         }
5425         else
5426             check(TOK.rightParenthesis);
5427         if (token.value == TOK.rightParenthesis)
5428         {
5429             if (condition) // if not an error in condition
5430                 format = "extra `)` after `%s (%s)`";
5431             nextToken();
5432         }
5433         if (format)
5434             error(token.loc, format.ptr, start.ptr, param ? "declaration".ptr : condition.toChars());
5435     }
5436 
5437     /*****************************************
5438      * Parses `foreach` statements, `static foreach` statements and
5439      * `static foreach` declarations.
5440      * Params:
5441      *  Foreach = one of Statement, StaticForeachStatement, StaticForeachDeclaration
5442      *  loc = location of foreach
5443      *  pLastDecl = non-null for StaticForeachDeclaration
5444      * Returns:
5445      *  the Foreach generated
5446      */
5447     private Foreach parseForeach(alias Foreach)(Loc loc, AST.Dsymbol* pLastDecl)
5448     {
5449         static if (is(Foreach == AST.StaticForeachStatement) || is(Foreach == AST.StaticForeachDeclaration))
5450         {
5451             nextToken();
5452         }
5453 
5454         TOK op = token.value;
5455 
5456         nextToken();
5457         check(TOK.leftParenthesis);
5458 
5459         auto parameters = new AST.Parameters();
5460         Identifier lastai;
5461         while (1)
5462         {
5463             Identifier ai = null;
5464             AST.Type at;
5465             Loc aloc;
5466 
5467             StorageClass storageClass = 0;
5468             StorageClass stc = 0;
5469         Lagain:
5470             if (stc)
5471             {
5472                 storageClass = appendStorageClass(storageClass, stc);
5473                 nextToken();
5474             }
5475             switch (token.value)
5476             {
5477                 case TOK.ref_:
5478                     stc = STC.ref_;
5479                     goto Lagain;
5480 
5481                 case TOK.scope_:
5482                     stc = STC.scope_;
5483                     goto Lagain;
5484 
5485                 case TOK.out_:
5486                     error("cannot declare `out` loop variable, use `ref` instead");
5487                     stc = STC.out_;
5488                     goto Lagain;
5489 
5490                 case TOK.auto_:
5491                     error("cannot declare `auto` loop variable, omit `auto` to still get type inference");
5492                     stc = STC.auto_;
5493                     goto Lagain;
5494 
5495                 case TOK.enum_:
5496                     stc = STC.manifest;
5497                     goto Lagain;
5498 
5499                 case TOK.alias_:
5500                     storageClass = appendStorageClass(storageClass, STC.alias_);
5501                     nextToken();
5502                     break;
5503 
5504                 case TOK.const_:
5505                     if (peekNext() != TOK.leftParenthesis)
5506                     {
5507                         stc = STC.const_;
5508                         goto Lagain;
5509                     }
5510                     break;
5511 
5512                 case TOK.immutable_:
5513                     if (peekNext() != TOK.leftParenthesis)
5514                     {
5515                         stc = STC.immutable_;
5516                         goto Lagain;
5517                     }
5518                     break;
5519 
5520                 case TOK.shared_:
5521                     if (peekNext() != TOK.leftParenthesis)
5522                     {
5523                         stc = STC.shared_;
5524                         goto Lagain;
5525                     }
5526                     break;
5527 
5528                 case TOK.inout_:
5529                     if (peekNext() != TOK.leftParenthesis)
5530                     {
5531                         stc = STC.wild;
5532                         goto Lagain;
5533                     }
5534                     break;
5535 
5536                 default:
5537                     break;
5538             }
5539             if (token.value == TOK.identifier)
5540             {
5541                 const tv = peekNext();
5542                 if (tv == TOK.comma || tv == TOK.semicolon || tv == TOK.rightParenthesis)
5543                 {
5544                     lastai = token.ident;
5545                     ai = token.ident;
5546                     at = null; // infer argument type
5547                     aloc = token.loc;
5548                     nextToken();
5549                     goto Larg;
5550                 }
5551             }
5552             at = parseType(&ai);
5553             if (!ai)
5554                 noIdentifierForDeclarator(at);
5555         Larg:
5556             auto p = new AST.Parameter(aloc, storageClass, at, ai, null, null);
5557             parameters.push(p);
5558             if (token.value == TOK.comma)
5559             {
5560                 nextToken();
5561                 continue;
5562             }
5563             break;
5564         }
5565         if (token.value != TOK.semicolon)
5566         {
5567             error("missing `; expression` before `)` of `foreach`");
5568             nextToken();
5569             if (lastai && parameters.length >= 2)
5570             {
5571                 eSink.errorSupplemental(loc, "perhaps the `;` goes before `%s`", lastai.toChars());
5572             }
5573             return null;
5574         }
5575         nextToken();
5576 
5577         AST.Expression aggr = parseExpression();
5578         if (token.value == TOK.slice && parameters.length == 1)
5579         {
5580             AST.Parameter p = (*parameters)[0];
5581             nextToken();
5582             AST.Expression upr = parseExpression();
5583             check(TOK.rightParenthesis);
5584             Loc endloc;
5585             static if (is(Foreach == AST.Statement) || is(Foreach == AST.StaticForeachStatement))
5586             {
5587                 AST.Statement _body = parseStatement(0, null, &endloc);
5588             }
5589             else
5590             {
5591                 AST.Statement _body = null;
5592             }
5593             auto rangefe = new AST.ForeachRangeStatement(loc, op, p, aggr, upr, _body, endloc);
5594             static if (is(Foreach == AST.Statement))
5595             {
5596                 return rangefe;
5597             }
5598             else static if(is(Foreach == AST.StaticForeachDeclaration))
5599             {
5600                 return new AST.StaticForeachDeclaration(new AST.StaticForeach(loc, null, rangefe), parseBlock(pLastDecl));
5601             }
5602             else static if (is(Foreach == AST.StaticForeachStatement))
5603             {
5604                 return new AST.StaticForeachStatement(loc, new AST.StaticForeach(loc, null, rangefe));
5605             }
5606         }
5607         else
5608         {
5609             check(TOK.rightParenthesis);
5610             Loc endloc;
5611             static if (is(Foreach == AST.Statement) || is(Foreach == AST.StaticForeachStatement))
5612             {
5613                 AST.Statement _body = parseStatement(0, null, &endloc);
5614             }
5615             else
5616             {
5617                 AST.Statement _body = null;
5618             }
5619             auto aggrfe = new AST.ForeachStatement(loc, op, parameters, aggr, _body, endloc);
5620             static if (is(Foreach == AST.Statement))
5621             {
5622                 return aggrfe;
5623             }
5624             else static if(is(Foreach == AST.StaticForeachDeclaration))
5625             {
5626                 return new AST.StaticForeachDeclaration(new AST.StaticForeach(loc, aggrfe, null), parseBlock(pLastDecl));
5627             }
5628             else static if (is(Foreach == AST.StaticForeachStatement))
5629             {
5630                 return new AST.StaticForeachStatement(loc, new AST.StaticForeach(loc, aggrfe, null));
5631             }
5632         }
5633 
5634     }
5635 
5636     /***
5637      * Parse an assignment condition for if or while statements.
5638      *
5639      * Returns:
5640      *      The variable that is declared inside the condition
5641      */
5642     AST.Parameter parseAssignCondition()
5643     {
5644         AST.Parameter param = null;
5645         StorageClass storageClass = 0;
5646         StorageClass stc = 0;
5647     Lwhile:
5648         while (1)
5649         {
5650             switch (token.value)
5651             {
5652             // parse ref for better error
5653             case TOK.ref_:
5654                 stc = STC.ref_;
5655                 break;
5656 
5657             case TOK.scope_:
5658                 stc = STC.scope_;
5659                 break;
5660 
5661             case TOK.auto_:
5662                 stc = STC.auto_;
5663                 break;
5664 
5665             case TOK.const_:
5666                 if (peekNext() != TOK.leftParenthesis)
5667                 {
5668                     stc = STC.const_;
5669                     break;
5670                 }
5671                 goto default;
5672 
5673             case TOK.immutable_:
5674                 if (peekNext() != TOK.leftParenthesis)
5675                 {
5676                     stc = STC.immutable_;
5677                     break;
5678                 }
5679                 goto default;
5680 
5681             case TOK.shared_:
5682                 if (peekNext() != TOK.leftParenthesis)
5683                 {
5684                     stc = STC.shared_;
5685                     break;
5686                 }
5687                 goto default;
5688 
5689             case TOK.inout_:
5690                 if (peekNext() != TOK.leftParenthesis)
5691                 {
5692                     stc = STC.wild;
5693                     break;
5694                 }
5695                 goto default;
5696 
5697             default:
5698                 break Lwhile;
5699             }
5700             storageClass = appendStorageClass(storageClass, stc);
5701             nextToken();
5702         }
5703         auto n = peek(&token);
5704         if (storageClass != 0 && token.value == TOK.identifier && n.value == TOK.assign)
5705         {
5706             Identifier ai = token.ident;
5707             AST.Type at = null; // infer parameter type
5708             const aloc = token.loc;
5709             nextToken();
5710             check(TOK.assign);
5711             param = new AST.Parameter(aloc, storageClass, at, ai, null, null);
5712         }
5713         else if (isDeclaration(&token, NeedDeclaratorId.must, TOK.assign, null))
5714         {
5715             Identifier ai;
5716             const aloc = token.loc;
5717             AST.Type at = parseType(&ai);
5718             check(TOK.assign);
5719             param = new AST.Parameter(aloc, storageClass, at, ai, null, null);
5720         }
5721         else if (storageClass != 0)
5722             error("found `%s` while expecting `=` or identifier", n.toChars());
5723 
5724         return param;
5725     }
5726 
5727     /*****************************************
5728      * Input:
5729      *      flags   PSxxxx
5730      * Output:
5731      *      pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement
5732      */
5733     AST.Statement parseStatement(int flags, const(char)** endPtr = null, Loc* pEndloc = null)
5734     {
5735         AST.Statement s;
5736         AST.Condition cond;
5737         AST.Statement ifbody;
5738         AST.Statement elsebody;
5739         bool isfinal;
5740         const loc = token.loc;
5741 
5742         //printf("parseStatement()\n");
5743         if (flags & ParseStatementFlags.curly && token.value != TOK.leftCurly)
5744             error("statement expected to be `{ }`, not `%s`", token.toChars());
5745 
5746         switch (token.value)
5747         {
5748         case TOK.identifier:
5749             {
5750                 /* A leading identifier can be a declaration, label, or expression.
5751                  * The easiest case to check first is label:
5752                  */
5753                 if (peekNext() == TOK.colonColon)
5754                 {
5755                     // skip ident::
5756                     nextToken();
5757                     nextToken();
5758                     error("use `.` for member lookup, not `::`");
5759                     break;
5760                 }
5761 
5762                 if (peekNext() == TOK.colon)
5763                 {
5764                     // It's a label
5765                     Identifier ident = token.ident;
5766                     nextToken();
5767                     nextToken();
5768                     if (token.value == TOK.rightCurly)
5769                         s = null;
5770                     else if (token.value == TOK.leftCurly)
5771                         s = parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_);
5772                     else if (flags & ParseStatementFlags.curlyScope)
5773                         s = parseStatement(ParseStatementFlags.semiOk | ParseStatementFlags.curlyScope);
5774                     else
5775                         s = parseStatement(ParseStatementFlags.semiOk);
5776                     s = new AST.LabelStatement(loc, ident, s);
5777                     break;
5778                 }
5779                 goto case TOK.dot;
5780             }
5781         case TOK.dot:
5782         case TOK.typeof_:
5783         case TOK.vector:
5784         case TOK.traits:
5785             /* https://issues.dlang.org/show_bug.cgi?id=15163
5786              * If tokens can be handled as
5787              * old C-style declaration or D expression, prefer the latter.
5788              */
5789             if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
5790                 goto Ldeclaration;
5791             goto Lexp;
5792 
5793         case TOK.assert_:
5794         case TOK.this_:
5795         case TOK.super_:
5796         case TOK.int32Literal:
5797         case TOK.uns32Literal:
5798         case TOK.int64Literal:
5799         case TOK.uns64Literal:
5800         case TOK.int128Literal:
5801         case TOK.uns128Literal:
5802         case TOK.float32Literal:
5803         case TOK.float64Literal:
5804         case TOK.float80Literal:
5805         case TOK.imaginary32Literal:
5806         case TOK.imaginary64Literal:
5807         case TOK.imaginary80Literal:
5808         case TOK.charLiteral:
5809         case TOK.wcharLiteral:
5810         case TOK.dcharLiteral:
5811         case TOK.null_:
5812         case TOK.true_:
5813         case TOK.false_:
5814         case TOK.string_:
5815         case TOK.hexadecimalString:
5816         case TOK.leftParenthesis:
5817         case TOK.cast_:
5818         case TOK.mul:
5819         case TOK.min:
5820         case TOK.add:
5821         case TOK.tilde:
5822         case TOK.not:
5823         case TOK.plusPlus:
5824         case TOK.minusMinus:
5825         case TOK.new_:
5826         case TOK.delete_:
5827         case TOK.delegate_:
5828         case TOK.function_:
5829         case TOK.typeid_:
5830         case TOK.is_:
5831         case TOK.leftBracket:
5832         case TOK.file:
5833         case TOK.fileFullPath:
5834         case TOK.line:
5835         case TOK.moduleString:
5836         case TOK.functionString:
5837         case TOK.prettyFunction:
5838         Lexp:
5839             {
5840                 AST.Expression exp = parseExpression();
5841                 /* https://issues.dlang.org/show_bug.cgi?id=15103
5842                  * Improve declaration / initialization syntax error message
5843                  * Error: found 'foo' when expecting ';' following expression
5844                  * becomes Error: found `(` when expecting `;` or `=`, did you mean `Foo foo = 42`?
5845                  */
5846                 if (token.value == TOK.identifier && exp.op == EXP.identifier)
5847                 {
5848                     error(token.loc, "found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
5849                     nextToken();
5850                 }
5851                 else
5852                 {
5853                     /*
5854                      * https://issues.dlang.org/show_bug.cgi?id=22529
5855                      * Avoid empty declaration error in case of missing semicolon
5856                      * followed by another token and another semicolon. E.g.:
5857                      *
5858                      *  foo()
5859                      *  return;
5860                      *
5861                      * When the missing `;` error is emitted, token is sitting on return.
5862                      * If we simply use `check` to emit the error, the token is advanced
5863                      * to `;` and the empty statement error would follow. To avoid that,
5864                      * we check if the next token is a semicolon and simply output the error,
5865                      * otherwise we fall back on the old path (advancing the token).
5866                      */
5867                     if (token.value != TOK.semicolon && peek(&token).value == TOK.semicolon)
5868                         error("found `%s` when expecting `;` following expression", token.toChars());
5869                     else
5870                     {
5871                         if (token.value != TOK.semicolon)
5872                         {
5873                             error("found `%s` when expecting `;` following expression", token.toChars());
5874                             eSink.errorSupplemental(exp.loc, "expression: `%s`", exp.toChars());
5875                         }
5876                         nextToken();
5877                     }
5878                 }
5879                 s = new AST.ExpStatement(loc, exp);
5880                 break;
5881             }
5882         case TOK.static_:
5883             {
5884                 // Look ahead to see if it's static assert() or static if()
5885                 const tv = peekNext();
5886                 if (tv == TOK.assert_)
5887                 {
5888                     s = new AST.StaticAssertStatement(parseStaticAssert());
5889                     break;
5890                 }
5891                 if (tv == TOK.if_)
5892                 {
5893                     cond = parseStaticIfCondition();
5894                     goto Lcondition;
5895                 }
5896                 if (tv == TOK.foreach_ || tv == TOK.foreach_reverse_)
5897                 {
5898                     s = parseForeach!(AST.StaticForeachStatement)(loc, null);
5899                     if (flags & ParseStatementFlags.scope_)
5900                         s = new AST.ScopeStatement(loc, s, token.loc);
5901                     break;
5902                 }
5903                 if (tv == TOK.import_)
5904                 {
5905                     AST.Dsymbols* imports = parseImport();
5906                     s = new AST.ImportStatement(loc, imports);
5907                     if (flags & ParseStatementFlags.scope_)
5908                         s = new AST.ScopeStatement(loc, s, token.loc);
5909                     break;
5910                 }
5911                 goto Ldeclaration;
5912             }
5913         case TOK.final_:
5914             if (peekNext() == TOK.switch_)
5915             {
5916                 nextToken();
5917                 isfinal = true;
5918                 goto Lswitch;
5919             }
5920             goto Ldeclaration;
5921 
5922         case TOK.wchar_:
5923         case TOK.dchar_:
5924         case TOK.bool_:
5925         case TOK.char_:
5926         case TOK.int8:
5927         case TOK.uns8:
5928         case TOK.int16:
5929         case TOK.uns16:
5930         case TOK.int32:
5931         case TOK.uns32:
5932         case TOK.int64:
5933         case TOK.uns64:
5934         case TOK.int128:
5935         case TOK.uns128:
5936         case TOK.float32:
5937         case TOK.float64:
5938         case TOK.float80:
5939         case TOK.imaginary32:
5940         case TOK.imaginary64:
5941         case TOK.imaginary80:
5942         case TOK.complex32:
5943         case TOK.complex64:
5944         case TOK.complex80:
5945         case TOK.void_:
5946             // bug 7773: int.max is always a part of expression
5947             if (peekNext() == TOK.dot)
5948                 goto Lexp;
5949             if (peekNext() == TOK.leftParenthesis)
5950                 goto Lexp;
5951             goto case;
5952 
5953         case TOK.alias_:
5954         case TOK.const_:
5955         case TOK.auto_:
5956         case TOK.abstract_:
5957         case TOK.extern_:
5958         case TOK.align_:
5959         case TOK.immutable_:
5960         case TOK.shared_:
5961         case TOK.inout_:
5962         case TOK.deprecated_:
5963         case TOK.nothrow_:
5964         case TOK.pure_:
5965         case TOK.ref_:
5966         case TOK.gshared:
5967         case TOK.at:
5968         case TOK.struct_:
5969         case TOK.union_:
5970         case TOK.class_:
5971         case TOK.interface_:
5972         Ldeclaration:
5973             {
5974                 AST.Dsymbols* a = parseDeclarations(false, null, null);
5975                 if (a.length > 1)
5976                 {
5977                     auto as = new AST.Statements();
5978                     as.reserve(a.length);
5979                     foreach (i; 0 .. a.length)
5980                     {
5981                         AST.Dsymbol d = (*a)[i];
5982                         s = new AST.ExpStatement(loc, d);
5983                         as.push(s);
5984                     }
5985                     s = new AST.CompoundDeclarationStatement(loc, as);
5986                 }
5987                 else if (a.length == 1)
5988                 {
5989                     AST.Dsymbol d = (*a)[0];
5990                     s = new AST.ExpStatement(loc, d);
5991                 }
5992                 else
5993                     s = new AST.ExpStatement(loc, cast(AST.Expression)null);
5994                 if (flags & ParseStatementFlags.scope_)
5995                     s = new AST.ScopeStatement(loc, s, token.loc);
5996                 break;
5997             }
5998         case TOK.enum_:
5999             {
6000                 /* Determine if this is a manifest constant declaration,
6001                  * or a conventional enum.
6002                  */
6003                 AST.Dsymbol d;
6004                 const tv = peekNext();
6005                 if (tv == TOK.leftCurly || tv == TOK.colon)
6006                     d = parseEnum();
6007                 else if (tv != TOK.identifier)
6008                     goto Ldeclaration;
6009                 else
6010                 {
6011                     const nextv = peekNext2();
6012                     if (nextv == TOK.leftCurly || nextv == TOK.colon || nextv == TOK.semicolon)
6013                         d = parseEnum();
6014                     else
6015                         goto Ldeclaration;
6016                 }
6017                 s = new AST.ExpStatement(loc, d);
6018                 if (flags & ParseStatementFlags.scope_)
6019                     s = new AST.ScopeStatement(loc, s, token.loc);
6020                 break;
6021             }
6022         case TOK.mixin_:
6023             {
6024                 if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
6025                     goto Ldeclaration;
6026                 const tv = peekNext();
6027                 if (tv == TOK.leftParenthesis)
6028                 {
6029                     // mixin(string)
6030                     AST.Expression e = parseAssignExp();
6031                     check(TOK.semicolon, "mixin");
6032                     if (e.op == EXP.mixin_)
6033                     {
6034                         AST.MixinExp cpe = cast(AST.MixinExp)e;
6035                         s = new AST.MixinStatement(loc, cpe.exps);
6036                     }
6037                     else
6038                     {
6039                         s = new AST.ExpStatement(loc, e);
6040                     }
6041                     break;
6042                 }
6043                 else if (tv == TOK.template_)
6044                 {
6045                     // mixin template
6046                     nextToken();
6047                     AST.Dsymbol d = parseTemplateDeclaration(true);
6048                     s = new AST.ExpStatement(loc, d);
6049                     break;
6050                 }
6051                 AST.Dsymbol d = parseMixin();
6052                 s = new AST.ExpStatement(loc, d);
6053                 if (flags & ParseStatementFlags.scope_)
6054                     s = new AST.ScopeStatement(loc, s, token.loc);
6055                 break;
6056             }
6057         case TOK.leftCurly:
6058             {
6059                 const lcLoc = token.loc;
6060                 const lookingForElseSave = lookingForElse;
6061                 lookingForElse = Loc.initial;
6062 
6063                 nextToken();
6064                 //if (token.value == TOK.semicolon)
6065                 //    error("use `{ }` for an empty statement, not `;`");
6066                 auto statements = new AST.Statements();
6067                 while (token.value != TOK.rightCurly && token.value != TOK.endOfFile)
6068                 {
6069                     statements.push(parseStatement(ParseStatementFlags.curlyScope | ParseStatementFlags.semiOk));
6070                 }
6071                 if (endPtr)
6072                     *endPtr = token.ptr;
6073                 endloc = token.loc;
6074                 if (pEndloc)
6075                 {
6076                     *pEndloc = token.loc;
6077                     pEndloc = null; // don't set it again
6078                 }
6079                 s = new AST.CompoundStatement(loc, statements);
6080                 if (flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope))
6081                     s = new AST.ScopeStatement(loc, s, token.loc);
6082                 if (token.value != TOK.rightCurly)
6083                 {
6084                     error(token.loc, "matching `}` expected following compound statement, not `%s`",
6085                         token.toChars());
6086                     eSink.errorSupplemental(lcLoc, "unmatched `{`");
6087                 }
6088                 else
6089                     nextToken();
6090                 lookingForElse = lookingForElseSave;
6091                 break;
6092             }
6093         case TOK.while_:
6094             {
6095                 nextToken();
6096                 check(TOK.leftParenthesis);
6097                 auto param = parseAssignCondition();
6098                 auto condition = parseExpression();
6099                 closeCondition("while", param, condition);
6100 
6101                 Loc endloc;
6102                 AST.Statement _body = parseStatement(ParseStatementFlags.scope_, null, &endloc);
6103                 s = new AST.WhileStatement(loc, condition, _body, endloc, param);
6104                 break;
6105             }
6106         case TOK.semicolon:
6107             if (!(flags & ParseStatementFlags.semiOk))
6108             {
6109                 error("use `{ }` for an empty statement, not `;`");
6110             }
6111             nextToken();
6112             s = new AST.ExpStatement(loc, cast(AST.Expression)null);
6113             break;
6114 
6115         case TOK.do_:
6116             {
6117                 AST.Statement _body;
6118 
6119                 nextToken();
6120                 const lookingForElseSave = lookingForElse;
6121                 lookingForElse = Loc.initial;
6122                 _body = parseStatement(ParseStatementFlags.scope_);
6123                 lookingForElse = lookingForElseSave;
6124                 check(TOK.while_);
6125                 check(TOK.leftParenthesis);
6126                 auto condition = parseExpression();
6127                 closeCondition("do .. while", null, condition);
6128                 if (token.value == TOK.semicolon)
6129                     nextToken();
6130                 else
6131                     error("terminating `;` required after do-while statement");
6132                 s = new AST.DoStatement(loc, _body, condition, token.loc);
6133                 break;
6134             }
6135         case TOK.for_:
6136             {
6137                 AST.Statement _init;
6138                 AST.Expression condition;
6139                 AST.Expression increment;
6140 
6141                 nextToken();
6142                 check(TOK.leftParenthesis);
6143                 if (token.value == TOK.semicolon)
6144                 {
6145                     _init = null;
6146                     nextToken();
6147                 }
6148                 else
6149                 {
6150                     const lookingForElseSave = lookingForElse;
6151                     lookingForElse = Loc.initial;
6152                     _init = parseStatement(0);
6153                     lookingForElse = lookingForElseSave;
6154                 }
6155                 if (token.value == TOK.semicolon)
6156                 {
6157                     condition = null;
6158                     nextToken();
6159                 }
6160                 else
6161                 {
6162                     condition = parseExpression();
6163                     check(TOK.semicolon, "`for` condition");
6164                 }
6165                 if (token.value == TOK.rightParenthesis)
6166                 {
6167                     increment = null;
6168                     nextToken();
6169                 }
6170                 else
6171                 {
6172                     increment = parseExpression();
6173                     check(TOK.rightParenthesis);
6174                 }
6175                 Loc endloc;
6176                 AST.Statement _body = parseStatement(ParseStatementFlags.scope_, null, &endloc);
6177                 s = new AST.ForStatement(loc, _init, condition, increment, _body, endloc);
6178                 break;
6179             }
6180         case TOK.foreach_:
6181         case TOK.foreach_reverse_:
6182             {
6183                 s = parseForeach!(AST.Statement)(loc, null);
6184                 break;
6185             }
6186         case TOK.if_:
6187             {
6188                 nextToken();
6189                 check(TOK.leftParenthesis);
6190                 auto param = parseAssignCondition();
6191                 auto condition = parseExpression();
6192                 closeCondition("if", param, condition);
6193 
6194                 {
6195                     const lookingForElseSave = lookingForElse;
6196                     lookingForElse = loc;
6197                     ifbody = parseStatement(ParseStatementFlags.scope_);
6198                     lookingForElse = lookingForElseSave;
6199                 }
6200                 if (token.value == TOK.else_)
6201                 {
6202                     const elseloc = token.loc;
6203                     nextToken();
6204                     elsebody = parseStatement(ParseStatementFlags.scope_);
6205                     checkDanglingElse(elseloc);
6206                 }
6207                 else
6208                     elsebody = null;
6209                 if (condition && ifbody)
6210                     s = new AST.IfStatement(loc, param, condition, ifbody, elsebody, token.loc);
6211                 else
6212                     s = null; // don't propagate parsing errors
6213                 break;
6214             }
6215 
6216         case TOK.else_:
6217             error("found `else` without a corresponding `if`, `version` or `debug` statement");
6218             goto Lerror;
6219 
6220         case TOK.scope_:
6221             if (peekNext() != TOK.leftParenthesis)
6222                 goto Ldeclaration; // scope used as storage class
6223             nextToken();
6224             check(TOK.leftParenthesis);
6225             if (token.value != TOK.identifier)
6226             {
6227                 error("scope identifier expected");
6228                 goto Lerror;
6229             }
6230             else
6231             {
6232                 TOK t = TOK.onScopeExit;
6233                 Identifier id = token.ident;
6234                 if (id == Id.exit)
6235                     t = TOK.onScopeExit;
6236                 else if (id == Id.failure)
6237                     t = TOK.onScopeFailure;
6238                 else if (id == Id.success)
6239                     t = TOK.onScopeSuccess;
6240                 else
6241                     error("valid scope identifiers are `exit`, `failure`, or `success`, not `%s`", id.toChars());
6242                 nextToken();
6243                 check(TOK.rightParenthesis);
6244                 AST.Statement st = parseStatement(ParseStatementFlags.scope_);
6245                 s = new AST.ScopeGuardStatement(loc, t, st);
6246                 break;
6247             }
6248 
6249         case TOK.debug_:
6250             nextToken();
6251             if (token.value == TOK.assign)
6252             {
6253                 if (auto ds = parseDebugSpecification())
6254                 {
6255                     if (ds.ident)
6256                         eSink.error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars);
6257                     else
6258                         eSink.error(ds.loc, "%s `%s` level declaration must be at module level", ds.kind, ds.toPrettyChars);
6259                 }
6260                 break;
6261             }
6262             cond = parseDebugCondition();
6263             goto Lcondition;
6264 
6265         case TOK.version_:
6266             nextToken();
6267             if (token.value == TOK.assign)
6268             {
6269                 if (auto vs = parseVersionSpecification())
6270                 {
6271                     if (vs.ident)
6272                         eSink.error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars);
6273                     else
6274                         eSink.error(vs.loc, "%s `%s` level declaration must be at module level", vs.kind, vs.toPrettyChars);
6275                 }
6276                 break;
6277             }
6278             cond = parseVersionCondition();
6279             goto Lcondition;
6280 
6281         Lcondition:
6282             {
6283                 const lookingForElseSave = lookingForElse;
6284                 lookingForElse = loc;
6285                 ifbody = parseStatement(0);
6286                 lookingForElse = lookingForElseSave;
6287             }
6288             elsebody = null;
6289             if (token.value == TOK.else_)
6290             {
6291                 const elseloc = token.loc;
6292                 nextToken();
6293                 elsebody = parseStatement(0);
6294                 checkDanglingElse(elseloc);
6295             }
6296             s = new AST.ConditionalStatement(loc, cond, ifbody, elsebody);
6297             if (flags & ParseStatementFlags.scope_)
6298                 s = new AST.ScopeStatement(loc, s, token.loc);
6299             break;
6300 
6301         case TOK.pragma_:
6302             {
6303                 Identifier ident;
6304                 AST.Expressions* args = null;
6305                 AST.Statement _body;
6306 
6307                 nextToken();
6308                 check(TOK.leftParenthesis);
6309                 if (token.value != TOK.identifier)
6310                 {
6311                     error("`pragma(identifier)` expected");
6312                     goto Lerror;
6313                 }
6314                 ident = token.ident;
6315                 nextToken();
6316                 if (token.value == TOK.comma && peekNext() != TOK.rightParenthesis)
6317                     args = parseArguments(); // pragma(identifier, args...);
6318                 else
6319                     check(TOK.rightParenthesis); // pragma(identifier);
6320                 if (token.value == TOK.semicolon)
6321                 {
6322                     nextToken();
6323                     _body = null;
6324                 }
6325                 else
6326                     _body = parseStatement(0);
6327                 s = new AST.PragmaStatement(loc, ident, args, _body);
6328                 break;
6329             }
6330         case TOK.switch_:
6331             isfinal = false;
6332             goto Lswitch;
6333 
6334         Lswitch:
6335             {
6336                 nextToken();
6337                 check(TOK.leftParenthesis);
6338                 auto param = parseAssignCondition();
6339                 AST.Expression condition = parseExpression();
6340                 closeCondition("switch", null, condition);
6341                 AST.Statement _body = parseStatement(ParseStatementFlags.scope_);
6342                 s = new AST.SwitchStatement(loc, param, condition, _body, isfinal, token.loc);
6343                 break;
6344             }
6345         case TOK.case_:
6346             {
6347                 AST.Expression exp;
6348                 AST.Expressions cases; // array of Expression's
6349                 AST.Expression last = null;
6350 
6351                 nextToken();
6352                 do
6353                 {
6354                     exp = parseAssignExp();
6355                     cases.push(exp);
6356                     if (token.value != TOK.comma)
6357                         break;
6358                     nextToken(); //comma
6359                 }
6360                 while (token.value != TOK.colon && token.value != TOK.endOfFile);
6361                 check(TOK.colon);
6362 
6363                 /* case exp: .. case last:
6364                  */
6365                 if (token.value == TOK.slice)
6366                 {
6367                     if (cases.length > 1)
6368                         error("only one `case` allowed for start of case range");
6369                     nextToken();
6370                     check(TOK.case_);
6371                     last = parseAssignExp();
6372                     check(TOK.colon);
6373                 }
6374 
6375                 if (flags & ParseStatementFlags.curlyScope)
6376                 {
6377                     auto statements = new AST.Statements();
6378                     while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
6379                     {
6380                         auto cur = parseStatement(ParseStatementFlags.curlyScope);
6381                         statements.push(cur);
6382 
6383                         // https://issues.dlang.org/show_bug.cgi?id=21739
6384                         // Stop at the last break s.t. the following non-case statements are
6385                         // not merged into the current case. This can happen for
6386                         // case 1: ... break;
6387                         // debug { case 2: ... }
6388                         if (cur && cur.isBreakStatement())
6389                             break;
6390                     }
6391                     s = new AST.CompoundStatement(loc, statements);
6392                 }
6393                 else
6394                 {
6395                     s = parseStatement(0);
6396                 }
6397                 s = new AST.ScopeStatement(loc, s, token.loc);
6398 
6399                 if (last)
6400                 {
6401                     s = new AST.CaseRangeStatement(loc, exp, last, s);
6402                 }
6403                 else
6404                 {
6405                     // Keep cases in order by building the case statements backwards
6406                     for (size_t i = cases.length; i; i--)
6407                     {
6408                         exp = cases[i - 1];
6409                         s = new AST.CaseStatement(loc, exp, s);
6410                     }
6411                 }
6412                 break;
6413             }
6414         case TOK.default_:
6415             {
6416                 nextToken();
6417                 check(TOK.colon);
6418 
6419                 if (flags & ParseStatementFlags.curlyScope)
6420                 {
6421                     auto statements = new AST.Statements();
6422                     while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
6423                     {
6424                         statements.push(parseStatement(ParseStatementFlags.curlyScope));
6425                     }
6426                     s = new AST.CompoundStatement(loc, statements);
6427                 }
6428                 else
6429                     s = parseStatement(0);
6430                 s = new AST.ScopeStatement(loc, s, token.loc);
6431                 s = new AST.DefaultStatement(loc, s);
6432                 break;
6433             }
6434         case TOK.return_:
6435             {
6436                 AST.Expression exp;
6437                 nextToken();
6438                 exp = token.value == TOK.semicolon ? null : parseExpression();
6439                 check(TOK.semicolon, "`return` statement");
6440                 s = new AST.ReturnStatement(loc, exp);
6441                 break;
6442             }
6443         case TOK.break_:
6444             {
6445                 Identifier ident;
6446                 nextToken();
6447                 ident = null;
6448                 if (token.value == TOK.identifier)
6449                 {
6450                     ident = token.ident;
6451                     nextToken();
6452                 }
6453                 check(TOK.semicolon, "`break` statement");
6454                 s = new AST.BreakStatement(loc, ident);
6455                 break;
6456             }
6457         case TOK.continue_:
6458             {
6459                 Identifier ident;
6460                 nextToken();
6461                 ident = null;
6462                 if (token.value == TOK.identifier)
6463                 {
6464                     ident = token.ident;
6465                     nextToken();
6466                 }
6467                 check(TOK.semicolon, "`continue` statement");
6468                 s = new AST.ContinueStatement(loc, ident);
6469                 break;
6470             }
6471         case TOK.goto_:
6472             {
6473                 Identifier ident;
6474                 nextToken();
6475                 if (token.value == TOK.default_)
6476                 {
6477                     nextToken();
6478                     s = new AST.GotoDefaultStatement(loc);
6479                 }
6480                 else if (token.value == TOK.case_)
6481                 {
6482                     AST.Expression exp = null;
6483                     nextToken();
6484                     if (token.value != TOK.semicolon)
6485                         exp = parseExpression();
6486                     s = new AST.GotoCaseStatement(loc, exp);
6487                 }
6488                 else
6489                 {
6490                     if (token.value != TOK.identifier)
6491                     {
6492                         error("identifier expected following `goto`");
6493                         ident = null;
6494                     }
6495                     else
6496                     {
6497                         ident = token.ident;
6498                         nextToken();
6499                     }
6500                     s = new AST.GotoStatement(loc, ident);
6501                 }
6502                 check(TOK.semicolon, "`goto` statement");
6503                 break;
6504             }
6505         case TOK.synchronized_:
6506             {
6507                 AST.Expression exp;
6508                 AST.Statement _body;
6509 
6510                 Token* t = peek(&token);
6511                 if (skipAttributes(t, &t) && t.value == TOK.class_)
6512                     goto Ldeclaration;
6513 
6514                 nextToken();
6515                 if (token.value == TOK.leftParenthesis)
6516                 {
6517                     nextToken();
6518                     exp = parseExpression();
6519                     closeCondition("synchronized", null, exp);
6520                 }
6521                 else
6522                     exp = null;
6523                 _body = parseStatement(ParseStatementFlags.scope_);
6524                 s = new AST.SynchronizedStatement(loc, exp, _body);
6525                 break;
6526             }
6527         case TOK.with_:
6528             {
6529                 AST.Expression exp;
6530                 AST.Statement _body;
6531                 Loc endloc = loc;
6532 
6533                 nextToken();
6534                 check(TOK.leftParenthesis);
6535                 exp = parseExpression();
6536                 closeCondition("with", null, exp);
6537                 _body = parseStatement(ParseStatementFlags.scope_, null, &endloc);
6538                 s = new AST.WithStatement(loc, exp, _body, endloc);
6539                 break;
6540             }
6541         case TOK.try_:
6542             {
6543                 AST.Statement _body;
6544                 AST.Catches* catches = null;
6545                 AST.Statement finalbody = null;
6546 
6547                 nextToken();
6548                 const lookingForElseSave = lookingForElse;
6549                 lookingForElse = Loc.initial;
6550                 _body = parseStatement(ParseStatementFlags.scope_);
6551                 lookingForElse = lookingForElseSave;
6552                 while (token.value == TOK.catch_)
6553                 {
6554                     AST.Statement handler;
6555                     AST.Catch c;
6556                     AST.Type t;
6557                     Identifier id;
6558                     const catchloc = token.loc;
6559 
6560                     nextToken();
6561                     if (token.value != TOK.leftParenthesis)
6562                     {
6563                         deprecation("`catch` statement without an exception specification is deprecated");
6564                         deprecationSupplemental("use `catch(Throwable)` for old behavior");
6565                         t = null;
6566                         id = null;
6567                     }
6568                     else
6569                     {
6570                         check(TOK.leftParenthesis);
6571                         id = null;
6572                         t = parseType(&id);
6573                         check(TOK.rightParenthesis);
6574                     }
6575                     handler = parseStatement(0);
6576                     c = new AST.Catch(catchloc, t, id, handler);
6577                     if (!catches)
6578                         catches = new AST.Catches();
6579                     catches.push(c);
6580                 }
6581 
6582                 if (token.value == TOK.finally_)
6583                 {
6584                     nextToken();
6585                     finalbody = parseStatement(ParseStatementFlags.scope_);
6586                 }
6587 
6588                 s = _body;
6589                 if (!catches && !finalbody)
6590                     error("`catch` or `finally` expected following `try`");
6591                 else
6592                 {
6593                     if (catches)
6594                         s = new AST.TryCatchStatement(loc, _body, catches);
6595                     if (finalbody)
6596                         s = new AST.TryFinallyStatement(loc, s, finalbody);
6597                 }
6598                 break;
6599             }
6600         case TOK.throw_:
6601             {
6602                 AST.Expression exp;
6603                 nextToken();
6604                 exp = parseExpression();
6605                 check(TOK.semicolon, "`throw` statement");
6606                 s = new AST.ThrowStatement(loc, exp);
6607                 break;
6608             }
6609 
6610         case TOK.asm_:
6611             s = parseAsm(false);
6612             break;
6613 
6614         case TOK.import_:
6615             {
6616                 /* https://issues.dlang.org/show_bug.cgi?id=16088
6617                  *
6618                  * At this point it can either be an
6619                  * https://dlang.org/spec/grammar.html#ImportExpression
6620                  * or an
6621                  * https://dlang.org/spec/grammar.html#ImportDeclaration.
6622                  * See if the next token after `import` is a `(`; if so,
6623                  * then it is an import expression.
6624                  */
6625                 if (peekNext() == TOK.leftParenthesis)
6626                 {
6627                     AST.Expression e = parseExpression();
6628                     check(TOK.semicolon, "`import` Expression");
6629                     s = new AST.ExpStatement(loc, e);
6630                 }
6631                 else
6632                 {
6633                     AST.Dsymbols* imports = parseImport();
6634                     s = new AST.ImportStatement(loc, imports);
6635                     if (flags & ParseStatementFlags.scope_)
6636                         s = new AST.ScopeStatement(loc, s, token.loc);
6637                 }
6638                 break;
6639             }
6640         case TOK.template_:
6641             {
6642                 AST.Dsymbol d = parseTemplateDeclaration();
6643                 s = new AST.ExpStatement(loc, d);
6644                 break;
6645             }
6646         default:
6647             error("found `%s` instead of statement", token.toChars());
6648             goto Lerror;
6649 
6650         Lerror:
6651             while (token.value != TOK.rightCurly && token.value != TOK.semicolon && token.value != TOK.endOfFile)
6652                 nextToken();
6653             if (token.value == TOK.semicolon)
6654                 nextToken();
6655             s = new AST.ErrorStatement;
6656             break;
6657         }
6658         if (pEndloc)
6659             *pEndloc = prevloc;
6660         return s;
6661     }
6662 
6663 
6664     private  AST.ExpInitializer parseExpInitializer(Loc loc)
6665     {
6666         auto ae = parseAssignExp();
6667         return new AST.ExpInitializer(loc, ae);
6668     }
6669 
6670     private AST.Initializer parseStructInitializer(Loc loc)
6671     {
6672         /* Scan ahead to discern between a struct initializer and
6673          * parameterless function literal.
6674          *
6675          * We'll scan the topmost curly bracket level for statement-related
6676          * tokens, thereby ruling out a struct initializer.  (A struct
6677          * initializer which itself contains function literals may have
6678          * statements at nested curly bracket levels.)
6679          *
6680          * It's important that this function literal check not be
6681          * pendantic, otherwise a function having the slightest syntax
6682          * error would emit confusing errors when we proceed to parse it
6683          * as a struct initializer.
6684          *
6685          * The following two ambiguous cases will be treated as a struct
6686          * initializer (best we can do without type info):
6687          *     {}
6688          *     {{statements...}}  - i.e. it could be struct initializer
6689          *        with one function literal, or function literal having an
6690          *        extra level of curly brackets
6691          * If a function literal is intended in these cases (unlikely),
6692          * source can use a more explicit function literal syntax
6693          * (e.g. prefix with "()" for empty parameter list).
6694          */
6695         int braces = 1;
6696         int parens = 0;
6697         for (auto t = peek(&token); 1; t = peek(t))
6698         {
6699             switch (t.value)
6700             {
6701                 case TOK.leftParenthesis:
6702                     parens++;
6703                     continue;
6704                 case TOK.rightParenthesis:
6705                     parens--;
6706                     continue;
6707                 // https://issues.dlang.org/show_bug.cgi?id=21163
6708                 // lambda params can have the `scope` storage class, e.g
6709                 // `S s = { (scope Type Id){} }`
6710                 case TOK.scope_:
6711                     if (!parens) goto case;
6712                     continue;
6713                 /* Look for a semicolon or keyword of statements which don't
6714                  * require a semicolon (typically containing BlockStatement).
6715                  * Tokens like "else", "catch", etc. are omitted where the
6716                  * leading token of the statement is sufficient.
6717                  */
6718                 case TOK.asm_:
6719                 case TOK.class_:
6720                 case TOK.debug_:
6721                 case TOK.enum_:
6722                 case TOK.if_:
6723                 case TOK.interface_:
6724                 case TOK.pragma_:
6725                 case TOK.semicolon:
6726                 case TOK.struct_:
6727                 case TOK.switch_:
6728                 case TOK.synchronized_:
6729                 case TOK.try_:
6730                 case TOK.union_:
6731                 case TOK.version_:
6732                 case TOK.while_:
6733                 case TOK.with_:
6734                     if (braces == 1)
6735                         return parseExpInitializer(loc);
6736                     continue;
6737 
6738                 case TOK.leftCurly:
6739                     braces++;
6740                     continue;
6741 
6742                 case TOK.rightCurly:
6743                     if (--braces == 0)
6744                         break;
6745                     continue;
6746 
6747                 case TOK.endOfFile:
6748                     break;
6749 
6750                 default:
6751                     continue;
6752             }
6753             break;
6754         }
6755 
6756         auto _is = new AST.StructInitializer(loc);
6757         bool commaExpected = false;
6758         nextToken();
6759         while (1)
6760         {
6761             switch (token.value)
6762             {
6763                 case TOK.identifier:
6764                 {
6765 
6766                     if (commaExpected)
6767                         error("comma expected separating field initializers");
6768                     const t = peek(&token);
6769                     Identifier id;
6770                     if (t.value == TOK.colon)
6771                     {
6772                         id = token.ident;
6773                         nextToken();
6774                         nextToken(); // skip over ':'
6775                     }
6776                     auto value = parseInitializer();
6777                     _is.addInit(id, value);
6778                     commaExpected = true;
6779                     continue;
6780                 }
6781                 case TOK.comma:
6782                     if (!commaExpected)
6783                         error("expression expected, not `,`");
6784                     nextToken();
6785                     commaExpected = false;
6786                     continue;
6787 
6788                 case TOK.rightCurly: // allow trailing comma's
6789                     nextToken();
6790                     break;
6791 
6792                 case TOK.endOfFile:
6793                     error("found end of file instead of initializer");
6794                     break;
6795 
6796                 default:
6797                     if (commaExpected)
6798                         error("comma expected separating field initializers");
6799                     auto value = parseInitializer();
6800                     _is.addInit(null, value);
6801                     commaExpected = true;
6802                     continue;
6803             }
6804             break;
6805         }
6806         return _is;
6807 
6808     }
6809 
6810     /*****************************************
6811      * Parse initializer for variable declaration.
6812      */
6813     private AST.Initializer parseInitializer()
6814     {
6815         const loc = token.loc;
6816 
6817         switch (token.value)
6818         {
6819         case TOK.leftCurly:
6820             return parseStructInitializer(loc);
6821 
6822         case TOK.leftBracket:
6823             /* Scan ahead to see if it is an array initializer or
6824              * an expression.
6825              * If it ends with a ';' ',' or ']', it is an array initializer.
6826              */
6827             int brackets = 1;
6828             for (auto t = peek(&token); 1; t = peek(t))
6829             {
6830                 switch (t.value)
6831                 {
6832                 case TOK.leftBracket:
6833                     brackets++;
6834                     continue;
6835 
6836                 case TOK.rightBracket:
6837                     if (--brackets == 0)
6838                     {
6839                         t = peek(t);
6840                         if (t.value != TOK.semicolon && t.value != TOK.comma && t.value != TOK.rightBracket && t.value != TOK.rightCurly)
6841                             return parseExpInitializer(loc);
6842                         break;
6843                     }
6844                     continue;
6845 
6846                 case TOK.endOfFile:
6847                     break;
6848 
6849                 default:
6850                     continue;
6851                 }
6852                 break;
6853             }
6854 
6855             auto ia = new AST.ArrayInitializer(loc);
6856             bool commaExpected = false;
6857 
6858             nextToken();
6859             while (1)
6860             {
6861                 switch (token.value)
6862                 {
6863                 default:
6864                     if (commaExpected)
6865                     {
6866                         error("comma expected separating array initializers, not `%s`", token.toChars());
6867                         nextToken();
6868                         break;
6869                     }
6870                     auto e = parseAssignExp();
6871                     if (!e)
6872                         break;
6873 
6874                     AST.Initializer value;
6875                     if (token.value == TOK.colon)
6876                     {
6877                         nextToken();
6878                         value = parseInitializer();
6879                     }
6880                     else
6881                     {
6882                         value = new AST.ExpInitializer(e.loc, e);
6883                         e = null;
6884                     }
6885                     ia.addInit(e, value);
6886                     commaExpected = true;
6887                     continue;
6888 
6889                 case TOK.leftCurly:
6890                 case TOK.leftBracket:
6891                     if (commaExpected)
6892                         error("comma expected separating array initializers, not `%s`", token.toChars());
6893                     auto value = parseInitializer();
6894                     AST.Expression e;
6895 
6896                     if (token.value == TOK.colon)
6897                     {
6898                         nextToken();
6899                         if (auto ei = value.isExpInitializer())
6900                         {
6901                             e = ei.exp;
6902                             value = parseInitializer();
6903                         }
6904                         else
6905                             error("initializer expression expected following colon, not `%s`", token.toChars());
6906                     }
6907                     ia.addInit(e, value);
6908                     commaExpected = true;
6909                     continue;
6910 
6911                 case TOK.comma:
6912                     if (!commaExpected)
6913                         error("expression expected, not `,`");
6914                     nextToken();
6915                     commaExpected = false;
6916                     continue;
6917 
6918                 case TOK.rightBracket: // allow trailing comma's
6919                     nextToken();
6920                     break;
6921 
6922                 case TOK.endOfFile:
6923                     error("found `%s` instead of array initializer", token.toChars());
6924                     break;
6925                 }
6926                 break;
6927             }
6928             return ia;
6929 
6930         case TOK.void_:
6931             const tv = peekNext();
6932             if (tv == TOK.semicolon || tv == TOK.comma)
6933             {
6934                 nextToken();
6935                 return new AST.VoidInitializer(loc);
6936             }
6937             return parseExpInitializer(loc);
6938 
6939         default:
6940             return parseExpInitializer(loc);
6941         }
6942     }
6943 
6944     /*****************************************
6945      * Parses default argument initializer expression that is an assign expression,
6946      * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
6947      */
6948     private AST.Expression parseDefaultInitExp()
6949     {
6950         AST.Expression e = null;
6951         const tv = peekNext();
6952         if (tv == TOK.comma || tv == TOK.rightParenthesis)
6953         {
6954             switch (token.value)
6955             {
6956             case TOK.file:           e = new AST.FileInitExp(token.loc, EXP.file); break;
6957             case TOK.fileFullPath:   e = new AST.FileInitExp(token.loc, EXP.fileFullPath); break;
6958             case TOK.line:           e = new AST.LineInitExp(token.loc); break;
6959             case TOK.moduleString:   e = new AST.ModuleInitExp(token.loc); break;
6960             case TOK.functionString: e = new AST.FuncInitExp(token.loc); break;
6961             case TOK.prettyFunction: e = new AST.PrettyFuncInitExp(token.loc); break;
6962             default: goto LExp;
6963             }
6964             nextToken();
6965             return e;
6966         }
6967         LExp:
6968         return parseAssignExp();
6969     }
6970 
6971     /********************
6972      * Parse inline assembler block.
6973      * Enters with token on the `asm`.
6974      * https://dlang.org/spec/iasm.html
6975      *
6976      * AsmStatement:
6977      *   asm FunctionAttributes(opt) { AsmInstructionListopt }
6978      * AsmInstructionList:
6979      *   AsmInstruction ;
6980      *   AsmInstruction ; AsmInstruction
6981      *
6982      * Params:
6983      *   endOfLine = true if EOL means end of asm statement
6984      * Returns:
6985      *   inline assembler block as a Statement
6986      */
6987     AST.Statement parseAsm(bool endOfLine)
6988     {
6989         // Parse the asm block into a sequence of AsmStatements,
6990         // each AsmStatement is one instruction.
6991         // Separate out labels.
6992         // Defer parsing of AsmStatements until semantic processing.
6993 
6994         const loc = token.loc;
6995         Loc labelloc;
6996 
6997         nextToken();
6998         StorageClass stc = parsePostfix(STC.undefined_, null);  // optional FunctionAttributes
6999         if (stc & (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild))
7000             error("`const`/`immutable`/`shared`/`inout` attributes are not allowed on `asm` blocks");
7001 
7002         check(TOK.leftCurly);
7003         Token* toklist = null;
7004         Token** ptoklist = &toklist;
7005         Identifier label = null;
7006         auto statements = new AST.Statements();
7007         size_t nestlevel = 0;
7008         while (1)
7009         {
7010             if (endOfLine)
7011                 nextDefineLine();
7012             switch (token.value)
7013             {
7014             case TOK.identifier:
7015                 if (!toklist)
7016                 {
7017                     // Look ahead to see if it is a label
7018                     if (peekNext() == TOK.colon)
7019                     {
7020                         // It's a label
7021                         label = token.ident;
7022                         labelloc = token.loc;
7023                         nextToken();
7024                         nextToken();
7025                         continue;
7026                     }
7027                 }
7028                 goto default;
7029 
7030             case TOK.leftCurly:
7031                 ++nestlevel;
7032                 goto default;
7033 
7034             case TOK.rightCurly:
7035                 if (nestlevel > 0)
7036                 {
7037                     --nestlevel;
7038                     goto default;
7039                 }
7040                 if (toklist || label)
7041                 {
7042                     error("`asm` statements must end in `;`");
7043                 }
7044                 break;
7045 
7046             case TOK.endOfLine:
7047                 nextDefineLine();
7048                 goto case;
7049 
7050             case TOK.semicolon:
7051                 if (nestlevel != 0)
7052                     error("mismatched number of curly brackets");
7053 
7054                 if (toklist || label)
7055                 {
7056                     // Create AsmStatement from list of tokens we've saved
7057                     AST.AsmStatement as = new AST.AsmStatement(token.loc, toklist);
7058                     as.caseSensitive = !endOfLine;
7059                     AST.Statement s = as;
7060                     toklist = null;
7061                     ptoklist = &toklist;
7062                     if (label)
7063                     {
7064                         s = new AST.LabelStatement(labelloc, label, s);
7065                         label = null;
7066                     }
7067                     statements.push(s);
7068                 }
7069                 nextToken();
7070                 continue;
7071 
7072             case TOK.endOfFile:
7073                 /* { */
7074                 error("matching `}` expected, not end of file");
7075                 break;
7076 
7077             case TOK.colonColon:  // treat as two separate : tokens for iasmgcc
7078                 *ptoklist = allocateToken();
7079                 memcpy(*ptoklist, &token, Token.sizeof);
7080                 (*ptoklist).value = TOK.colon;
7081                 ptoklist = &(*ptoklist).next;
7082 
7083                 *ptoklist = allocateToken();
7084                 memcpy(*ptoklist, &token, Token.sizeof);
7085                 (*ptoklist).value = TOK.colon;
7086                 ptoklist = &(*ptoklist).next;
7087 
7088                 *ptoklist = null;
7089                 nextToken();
7090                 continue;
7091 
7092             default:
7093                 *ptoklist = allocateToken();
7094                 memcpy(*ptoklist, &token, Token.sizeof);
7095                 ptoklist = &(*ptoklist).next;
7096                 *ptoklist = null;
7097                 nextToken();
7098                 continue;
7099             }
7100             break;
7101         }
7102         nextToken();
7103         if (token.value == TOK.endOfLine)
7104             nextToken();
7105         auto s = new AST.CompoundAsmStatement(loc, statements, stc);
7106         return s;
7107     }
7108 
7109     /**********************************
7110      * Issue error if the current token is not `value`,
7111      * advance to next token.
7112      * Params:
7113      *  loc = location for error message
7114      *  value = token value to compare with
7115      */
7116     void check(Loc loc, TOK value)
7117     {
7118         if (token.value != value)
7119             error(loc, "found `%s` when expecting `%s`", token.toChars(), Token.toChars(value));
7120         nextToken();
7121     }
7122 
7123     /**********************************
7124      * Issue error if the current token is not `value`,
7125      * advance to next token.
7126      * Params:
7127      *  value = token value to compare with
7128      */
7129     void check(TOK value)
7130     {
7131         check(token.loc, value);
7132     }
7133 
7134     /**********************************
7135      * Issue error if the current token is not `value`,
7136      * advance to next token.
7137      * Params:
7138      *  value = token value to compare with
7139      *  string = for error message
7140      */
7141     void check(TOK value, const(char)* string)
7142     {
7143         if (token.value != value)
7144             error(token.loc, "found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(value), string);
7145         nextToken();
7146     }
7147 
7148     private void checkParens(TOK value, AST.Expression e)
7149     {
7150         if (precedence[e.op] == PREC.rel)
7151             error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(value));
7152     }
7153 
7154     ///
7155     enum NeedDeclaratorId
7156     {
7157         no,             // Declarator part must have no identifier
7158         opt,            // Declarator part identifier is optional
7159         must,           // Declarator part must have identifier
7160         mustIfDstyle,   // Declarator part must have identifier, but don't recognize old C-style syntax
7161     }
7162 
7163     /************************************
7164      * Determine if the scanner is sitting on the start of a declaration.
7165      * Params:
7166      *      t       = current token of the scanner
7167      *      needId  = flag with additional requirements for a declaration
7168      *      endtok  = ending token
7169      *      pt      = will be set ending token (if not null)
7170      * Output:
7171      *      true if the token `t` is a declaration, false otherwise
7172      */
7173     private bool isDeclaration(Token* t, NeedDeclaratorId needId, TOK endtok, Token** pt)
7174     {
7175         //printf("isDeclaration(needId = %d)\n", needId);
7176         int haveId = 0;
7177         int haveTpl = 0;
7178 
7179         while (1)
7180         {
7181             if ((t.value == TOK.const_ || t.value == TOK.immutable_ || t.value == TOK.inout_ || t.value == TOK.shared_) && peek(t).value != TOK.leftParenthesis)
7182             {
7183                 /* const type
7184                  * immutable type
7185                  * shared type
7186                  * wild type
7187                  */
7188                 t = peek(t);
7189                 continue;
7190             }
7191             break;
7192         }
7193 
7194         if (!isBasicType(&t))
7195         {
7196             goto Lisnot;
7197         }
7198         if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != NeedDeclaratorId.mustIfDstyle))
7199             goto Lisnot;
7200         if ((needId == NeedDeclaratorId.no && !haveId) ||
7201             (needId == NeedDeclaratorId.opt) ||
7202             (needId == NeedDeclaratorId.must && haveId) ||
7203             (needId == NeedDeclaratorId.mustIfDstyle && haveId))
7204         {
7205             if (pt)
7206                 *pt = t;
7207             goto Lis;
7208         }
7209         goto Lisnot;
7210 
7211     Lis:
7212         //printf("\tis declaration, t = %s\n", t.toChars());
7213         return true;
7214 
7215     Lisnot:
7216         //printf("\tis not declaration\n");
7217         return false;
7218     }
7219 
7220     private bool isBasicType(Token** pt)
7221     {
7222         // This code parallels parseBasicType()
7223         Token* t = *pt;
7224         switch (t.value)
7225         {
7226         case TOK.wchar_:
7227         case TOK.dchar_:
7228         case TOK.bool_:
7229         case TOK.char_:
7230         case TOK.int8:
7231         case TOK.uns8:
7232         case TOK.int16:
7233         case TOK.uns16:
7234         case TOK.int32:
7235         case TOK.uns32:
7236         case TOK.int64:
7237         case TOK.uns64:
7238         case TOK.int128:
7239         case TOK.uns128:
7240         case TOK.float32:
7241         case TOK.float64:
7242         case TOK.float80:
7243         case TOK.imaginary32:
7244         case TOK.imaginary64:
7245         case TOK.imaginary80:
7246         case TOK.complex32:
7247         case TOK.complex64:
7248         case TOK.complex80:
7249         case TOK.void_:
7250             t = peek(t);
7251             break;
7252 
7253         case TOK.identifier:
7254         L5:
7255             t = peek(t);
7256             if (t.value == TOK.not)
7257             {
7258                 goto L4;
7259             }
7260             goto L3;
7261             while (1)
7262             {
7263             L2:
7264                 t = peek(t);
7265             L3:
7266                 if (t.value == TOK.dot)
7267                 {
7268                 Ldot:
7269                     t = peek(t);
7270                     if (t.value != TOK.identifier)
7271                         goto Lfalse;
7272                     t = peek(t);
7273                     if (t.value != TOK.not)
7274                         goto L3;
7275                 L4:
7276                     /* Seen a !
7277                      * Look for:
7278                      * !( args ), !identifier, etc.
7279                      */
7280                     t = peek(t);
7281                     switch (t.value)
7282                     {
7283                     case TOK.identifier:
7284                         goto L5;
7285 
7286                     case TOK.leftParenthesis:
7287                         if (!skipParens(t, &t))
7288                             goto Lfalse;
7289                         goto L3;
7290 
7291                     case TOK.wchar_:
7292                     case TOK.dchar_:
7293                     case TOK.bool_:
7294                     case TOK.char_:
7295                     case TOK.int8:
7296                     case TOK.uns8:
7297                     case TOK.int16:
7298                     case TOK.uns16:
7299                     case TOK.int32:
7300                     case TOK.uns32:
7301                     case TOK.int64:
7302                     case TOK.uns64:
7303                     case TOK.int128:
7304                     case TOK.uns128:
7305                     case TOK.float32:
7306                     case TOK.float64:
7307                     case TOK.float80:
7308                     case TOK.imaginary32:
7309                     case TOK.imaginary64:
7310                     case TOK.imaginary80:
7311                     case TOK.complex32:
7312                     case TOK.complex64:
7313                     case TOK.complex80:
7314                     case TOK.void_:
7315                     case TOK.int32Literal:
7316                     case TOK.uns32Literal:
7317                     case TOK.int64Literal:
7318                     case TOK.uns64Literal:
7319                     case TOK.int128Literal:
7320                     case TOK.uns128Literal:
7321                     case TOK.float32Literal:
7322                     case TOK.float64Literal:
7323                     case TOK.float80Literal:
7324                     case TOK.imaginary32Literal:
7325                     case TOK.imaginary64Literal:
7326                     case TOK.imaginary80Literal:
7327                     case TOK.null_:
7328                     case TOK.true_:
7329                     case TOK.false_:
7330                     case TOK.charLiteral:
7331                     case TOK.wcharLiteral:
7332                     case TOK.dcharLiteral:
7333                     case TOK.string_:
7334                     case TOK.hexadecimalString:
7335                     case TOK.file:
7336                     case TOK.fileFullPath:
7337                     case TOK.line:
7338                     case TOK.moduleString:
7339                     case TOK.functionString:
7340                     case TOK.prettyFunction:
7341                         goto L2;
7342 
7343                     default:
7344                         goto Lfalse;
7345                     }
7346                 }
7347                 break;
7348             }
7349             break;
7350 
7351         case TOK.dot:
7352             goto Ldot;
7353 
7354         case TOK.typeof_:
7355         case TOK.vector:
7356         case TOK.mixin_:
7357             /* typeof(exp).identifier...
7358              */
7359             t = peek(t);
7360             if (!skipParens(t, &t))
7361                 goto Lfalse;
7362             goto L3;
7363 
7364         case TOK.traits:
7365             // __traits(getMember
7366             t = peek(t);
7367             if (t.value != TOK.leftParenthesis)
7368                 goto Lfalse;
7369             auto lp = t;
7370             t = peek(t);
7371             if (t.value != TOK.identifier || t.ident != Id.getMember)
7372                 goto Lfalse;
7373             if (!skipParens(lp, &lp))
7374                 goto Lfalse;
7375             // we are in a lookup for decl VS statement
7376             // so we expect a declarator following __trait if it's a type.
7377             // other usages wont be ambiguous (alias, template instance, type qual, etc.)
7378             if (lp.value != TOK.identifier)
7379                 goto Lfalse;
7380 
7381             break;
7382 
7383         case TOK.const_:
7384         case TOK.immutable_:
7385         case TOK.shared_:
7386         case TOK.inout_:
7387             // const(type)  or  immutable(type)  or  shared(type)  or  wild(type)
7388             t = peek(t);
7389             if (t.value != TOK.leftParenthesis)
7390                 goto Lfalse;
7391             t = peek(t);
7392             if (!isDeclaration(t, NeedDeclaratorId.no, TOK.rightParenthesis, &t))
7393             {
7394                 goto Lfalse;
7395             }
7396             t = peek(t);
7397             break;
7398 
7399         default:
7400             goto Lfalse;
7401         }
7402         *pt = t;
7403         //printf("is\n");
7404         return true;
7405 
7406     Lfalse:
7407         //printf("is not\n");
7408         return false;
7409     }
7410 
7411     private bool isDeclarator(Token** pt, int* haveId, int* haveTpl, TOK endtok, bool allowAltSyntax = true)
7412     {
7413         // This code parallels parseDeclarator()
7414         Token* t = *pt;
7415         bool parens;
7416 
7417         //printf("Parser::isDeclarator() %s\n", t.toChars());
7418         if (t.value == TOK.assign)
7419             return false;
7420 
7421         while (1)
7422         {
7423             parens = false;
7424             switch (t.value)
7425             {
7426             case TOK.mul:
7427             //case TOK.and:
7428                 t = peek(t);
7429                 continue;
7430 
7431             case TOK.leftBracket:
7432                 t = peek(t);
7433                 if (t.value == TOK.rightBracket)
7434                 {
7435                     t = peek(t);
7436                 }
7437                 else if (isDeclaration(t, NeedDeclaratorId.no, TOK.rightBracket, &t))
7438                 {
7439                     // It's an associative array declaration
7440                     t = peek(t);
7441 
7442                     // ...[type].ident
7443                     if (t.value == TOK.dot && peek(t).value == TOK.identifier)
7444                     {
7445                         t = peek(t);
7446                         t = peek(t);
7447                     }
7448                 }
7449                 else
7450                 {
7451                     // [ expression ]
7452                     // [ expression .. expression ]
7453                     if (!isExpression(&t))
7454                         return false;
7455                     if (t.value == TOK.slice)
7456                     {
7457                         t = peek(t);
7458                         if (!isExpression(&t))
7459                             return false;
7460                         if (t.value != TOK.rightBracket)
7461                             return false;
7462                         t = peek(t);
7463                     }
7464                     else
7465                     {
7466                         if (t.value != TOK.rightBracket)
7467                             return false;
7468                         t = peek(t);
7469                         // ...[index].ident
7470                         if (t.value == TOK.dot && peek(t).value == TOK.identifier)
7471                         {
7472                             t = peek(t);
7473                             t = peek(t);
7474                         }
7475                     }
7476                 }
7477                 continue;
7478 
7479             case TOK.identifier:
7480                 if (*haveId)
7481                     return false;
7482                 *haveId = true;
7483                 t = peek(t);
7484                 break;
7485 
7486             case TOK.leftParenthesis:
7487                 if (!allowAltSyntax)
7488                     return false;   // Do not recognize C-style declarations.
7489 
7490                 t = peek(t);
7491                 if (t.value == TOK.rightParenthesis)
7492                     return false; // () is not a declarator
7493 
7494                 /* Regard ( identifier ) as not a declarator
7495                  * BUG: what about ( *identifier ) in
7496                  *      f(*p)(x);
7497                  * where f is a class instance with overloaded () ?
7498                  * Should we just disallow C-style function pointer declarations?
7499                  */
7500                 if (t.value == TOK.identifier)
7501                 {
7502                     Token* t2 = peek(t);
7503                     if (t2.value == TOK.rightParenthesis)
7504                         return false;
7505                 }
7506 
7507                 if (!isDeclarator(&t, haveId, null, TOK.rightParenthesis))
7508                     return false;
7509                 t = peek(t);
7510                 parens = true;
7511                 break;
7512 
7513             case TOK.delegate_:
7514             case TOK.function_:
7515                 t = peek(t);
7516                 if (!isParameters(&t))
7517                     return false;
7518                 skipAttributes(t, &t);
7519                 continue;
7520 
7521             default:
7522                 break;
7523             }
7524             break;
7525         }
7526 
7527         while (1)
7528         {
7529             switch (t.value)
7530             {
7531                 static if (CARRAYDECL)
7532                 {
7533                 case TOK.leftBracket:
7534                     parens = false;
7535                     t = peek(t);
7536                     if (t.value == TOK.rightBracket)
7537                     {
7538                         t = peek(t);
7539                     }
7540                     else if (isDeclaration(t, NeedDeclaratorId.no, TOK.rightBracket, &t))
7541                     {
7542                         // It's an associative array declaration
7543                         t = peek(t);
7544                     }
7545                     else
7546                     {
7547                         // [ expression ]
7548                         if (!isExpression(&t))
7549                             return false;
7550                         if (t.value != TOK.rightBracket)
7551                             return false;
7552                         t = peek(t);
7553                     }
7554                     continue;
7555                 }
7556 
7557             case TOK.leftParenthesis:
7558                 parens = false;
7559                 if (Token* tk = peekPastParen(t))
7560                 {
7561                     if (tk.value == TOK.leftParenthesis)
7562                     {
7563                         if (!haveTpl)
7564                             return false;
7565                         *haveTpl = 1;
7566                         t = tk;
7567                     }
7568                     else if (tk.value == TOK.assign)
7569                     {
7570                         if (!haveTpl)
7571                             return false;
7572                         *haveTpl = 1;
7573                         *pt = tk;
7574                         return true;
7575                     }
7576                 }
7577                 if (!isParameters(&t))
7578                     return false;
7579                 while (1)
7580                 {
7581                     switch (t.value)
7582                     {
7583                     case TOK.const_:
7584                     case TOK.immutable_:
7585                     case TOK.shared_:
7586                     case TOK.inout_:
7587                     case TOK.pure_:
7588                     case TOK.nothrow_:
7589                     case TOK.return_:
7590                     case TOK.scope_:
7591                         t = peek(t);
7592                         continue;
7593 
7594                     case TOK.at:
7595                         t = peek(t); // skip '@'
7596                         t = peek(t); // skip identifier
7597                         continue;
7598 
7599                     default:
7600                         break;
7601                     }
7602                     break;
7603                 }
7604                 continue;
7605 
7606             // Valid tokens that follow the start of a declaration
7607             case TOK.rightParenthesis:
7608             case TOK.rightBracket:
7609             case TOK.assign:
7610             case TOK.comma:
7611             case TOK.dotDotDot:
7612             case TOK.semicolon:
7613             case TOK.leftCurly:
7614             case TOK.in_:
7615             case TOK.out_:
7616             case TOK.do_:
7617                 // The !parens is to disallow unnecessary parentheses
7618                 if (!parens && (endtok == TOK.reserved || endtok == t.value))
7619                 {
7620                     *pt = t;
7621                     return true;
7622                 }
7623                 return false;
7624 
7625             // To recognize the shortened function declaration syntax
7626             case TOK.goesTo:
7627                 /*
7628                     1. https://issues.dlang.org/show_bug.cgi?id=24088
7629 
7630                     2. We need to make sure the would-be
7631                        declarator has an identifier otherwise function literals
7632                        are handled incorrectly. Some special treatment is required
7633                        here, it turns out that a lot of code in the compiler relies
7634                        on this mess (in the parser), i.e. having isDeclarator be more
7635                        precise the parsing of other things go kaboom, so we do it in a
7636                        separate case.
7637                 */
7638                 if (*haveId)
7639                     goto case TOK.do_;
7640                 goto default;
7641 
7642             case TOK.identifier:
7643                 if (t.ident == Id._body)
7644                 {
7645                     usageOfBodyKeyword();
7646                     goto case TOK.do_;
7647                 }
7648                 goto default;
7649 
7650             case TOK.if_:
7651                 return haveTpl ? true : false;
7652 
7653             // Used for mixin type parsing
7654             case TOK.endOfFile:
7655                 if (endtok == TOK.endOfFile)
7656                     goto case TOK.do_;
7657                 return false;
7658 
7659             default:
7660                 return false;
7661             }
7662         }
7663         assert(0);
7664     }
7665 
7666     private bool isParameters(Token** pt)
7667     {
7668         // This code parallels parseParameterList()
7669         Token* t = *pt;
7670 
7671         //printf("isParameters()\n");
7672         if (t.value != TOK.leftParenthesis)
7673             return false;
7674 
7675         t = peek(t);
7676         for (; 1; t = peek(t))
7677         {
7678         L1:
7679             switch (t.value)
7680             {
7681             case TOK.rightParenthesis:
7682                 break;
7683 
7684             case TOK.at:
7685                 Token* pastAttr;
7686                 if (skipAttributes(t, &pastAttr))
7687                 {
7688                     t = pastAttr;
7689                     goto default;
7690                 }
7691                 break;
7692 
7693             case TOK.dotDotDot:
7694                 t = peek(t);
7695                 break;
7696 
7697             case TOK.in_:
7698             case TOK.out_:
7699             case TOK.ref_:
7700             case TOK.lazy_:
7701             case TOK.scope_:
7702             case TOK.final_:
7703             case TOK.auto_:
7704             case TOK.return_:
7705                 continue;
7706 
7707             case TOK.const_:
7708             case TOK.immutable_:
7709             case TOK.shared_:
7710             case TOK.inout_:
7711                 t = peek(t);
7712                 if (t.value == TOK.leftParenthesis)
7713                 {
7714                     t = peek(t);
7715                     if (!isDeclaration(t, NeedDeclaratorId.no, TOK.rightParenthesis, &t))
7716                         return false;
7717                     t = peek(t); // skip past closing ')'
7718                     goto L2;
7719                 }
7720                 goto L1;
7721 
7722             default:
7723                 {
7724                     if (!isBasicType(&t))
7725                         return false;
7726                 L2:
7727                     int tmp = false;
7728                     if (t.value != TOK.dotDotDot && !isDeclarator(&t, &tmp, null, TOK.reserved))
7729                         return false;
7730                     if (t.value == TOK.assign)
7731                     {
7732                         t = peek(t);
7733                         if (!isExpression(&t))
7734                             return false;
7735                     }
7736                     if (t.value == TOK.dotDotDot)
7737                     {
7738                         t = peek(t);
7739                         break;
7740                     }
7741                 }
7742                 if (t.value == TOK.comma)
7743                 {
7744                     continue;
7745                 }
7746                 break;
7747             }
7748             break;
7749         }
7750         if (t.value != TOK.rightParenthesis)
7751             return false;
7752         t = peek(t);
7753         *pt = t;
7754         return true;
7755     }
7756 
7757     private bool isExpression(Token** pt)
7758     {
7759         // This is supposed to determine if something is an expression.
7760         // What it actually does is scan until a closing right bracket
7761         // is found.
7762 
7763         Token* t = *pt;
7764         int brnest = 0;
7765         int panest = 0;
7766         int curlynest = 0;
7767 
7768         for (;; t = peek(t))
7769         {
7770             switch (t.value)
7771             {
7772             case TOK.leftBracket:
7773                 brnest++;
7774                 continue;
7775 
7776             case TOK.rightBracket:
7777                 if (--brnest >= 0)
7778                     continue;
7779                 break;
7780 
7781             case TOK.leftParenthesis:
7782                 panest++;
7783                 continue;
7784 
7785             case TOK.comma:
7786                 if (brnest || panest)
7787                     continue;
7788                 break;
7789 
7790             case TOK.rightParenthesis:
7791                 if (--panest >= 0)
7792                     continue;
7793                 break;
7794 
7795             case TOK.leftCurly:
7796                 curlynest++;
7797                 continue;
7798 
7799             case TOK.rightCurly:
7800                 if (--curlynest >= 0)
7801                     continue;
7802                 return false;
7803 
7804             case TOK.slice:
7805                 if (brnest)
7806                     continue;
7807                 break;
7808 
7809             case TOK.semicolon:
7810                 if (curlynest)
7811                     continue;
7812                 return false;
7813 
7814             case TOK.endOfFile:
7815                 return false;
7816 
7817             default:
7818                 continue;
7819             }
7820             break;
7821         }
7822 
7823         *pt = t;
7824         return true;
7825     }
7826 
7827     /*******************************************
7828      * Skip parentheses.
7829      * Params:
7830      *      t = on opening $(LPAREN)
7831      *      pt = *pt is set to token past '$(RPAREN)' on true
7832      * Returns:
7833      *      true    successful
7834      *      false   some parsing error
7835      */
7836     bool skipParens(Token* t, Token** pt)
7837     {
7838         if (t.value != TOK.leftParenthesis)
7839             return false;
7840 
7841         int parens = 0;
7842 
7843         while (1)
7844         {
7845             switch (t.value)
7846             {
7847             case TOK.leftParenthesis:
7848                 parens++;
7849                 break;
7850 
7851             case TOK.rightParenthesis:
7852                 parens--;
7853                 if (parens < 0)
7854                     goto Lfalse;
7855                 if (parens == 0)
7856                     goto Ldone;
7857                 break;
7858 
7859             case TOK.endOfFile:
7860                 goto Lfalse;
7861 
7862             default:
7863                 break;
7864             }
7865             t = peek(t);
7866         }
7867     Ldone:
7868         if (pt)
7869             *pt = peek(t); // skip found rparen
7870         return true;
7871 
7872     Lfalse:
7873         return false;
7874     }
7875 
7876     private bool skipParensIf(Token* t, Token** pt)
7877     {
7878         if (t.value != TOK.leftParenthesis)
7879         {
7880             if (pt)
7881                 *pt = t;
7882             return true;
7883         }
7884         return skipParens(t, pt);
7885     }
7886 
7887     //returns true if the next value (after optional matching parens) is expected
7888     private bool hasOptionalParensThen(Token* t, TOK expected)
7889     {
7890         Token* tk;
7891         if (!skipParensIf(t, &tk))
7892             return false;
7893         return tk.value == expected;
7894     }
7895 
7896     /*******************************************
7897      * Skip attributes.
7898      * Input:
7899      *      t is on a candidate attribute
7900      * Output:
7901      *      *pt is set to first non-attribute token on success
7902      * Returns:
7903      *      true    successful
7904      *      false   some parsing error
7905      */
7906     private bool skipAttributes(Token* t, Token** pt)
7907     {
7908         while (1)
7909         {
7910             switch (t.value)
7911             {
7912             case TOK.const_:
7913             case TOK.immutable_:
7914             case TOK.shared_:
7915             case TOK.inout_:
7916             case TOK.final_:
7917             case TOK.auto_:
7918             case TOK.scope_:
7919             case TOK.override_:
7920             case TOK.abstract_:
7921             case TOK.synchronized_:
7922                 break;
7923 
7924             case TOK.deprecated_:
7925                 if (peek(t).value == TOK.leftParenthesis)
7926                 {
7927                     t = peek(t);
7928                     if (!skipParens(t, &t))
7929                         goto Lerror;
7930                     // t is on the next of closing parenthesis
7931                     continue;
7932                 }
7933                 break;
7934 
7935             case TOK.nothrow_:
7936             case TOK.pure_:
7937             case TOK.ref_:
7938             case TOK.gshared:
7939             case TOK.return_:
7940                 break;
7941 
7942             case TOK.at:
7943                 t = peek(t);
7944                 if (t.value == TOK.identifier)
7945                 {
7946                     /* @identifier
7947                      * @identifier!arg
7948                      * @identifier!(arglist)
7949                      * any of the above followed by (arglist)
7950                      * @predefined_attribute
7951                      */
7952                     if (isBuiltinAtAttribute(t.ident))
7953                         break;
7954                     t = peek(t);
7955                     if (t.value == TOK.not)
7956                     {
7957                         t = peek(t);
7958                         if (t.value == TOK.leftParenthesis)
7959                         {
7960                             // @identifier!(arglist)
7961                             if (!skipParens(t, &t))
7962                                 goto Lerror;
7963                             // t is on the next of closing parenthesis
7964                         }
7965                         else
7966                         {
7967                             // @identifier!arg
7968                             // Do low rent skipTemplateArgument
7969                             if (t.value == TOK.vector)
7970                             {
7971                                 // identifier!__vector(type)
7972                                 t = peek(t);
7973                                 if (!skipParens(t, &t))
7974                                     goto Lerror;
7975                             }
7976                             else
7977                                 t = peek(t);
7978                         }
7979                     }
7980                     if (t.value == TOK.leftParenthesis)
7981                     {
7982                         if (!skipParens(t, &t))
7983                             goto Lerror;
7984                         // t is on the next of closing parenthesis
7985                         continue;
7986                     }
7987                     continue;
7988                 }
7989                 if (t.value == TOK.leftParenthesis)
7990                 {
7991                     // @( ArgumentList )
7992                     if (!skipParens(t, &t))
7993                         goto Lerror;
7994                     // t is on the next of closing parenthesis
7995                     continue;
7996                 }
7997                 goto Lerror;
7998 
7999             default:
8000                 goto Ldone;
8001             }
8002             t = peek(t);
8003         }
8004     Ldone:
8005         if (pt)
8006             *pt = t;
8007         return true;
8008 
8009     Lerror:
8010         return false;
8011     }
8012 
8013     AST.Expression parseExpression()
8014     {
8015         auto loc = token.loc;
8016 
8017         //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
8018         auto e = parseAssignExp();
8019         while (token.value == TOK.comma)
8020         {
8021             nextToken();
8022             auto e2 = parseAssignExp();
8023             e = new AST.CommaExp(loc, e, e2, false);
8024             loc = token.loc;
8025         }
8026         return e;
8027     }
8028 
8029     /********************************* Expression Parser ***************************/
8030 
8031     AST.Expression parsePrimaryExp()
8032     {
8033         AST.Expression e;
8034         AST.Type t;
8035         Identifier id;
8036         const loc = token.loc;
8037 
8038         //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
8039         switch (token.value)
8040         {
8041         case TOK.identifier:
8042             {
8043                 if (peekNext() == TOK.arrow)
8044                 {
8045                     // skip `identifier ->`
8046                     nextToken();
8047                     nextToken();
8048                     error("use `.` for member lookup, not `->`");
8049                     goto Lerr;
8050                 }
8051 
8052                 if (peekNext() == TOK.goesTo)
8053                     goto case_delegate;
8054 
8055                 id = token.ident;
8056                 nextToken();
8057                 TOK save;
8058                 if (token.value == TOK.not && (save = peekNext()) != TOK.is_ && save != TOK.in_)
8059                 {
8060                     // identifier!(template-argument-list)
8061                     auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments());
8062                     e = new AST.ScopeExp(loc, tempinst);
8063                 }
8064                 else
8065                     e = new AST.IdentifierExp(loc, id);
8066                 break;
8067             }
8068         case TOK.dollar:
8069             if (!inBrackets)
8070                 error("`$` is valid only inside [] of index or slice");
8071             e = new AST.DollarExp(loc);
8072             nextToken();
8073             break;
8074 
8075         case TOK.dot:
8076             // Signal global scope '.' operator with "" identifier
8077             e = new AST.IdentifierExp(loc, Id.empty);
8078             break;
8079 
8080         case TOK.this_:
8081             e = new AST.ThisExp(loc);
8082             nextToken();
8083             break;
8084 
8085         case TOK.super_:
8086             e = new AST.SuperExp(loc);
8087             nextToken();
8088             break;
8089 
8090         case TOK.int32Literal:
8091             e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint32);
8092             nextToken();
8093             break;
8094 
8095         case TOK.uns32Literal:
8096             e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32);
8097             nextToken();
8098             break;
8099 
8100         case TOK.int64Literal:
8101             e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint64);
8102             nextToken();
8103             break;
8104 
8105         case TOK.uns64Literal:
8106             e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns64);
8107             nextToken();
8108             break;
8109 
8110         case TOK.float32Literal:
8111             e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat32);
8112             nextToken();
8113             break;
8114 
8115         case TOK.float64Literal:
8116             e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat64);
8117             nextToken();
8118             break;
8119 
8120         case TOK.float80Literal:
8121             e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat80);
8122             nextToken();
8123             break;
8124 
8125         case TOK.imaginary32Literal:
8126             e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary32);
8127             nextToken();
8128             break;
8129 
8130         case TOK.imaginary64Literal:
8131             e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary64);
8132             nextToken();
8133             break;
8134 
8135         case TOK.imaginary80Literal:
8136             e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary80);
8137             nextToken();
8138             break;
8139 
8140         case TOK.null_:
8141             e = new AST.NullExp(loc);
8142             nextToken();
8143             break;
8144 
8145         case TOK.file:
8146             {
8147                 const(char)* s = loc.filename ? loc.filename : mod.ident.toChars();
8148                 e = new AST.StringExp(loc, s.toDString());
8149                 nextToken();
8150                 break;
8151             }
8152         case TOK.fileFullPath:
8153             {
8154                 assert(loc.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location");
8155                 const s = FileName.toAbsolute(loc.filename);
8156                 e = new AST.StringExp(loc, s.toDString());
8157                 nextToken();
8158                 break;
8159             }
8160 
8161         case TOK.line:
8162             e = new AST.IntegerExp(loc, loc.linnum, AST.Type.tint32);
8163             nextToken();
8164             break;
8165 
8166         case TOK.moduleString:
8167             {
8168                 const(char)* s = md ? md.toChars() : mod.toChars();
8169                 e = new AST.StringExp(loc, s.toDString());
8170                 nextToken();
8171                 break;
8172             }
8173         case TOK.functionString:
8174             e = new AST.FuncInitExp(loc);
8175             nextToken();
8176             break;
8177 
8178         case TOK.prettyFunction:
8179             e = new AST.PrettyFuncInitExp(loc);
8180             nextToken();
8181             break;
8182 
8183         case TOK.true_:
8184             e = new AST.IntegerExp(loc, 1, AST.Type.tbool);
8185             nextToken();
8186             break;
8187 
8188         case TOK.false_:
8189             e = new AST.IntegerExp(loc, 0, AST.Type.tbool);
8190             nextToken();
8191             break;
8192 
8193         case TOK.charLiteral:
8194             e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tchar);
8195             nextToken();
8196             break;
8197 
8198         case TOK.wcharLiteral:
8199             e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.twchar);
8200             nextToken();
8201             break;
8202 
8203         case TOK.dcharLiteral:
8204             e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tdchar);
8205             nextToken();
8206             break;
8207 
8208         case TOK.string_:
8209         case TOK.hexadecimalString:
8210             const bool hexString = token.value == TOK.hexadecimalString;
8211             {
8212                 // cat adjacent strings
8213                 auto s = token.ustring;
8214                 auto len = token.len;
8215                 auto postfix = token.postfix;
8216                 while (1)
8217                 {
8218                     const prev = token;
8219                     nextToken();
8220                     if (token.value == TOK.string_ || token.value == TOK.hexadecimalString)
8221                     {
8222                         if (token.postfix)
8223                         {
8224                             if (token.postfix != postfix)
8225                                 error(token.loc, "mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
8226                             postfix = token.postfix;
8227                         }
8228 
8229                         error("implicit string concatenation is error-prone and disallowed in D");
8230                         eSink.errorSupplemental(token.loc, "Use the explicit syntax instead " ~
8231                              "(concatenating literals is `@nogc`): %s ~ %s",
8232                              prev.toChars(), token.toChars());
8233 
8234                         const len1 = len;
8235                         const len2 = token.len;
8236                         len = len1 + len2;
8237                         auto s2 = cast(char*)mem.xmalloc_noscan(len * char.sizeof);
8238                         memcpy(s2, s, len1 * char.sizeof);
8239                         memcpy(s2 + len1, token.ustring, len2 * char.sizeof);
8240                         s = s2;
8241                     }
8242                     else
8243                         break;
8244                 }
8245                 e = new AST.StringExp(loc, s[0 .. len], len, 1, postfix);
8246                 e.isStringExp().hexString = hexString;
8247                 break;
8248             }
8249         case TOK.void_:
8250             t = AST.Type.tvoid;
8251             goto LabelX;
8252 
8253         case TOK.int8:
8254             t = AST.Type.tint8;
8255             goto LabelX;
8256 
8257         case TOK.uns8:
8258             t = AST.Type.tuns8;
8259             goto LabelX;
8260 
8261         case TOK.int16:
8262             t = AST.Type.tint16;
8263             goto LabelX;
8264 
8265         case TOK.uns16:
8266             t = AST.Type.tuns16;
8267             goto LabelX;
8268 
8269         case TOK.int32:
8270             t = AST.Type.tint32;
8271             goto LabelX;
8272 
8273         case TOK.uns32:
8274             t = AST.Type.tuns32;
8275             goto LabelX;
8276 
8277         case TOK.int64:
8278             t = AST.Type.tint64;
8279             goto LabelX;
8280 
8281         case TOK.uns64:
8282             t = AST.Type.tuns64;
8283             goto LabelX;
8284 
8285         case TOK.int128:
8286             t = AST.Type.tint128;
8287             goto LabelX;
8288 
8289         case TOK.uns128:
8290             t = AST.Type.tuns128;
8291             goto LabelX;
8292 
8293         case TOK.float32:
8294             t = AST.Type.tfloat32;
8295             goto LabelX;
8296 
8297         case TOK.float64:
8298             t = AST.Type.tfloat64;
8299             goto LabelX;
8300 
8301         case TOK.float80:
8302             t = AST.Type.tfloat80;
8303             goto LabelX;
8304 
8305         case TOK.imaginary32:
8306             t = AST.Type.timaginary32;
8307             goto LabelX;
8308 
8309         case TOK.imaginary64:
8310             t = AST.Type.timaginary64;
8311             goto LabelX;
8312 
8313         case TOK.imaginary80:
8314             t = AST.Type.timaginary80;
8315             goto LabelX;
8316 
8317         case TOK.complex32:
8318             t = AST.Type.tcomplex32;
8319             goto LabelX;
8320 
8321         case TOK.complex64:
8322             t = AST.Type.tcomplex64;
8323             goto LabelX;
8324 
8325         case TOK.complex80:
8326             t = AST.Type.tcomplex80;
8327             goto LabelX;
8328 
8329         case TOK.bool_:
8330             t = AST.Type.tbool;
8331             goto LabelX;
8332 
8333         case TOK.char_:
8334             t = AST.Type.tchar;
8335             goto LabelX;
8336 
8337         case TOK.wchar_:
8338             t = AST.Type.twchar;
8339             goto LabelX;
8340 
8341         case TOK.dchar_:
8342             t = AST.Type.tdchar;
8343             goto LabelX;
8344         LabelX:
8345             const next = peekNext();
8346             if (next != TOK.leftParenthesis && next != TOK.dot)
8347             {
8348                 // defer error for better diagnostics
8349                 e = new AST.TypeExp(loc, parseType);
8350                 break;
8351             }
8352             nextToken();
8353             if (token.value == TOK.leftParenthesis)
8354             {
8355                 e = new AST.TypeExp(loc, t);
8356                 e = new AST.CallExp(loc, e, parseArguments());
8357                 break;
8358             }
8359             check(TOK.dot);
8360             if (token.value != TOK.identifier)
8361             {
8362                 error(token.loc, "found `%s` when expecting identifier following `%s`.", token.toChars(), t.toChars());
8363                 goto Lerr;
8364             }
8365             e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident);
8366             nextToken();
8367             break;
8368 
8369         case TOK.typeof_:
8370             {
8371                 t = parseTypeof();
8372                 e = new AST.TypeExp(loc, t);
8373                 break;
8374             }
8375         case TOK.vector:
8376             {
8377                 t = parseVector();
8378                 e = new AST.TypeExp(loc, t);
8379                 break;
8380             }
8381         case TOK.typeid_:
8382             {
8383                 nextToken();
8384                 check(TOK.leftParenthesis, "`typeid`");
8385                 RootObject o = parseTypeOrAssignExp();
8386                 check(TOK.rightParenthesis);
8387                 e = new AST.TypeidExp(loc, o);
8388                 break;
8389             }
8390         case TOK.traits:
8391             {
8392                 /* __traits(identifier, args...)
8393                  */
8394                 Identifier ident;
8395                 AST.Objects* args = null;
8396 
8397                 nextToken();
8398                 check(TOK.leftParenthesis);
8399                 if (token.value != TOK.identifier)
8400                 {
8401                     error("`__traits(identifier, args...)` expected");
8402                     goto Lerr;
8403                 }
8404                 ident = token.ident;
8405                 nextToken();
8406                 if (token.value == TOK.comma)
8407                     args = parseTemplateArgumentList(); // __traits(identifier, args...)
8408                 else
8409                     check(TOK.rightParenthesis); // __traits(identifier)
8410 
8411                 e = new AST.TraitsExp(loc, ident, args);
8412                 break;
8413             }
8414         case TOK.is_:
8415             {
8416                 AST.Type targ;
8417                 Identifier ident = null;
8418                 AST.Type tspec = null;
8419                 TOK tok = TOK.reserved;
8420                 TOK tok2 = TOK.reserved;
8421                 AST.TemplateParameters* tpl = null;
8422 
8423                 nextToken();
8424                 if (token.value == TOK.leftParenthesis)
8425                 {
8426                     nextToken();
8427                     if (token.value == TOK.identifier && peekNext() == TOK.leftParenthesis)
8428                     {
8429                         error(loc, "unexpected `(` after `%s`, inside `is` expression. Try enclosing the contents of `is` with a `typeof` expression", token.toChars());
8430                         nextToken();
8431                         Token* tempTok = peekPastParen(&token);
8432                         memcpy(&token, tempTok, Token.sizeof);
8433                         goto Lerr;
8434                     }
8435                     targ = parseType(&ident);
8436                     if (token.value == TOK.colon || token.value == TOK.equal)
8437                     {
8438                         tok = token.value;
8439                         nextToken();
8440                         if (tok == TOK.equal && (token.value == TOK.struct_ || token.value == TOK.union_
8441                             || token.value == TOK.class_ || token.value == TOK.super_ || token.value == TOK.enum_
8442                             || token.value == TOK.interface_ || token.value == TOK.package_ || token.value == TOK.module_
8443                             || token.value == TOK.argumentTypes || token.value == TOK.parameters
8444                             || token.value == TOK.const_ && peekNext() == TOK.rightParenthesis
8445                             || token.value == TOK.immutable_ && peekNext() == TOK.rightParenthesis
8446                             || token.value == TOK.shared_ && peekNext() == TOK.rightParenthesis
8447                             || token.value == TOK.inout_ && peekNext() == TOK.rightParenthesis || token.value == TOK.function_
8448                             || token.value == TOK.delegate_ || token.value == TOK.return_
8449                             || (token.value == TOK.vector && peekNext() == TOK.rightParenthesis)))
8450                         {
8451                             tok2 = token.value;
8452                             nextToken();
8453                         }
8454                         else
8455                         {
8456                             tspec = parseType();
8457                         }
8458                     }
8459                     if (tspec)
8460                     {
8461                         if (token.value == TOK.comma)
8462                             tpl = parseTemplateParameterList(1);
8463                         else
8464                         {
8465                             tpl = new AST.TemplateParameters();
8466                             check(TOK.rightParenthesis);
8467                         }
8468                     }
8469                     else
8470                         check(TOK.rightParenthesis);
8471                 }
8472                 else
8473                 {
8474                     error("`type identifier : specialization` expected following `is`");
8475                     goto Lerr;
8476                 }
8477                 e = new AST.IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
8478                 break;
8479             }
8480         case TOK.assert_:
8481             {
8482                 // https://dlang.org/spec/expression.html#assert_expressions
8483                 AST.Expression msg = null;
8484 
8485                 nextToken();
8486                 check(TOK.leftParenthesis, "`assert`");
8487                 e = parseAssignExp();
8488                 if (token.value == TOK.comma)
8489                 {
8490                     nextToken();
8491                     if (token.value != TOK.rightParenthesis)
8492                     {
8493                         msg = parseAssignExp();
8494                         if (token.value == TOK.comma)
8495                             nextToken();
8496                     }
8497                 }
8498                 check(TOK.rightParenthesis);
8499                 e = new AST.AssertExp(loc, e, msg);
8500                 break;
8501             }
8502         case TOK.mixin_:
8503             {
8504                 // https://dlang.org/spec/expression.html#mixin_expressions
8505                 nextToken();
8506                 if (token.value != TOK.leftParenthesis)
8507                     error(token.loc, "found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis));
8508                 auto exps = parseArguments();
8509                 e = new AST.MixinExp(loc, exps);
8510                 break;
8511             }
8512         case TOK.import_:
8513             {
8514                 nextToken();
8515                 check(TOK.leftParenthesis, "`import`");
8516                 e = parseAssignExp();
8517                 check(TOK.rightParenthesis);
8518                 e = new AST.ImportExp(loc, e);
8519                 break;
8520             }
8521         case TOK.new_:
8522             e = parseNewExp(null);
8523             break;
8524 
8525         case TOK.auto_:
8526             {
8527                 if (peekNext() == TOK.ref_ && peekNext2() == TOK.leftParenthesis)
8528                 {
8529                     Token* tk = peekPastParen(peek(peek(&token)));
8530                     if (skipAttributes(tk, &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly))
8531                     {
8532                         // auto ref (arguments) => expression
8533                         // auto ref (arguments) { statements... }
8534                         goto case_delegate;
8535                     }
8536                 }
8537                 nextToken();
8538                 error("found `%s` when expecting `ref` and function literal following `auto`", token.toChars());
8539                 goto Lerr;
8540             }
8541         case TOK.ref_:
8542             {
8543                 if (peekNext() == TOK.leftParenthesis)
8544                 {
8545                     Token* tk = peekPastParen(peek(&token));
8546                     if (skipAttributes(tk, &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly))
8547                     {
8548                         // ref (arguments) => expression
8549                         // ref (arguments) { statements... }
8550                         goto case_delegate;
8551                     }
8552                 }
8553                 nextToken();
8554                 error("found `%s` when expecting function literal following `ref`", token.toChars());
8555                 goto Lerr;
8556             }
8557         case TOK.leftParenthesis:
8558             {
8559                 Token* tk = peekPastParen(&token);
8560                 if (skipAttributes(tk, &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly))
8561                 {
8562                     // (arguments) => expression
8563                     // (arguments) { statements... }
8564                     goto case_delegate;
8565                 }
8566 
8567                 // ( expression )
8568                 nextToken();
8569                 e = parseExpression();
8570                 check(loc, TOK.rightParenthesis);
8571                 break;
8572             }
8573         case TOK.leftBracket:
8574             {
8575                 /* Parse array literals and associative array literals:
8576                  *  [ value, value, value ... ]
8577                  *  [ key:value, key:value, key:value ... ]
8578                  */
8579                 auto values = new AST.Expressions();
8580                 AST.Expressions* keys = null;
8581 
8582                 nextToken();
8583                 while (token.value != TOK.rightBracket && token.value != TOK.endOfFile)
8584                 {
8585                     e = parseAssignExp();
8586                     if (token.value == TOK.colon && (keys || values.length == 0))
8587                     {
8588                         nextToken();
8589                         if (!keys)
8590                             keys = new AST.Expressions();
8591                         keys.push(e);
8592                         e = parseAssignExp();
8593                     }
8594                     else if (keys)
8595                     {
8596                         error("`key:value` expected for associative array literal");
8597                         keys = null;
8598                     }
8599                     values.push(e);
8600                     if (token.value == TOK.rightBracket)
8601                         break;
8602                     check(TOK.comma);
8603                 }
8604                 check(loc, TOK.rightBracket);
8605 
8606                 if (keys)
8607                     e = new AST.AssocArrayLiteralExp(loc, keys, values);
8608                 else
8609                     e = new AST.ArrayLiteralExp(loc, null, values);
8610                 break;
8611             }
8612         case TOK.leftCurly:
8613         case TOK.function_:
8614         case TOK.delegate_:
8615         case_delegate:
8616             {
8617                 AST.Dsymbol s = parseFunctionLiteral();
8618                 e = new AST.FuncExp(loc, s);
8619                 break;
8620             }
8621 
8622         default:
8623             error("expression expected, not `%s`", token.toChars());
8624         Lerr:
8625             // Anything for e, as long as it's not NULL
8626             e = new AST.IntegerExp(loc, 0, AST.Type.tint32);
8627             nextToken();
8628             break;
8629         }
8630         return e;
8631     }
8632 
8633     private AST.Expression parseUnaryExp()
8634     {
8635         AST.Expression e;
8636         const loc = token.loc;
8637 
8638         switch (token.value)
8639         {
8640         case TOK.and:
8641             nextToken();
8642             e = parseUnaryExp();
8643             e = new AST.AddrExp(loc, e);
8644             break;
8645 
8646         case TOK.plusPlus:
8647             nextToken();
8648             e = parseUnaryExp();
8649             //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
8650             e = new AST.PreExp(EXP.prePlusPlus, loc, e);
8651             break;
8652 
8653         case TOK.minusMinus:
8654             nextToken();
8655             e = parseUnaryExp();
8656             //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
8657             e = new AST.PreExp(EXP.preMinusMinus, loc, e);
8658             break;
8659 
8660         case TOK.mul:
8661             nextToken();
8662             e = parseUnaryExp();
8663             e = new AST.PtrExp(loc, e);
8664             break;
8665 
8666         case TOK.min:
8667             nextToken();
8668             e = parseUnaryExp();
8669             e = new AST.NegExp(loc, e);
8670             break;
8671 
8672         case TOK.add:
8673             nextToken();
8674             e = parseUnaryExp();
8675             e = new AST.UAddExp(loc, e);
8676             break;
8677 
8678         case TOK.not:
8679             nextToken();
8680             e = parseUnaryExp();
8681             e = new AST.NotExp(loc, e);
8682             break;
8683 
8684         case TOK.tilde:
8685             nextToken();
8686             e = parseUnaryExp();
8687             e = new AST.ComExp(loc, e);
8688             break;
8689 
8690         case TOK.delete_:
8691             // @@@DEPRECATED_2.109@@@
8692             // Use of `delete` keyword has been an error since 2.099.
8693             // Remove from the parser after 2.109.
8694             nextToken();
8695             e = parseUnaryExp();
8696             e = new AST.DeleteExp(loc, e, false);
8697             break;
8698 
8699         case TOK.cast_: // cast(type) expression
8700             {
8701                 nextToken();
8702                 check(TOK.leftParenthesis);
8703                 /* Look for cast(), cast(const), cast(immutable),
8704                  * cast(shared), cast(shared const), cast(wild), cast(shared wild)
8705                  */
8706                 ubyte m = 0;
8707                 while (1)
8708                 {
8709                     switch (token.value)
8710                     {
8711                     case TOK.const_:
8712                         if (peekNext() == TOK.leftParenthesis)
8713                             break; // const as type constructor
8714                         m |= MODFlags.const_; // const as storage class
8715                         nextToken();
8716                         continue;
8717 
8718                     case TOK.immutable_:
8719                         if (peekNext() == TOK.leftParenthesis)
8720                             break;
8721                         m |= MODFlags.immutable_;
8722                         nextToken();
8723                         continue;
8724 
8725                     case TOK.shared_:
8726                         if (peekNext() == TOK.leftParenthesis)
8727                             break;
8728                         m |= MODFlags.shared_;
8729                         nextToken();
8730                         continue;
8731 
8732                     case TOK.inout_:
8733                         if (peekNext() == TOK.leftParenthesis)
8734                             break;
8735                         m |= MODFlags.wild;
8736                         nextToken();
8737                         continue;
8738 
8739                     default:
8740                         break;
8741                     }
8742                     break;
8743                 }
8744                 if (token.value == TOK.rightParenthesis)
8745                 {
8746                     nextToken();
8747                     e = parseUnaryExp();
8748                     e = new AST.CastExp(loc, e, m);
8749                 }
8750                 else
8751                 {
8752                     AST.Type t = parseType(); // cast( type )
8753                     t = t.addMod(m); // cast( const type )
8754                     check(TOK.rightParenthesis);
8755                     e = parseUnaryExp();
8756                     e = new AST.CastExp(loc, e, t);
8757                 }
8758                 break;
8759             }
8760         case TOK.inout_:
8761         case TOK.shared_:
8762         case TOK.const_:
8763         case TOK.immutable_: // immutable(type)(arguments) / immutable(type).init
8764             {
8765                 StorageClass stc = parseTypeCtor();
8766 
8767                 AST.Type t = parseBasicType();
8768                 t = t.addSTC(stc);
8769 
8770                 if (stc == 0 && token.value == TOK.dot)
8771                 {
8772                     nextToken();
8773                     if (token.value != TOK.identifier)
8774                     {
8775                         error("identifier expected following `%s.`, not `%s`",
8776                             t.toChars(), token.toChars());
8777                         return AST.ErrorExp.get();
8778                     }
8779                     e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident);
8780                     nextToken();
8781                     e = parsePostExp(e);
8782                 }
8783                 else
8784                 {
8785                     e = new AST.TypeExp(loc, t);
8786                     if (token.value != TOK.leftParenthesis)
8787                     {
8788                         error("`(arguments)` expected following `%s`, not `%s`",
8789                             t.toChars(), token.toChars());
8790                         return e;
8791                     }
8792                     e = new AST.CallExp(loc, e, parseArguments());
8793                 }
8794                 break;
8795             }
8796         case TOK.leftParenthesis:
8797             {
8798                 auto tk = peek(&token);
8799                 static if (CCASTSYNTAX)
8800                 {
8801                     // If cast
8802                     if (isDeclaration(tk, NeedDeclaratorId.no, TOK.rightParenthesis, &tk))
8803                     {
8804                         tk = peek(tk); // skip over right parenthesis
8805                         switch (tk.value)
8806                         {
8807                         case TOK.not:
8808                             tk = peek(tk);
8809                             if (tk.value == TOK.is_ || tk.value == TOK.in_) // !is or !in
8810                                 break;
8811                             goto case;
8812 
8813                         case TOK.dot:
8814                         case TOK.plusPlus:
8815                         case TOK.minusMinus:
8816                         case TOK.delete_:
8817                         case TOK.new_:
8818                         case TOK.leftParenthesis:
8819                         case TOK.identifier:
8820                         case TOK.this_:
8821                         case TOK.super_:
8822                         case TOK.int32Literal:
8823                         case TOK.uns32Literal:
8824                         case TOK.int64Literal:
8825                         case TOK.uns64Literal:
8826                         case TOK.int128Literal:
8827                         case TOK.uns128Literal:
8828                         case TOK.float32Literal:
8829                         case TOK.float64Literal:
8830                         case TOK.float80Literal:
8831                         case TOK.imaginary32Literal:
8832                         case TOK.imaginary64Literal:
8833                         case TOK.imaginary80Literal:
8834                         case TOK.null_:
8835                         case TOK.true_:
8836                         case TOK.false_:
8837                         case TOK.charLiteral:
8838                         case TOK.wcharLiteral:
8839                         case TOK.dcharLiteral:
8840                         case TOK.string_:
8841                         case TOK.function_:
8842                         case TOK.delegate_:
8843                         case TOK.typeof_:
8844                         case TOK.traits:
8845                         case TOK.vector:
8846                         case TOK.file:
8847                         case TOK.fileFullPath:
8848                         case TOK.line:
8849                         case TOK.moduleString:
8850                         case TOK.functionString:
8851                         case TOK.prettyFunction:
8852                         case TOK.wchar_:
8853                         case TOK.dchar_:
8854                         case TOK.bool_:
8855                         case TOK.char_:
8856                         case TOK.int8:
8857                         case TOK.uns8:
8858                         case TOK.int16:
8859                         case TOK.uns16:
8860                         case TOK.int32:
8861                         case TOK.uns32:
8862                         case TOK.int64:
8863                         case TOK.uns64:
8864                         case TOK.int128:
8865                         case TOK.uns128:
8866                         case TOK.float32:
8867                         case TOK.float64:
8868                         case TOK.float80:
8869                         case TOK.imaginary32:
8870                         case TOK.imaginary64:
8871                         case TOK.imaginary80:
8872                         case TOK.complex32:
8873                         case TOK.complex64:
8874                         case TOK.complex80:
8875                         case TOK.void_:
8876                             {
8877                                 // (type) una_exp
8878                                 nextToken();
8879                                 // Note: `t` may be an expression that looks like a type
8880                                 auto t = parseType();
8881                                 check(TOK.rightParenthesis);
8882 
8883                                 // if .identifier
8884                                 // or .identifier!( ... )
8885                                 if (token.value == TOK.dot)
8886                                 {
8887                                     if (peekNext() != TOK.identifier && peekNext() != TOK.new_)
8888                                     {
8889                                         error("identifier or new keyword expected following `(...)`.");
8890                                         nextToken();
8891                                         return AST.ErrorExp.get();
8892                                     }
8893                                     auto te = new AST.TypeExp(loc, t);
8894                                     te.parens = true;
8895                                     e = parsePostExp(te);
8896                                 }
8897                                 else if (token.value == TOK.leftParenthesis ||
8898                                     token.value == TOK.plusPlus || token.value == TOK.minusMinus)
8899                                 {
8900                                     // (type)(expr)
8901                                     // (callable)(args)
8902                                     // (expr)++
8903                                     auto te = new AST.TypeExp(loc, t);
8904                                     te.parens = true;
8905                                     e = parsePostExp(te);
8906                                 }
8907                                 else
8908                                 {
8909                                     e = parseUnaryExp();
8910                                     e = new AST.CastExp(loc, e, t);
8911                                     error(loc, "C style cast illegal, use `%s`", e.toChars());
8912                                 }
8913                                 return e;
8914                             }
8915                         default:
8916                             break;
8917                         }
8918                     }
8919                 }
8920                 e = parsePrimaryExp();
8921                 e = parsePostExp(e);
8922                 break;
8923             }
8924         case TOK.throw_:
8925             {
8926                 nextToken();
8927                 // Deviation from the DIP:
8928                 // Parse AssignExpression instead of Expression to avoid conflicts for comma
8929                 // separated lists, e.g. function arguments
8930                 AST.Expression exp = parseAssignExp();
8931                 e = new AST.ThrowExp(loc, exp);
8932                 break;
8933             }
8934 
8935         default:
8936             e = parsePrimaryExp();
8937             e = parsePostExp(e);
8938             break;
8939         }
8940         assert(e);
8941 
8942         // ^^ is right associative and has higher precedence than the unary operators
8943         while (token.value == TOK.pow)
8944         {
8945             nextToken();
8946             AST.Expression e2 = parseUnaryExp();
8947             e = new AST.PowExp(loc, e, e2);
8948         }
8949 
8950         return e;
8951     }
8952 
8953     private AST.Expression parsePostExp(AST.Expression e)
8954     {
8955         while (1)
8956         {
8957             const loc = token.loc;
8958             switch (token.value)
8959             {
8960             case TOK.dot:
8961                 nextToken();
8962                 if (token.value == TOK.identifier)
8963                 {
8964                     Identifier id = token.ident;
8965 
8966                     nextToken();
8967                     if (token.value == TOK.not && peekNext() != TOK.is_ && peekNext() != TOK.in_)
8968                     {
8969                         AST.Objects* tiargs = parseTemplateArguments();
8970                         e = new AST.DotTemplateInstanceExp(loc, e, id, tiargs);
8971                     }
8972                     else
8973                         e = new AST.DotIdExp(loc, e, id);
8974                     continue;
8975                 }
8976                 if (token.value == TOK.new_)
8977                 {
8978                     e = parseNewExp(e);
8979                     continue;
8980                 }
8981                 error("identifier or `new` expected following `.`, not `%s`", token.toChars());
8982                 break;
8983 
8984             case TOK.plusPlus:
8985                 e = new AST.PostExp(EXP.plusPlus, loc, e);
8986                 break;
8987 
8988             case TOK.minusMinus:
8989                 e = new AST.PostExp(EXP.minusMinus, loc, e);
8990                 break;
8991 
8992             case TOK.leftParenthesis:
8993                 AST.Expressions* args = new AST.Expressions();
8994                 AST.Identifiers* names = new AST.Identifiers();
8995                 parseNamedArguments(args, names);
8996                 e = new AST.CallExp(loc, e, args, names);
8997                 continue;
8998 
8999             case TOK.leftBracket:
9000                 {
9001                     // array dereferences:
9002                     //      array[index]
9003                     //      array[]
9004                     //      array[lwr .. upr]
9005                     AST.Expression index;
9006                     AST.Expression upr;
9007                     auto arguments = new AST.Expressions();
9008 
9009                     inBrackets++;
9010                     nextToken();
9011                     while (token.value != TOK.rightBracket && token.value != TOK.endOfFile)
9012                     {
9013                         index = parseAssignExp();
9014                         if (token.value == TOK.slice)
9015                         {
9016                             // array[..., lwr..upr, ...]
9017                             nextToken();
9018                             upr = parseAssignExp();
9019                             arguments.push(new AST.IntervalExp(loc, index, upr));
9020                         }
9021                         else
9022                             arguments.push(index);
9023                         if (token.value == TOK.rightBracket)
9024                             break;
9025                         check(TOK.comma);
9026                     }
9027                     check(TOK.rightBracket);
9028                     inBrackets--;
9029                     e = new AST.ArrayExp(loc, e, arguments);
9030                     continue;
9031                 }
9032             default:
9033                 return e;
9034             }
9035             nextToken();
9036         }
9037     }
9038 
9039     private AST.Expression parseMulExp()
9040     {
9041         const loc = token.loc;
9042         auto e = parseUnaryExp();
9043 
9044         while (1)
9045         {
9046             switch (token.value)
9047             {
9048             case TOK.mul:
9049                 nextToken();
9050                 auto e2 = parseUnaryExp();
9051                 e = new AST.MulExp(loc, e, e2);
9052                 continue;
9053 
9054             case TOK.div:
9055                 nextToken();
9056                 auto e2 = parseUnaryExp();
9057                 e = new AST.DivExp(loc, e, e2);
9058                 continue;
9059 
9060             case TOK.mod:
9061                 nextToken();
9062                 auto e2 = parseUnaryExp();
9063                 e = new AST.ModExp(loc, e, e2);
9064                 continue;
9065 
9066             default:
9067                 break;
9068             }
9069             break;
9070         }
9071         return e;
9072     }
9073 
9074     private AST.Expression parseAddExp()
9075     {
9076         const loc = token.loc;
9077         auto e = parseMulExp();
9078 
9079         while (1)
9080         {
9081             switch (token.value)
9082             {
9083             case TOK.add:
9084                 nextToken();
9085                 auto e2 = parseMulExp();
9086                 e = new AST.AddExp(loc, e, e2);
9087                 continue;
9088 
9089             case TOK.min:
9090                 nextToken();
9091                 auto e2 = parseMulExp();
9092                 e = new AST.MinExp(loc, e, e2);
9093                 continue;
9094 
9095             case TOK.tilde:
9096                 nextToken();
9097                 auto e2 = parseMulExp();
9098                 e = new AST.CatExp(loc, e, e2);
9099                 continue;
9100 
9101             default:
9102                 break;
9103             }
9104             break;
9105         }
9106         return e;
9107     }
9108 
9109     private AST.Expression parseShiftExp()
9110     {
9111         const loc = token.loc;
9112         auto e = parseAddExp();
9113 
9114         while (1)
9115         {
9116             switch (token.value)
9117             {
9118             case TOK.leftShift:
9119                 nextToken();
9120                 auto e2 = parseAddExp();
9121                 e = new AST.ShlExp(loc, e, e2);
9122                 continue;
9123 
9124             case TOK.rightShift:
9125                 nextToken();
9126                 auto e2 = parseAddExp();
9127                 e = new AST.ShrExp(loc, e, e2);
9128                 continue;
9129 
9130             case TOK.unsignedRightShift:
9131                 nextToken();
9132                 auto e2 = parseAddExp();
9133                 e = new AST.UshrExp(loc, e, e2);
9134                 continue;
9135 
9136             default:
9137                 break;
9138             }
9139             break;
9140         }
9141         return e;
9142     }
9143 
9144     private AST.Expression parseCmpExp()
9145     {
9146         const loc = token.loc;
9147 
9148         auto e = parseShiftExp();
9149         EXP op = EXP.reserved;
9150 
9151         switch (token.value)
9152         {
9153         case TOK.equal:         op = EXP.equal; goto Lequal;
9154         case TOK.notEqual:      op = EXP.notEqual; goto Lequal;
9155         Lequal:
9156             nextToken();
9157             auto e2 = parseShiftExp();
9158             e = new AST.EqualExp(op, loc, e, e2);
9159             break;
9160 
9161         case TOK.not:
9162         {
9163             // Attempt to identify '!is'
9164             const tv = peekNext();
9165             if (tv == TOK.in_)
9166             {
9167                 nextToken();
9168                 nextToken();
9169                 auto e2 = parseShiftExp();
9170                 e = new AST.InExp(loc, e, e2);
9171                 e = new AST.NotExp(loc, e);
9172                 break;
9173             }
9174             if (tv != TOK.is_)
9175                 break;
9176             nextToken();
9177             op = EXP.notIdentity;
9178             goto Lidentity;
9179         }
9180         case TOK.is_:           op = EXP.identity; goto Lidentity;
9181         Lidentity:
9182             nextToken();
9183             auto e2 = parseShiftExp();
9184             e = new AST.IdentityExp(op, loc, e, e2);
9185             break;
9186 
9187         case TOK.lessThan:       op = EXP.lessThan;       goto Lcmp;
9188         case TOK.lessOrEqual:    op = EXP.lessOrEqual;    goto Lcmp;
9189         case TOK.greaterThan:    op = EXP.greaterThan;    goto Lcmp;
9190         case TOK.greaterOrEqual: op = EXP.greaterOrEqual; goto Lcmp;
9191         Lcmp:
9192             nextToken();
9193             auto e2 = parseShiftExp();
9194             e = new AST.CmpExp(op, loc, e, e2);
9195             break;
9196 
9197         case TOK.in_:
9198             nextToken();
9199             auto e2 = parseShiftExp();
9200             e = new AST.InExp(loc, e, e2);
9201             break;
9202 
9203         default:
9204             break;
9205         }
9206         return e;
9207     }
9208 
9209     private AST.Expression parseAndExp()
9210     {
9211         Loc loc = token.loc;
9212         bool parens = token.value == TOK.leftParenthesis;
9213         auto e = parseCmpExp();
9214         while (token.value == TOK.and)
9215         {
9216             if (!parens)
9217                 checkParens(TOK.and, e);
9218             parens = nextToken() == TOK.leftParenthesis;
9219             auto e2 = parseCmpExp();
9220             if (!parens)
9221                 checkParens(TOK.and, e2);
9222             e = new AST.AndExp(loc, e, e2);
9223             parens = true;              // don't call checkParens() for And
9224             loc = token.loc;
9225         }
9226         return e;
9227     }
9228 
9229     private AST.Expression parseXorExp()
9230     {
9231         Loc loc = token.loc;
9232 
9233         bool parens = token.value == TOK.leftParenthesis;
9234         auto e = parseAndExp();
9235         while (token.value == TOK.xor)
9236         {
9237             if (!parens)
9238                 checkParens(TOK.xor, e);
9239             parens = nextToken() == TOK.leftParenthesis;
9240             auto e2 = parseAndExp();
9241             if (!parens)
9242                 checkParens(TOK.xor, e2);
9243             e = new AST.XorExp(loc, e, e2);
9244             parens = true;
9245             loc = token.loc;
9246         }
9247         return e;
9248     }
9249 
9250     private AST.Expression parseOrExp()
9251     {
9252         Loc loc = token.loc;
9253 
9254         bool parens = token.value == TOK.leftParenthesis;
9255         auto e = parseXorExp();
9256         while (token.value == TOK.or)
9257         {
9258             if (!parens)
9259                 checkParens(TOK.or, e);
9260             parens = nextToken() == TOK.leftParenthesis;
9261             auto e2 = parseXorExp();
9262             if (!parens)
9263                 checkParens(TOK.or, e2);
9264             e = new AST.OrExp(loc, e, e2);
9265             parens = true;
9266             loc = token.loc;
9267         }
9268         return e;
9269     }
9270 
9271     private AST.Expression parseAndAndExp()
9272     {
9273         const loc = token.loc;
9274 
9275         auto e = parseOrExp();
9276         while (token.value == TOK.andAnd)
9277         {
9278             nextToken();
9279             auto e2 = parseOrExp();
9280             e = new AST.LogicalExp(loc, EXP.andAnd, e, e2);
9281         }
9282         return e;
9283     }
9284 
9285     private AST.Expression parseOrOrExp()
9286     {
9287         const loc = token.loc;
9288 
9289         auto e = parseAndAndExp();
9290         while (token.value == TOK.orOr)
9291         {
9292             nextToken();
9293             auto e2 = parseAndAndExp();
9294             e = new AST.LogicalExp(loc, EXP.orOr, e, e2);
9295         }
9296         return e;
9297     }
9298 
9299     private AST.Expression parseCondExp()
9300     {
9301         const loc = token.loc;
9302 
9303         auto e = parseOrOrExp();
9304         if (token.value == TOK.question)
9305         {
9306             nextToken();
9307             auto e1 = parseExpression();
9308             check(TOK.colon);
9309             auto e2 = parseCondExp();
9310             e = new AST.CondExp(loc, e, e1, e2);
9311         }
9312         return e;
9313     }
9314 
9315     AST.Expression parseAssignExp()
9316     {
9317         bool parens = token.value == TOK.leftParenthesis;
9318         AST.Expression e;
9319         e = parseCondExp();
9320         if (e is null)
9321             return e;
9322 
9323         // require parens for e.g. `t ? a = 1 : b = 2`
9324         void checkRequiredParens()
9325         {
9326             if (e.op == EXP.question && !parens)
9327                 eSink.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`",
9328                     e.toChars(), Token.toChars(token.value));
9329         }
9330 
9331         const loc = token.loc;
9332         switch (token.value)
9333         {
9334         case TOK.assign:
9335             checkRequiredParens();
9336             nextToken();
9337             auto e2 = parseAssignExp();
9338             e = new AST.AssignExp(loc, e, e2);
9339             break;
9340 
9341         case TOK.addAssign:
9342             checkRequiredParens();
9343             nextToken();
9344             auto e2 = parseAssignExp();
9345             e = new AST.AddAssignExp(loc, e, e2);
9346             break;
9347 
9348         case TOK.minAssign:
9349             checkRequiredParens();
9350             nextToken();
9351             auto e2 = parseAssignExp();
9352             e = new AST.MinAssignExp(loc, e, e2);
9353             break;
9354 
9355         case TOK.mulAssign:
9356             checkRequiredParens();
9357             nextToken();
9358             auto e2 = parseAssignExp();
9359             e = new AST.MulAssignExp(loc, e, e2);
9360             break;
9361 
9362         case TOK.divAssign:
9363             checkRequiredParens();
9364             nextToken();
9365             auto e2 = parseAssignExp();
9366             e = new AST.DivAssignExp(loc, e, e2);
9367             break;
9368 
9369         case TOK.modAssign:
9370             checkRequiredParens();
9371             nextToken();
9372             auto e2 = parseAssignExp();
9373             e = new AST.ModAssignExp(loc, e, e2);
9374             break;
9375 
9376         case TOK.powAssign:
9377             checkRequiredParens();
9378             nextToken();
9379             auto e2 = parseAssignExp();
9380             e = new AST.PowAssignExp(loc, e, e2);
9381             break;
9382 
9383         case TOK.andAssign:
9384             checkRequiredParens();
9385             nextToken();
9386             auto e2 = parseAssignExp();
9387             e = new AST.AndAssignExp(loc, e, e2);
9388             break;
9389 
9390         case TOK.orAssign:
9391             checkRequiredParens();
9392             nextToken();
9393             auto e2 = parseAssignExp();
9394             e = new AST.OrAssignExp(loc, e, e2);
9395             break;
9396 
9397         case TOK.xorAssign:
9398             checkRequiredParens();
9399             nextToken();
9400             auto e2 = parseAssignExp();
9401             e = new AST.XorAssignExp(loc, e, e2);
9402             break;
9403 
9404         case TOK.leftShiftAssign:
9405             checkRequiredParens();
9406             nextToken();
9407             auto e2 = parseAssignExp();
9408             e = new AST.ShlAssignExp(loc, e, e2);
9409             break;
9410 
9411         case TOK.rightShiftAssign:
9412             checkRequiredParens();
9413             nextToken();
9414             auto e2 = parseAssignExp();
9415             e = new AST.ShrAssignExp(loc, e, e2);
9416             break;
9417 
9418         case TOK.unsignedRightShiftAssign:
9419             checkRequiredParens();
9420             nextToken();
9421             auto e2 = parseAssignExp();
9422             e = new AST.UshrAssignExp(loc, e, e2);
9423             break;
9424 
9425         case TOK.concatenateAssign:
9426             checkRequiredParens();
9427             nextToken();
9428             auto e2 = parseAssignExp();
9429             e = new AST.CatAssignExp(loc, e, e2);
9430             break;
9431 
9432         default:
9433             break;
9434         }
9435 
9436         return e;
9437     }
9438 
9439     /*************************
9440      * Collect argument list.
9441      * Assume current token is ',', '$(LPAREN)' or '['.
9442      */
9443     private AST.Expressions* parseArguments()
9444     {
9445         // function call
9446         AST.Expressions* arguments = new AST.Expressions();
9447         parseNamedArguments(arguments, null);
9448         return arguments;
9449     }
9450 
9451     /*************************
9452      * Collect argument list.
9453      * Assume current token is ',', '$(LPAREN)' or '['.
9454      */
9455     private void parseNamedArguments(AST.Expressions* arguments, AST.Identifiers* names)
9456     {
9457         assert(arguments);
9458 
9459         const endtok = token.value == TOK.leftBracket ? TOK.rightBracket : TOK.rightParenthesis;
9460 
9461         nextToken();
9462 
9463         while (token.value != endtok && token.value != TOK.endOfFile)
9464         {
9465             if (peekNext() == TOK.colon)
9466             {
9467                 // Named argument `name: exp`
9468                 auto loc = token.loc;
9469                 auto ident = token.ident;
9470                 check(TOK.identifier);
9471                 check(TOK.colon);
9472                 if (names)
9473                     names.push(ident);
9474                 else
9475                     error(loc, "named arguments not allowed here");
9476             }
9477             else
9478             {
9479                 if (names)
9480                     names.push(null);
9481             }
9482 
9483             auto arg = parseAssignExp();
9484             arguments.push(arg);
9485 
9486             if (token.value != TOK.comma)
9487                 break;
9488 
9489             nextToken(); //comma
9490         }
9491         check(endtok);
9492     }
9493 
9494     /*******************************************
9495      */
9496     private AST.Expression parseNewExp(AST.Expression thisexp)
9497     {
9498         const loc = token.loc;
9499 
9500         nextToken();
9501         AST.Expressions* arguments = null;
9502         AST.Identifiers* names = null;
9503 
9504         // An anonymous nested class starts with "class"
9505         if (token.value == TOK.class_)
9506         {
9507             nextToken();
9508             if (token.value == TOK.leftParenthesis)
9509             {
9510                 arguments = new AST.Expressions();
9511                 names = new AST.Identifiers();
9512                 parseNamedArguments(arguments, names);
9513             }
9514 
9515             AST.BaseClasses* baseclasses = null;
9516             if (token.value != TOK.leftCurly)
9517                 baseclasses = parseBaseClasses();
9518 
9519             Identifier id = null;
9520             AST.Dsymbols* members = null;
9521 
9522             if (token.value != TOK.leftCurly)
9523             {
9524                 error("`{ members }` expected for anonymous class");
9525             }
9526             else
9527             {
9528                 nextToken();
9529                 members = parseDeclDefs(0);
9530                 if (token.value != TOK.rightCurly)
9531                     error("class member expected");
9532                 nextToken();
9533             }
9534 
9535             auto cd = new AST.ClassDeclaration(loc, id, baseclasses, members, false);
9536             auto e = new AST.NewAnonClassExp(loc, thisexp, cd, arguments);
9537             return e;
9538         }
9539 
9540         const stc = parseTypeCtor();
9541         auto t = parseBasicType(true);
9542         t = parseTypeSuffixes(t);
9543         t = t.addSTC(stc);
9544         if (t.ty == Taarray)
9545         {
9546             AST.TypeAArray taa = cast(AST.TypeAArray)t;
9547             AST.Type index = taa.index;
9548             // `new Type[expr]` is a static array
9549             auto edim = AST.typeToExpression(index);
9550             if (edim)
9551                 t = new AST.TypeSArray(taa.next, edim);
9552         }
9553         else if (token.value == TOK.leftParenthesis && t.ty != Tsarray)
9554         {
9555             arguments = new AST.Expressions();
9556             names = new AST.Identifiers();
9557             parseNamedArguments(arguments, names);
9558         }
9559 
9560         auto e = new AST.NewExp(loc, thisexp, t, arguments, names);
9561         return e;
9562     }
9563 
9564     /**********************************************
9565      */
9566     private void addComment(AST.Dsymbol s, const(char)* blockComment)
9567     {
9568         if (s !is null)
9569             this.addComment(s, blockComment.toDString());
9570     }
9571 
9572     private void addComment(AST.Dsymbol s, const(char)[] blockComment)
9573     {
9574         if (s !is null)
9575         {
9576             s.addComment(combineComments(blockComment, token.lineComment, true));
9577             token.lineComment = null;
9578         }
9579     }
9580 
9581     /**********************************************
9582      * Recognize builtin @ attributes
9583      * Params:
9584      *  ident = identifier
9585      * Returns:
9586      *  storage class for attribute, 0 if not
9587      */
9588     static StorageClass isBuiltinAtAttribute(Identifier ident)
9589     {
9590         return (ident == Id.property) ? STC.property :
9591                (ident == Id.nogc)     ? STC.nogc     :
9592                (ident == Id.safe)     ? STC.safe     :
9593                (ident == Id.trusted)  ? STC.trusted  :
9594                (ident == Id.system)   ? STC.system   :
9595                (ident == Id.live)     ? STC.live     :
9596                (ident == Id.future)   ? STC.future   :
9597                (ident == Id.disable)  ? STC.disable  :
9598                0;
9599     }
9600 
9601     enum StorageClass atAttrGroup =
9602                 STC.property |
9603                 STC.nogc     |
9604                 STC.safe     |
9605                 STC.trusted  |
9606                 STC.system   |
9607                 STC.live     |
9608                 /*STC.future   |*/ // probably should be included
9609                 STC.disable;
9610 
9611     void usageOfBodyKeyword()
9612     {
9613         version (none)  // disable obsolete warning
9614         {
9615             eSink.warning(token.loc, "usage of identifer `body` as a keyword is obsolete. Use `do` instead.");
9616         }
9617     }
9618 }
9619 
9620 enum PREC : int
9621 {
9622     zero,
9623     expr,
9624     assign,
9625     cond,
9626     oror,
9627     andand,
9628     or,
9629     xor,
9630     and,
9631     equal,
9632     rel,
9633     shift,
9634     add,
9635     mul,
9636     pow,
9637     unary,
9638     primary,
9639 }
9640 
9641 /**********************************
9642  * Set operator precedence for each operator.
9643  *
9644  * Used by hdrgen
9645  */
9646 immutable PREC[EXP.max + 1] precedence =
9647 [
9648     EXP.type : PREC.expr,
9649     EXP.error : PREC.expr,
9650     EXP.objcClassReference : PREC.expr, // Objective-C class reference, same as EXP.type
9651 
9652     EXP.mixin_ : PREC.primary,
9653 
9654     EXP.import_ : PREC.primary,
9655     EXP.dotVariable : PREC.primary,
9656     EXP.scope_ : PREC.primary,
9657     EXP.identifier : PREC.primary,
9658     EXP.this_ : PREC.primary,
9659     EXP.super_ : PREC.primary,
9660     EXP.int64 : PREC.primary,
9661     EXP.float64 : PREC.primary,
9662     EXP.complex80 : PREC.primary,
9663     EXP.null_ : PREC.primary,
9664     EXP.string_ : PREC.primary,
9665     EXP.arrayLiteral : PREC.primary,
9666     EXP.assocArrayLiteral : PREC.primary,
9667     EXP.classReference : PREC.primary,
9668     EXP.file : PREC.primary,
9669     EXP.fileFullPath : PREC.primary,
9670     EXP.line : PREC.primary,
9671     EXP.moduleString : PREC.primary,
9672     EXP.functionString : PREC.primary,
9673     EXP.prettyFunction : PREC.primary,
9674     EXP.typeid_ : PREC.primary,
9675     EXP.is_ : PREC.primary,
9676     EXP.assert_ : PREC.primary,
9677     EXP.halt : PREC.primary,
9678     EXP.template_ : PREC.primary,
9679     EXP.dSymbol : PREC.primary,
9680     EXP.function_ : PREC.primary,
9681     EXP.variable : PREC.primary,
9682     EXP.symbolOffset : PREC.primary,
9683     EXP.structLiteral : PREC.primary,
9684     EXP.compoundLiteral : PREC.primary,
9685     EXP.arrayLength : PREC.primary,
9686     EXP.delegatePointer : PREC.primary,
9687     EXP.delegateFunctionPointer : PREC.primary,
9688     EXP.remove : PREC.primary,
9689     EXP.tuple : PREC.primary,
9690     EXP.traits : PREC.primary,
9691     EXP.overloadSet : PREC.primary,
9692     EXP.void_ : PREC.primary,
9693     EXP.vectorArray : PREC.primary,
9694     EXP._Generic : PREC.primary,
9695 
9696     // post
9697     EXP.dotTemplateInstance : PREC.primary,
9698     EXP.dotIdentifier : PREC.primary,
9699     EXP.dotTemplateDeclaration : PREC.primary,
9700     EXP.dot : PREC.primary,
9701     EXP.dotType : PREC.primary,
9702     EXP.plusPlus : PREC.primary,
9703     EXP.minusMinus : PREC.primary,
9704     EXP.prePlusPlus : PREC.primary,
9705     EXP.preMinusMinus : PREC.primary,
9706     EXP.call : PREC.primary,
9707     EXP.slice : PREC.primary,
9708     EXP.array : PREC.primary,
9709     EXP.index : PREC.primary,
9710 
9711     EXP.delegate_ : PREC.unary,
9712     EXP.address : PREC.unary,
9713     EXP.star : PREC.unary,
9714     EXP.negate : PREC.unary,
9715     EXP.uadd : PREC.unary,
9716     EXP.not : PREC.unary,
9717     EXP.tilde : PREC.unary,
9718     EXP.delete_ : PREC.unary,
9719     EXP.new_ : PREC.unary,
9720     EXP.newAnonymousClass : PREC.unary,
9721     EXP.cast_ : PREC.unary,
9722     EXP.throw_ : PREC.unary,
9723 
9724     EXP.vector : PREC.unary,
9725     EXP.pow : PREC.pow,
9726 
9727     EXP.mul : PREC.mul,
9728     EXP.div : PREC.mul,
9729     EXP.mod : PREC.mul,
9730 
9731     EXP.add : PREC.add,
9732     EXP.min : PREC.add,
9733     EXP.concatenate : PREC.add,
9734 
9735     EXP.leftShift : PREC.shift,
9736     EXP.rightShift : PREC.shift,
9737     EXP.unsignedRightShift : PREC.shift,
9738 
9739     EXP.lessThan : PREC.rel,
9740     EXP.lessOrEqual : PREC.rel,
9741     EXP.greaterThan : PREC.rel,
9742     EXP.greaterOrEqual : PREC.rel,
9743     EXP.in_ : PREC.rel,
9744 
9745     /* Note that we changed precedence, so that < and != have the same
9746      * precedence. This change is in the parser, too.
9747      */
9748     EXP.equal : PREC.rel,
9749     EXP.notEqual : PREC.rel,
9750     EXP.identity : PREC.rel,
9751     EXP.notIdentity : PREC.rel,
9752 
9753     EXP.and : PREC.and,
9754     EXP.xor : PREC.xor,
9755     EXP.or : PREC.or,
9756 
9757     EXP.andAnd : PREC.andand,
9758     EXP.orOr : PREC.oror,
9759 
9760     EXP.question : PREC.cond,
9761 
9762     EXP.assign : PREC.assign,
9763     EXP.construct : PREC.assign,
9764     EXP.blit : PREC.assign,
9765     EXP.addAssign : PREC.assign,
9766     EXP.minAssign : PREC.assign,
9767     EXP.concatenateAssign : PREC.assign,
9768     EXP.concatenateElemAssign : PREC.assign,
9769     EXP.concatenateDcharAssign : PREC.assign,
9770     EXP.mulAssign : PREC.assign,
9771     EXP.divAssign : PREC.assign,
9772     EXP.modAssign : PREC.assign,
9773     EXP.powAssign : PREC.assign,
9774     EXP.leftShiftAssign : PREC.assign,
9775     EXP.rightShiftAssign : PREC.assign,
9776     EXP.unsignedRightShiftAssign : PREC.assign,
9777     EXP.andAssign : PREC.assign,
9778     EXP.orAssign : PREC.assign,
9779     EXP.xorAssign : PREC.assign,
9780 
9781     EXP.comma : PREC.expr,
9782     EXP.declaration : PREC.expr,
9783 
9784     EXP.interval : PREC.assign,
9785 ];
9786 
9787 enum ParseStatementFlags : int
9788 {
9789     scope_        = 2,        // start a new scope
9790     curly         = 4,        // { } statement is required
9791     curlyScope    = 8,        // { } starts a new scope
9792     semiOk        = 0x10,     // empty ';' are really ok
9793 }
9794 
9795 struct PrefixAttributes(AST)
9796 {
9797     StorageClass storageClass;
9798     AST.Expression depmsg;
9799     LINK link;
9800     AST.Visibility visibility;
9801     bool setAlignment;
9802     AST.Expression ealign;
9803     AST.Expressions* udas;
9804     const(char)* comment;
9805 }
9806 
9807 /// The result of the `ParseLinkage` function
9808 struct ParsedLinkage(AST)
9809 {
9810     /// What linkage was specified
9811     LINK link;
9812     /// If `extern(C++, class|struct)`, contains the `class|struct`
9813     CPPMANGLE cppmangle;
9814     /// If `extern(C++, some.identifier)`, will be the identifiers
9815     AST.Identifiers* idents;
9816     /// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions
9817     AST.Expressions* identExps;
9818 }
9819 
9820 
9821 /*********************************** Private *************************************/
9822 
9823 /***********************
9824  * How multiple declarations are parsed.
9825  * If 1, treat as C.
9826  * If 0, treat:
9827  *      int *p, i;
9828  * as:
9829  *      int* p;
9830  *      int* i;
9831  */
9832 private enum CDECLSYNTAX = 0;
9833 
9834 /*****
9835  * Support C cast syntax:
9836  *      (type)(expression)
9837  */
9838 private enum CCASTSYNTAX = 1;
9839 
9840 /*****
9841  * Support postfix C array declarations, such as
9842  *      int a[3][4];
9843  */
9844 private enum CARRAYDECL = 1;
9845 
9846 /*****************************
9847  * Destructively extract storage class from pAttrs.
9848  */
9849 private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs)
9850 {
9851     StorageClass stc = STC.undefined_;
9852     if (pAttrs)
9853     {
9854         stc = pAttrs.storageClass;
9855         pAttrs.storageClass = STC.undefined_;
9856     }
9857     return stc;
9858 }