1 /**
2  * Defines a function declaration.
3  *
4  * Includes:
5  * - function/delegate literals
6  * - function aliases
7  * - (static/shared) constructors/destructors/post-blits
8  * - `invariant`
9  * - `unittest`
10  *
11  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
12  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
13  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
14  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d)
15  * Documentation:  https://dlang.org/phobos/dmd_func.html
16  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d
17  */
18 
19 module dmd.func;
20 
21 import core.stdc.stdio;
22 import core.stdc..string;
23 import dmd.aggregate;
24 import dmd.arraytypes;
25 import dmd.blockexit;
26 import dmd.gluelayer;
27 import dmd.dclass;
28 import dmd.declaration;
29 import dmd.delegatize;
30 import dmd.dinterpret;
31 import dmd.dmodule;
32 import dmd.dscope;
33 import dmd.dstruct;
34 import dmd.dsymbol;
35 import dmd.dsymbolsem;
36 import dmd.dtemplate;
37 import dmd.errors;
38 import dmd.escape;
39 import dmd.expression;
40 import dmd.globals;
41 import dmd.hdrgen;
42 import dmd.id;
43 import dmd.identifier;
44 import dmd.init;
45 import dmd.mtype;
46 import dmd.objc;
47 import dmd.root.outbuffer;
48 import dmd.root.rootobject;
49 import dmd.root..string;
50 import dmd.semantic2;
51 import dmd.semantic3;
52 import dmd.statement_rewrite_walker;
53 import dmd.statement;
54 import dmd.statementsem;
55 import dmd.tokens;
56 import dmd.visitor;
57 
58 /// Inline Status
59 enum ILS : int
60 {
61     uninitialized,       /// not computed yet
62     no,                  /// cannot inline
63     yes,                 /// can inline
64 }
65 
66 enum BUILTIN : int
67 {
68     unknown = -1,    /// not known if this is a builtin
69     unimp,           /// this is not a builtin
70     sin,
71     cos,
72     tan,
73     sqrt,
74     fabs,
75     ldexp,
76     log,
77     log2,
78     log10,
79     exp,
80     expm1,
81     exp2,
82     round,
83     floor,
84     ceil,
85     trunc,
86     copysign,
87     pow,
88     fmin,
89     fmax,
90     fma,
91     isnan,
92     isinfinity,
93     isfinite,
94     bsf,
95     bsr,
96     bswap,
97     popcnt,
98     yl2x,
99     yl2xp1,
100     toPrecFloat,
101     toPrecDouble,
102     toPrecReal
103 }
104 
105 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
106  */
107 extern (C++) final class NrvoWalker : StatementRewriteWalker
108 {
109     alias visit = typeof(super).visit;
110 public:
111     FuncDeclaration fd;
112     Scope* sc;
113 
114     override void visit(ReturnStatement s)
115     {
116         // See if all returns are instead to be replaced with a goto returnLabel;
117         if (fd.returnLabel)
118         {
119             /* Rewrite:
120              *  return exp;
121              * as:
122              *  vresult = exp; goto Lresult;
123              */
124             auto gs = new GotoStatement(s.loc, Id.returnLabel);
125             gs.label = fd.returnLabel;
126 
127             Statement s1 = gs;
128             if (s.exp)
129                 s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
130 
131             replaceCurrent(s1);
132         }
133     }
134 
135     override void visit(TryFinallyStatement s)
136     {
137         DtorExpStatement des;
138         if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
139             fd.nrvo_var == des.var)
140         {
141             if (!(global.params.useExceptions && ClassDeclaration.throwable))
142             {
143                 /* Don't need to call destructor at all, since it is nrvo
144                  */
145                 replaceCurrent(s._body);
146                 s._body.accept(this);
147                 return;
148             }
149 
150             /* Normally local variable dtors are called regardless exceptions.
151              * But for nrvo_var, its dtor should be called only when exception is thrown.
152              *
153              * Rewrite:
154              *      try { s.body; } finally { nrvo_var.edtor; }
155              *      // equivalent with:
156              *      //    s.body; scope(exit) nrvo_var.edtor;
157              * as:
158              *      try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
159              *      // equivalent with:
160              *      //    s.body; scope(failure) nrvo_var.edtor;
161              */
162             Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
163             Identifier id = Identifier.generateId("__o");
164 
165             Statement handler = new PeelStatement(sexception);
166             if (sexception.blockExit(fd, false) & BE.fallthru)
167             {
168                 auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
169                 ts.internalThrow = true;
170                 handler = new CompoundStatement(Loc.initial, handler, ts);
171             }
172 
173             auto catches = new Catches();
174             auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
175             ctch.internalCatch = true;
176             ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
177             catches.push(ctch);
178 
179             Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
180             fd.eh_none = false;
181             replaceCurrent(s2);
182             s2.accept(this);
183         }
184         else
185             StatementRewriteWalker.visit(s);
186     }
187 }
188 
189 enum FUNCFLAG : uint
190 {
191     purityInprocess  = 1,      /// working on determining purity
192     safetyInprocess  = 2,      /// working on determining safety
193     nothrowInprocess = 4,      /// working on determining nothrow
194     nogcInprocess    = 8,      /// working on determining @nogc
195     returnInprocess  = 0x10,   /// working on inferring 'return' for parameters
196     inlineScanned    = 0x20,   /// function has been scanned for inline possibilities
197     inferScope       = 0x40,   /// infer 'scope' for parameters
198     hasCatches       = 0x80,   /// function has try-catch statements
199     compileTimeOnly  = 0x100,  /// is a compile time only function; no code will be generated for it
200     printf           = 0x200,  /// is a printf-like function
201     scanf            = 0x400,  /// is a scanf-like function
202 }
203 
204 /***********************************************************
205  * Tuple of result identifier (possibly null) and statement.
206  * This is used to store out contracts: out(id){ ensure }
207  */
208 extern (C++) struct Ensure
209 {
210     Identifier id;
211     Statement ensure;
212 
213     Ensure syntaxCopy()
214     {
215         return Ensure(id, ensure.syntaxCopy());
216     }
217 
218     /*****************************************
219      * Do syntax copy of an array of Ensure's.
220      */
221     static Ensures* arraySyntaxCopy(Ensures* a)
222     {
223         Ensures* b = null;
224         if (a)
225         {
226             b = a.copy();
227             foreach (i, e; *a)
228             {
229                 (*b)[i] = e.syntaxCopy();
230             }
231         }
232         return b;
233     }
234 
235 }
236 
237 /***********************************************************
238  */
239 extern (C++) class FuncDeclaration : Declaration
240 {
241     Statements* frequires;              /// in contracts
242     Ensures* fensures;                  /// out contracts
243     Statement frequire;                 /// lowered in contract
244     Statement fensure;                  /// lowered out contract
245     Statement fbody;                    /// function body
246 
247     FuncDeclarations foverrides;        /// functions this function overrides
248     FuncDeclaration fdrequire;          /// function that does the in contract
249     FuncDeclaration fdensure;           /// function that does the out contract
250 
251     Expressions* fdrequireParams;       /// argument list for __require
252     Expressions* fdensureParams;        /// argument list for __ensure
253 
254     const(char)* mangleString;          /// mangled symbol created from mangleExact()
255 
256     VarDeclaration vresult;             /// result variable for out contracts
257     LabelDsymbol returnLabel;           /// where the return goes
258 
259     // used to prevent symbols in different
260     // scopes from having the same name
261     DsymbolTable localsymtab;
262     VarDeclaration vthis;               /// 'this' parameter (member and nested)
263     bool isThis2;                       /// has a dual-context 'this' parameter
264     VarDeclaration v_arguments;         /// '_arguments' parameter
265     ObjcSelector* selector;             /// Objective-C method selector (member function only)
266     VarDeclaration selectorParameter;   /// Objective-C implicit selector parameter
267 
268     VarDeclaration v_argptr;            /// '_argptr' variable
269     VarDeclarations* parameters;        /// Array of VarDeclaration's for parameters
270     DsymbolTable labtab;                /// statement label symbol table
271     Dsymbol overnext;                   /// next in overload list
272     FuncDeclaration overnext0;          /// next in overload list (only used during IFTI)
273     Loc endloc;                         /// location of closing curly bracket
274     int vtblIndex = -1;                 /// for member functions, index into vtbl[]
275     bool naked;                         /// true if naked
276     bool generated;                     /// true if function was generated by the compiler rather than
277                                         /// supplied by the user
278     ubyte isCrtCtorDtor;                /// has attribute pragma(crt_constructor(1)/crt_destructor(2))
279                                         /// not set before the glue layer
280 
281     ILS inlineStatusStmt = ILS.uninitialized;
282     ILS inlineStatusExp = ILS.uninitialized;
283     PINLINE inlining = PINLINE.default_;
284 
285     int inlineNest;                     /// !=0 if nested inline
286     bool isArrayOp;                     /// true if array operation
287     bool eh_none;                       /// true if no exception unwinding is needed
288 
289     bool semantic3Errors;               /// true if errors in semantic3 this function's frame ptr
290     ForeachStatement fes;               /// if foreach body, this is the foreach
291     BaseClass* interfaceVirtual;        /// if virtual, but only appears in base interface vtbl[]
292     bool introducing;                   /// true if 'introducing' function
293     /** if !=NULL, then this is the type
294     of the 'introducing' function
295     this one is overriding
296     */
297     Type tintro;
298 
299     bool inferRetType;                  /// true if return type is to be inferred
300     StorageClass storage_class2;        /// storage class for template onemember's
301 
302     // Things that should really go into Scope
303 
304     /// 1 if there's a return exp; statement
305     /// 2 if there's a throw statement
306     /// 4 if there's an assert(0)
307     /// 8 if there's inline asm
308     /// 16 if there are multiple return statements
309     int hasReturnExp;
310 
311     // Support for NRVO (named return value optimization)
312     bool nrvo_can = true;               /// true means we can do NRVO
313     VarDeclaration nrvo_var;            /// variable to replace with shidden
314     Symbol* shidden;                    /// hidden pointer passed to function
315 
316     ReturnStatements* returns;
317 
318     GotoStatements* gotos;              /// Gotos with forward references
319 
320     /// set if this is a known, builtin function we can evaluate at compile time
321     BUILTIN builtin = BUILTIN.unknown;
322 
323     /// set if someone took the address of this function
324     int tookAddressOf;
325 
326     bool requiresClosure;               // this function needs a closure
327 
328     /** local variables in this function which are referenced by nested functions
329      * (They'll get put into the "closure" for this function.)
330      */
331     VarDeclarations closureVars;
332 
333     /** Outer variables which are referenced by this nested function
334      * (the inverse of closureVars)
335      */
336     VarDeclarations outerVars;
337 
338     /// Sibling nested functions which called this one
339     FuncDeclarations siblingCallers;
340 
341     FuncDeclarations *inlinedNestedCallees;
342 
343     uint flags;                        /// FUNCFLAG.xxxxx
344 
345     extern (D) bool delegate(FuncDeclaration func, Scope* scope_, bool delegate(Scope*) defaultCanInferAttributes) canInferAttributesOverride;
346 
347     extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type)
348     {
349         super(loc, ident);
350         //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type);
351         //printf("storage_class = x%x\n", storage_class);
352         this.storage_class = storage_class;
353         this.type = type;
354         if (type)
355         {
356             // Normalize storage_class, because function-type related attributes
357             // are already set in the 'type' in parsing phase.
358             this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
359         }
360         this.endloc = endloc;
361         /* The type given for "infer the return type" is a TypeFunction with
362          * NULL for the return type.
363          */
364         inferRetType = (type && type.nextOf() is null);
365     }
366 
367     static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type)
368     {
369         return new FuncDeclaration(loc, endloc, id, storage_class, type);
370     }
371 
372     override Dsymbol syntaxCopy(Dsymbol s)
373     {
374         //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
375         FuncDeclaration f = s ? cast(FuncDeclaration)s : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy());
376         f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
377         f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
378         f.fbody = fbody ? fbody.syntaxCopy() : null;
379         return f;
380     }
381 
382     /****************************************************
383      * Resolve forward reference of function signature -
384      * parameter types, return type, and attributes.
385      * Returns false if any errors exist in the signature.
386      */
387     final bool functionSemantic()
388     {
389         if (!_scope)
390             return !errors;
391 
392         if (!originalType) // semantic not yet run
393         {
394             TemplateInstance spec = isSpeculative();
395             uint olderrs = global.errors;
396             uint oldgag = global.gag;
397             if (global.gag && !spec)
398                 global.gag = 0;
399             dsymbolSemantic(this, _scope);
400             global.gag = oldgag;
401             if (spec && global.errors != olderrs)
402                 spec.errors = (global.errors - olderrs != 0);
403             if (olderrs != global.errors) // if errors compiling this function
404                 return false;
405         }
406 
407         this.cppnamespace = _scope.namespace;
408 
409         // if inferring return type, sematic3 needs to be run
410         // - When the function body contains any errors, we cannot assume
411         //   the inferred return type is valid.
412         //   So, the body errors should become the function signature error.
413         if (inferRetType && type && !type.nextOf())
414             return functionSemantic3();
415 
416         TemplateInstance ti;
417         if (isInstantiated() && !isVirtualMethod() &&
418             ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident))
419         {
420             AggregateDeclaration ad = isMemberLocal();
421             if (ad && ad.sizeok != Sizeok.done)
422             {
423                 /* Currently dmd cannot resolve forward references per methods,
424                  * then setting SIZOKfwd is too conservative and would break existing code.
425                  * So, just stop method attributes inference until ad.dsymbolSemantic() done.
426                  */
427                 //ad.sizeok = Sizeok.fwd;
428             }
429             else
430                 return functionSemantic3() || !errors;
431         }
432 
433         if (storage_class & STC.inference)
434             return functionSemantic3() || !errors;
435 
436         return !errors;
437     }
438 
439     /****************************************************
440      * Resolve forward reference of function body.
441      * Returns false if any errors exist in the body.
442      */
443     final bool functionSemantic3()
444     {
445         if (semanticRun < PASS.semantic3 && _scope)
446         {
447             /* Forward reference - we need to run semantic3 on this function.
448              * If errors are gagged, and it's not part of a template instance,
449              * we need to temporarily ungag errors.
450              */
451             TemplateInstance spec = isSpeculative();
452             uint olderrs = global.errors;
453             uint oldgag = global.gag;
454             if (global.gag && !spec)
455                 global.gag = 0;
456             semantic3(this, _scope);
457             global.gag = oldgag;
458 
459             // If it is a speculatively-instantiated template, and errors occur,
460             // we need to mark the template as having errors.
461             if (spec && global.errors != olderrs)
462                 spec.errors = (global.errors - olderrs != 0);
463             if (olderrs != global.errors) // if errors compiling this function
464                 return false;
465         }
466 
467         return !errors && !semantic3Errors;
468     }
469 
470     /****************************************************
471      * Check that this function type is properly resolved.
472      * If not, report "forward reference error" and return true.
473      */
474     extern (D) final bool checkForwardRef(const ref Loc loc)
475     {
476         if (!functionSemantic())
477             return true;
478 
479         /* No deco means the functionSemantic() call could not resolve
480          * forward referenes in the type of this function.
481          */
482         if (!type.deco)
483         {
484             bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3);
485             .error(loc, "forward reference to %s`%s`",
486                 (inSemantic3 ? "inferred return type of function " : "").ptr,
487                 toChars());
488             return true;
489         }
490         return false;
491     }
492 
493     // called from semantic3
494     /**
495      * Creates and returns the hidden parameters for this function declaration.
496      *
497      * Hidden parameters include the `this` parameter of a class, struct or
498      * nested function and the selector parameter for Objective-C methods.
499      */
500     extern (D) final void declareThis(Scope* sc)
501     {
502         isThis2 = toParent2() != toParentLocal();
503         auto ad = isThis();
504         if (!isThis2 && !ad && !isNested())
505         {
506             vthis = null;
507             selectorParameter = null;
508             return;
509         }
510 
511         Type addModStc(Type t)
512         {
513             return t.addMod(type.mod).addStorageClass(storage_class);
514         }
515 
516         if (isThis2 || isNested())
517         {
518             /* The 'this' for a nested function is the link to the
519              * enclosing function's stack frame.
520              * Note that nested functions and member functions are disjoint.
521              */
522             Type tthis = addModStc(isThis2 ?
523                                    Type.tvoidptr.sarrayOf(2).pointerTo() :
524                                    Type.tvoid.pointerTo());
525             vthis = new VarDeclaration(loc, tthis, isThis2 ? Id.this2 : Id.capture, null);
526             vthis.storage_class |= STC.parameter | STC.nodtor;
527         }
528         else if (ad)
529         {
530             Type thandle = addModStc(ad.handleType());
531             vthis = new ThisDeclaration(loc, thandle);
532             vthis.storage_class |= STC.parameter;
533             if (thandle.ty == Tstruct)
534             {
535                 vthis.storage_class |= STC.ref_;
536                 // if member function is marked 'inout', then 'this' is 'return ref'
537                 if (type.ty == Tfunction && (cast(TypeFunction)type).iswild & 2)
538                     vthis.storage_class |= STC.return_;
539             }
540         }
541 
542         if (type.ty == Tfunction)
543         {
544             TypeFunction tf = cast(TypeFunction)type;
545             if (tf.isreturn)
546                 vthis.storage_class |= STC.return_;
547             if (tf.isscope)
548                 vthis.storage_class |= STC.scope_;
549         }
550         if (flags & FUNCFLAG.inferScope && !(vthis.storage_class & STC.scope_))
551             vthis.storage_class |= STC.maybescope;
552 
553         vthis.dsymbolSemantic(sc);
554         if (!sc.insert(vthis))
555             assert(0);
556         vthis.parent = this;
557         if (ad)
558             selectorParameter = objc.createSelectorParameter(this, sc);
559     }
560 
561     override final bool equals(const RootObject o) const
562     {
563         if (this == o)
564             return true;
565 
566         if (auto s = isDsymbol(o))
567         {
568             auto fd1 = this;
569             auto fd2 = s.isFuncDeclaration();
570             if (!fd2)
571                 return false;
572 
573             auto fa1 = fd1.isFuncAliasDeclaration();
574             auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
575 
576             auto fa2 = fd2.isFuncAliasDeclaration();
577             auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
578 
579             if (fa1 && fa2)
580             {
581                 return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
582             }
583 
584             bool b1 = fa1 !is null;
585             if (b1 && faf1.isUnique() && !fa1.hasOverloads)
586                 b1 = false;
587 
588             bool b2 = fa2 !is null;
589             if (b2 && faf2.isUnique() && !fa2.hasOverloads)
590                 b2 = false;
591 
592             if (b1 != b2)
593                 return false;
594 
595             return faf1.toParent().equals(faf2.toParent()) &&
596                    faf1.ident.equals(faf2.ident) &&
597                    faf1.type.equals(faf2.type);
598         }
599         return false;
600     }
601 
602     /****************************************************
603      * Determine if 'this' overrides fd.
604      * Return !=0 if it does.
605      */
606     final int overrides(FuncDeclaration fd)
607     {
608         int result = 0;
609         if (fd.ident == ident)
610         {
611             int cov = type.covariant(fd.type);
612             if (cov)
613             {
614                 ClassDeclaration cd1 = toParent().isClassDeclaration();
615                 ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
616                 if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
617                     result = 1;
618             }
619         }
620         return result;
621     }
622 
623     /*************************************************
624      * Find index of function in vtbl[0..dim] that
625      * this function overrides.
626      * Prefer an exact match to a covariant one.
627      * Params:
628      *      vtbl     = vtable to use
629      *      dim      = maximal vtable dimension
630      *      fix17349 = enable fix https://issues.dlang.org/show_bug.cgi?id=17349
631      * Returns:
632      *      -1      didn't find one
633      *      -2      can't determine because of forward references
634      */
635     final int findVtblIndex(Dsymbols* vtbl, int dim, bool fix17349 = true)
636     {
637         //printf("findVtblIndex() %s\n", toChars());
638         FuncDeclaration mismatch = null;
639         StorageClass mismatchstc = 0;
640         int mismatchvi = -1;
641         int exactvi = -1;
642         int bestvi = -1;
643         for (int vi = 0; vi < dim; vi++)
644         {
645             FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration();
646             if (fdv && fdv.ident == ident)
647             {
648                 if (type.equals(fdv.type)) // if exact match
649                 {
650                     if (fdv.parent.isClassDeclaration())
651                     {
652                         if (fdv.isFuture())
653                         {
654                             bestvi = vi;
655                             continue;           // keep looking
656                         }
657                         return vi; // no need to look further
658                     }
659 
660                     if (exactvi >= 0)
661                     {
662                         error("cannot determine overridden function");
663                         return exactvi;
664                     }
665                     exactvi = vi;
666                     bestvi = vi;
667                     continue;
668                 }
669 
670                 StorageClass stc = 0;
671                 int cov = type.covariant(fdv.type, &stc, fix17349);
672                 //printf("\tbaseclass cov = %d\n", cov);
673                 switch (cov)
674                 {
675                 case 0:
676                     // types are distinct
677                     break;
678 
679                 case 1:
680                     bestvi = vi; // covariant, but not identical
681                     break;
682                     // keep looking for an exact match
683 
684                 case 2:
685                     mismatchvi = vi;
686                     mismatchstc = stc;
687                     mismatch = fdv; // overrides, but is not covariant
688                     break;
689                     // keep looking for an exact match
690 
691                 case 3:
692                     return -2; // forward references
693 
694                 default:
695                     assert(0);
696                 }
697             }
698         }
699         if (bestvi == -1 && mismatch)
700         {
701             //type.print();
702             //mismatch.type.print();
703             //printf("%s %s\n", type.deco, mismatch.type.deco);
704             //printf("stc = %llx\n", mismatchstc);
705             if (mismatchstc)
706             {
707                 // Fix it by modifying the type to add the storage classes
708                 type = type.addStorageClass(mismatchstc);
709                 bestvi = mismatchvi;
710             }
711         }
712         return bestvi;
713     }
714 
715     /*********************************
716      * If function a function in a base class,
717      * return that base class.
718      * Returns:
719      *  base class if overriding, null if not
720      */
721     final BaseClass* overrideInterface()
722     {
723         if (ClassDeclaration cd = toParent2().isClassDeclaration())
724         {
725             foreach (b; cd.interfaces)
726             {
727                 auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim);
728                 if (v >= 0)
729                     return b;
730             }
731         }
732         return null;
733     }
734 
735     /****************************************************
736      * Overload this FuncDeclaration with the new one f.
737      * Return true if successful; i.e. no conflict.
738      */
739     override bool overloadInsert(Dsymbol s)
740     {
741         //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
742         assert(s != this);
743         AliasDeclaration ad = s.isAliasDeclaration();
744         if (ad)
745         {
746             if (overnext)
747                 return overnext.overloadInsert(ad);
748             if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof)
749             {
750                 //printf("\tad = '%s'\n", ad.type.toChars());
751                 return false;
752             }
753             overnext = ad;
754             //printf("\ttrue: no conflict\n");
755             return true;
756         }
757         TemplateDeclaration td = s.isTemplateDeclaration();
758         if (td)
759         {
760             if (!td.funcroot)
761                 td.funcroot = this;
762             if (overnext)
763                 return overnext.overloadInsert(td);
764             overnext = td;
765             return true;
766         }
767         FuncDeclaration fd = s.isFuncDeclaration();
768         if (!fd)
769             return false;
770 
771         version (none)
772         {
773             /* Disable this check because:
774              *  const void foo();
775              * semantic() isn't run yet on foo(), so the const hasn't been
776              * applied yet.
777              */
778             if (type)
779             {
780                 printf("type = %s\n", type.toChars());
781                 printf("fd.type = %s\n", fd.type.toChars());
782             }
783             // fd.type can be NULL for overloaded constructors
784             if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
785             {
786                 //printf("\tfalse: conflict %s\n", kind());
787                 return false;
788             }
789         }
790 
791         if (overnext)
792         {
793             td = overnext.isTemplateDeclaration();
794             if (td)
795                 fd.overloadInsert(td);
796             else
797                 return overnext.overloadInsert(fd);
798         }
799         overnext = fd;
800         //printf("\ttrue: no conflict\n");
801         return true;
802     }
803 
804     /********************************************
805      * Find function in overload list that exactly matches t.
806      */
807     extern (D) final FuncDeclaration overloadExactMatch(Type t)
808     {
809         FuncDeclaration fd;
810         overloadApply(this, (Dsymbol s)
811         {
812             auto f = s.isFuncDeclaration();
813             if (!f)
814                 return 0;
815             if (t.equals(f.type))
816             {
817                 fd = f;
818                 return 1;
819             }
820 
821             /* Allow covariant matches, as long as the return type
822              * is just a const conversion.
823              * This allows things like pure functions to match with an impure function type.
824              */
825             if (t.ty == Tfunction)
826             {
827                 auto tf = cast(TypeFunction)f.type;
828                 if (tf.covariant(t) == 1 &&
829                     tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
830                 {
831                     fd = f;
832                     return 1;
833                 }
834             }
835             return 0;
836         });
837         return fd;
838     }
839 
840     /********************************************
841      * Find function in overload list that matches to the 'this' modifier.
842      * There's four result types.
843      *
844      * 1. If the 'tthis' matches only one candidate, it's an "exact match".
845      *    Returns the function and 'hasOverloads' is set to false.
846      *      eg. If 'tthis" is mutable and there's only one mutable method.
847      * 2. If there's two or more match candidates, but a candidate function will be
848      *    a "better match".
849      *    Returns the better match function but 'hasOverloads' is set to true.
850      *      eg. If 'tthis' is mutable, and there's both mutable and const methods,
851      *          the mutable method will be a better match.
852      * 3. If there's two or more match candidates, but there's no better match,
853      *    Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
854      *      eg. If 'tthis' is mutable, and there's two or more mutable methods.
855      * 4. If there's no candidates, it's "no match" and returns null with error report.
856      *      e.g. If 'tthis' is const but there's no const methods.
857      */
858     extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
859     {
860         //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
861         MatchAccumulator m;
862         overloadApply(this, (Dsymbol s)
863         {
864             auto f = s.isFuncDeclaration();
865             if (!f || f == m.lastf) // skip duplicates
866                 return 0;
867 
868             auto tf = f.type.toTypeFunction();
869             //printf("tf = %s\n", tf.toChars());
870 
871             MATCH match;
872             if (tthis) // non-static functions are preferred than static ones
873             {
874                 if (f.needThis())
875                     match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
876                 else
877                     match = MATCH.constant; // keep static function in overload candidates
878             }
879             else // static functions are preferred than non-static ones
880             {
881                 if (f.needThis())
882                     match = MATCH.convert;
883                 else
884                     match = MATCH.exact;
885             }
886             if (match == MATCH.nomatch)
887                 return 0;
888 
889             if (match > m.last) goto LcurrIsBetter;
890             if (match < m.last) goto LlastIsBetter;
891 
892             // See if one of the matches overrides the other.
893             if (m.lastf.overrides(f)) goto LlastIsBetter;
894             if (f.overrides(m.lastf)) goto LcurrIsBetter;
895 
896             //printf("\tambiguous\n");
897             m.nextf = f;
898             m.count++;
899             return 0;
900 
901         LlastIsBetter:
902             //printf("\tlastbetter\n");
903             m.count++; // count up
904             return 0;
905 
906         LcurrIsBetter:
907             //printf("\tisbetter\n");
908             if (m.last <= MATCH.convert)
909             {
910                 // clear last secondary matching
911                 m.nextf = null;
912                 m.count = 0;
913             }
914             m.last = match;
915             m.lastf = f;
916             m.count++; // count up
917             return 0;
918         });
919 
920         if (m.count == 1)       // exact match
921         {
922             hasOverloads = false;
923         }
924         else if (m.count > 1)   // better or ambiguous match
925         {
926             hasOverloads = true;
927         }
928         else                    // no match
929         {
930             hasOverloads = true;
931             auto tf = this.type.toTypeFunction();
932             assert(tthis);
933             assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
934             {
935                 OutBuffer thisBuf, funcBuf;
936                 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
937                 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
938                 .error(loc, "%smethod %s is not callable using a %sobject",
939                     funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
940             }
941         }
942         return m.lastf;
943     }
944 
945     /********************************************
946      * find function template root in overload list
947      */
948     extern (D) final TemplateDeclaration findTemplateDeclRoot()
949     {
950         FuncDeclaration f = this;
951         while (f && f.overnext)
952         {
953             //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
954             TemplateDeclaration td = f.overnext.isTemplateDeclaration();
955             if (td)
956                 return td;
957             f = f.overnext.isFuncDeclaration();
958         }
959         return null;
960     }
961 
962     /********************************************
963      * Returns true if function was declared
964      * directly or indirectly in a unittest block
965      */
966     final bool inUnittest()
967     {
968         Dsymbol f = this;
969         do
970         {
971             if (f.isUnitTestDeclaration())
972                 return true;
973             f = f.toParent();
974         }
975         while (f);
976         return false;
977     }
978 
979     /*************************************
980      * Determine partial specialization order of 'this' vs g.
981      * This is very similar to TemplateDeclaration::leastAsSpecialized().
982      * Returns:
983      *      match   'this' is at least as specialized as g
984      *      0       g is more specialized than 'this'
985      */
986     final MATCH leastAsSpecialized(FuncDeclaration g)
987     {
988         enum LOG_LEASTAS = 0;
989         static if (LOG_LEASTAS)
990         {
991             printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars());
992             printf("%s, %s\n", type.toChars(), g.type.toChars());
993         }
994 
995         /* This works by calling g() with f()'s parameters, and
996          * if that is possible, then f() is at least as specialized
997          * as g() is.
998          */
999 
1000         TypeFunction tf = type.toTypeFunction();
1001         TypeFunction tg = g.type.toTypeFunction();
1002         size_t nfparams = tf.parameterList.length;
1003 
1004         /* If both functions have a 'this' pointer, and the mods are not
1005          * the same and g's is not const, then this is less specialized.
1006          */
1007         if (needThis() && g.needThis() && tf.mod != tg.mod)
1008         {
1009             if (isCtorDeclaration())
1010             {
1011                 if (!MODimplicitConv(tg.mod, tf.mod))
1012                     return MATCH.nomatch;
1013             }
1014             else
1015             {
1016                 if (!MODimplicitConv(tf.mod, tg.mod))
1017                     return MATCH.nomatch;
1018             }
1019         }
1020 
1021         /* Create a dummy array of arguments out of the parameters to f()
1022          */
1023         Expressions args = Expressions(nfparams);
1024         for (size_t u = 0; u < nfparams; u++)
1025         {
1026             Parameter p = tf.parameterList[u];
1027             Expression e;
1028             if (p.storageClass & (STC.ref_ | STC.out_))
1029             {
1030                 e = new IdentifierExp(Loc.initial, p.ident);
1031                 e.type = p.type;
1032             }
1033             else
1034                 e = p.type.defaultInitLiteral(Loc.initial);
1035             args[u] = e;
1036         }
1037 
1038         MATCH m = tg.callMatch(null, args[], 1);
1039         if (m > MATCH.nomatch)
1040         {
1041             /* A variadic parameter list is less specialized than a
1042              * non-variadic one.
1043              */
1044             if (tf.parameterList.varargs && !tg.parameterList.varargs)
1045                 goto L1; // less specialized
1046 
1047             static if (LOG_LEASTAS)
1048             {
1049                 printf("  matches %d, so is least as specialized\n", m);
1050             }
1051             return m;
1052         }
1053     L1:
1054         static if (LOG_LEASTAS)
1055         {
1056             printf("  doesn't match, so is not as specialized\n");
1057         }
1058         return MATCH.nomatch;
1059     }
1060 
1061     /********************************
1062      * Labels are in a separate scope, one per function.
1063      */
1064     final LabelDsymbol searchLabel(Identifier ident)
1065     {
1066         Dsymbol s;
1067         if (!labtab)
1068             labtab = new DsymbolTable(); // guess we need one
1069 
1070         s = labtab.lookup(ident);
1071         if (!s)
1072         {
1073             s = new LabelDsymbol(ident);
1074             labtab.insert(s);
1075         }
1076         return cast(LabelDsymbol)s;
1077     }
1078 
1079     /*****************************************
1080      * Determine lexical level difference from `this` to nested function `fd`.
1081      * Params:
1082      *      fd = target of call
1083      *      intypeof = !=0 if inside typeof
1084      * Returns:
1085      *      0       same level
1086      *      >0      decrease nesting by number
1087      *      -1      increase nesting by 1 (`fd` is nested within `this`)
1088      *      LevelError  error, `this` cannot call `fd`
1089      */
1090     final int getLevel(FuncDeclaration fd, int intypeof)
1091     {
1092         //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
1093         Dsymbol fdparent = fd.toParent2();
1094         if (fdparent == this)
1095             return -1;
1096 
1097         Dsymbol s = this;
1098         int level = 0;
1099         while (fd != s && fdparent != s.toParent2())
1100         {
1101             //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
1102             if (auto thisfd = s.isFuncDeclaration())
1103             {
1104                 if (!thisfd.isNested() && !thisfd.vthis && !intypeof)
1105                     return LevelError;
1106             }
1107             else
1108             {
1109                 if (auto thiscd = s.isAggregateDeclaration())
1110                 {
1111                     /* AggregateDeclaration::isNested returns true only when
1112                      * it has a hidden pointer.
1113                      * But, calling the function belongs unrelated lexical scope
1114                      * is still allowed inside typeof.
1115                      *
1116                      * struct Map(alias fun) {
1117                      *   typeof({ return fun(); }) RetType;
1118                      *   // No member function makes Map struct 'not nested'.
1119                      * }
1120                      */
1121                     if (!thiscd.isNested() && !intypeof)
1122                         return LevelError;
1123                 }
1124                 else
1125                     return LevelError;
1126             }
1127 
1128             s = s.toParentP(fd);
1129             assert(s);
1130             level++;
1131         }
1132         return level;
1133     }
1134 
1135     /***********************************
1136      * Determine lexical level difference from `this` to nested function `fd`.
1137      * Issue error if `this` cannot call `fd`.
1138      * Params:
1139      *      loc = location for error messages
1140      *      sc = context
1141      *      fd = target of call
1142      * Returns:
1143      *      0       same level
1144      *      >0      decrease nesting by number
1145      *      -1      increase nesting by 1 (`fd` is nested within 'this')
1146      *      LevelError  error
1147      */
1148     final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd)
1149     {
1150         int level = getLevel(fd, sc.intypeof);
1151         if (level != LevelError)
1152             return level;
1153 
1154         // Don't give error if in template constraint
1155         if (!(sc.flags & SCOPE.constraint))
1156         {
1157             const(char)* xstatic = isStatic() ? "static " : "";
1158             // better diagnostics for static functions
1159             .error(loc, "%s%s %s cannot access frame of function %s",
1160                 xstatic, kind(), toPrettyChars(), fd.toPrettyChars());
1161             return LevelError;
1162         }
1163         return 1;
1164     }
1165 
1166     enum LevelError = -2;
1167 
1168     override const(char)* toPrettyChars(bool QualifyTypes = false)
1169     {
1170         if (isMain())
1171             return "D main";
1172         else
1173             return Dsymbol.toPrettyChars(QualifyTypes);
1174     }
1175 
1176     /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
1177     final const(char)* toFullSignature()
1178     {
1179         OutBuffer buf;
1180         functionToBufferWithIdent(type.toTypeFunction(), &buf, toChars());
1181         return buf.extractChars();
1182     }
1183 
1184     final bool isMain() const
1185     {
1186         return ident == Id.main && linkage != LINK.c && !isMember() && !isNested();
1187     }
1188 
1189     final bool isCMain() const
1190     {
1191         return ident == Id.main && linkage == LINK.c && !isMember() && !isNested();
1192     }
1193 
1194     final bool isWinMain() const
1195     {
1196         //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1197         version (none)
1198         {
1199             bool x = ident == Id.WinMain && linkage != LINK.c && !isMember();
1200             printf("%s\n", x ? "yes" : "no");
1201             return x;
1202         }
1203         else
1204         {
1205             return ident == Id.WinMain && linkage != LINK.c && !isMember();
1206         }
1207     }
1208 
1209     final bool isDllMain() const
1210     {
1211         return ident == Id.DllMain && linkage != LINK.c && !isMember();
1212     }
1213 
1214     final bool isRtInit() const
1215     {
1216         return ident == Id.rt_init && linkage == LINK.c && !isMember() && !isNested();
1217     }
1218 
1219     override final bool isExport() const
1220     {
1221         return protection.kind == Prot.Kind.export_;
1222     }
1223 
1224     override final bool isImportedSymbol() const
1225     {
1226         //printf("isImportedSymbol()\n");
1227         //printf("protection = %d\n", protection);
1228         return (protection.kind == Prot.Kind.export_) && !fbody;
1229     }
1230 
1231     override final bool isCodeseg() const pure nothrow @nogc @safe
1232     {
1233         return true; // functions are always in the code segment
1234     }
1235 
1236     override final bool isOverloadable() const
1237     {
1238         return true; // functions can be overloaded
1239     }
1240 
1241     /***********************************
1242      * Override so it can work even if semantic() hasn't yet
1243      * been run.
1244      */
1245     override final bool isAbstract()
1246     {
1247         if (storage_class & STC.abstract_)
1248             return true;
1249         if (semanticRun >= PASS.semanticdone)
1250             return false;
1251 
1252         if (_scope)
1253         {
1254            if (_scope.stc & STC.abstract_)
1255                 return true;
1256            parent = _scope.parent;
1257            Dsymbol parent = toParent();
1258            if (parent.isInterfaceDeclaration())
1259                 return true;
1260         }
1261         return false;
1262     }
1263 
1264     /**********************************
1265      * Decide if attributes for this function can be inferred from examining
1266      * the function body.
1267      * Returns:
1268      *  true if can
1269      */
1270     final bool canInferAttributes(Scope* sc)
1271     {
1272         if (canInferAttributesOverride)
1273             return canInferAttributesOverride(this, sc, &canInferAttributesImpl);
1274 
1275         return canInferAttributesImpl(sc);
1276     }
1277 
1278     extern (D) final bool canInferAttributesImpl(Scope* sc)
1279     {
1280         if (!fbody)
1281             return false;
1282 
1283         if (isVirtualMethod())
1284             return false;               // since they may be overridden
1285 
1286         if (sc.func &&
1287             /********** this is for backwards compatibility for the moment ********/
1288             (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
1289             return true;
1290 
1291         if (isFuncLiteralDeclaration() ||               // externs are not possible with literals
1292             (storage_class & STC.inference) ||           // do attribute inference
1293             (inferRetType && !isCtorDeclaration()))
1294             return true;
1295 
1296         if (isInstantiated())
1297         {
1298             auto ti = parent.isTemplateInstance();
1299             if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
1300                 return true;
1301         }
1302 
1303         return false;
1304     }
1305 
1306     /*****************************************
1307      * Initialize for inferring the attributes of this function.
1308      */
1309     final void initInferAttributes()
1310     {
1311         //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1312         TypeFunction tf = type.toTypeFunction();
1313         if (tf.purity == PURE.impure) // purity not specified
1314             flags |= FUNCFLAG.purityInprocess;
1315 
1316         if (tf.trust == TRUST.default_)
1317             flags |= FUNCFLAG.safetyInprocess;
1318 
1319         if (!tf.isnothrow)
1320             flags |= FUNCFLAG.nothrowInprocess;
1321 
1322         if (!tf.isnogc)
1323             flags |= FUNCFLAG.nogcInprocess;
1324 
1325         if (!isVirtual() || introducing)
1326             flags |= FUNCFLAG.returnInprocess;
1327 
1328         // Initialize for inferring STC.scope_
1329         if (global.params.vsafe)
1330             flags |= FUNCFLAG.inferScope;
1331     }
1332 
1333     final PURE isPure()
1334     {
1335         //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1336         TypeFunction tf = type.toTypeFunction();
1337         if (flags & FUNCFLAG.purityInprocess)
1338             setImpure();
1339         if (tf.purity == PURE.fwdref)
1340             tf.purityLevel();
1341         PURE purity = tf.purity;
1342         if (purity > PURE.weak && isNested())
1343             purity = PURE.weak;
1344         if (purity > PURE.weak && needThis())
1345         {
1346             // The attribute of the 'this' reference affects purity strength
1347             if (type.mod & MODFlags.immutable_)
1348             {
1349             }
1350             else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
1351                 purity = PURE.const_;
1352             else
1353                 purity = PURE.weak;
1354         }
1355         tf.purity = purity;
1356         // ^ This rely on the current situation that every FuncDeclaration has a
1357         //   unique TypeFunction.
1358         return purity;
1359     }
1360 
1361     final PURE isPureBypassingInference()
1362     {
1363         if (flags & FUNCFLAG.purityInprocess)
1364             return PURE.fwdref;
1365         else
1366             return isPure();
1367     }
1368 
1369     /**************************************
1370      * The function is doing something impure,
1371      * so mark it as impure.
1372      * If there's a purity error, return true.
1373      */
1374     extern (D) final bool setImpure()
1375     {
1376         if (flags & FUNCFLAG.purityInprocess)
1377         {
1378             flags &= ~FUNCFLAG.purityInprocess;
1379             if (fes)
1380                 fes.func.setImpure();
1381         }
1382         else if (isPure())
1383             return true;
1384         return false;
1385     }
1386 
1387     final bool isSafe()
1388     {
1389         if (flags & FUNCFLAG.safetyInprocess)
1390             setUnsafe();
1391         return type.toTypeFunction().trust == TRUST.safe;
1392     }
1393 
1394     final bool isSafeBypassingInference()
1395     {
1396         return !(flags & FUNCFLAG.safetyInprocess) && isSafe();
1397     }
1398 
1399     final bool isTrusted()
1400     {
1401         if (flags & FUNCFLAG.safetyInprocess)
1402             setUnsafe();
1403         return type.toTypeFunction().trust == TRUST.trusted;
1404     }
1405 
1406     /**************************************
1407      * The function is doing something unsafe,
1408      * so mark it as unsafe.
1409      * If there's a safe error, return true.
1410      */
1411     extern (D) final bool setUnsafe()
1412     {
1413         if (flags & FUNCFLAG.safetyInprocess)
1414         {
1415             flags &= ~FUNCFLAG.safetyInprocess;
1416             type.toTypeFunction().trust = TRUST.system;
1417             if (fes)
1418                 fes.func.setUnsafe();
1419         }
1420         else if (isSafe())
1421             return true;
1422         return false;
1423     }
1424 
1425     final bool isNogc()
1426     {
1427         //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1428         if (flags & FUNCFLAG.nogcInprocess)
1429             setGC();
1430         return type.toTypeFunction().isnogc;
1431     }
1432 
1433     final bool isNogcBypassingInference()
1434     {
1435         return !(flags & FUNCFLAG.nogcInprocess) && isNogc();
1436     }
1437 
1438     /**************************************
1439      * The function is doing something that may allocate with the GC,
1440      * so mark it as not nogc (not no-how).
1441      * Returns:
1442      *      true if function is marked as @nogc, meaning a user error occurred
1443      */
1444     extern (D) final bool setGC()
1445     {
1446         //printf("setGC() %s\n", toChars());
1447         if (flags & FUNCFLAG.nogcInprocess && semanticRun < PASS.semantic3 && _scope)
1448         {
1449             this.semantic2(_scope);
1450             this.semantic3(_scope);
1451         }
1452 
1453         if (flags & FUNCFLAG.nogcInprocess)
1454         {
1455             flags &= ~FUNCFLAG.nogcInprocess;
1456             type.toTypeFunction().isnogc = false;
1457             if (fes)
1458                 fes.func.setGC();
1459         }
1460         else if (isNogc())
1461             return true;
1462         return false;
1463     }
1464 
1465     extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
1466     {
1467         if (!global.params.vgc)
1468             return;
1469 
1470         Module m = getModule();
1471         if (m && m.isRoot() && !inUnittest())
1472         {
1473             message(loc, "vgc: %s", warn);
1474         }
1475     }
1476 
1477     /********************************************
1478      * See if pointers from function parameters, mutable globals, or uplevel functions
1479      * could leak into return value.
1480      * Returns:
1481      *   true if the function return value is isolated from
1482      *   any inputs to the function
1483      */
1484     extern (D) final bool isReturnIsolated()
1485     {
1486         TypeFunction tf = type.toTypeFunction();
1487         assert(tf.next);
1488 
1489         Type treti = tf.next;
1490         if (tf.isref)
1491             return isTypeIsolatedIndirect(treti);              // check influence from parameters
1492 
1493         return isTypeIsolated(treti);
1494     }
1495 
1496     /********************
1497      * See if pointers from function parameters, mutable globals, or uplevel functions
1498      * could leak into type `t`.
1499      * Params:
1500      *   t = type to check if it is isolated
1501      * Returns:
1502      *   true if `t` is isolated from
1503      *   any inputs to the function
1504      */
1505     extern (D) final bool isTypeIsolated(Type t)
1506     {
1507         //printf("isTypeIsolated(t: %s)\n", t.toChars());
1508 
1509         t = t.baseElemOf();
1510         switch (t.ty)
1511         {
1512             case Tarray:
1513             case Tpointer:
1514                 return isTypeIsolatedIndirect(t.nextOf()); // go down one level
1515 
1516             case Taarray:
1517             case Tclass:
1518                 return isTypeIsolatedIndirect(t);
1519 
1520             case Tstruct:
1521                 /* Drill down and check the struct's fields
1522                  */
1523                 auto sym = t.toDsymbol(null).isStructDeclaration();
1524                 foreach (v; sym.fields)
1525                 {
1526                     Type tmi = v.type.addMod(t.mod);
1527                     //printf("\tt = %s, tmi = %s\n", t.toChars(), tmi.toChars());
1528                     if (!isTypeIsolated(tmi))
1529                         return false;
1530                 }
1531                 return true;
1532 
1533             default:
1534                 return true;
1535         }
1536     }
1537 
1538     /********************************************
1539      * Params:
1540      *    t = type of object to test one level of indirection down
1541      * Returns:
1542      *    true if an object typed `t` has no indirections
1543      *    which could have come from the function's parameters, mutable
1544      *    globals, or uplevel functions.
1545      */
1546     private bool isTypeIsolatedIndirect(Type t)
1547     {
1548         //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1549         assert(t);
1550 
1551         /* Since `t` is one level down from an indirection, it could pick
1552          * up a reference to a mutable global or an outer function, so
1553          * return false.
1554          */
1555         if (!isPureBypassingInference() || isNested())
1556             return false;
1557 
1558         TypeFunction tf = type.toTypeFunction();
1559 
1560         //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1561 
1562         size_t dim = tf.parameterList.length;
1563         for (size_t i = 0; i < dim; i++)
1564         {
1565             Parameter fparam = tf.parameterList[i];
1566             Type tp = fparam.type;
1567             if (!tp)
1568                 continue;
1569 
1570             if (fparam.storageClass & (STC.lazy_ | STC.out_ | STC.ref_))
1571             {
1572                 if (!traverseIndirections(tp, t))
1573                     return false;
1574                 continue;
1575             }
1576 
1577             /* Goes down one level of indirection, then calls traverseIndirection() on
1578              * the result.
1579              * Returns:
1580              *  true if t is isolated from tp
1581              */
1582             static bool traverse(Type tp, Type t)
1583             {
1584                 tp = tp.baseElemOf();
1585                 switch (tp.ty)
1586                 {
1587                     case Tarray:
1588                     case Tpointer:
1589                         return traverseIndirections(tp.nextOf(), t);
1590 
1591                     case Taarray:
1592                     case Tclass:
1593                         return traverseIndirections(tp, t);
1594 
1595                     case Tstruct:
1596                         /* Drill down and check the struct's fields
1597                          */
1598                         auto sym = tp.toDsymbol(null).isStructDeclaration();
1599                         foreach (v; sym.fields)
1600                         {
1601                             Type tprmi = v.type.addMod(tp.mod);
1602                             //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1603                             if (!traverse(tprmi, t))
1604                                 return false;
1605                         }
1606                         return true;
1607 
1608                     default:
1609                         return true;
1610                 }
1611             }
1612 
1613             if (!traverse(tp, t))
1614                 return false;
1615         }
1616         // The 'this' reference is a parameter, too
1617         if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
1618         {
1619             Type tthis = ad.getType().addMod(tf.mod);
1620             //printf("\ttthis = %s\n", tthis.toChars());
1621             if (!traverseIndirections(tthis, t))
1622                 return false;
1623         }
1624 
1625         return true;
1626     }
1627 
1628     /****************************************
1629      * Determine if function needs a static frame pointer.
1630      * Returns:
1631      *  `true` if function is really nested within other function.
1632      * Contracts:
1633      *  If isNested() returns true, isThis() should return false,
1634      *  unless the function needs a dual-context pointer.
1635      */
1636     bool isNested() const
1637     {
1638         auto f = toAliasFunc();
1639         //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1640         return ((f.storage_class & STC.static_) == 0) &&
1641                 (f.linkage == LINK.d) &&
1642                 (f.toParent2().isFuncDeclaration() !is null ||
1643                  f.toParent2() !is f.toParentLocal());
1644     }
1645 
1646     /****************************************
1647      * Determine if function is a non-static member function
1648      * that has an implicit 'this' expression.
1649      * Returns:
1650      *  The aggregate it is a member of, or null.
1651      * Contracts:
1652      *  Both isThis() and isNested() should return true if function needs a dual-context pointer,
1653      *  otherwise if isThis() returns true, isNested() should return false.
1654      */
1655     override inout(AggregateDeclaration) isThis() inout
1656     {
1657         //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1658         auto ad = (storage_class & STC.static_) ? objc.isThis(this) : isMemberLocal();
1659         //printf("-FuncDeclaration::isThis() %p\n", ad);
1660         return ad;
1661     }
1662 
1663     override final bool needThis()
1664     {
1665         //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1666         return toAliasFunc().isThis() !is null;
1667     }
1668 
1669     // Determine if a function is pedantically virtual
1670     final bool isVirtualMethod()
1671     {
1672         if (toAliasFunc() != this)
1673             return toAliasFunc().isVirtualMethod();
1674 
1675         //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1676         if (!isVirtual())
1677             return false;
1678         // If it's a final method, and does not override anything, then it is not virtual
1679         if (isFinalFunc() && foverrides.dim == 0)
1680         {
1681             return false;
1682         }
1683         return true;
1684     }
1685 
1686     // Determine if function goes into virtual function pointer table
1687     bool isVirtual() const
1688     {
1689         if (toAliasFunc() != this)
1690             return toAliasFunc().isVirtual();
1691 
1692         auto p = toParent();
1693 
1694         if (!isMember || !p.isClassDeclaration)
1695             return false;
1696                                                              // https://issues.dlang.org/show_bug.cgi?id=19654
1697         if (p.isClassDeclaration.classKind == ClassKind.objc && !p.isInterfaceDeclaration)
1698             return objc.isVirtual(this);
1699 
1700         version (none)
1701         {
1702             printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1703             printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == Prot.Kind.private_, isCtorDeclaration(), linkage != LINK.d);
1704             printf("result is %d\n", isMember() && !(isStatic() || protection == Prot.Kind.private_ || protection == Prot.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()));
1705         }
1706         return !(isStatic() || protection.kind == Prot.Kind.private_ || protection.kind == Prot.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc());
1707     }
1708 
1709     final bool isFinalFunc() const
1710     {
1711         if (toAliasFunc() != this)
1712             return toAliasFunc().isFinalFunc();
1713 
1714         version (none)
1715         {{
1716             auto cd = toParent().isClassDeclaration();
1717             printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal());
1718             printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_));
1719             printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_)));
1720             if (cd)
1721                 printf("\tmember of %s\n", cd.toChars());
1722         }}
1723         if (!isMember())
1724             return false;
1725         if (Declaration.isFinal())
1726             return true;
1727         auto cd = toParent().isClassDeclaration();
1728         return (cd !is null) && (cd.storage_class & STC.final_);
1729     }
1730 
1731     bool addPreInvariant()
1732     {
1733         auto ad = isThis();
1734         ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1735         return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (protection.kind == Prot.Kind.protected_ || protection.kind == Prot.Kind.public_ || protection.kind == Prot.Kind.export_) && !naked);
1736     }
1737 
1738     bool addPostInvariant()
1739     {
1740         auto ad = isThis();
1741         ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1742         return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (protection.kind == Prot.Kind.protected_ || protection.kind == Prot.Kind.public_ || protection.kind == Prot.Kind.export_) && !naked);
1743     }
1744 
1745     override const(char)* kind() const
1746     {
1747         return generated ? "generated function" : "function";
1748     }
1749 
1750     /********************************************
1751      * Returns:
1752      *  true if there are no overloads of this function
1753      */
1754     final bool isUnique() const
1755     {
1756         bool result = false;
1757         overloadApply(cast() this, (Dsymbol s)
1758         {
1759             auto f = s.isFuncDeclaration();
1760             if (!f)
1761                 return 0;
1762             if (result)
1763             {
1764                 result = false;
1765                 return 1; // ambiguous, done
1766             }
1767             else
1768             {
1769                 result = true;
1770                 return 0;
1771             }
1772         });
1773         return result;
1774     }
1775 
1776     /*********************************************
1777      * In the current function, we are calling 'this' function.
1778      * 1. Check to see if the current function can call 'this' function, issue error if not.
1779      * 2. If the current function is not the parent of 'this' function, then add
1780      *    the current function to the list of siblings of 'this' function.
1781      * 3. If the current function is a literal, and it's accessing an uplevel scope,
1782      *    then mark it as a delegate.
1783      * Returns true if error occurs.
1784      */
1785     extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
1786     {
1787         //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
1788 
1789         if (auto fld = this.isFuncLiteralDeclaration())
1790         {
1791             if (fld.tok == TOK.reserved)
1792             {
1793                 fld.tok = TOK.function_;
1794                 fld.vthis = null;
1795             }
1796         }
1797 
1798         if (!parent || parent == sc.parent)
1799             return false;
1800         if (ident == Id.require || ident == Id.ensure)
1801             return false;
1802         if (!isThis() && !isNested())
1803             return false;
1804 
1805         // The current function
1806         FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
1807         if (!fdthis)
1808             return false; // out of function scope
1809 
1810         Dsymbol p = toParentLocal();
1811         Dsymbol p2 = toParent2();
1812 
1813         // Function literals from fdthis to p must be delegates
1814         ensureStaticLinkTo(fdthis, p);
1815         if (p != p2)
1816             ensureStaticLinkTo(fdthis, p2);
1817 
1818         if (isNested())
1819         {
1820             // The function that this function is in
1821             bool checkEnclosing(FuncDeclaration fdv)
1822             {
1823                 if (!fdv)
1824                     return false;
1825                 if (fdv == fdthis)
1826                     return false;
1827 
1828                 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
1829                 //printf("fdv  = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
1830                 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
1831 
1832                 // Add this function to the list of those which called us
1833                 if (fdthis != this)
1834                 {
1835                     bool found = false;
1836                     for (size_t i = 0; i < siblingCallers.dim; ++i)
1837                     {
1838                         if (siblingCallers[i] == fdthis)
1839                             found = true;
1840                     }
1841                     if (!found)
1842                     {
1843                         //printf("\tadding sibling %s\n", fdthis.toPrettyChars());
1844                         if (!sc.intypeof && !(sc.flags & SCOPE.compile))
1845                             siblingCallers.push(fdthis);
1846                     }
1847                 }
1848 
1849                 const lv = fdthis.getLevelAndCheck(loc, sc, fdv);
1850                 if (lv == LevelError)
1851                     return true; // error
1852                 if (lv == -1)
1853                     return false; // downlevel call
1854                 if (lv == 0)
1855                     return false; // same level call
1856 
1857                 return false; // Uplevel call
1858             }
1859 
1860             if (checkEnclosing(p.isFuncDeclaration()))
1861                 return true;
1862             if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
1863                 return true;
1864         }
1865         return false;
1866     }
1867 
1868     /*******************************
1869      * Look at all the variables in this function that are referenced
1870      * by nested functions, and determine if a closure needs to be
1871      * created for them.
1872      */
1873     final bool needsClosure()
1874     {
1875         /* Need a closure for all the closureVars[] if any of the
1876          * closureVars[] are accessed by a
1877          * function that escapes the scope of this function.
1878          * We take the conservative approach and decide that a function needs
1879          * a closure if it:
1880          * 1) is a virtual function
1881          * 2) has its address taken
1882          * 3) has a parent that escapes
1883          * 4) calls another nested function that needs a closure
1884          *
1885          * Note that since a non-virtual function can be called by
1886          * a virtual one, if that non-virtual function accesses a closure
1887          * var, the closure still has to be taken. Hence, we check for isThis()
1888          * instead of isVirtual(). (thanks to David Friedman)
1889          *
1890          * When the function returns a local struct or class, `requiresClosure`
1891          * is already set to `true` upon entering this function when the
1892          * struct/class refers to a local variable and a closure is needed.
1893          */
1894 
1895         //printf("FuncDeclaration::needsClosure() %s\n", toChars());
1896 
1897         if (requiresClosure)
1898             goto Lyes;
1899 
1900         for (size_t i = 0; i < closureVars.dim; i++)
1901         {
1902             VarDeclaration v = closureVars[i];
1903             //printf("\tv = %s\n", v.toChars());
1904 
1905             for (size_t j = 0; j < v.nestedrefs.dim; j++)
1906             {
1907                 FuncDeclaration f = v.nestedrefs[j];
1908                 assert(f != this);
1909 
1910                 /* __require and __ensure will always get called directly,
1911                  * so they never make outer functions closure.
1912                  */
1913                 if (f.ident == Id.require || f.ident == Id.ensure)
1914                     continue;
1915 
1916                 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
1917 
1918                 /* Look to see if f escapes. We consider all parents of f within
1919                  * this, and also all siblings which call f; if any of them escape,
1920                  * so does f.
1921                  * Mark all affected functions as requiring closures.
1922                  */
1923                 for (Dsymbol s = f; s && s != this; s = s.toParentP(this))
1924                 {
1925                     FuncDeclaration fx = s.isFuncDeclaration();
1926                     if (!fx)
1927                         continue;
1928                     if (fx.isThis() || fx.tookAddressOf)
1929                     {
1930                         //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
1931 
1932                         /* Mark as needing closure any functions between this and f
1933                          */
1934                         markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this);
1935 
1936                         requiresClosure = true;
1937                     }
1938 
1939                     /* We also need to check if any sibling functions that
1940                      * called us, have escaped. This is recursive: we need
1941                      * to check the callers of our siblings.
1942                      */
1943                     if (checkEscapingSiblings(fx, this))
1944                         requiresClosure = true;
1945 
1946                     /* https://issues.dlang.org/show_bug.cgi?id=12406
1947                      * Iterate all closureVars to mark all descendant
1948                      * nested functions that access to the closing context of this function.
1949                      */
1950                 }
1951             }
1952         }
1953         if (requiresClosure)
1954             goto Lyes;
1955 
1956         return false;
1957 
1958     Lyes:
1959         //printf("\tneeds closure\n");
1960         return true;
1961     }
1962 
1963     /***********************************************
1964      * Check that the function contains any closure.
1965      * If it's @nogc, report suitable errors.
1966      * This is mostly consistent with FuncDeclaration::needsClosure().
1967      *
1968      * Returns:
1969      *      true if any errors occur.
1970      */
1971     extern (D) final bool checkClosure()
1972     {
1973         if (!needsClosure())
1974             return false;
1975 
1976         if (setGC())
1977         {
1978             error("is `@nogc` yet allocates closures with the GC");
1979             if (global.gag)     // need not report supplemental errors
1980                 return true;
1981         }
1982         else
1983         {
1984             printGCUsage(loc, "using closure causes GC allocation");
1985             return false;
1986         }
1987 
1988         FuncDeclarations a;
1989         foreach (v; closureVars)
1990         {
1991             foreach (f; v.nestedrefs)
1992             {
1993                 assert(f !is this);
1994 
1995             LcheckAncestorsOfANestedRef:
1996                 for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
1997                 {
1998                     auto fx = s.isFuncDeclaration();
1999                     if (!fx)
2000                         continue;
2001                     if (fx.isThis() ||
2002                         fx.tookAddressOf ||
2003                         checkEscapingSiblings(fx, this))
2004                     {
2005                         foreach (f2; a)
2006                         {
2007                             if (f2 == f)
2008                                 break LcheckAncestorsOfANestedRef;
2009                         }
2010                         a.push(f);
2011                         .errorSupplemental(f.loc, "%s closes over variable %s at %s",
2012                             f.toPrettyChars(), v.toChars(), v.loc.toChars());
2013                         break LcheckAncestorsOfANestedRef;
2014                     }
2015                 }
2016             }
2017         }
2018 
2019         return true;
2020     }
2021 
2022     /***********************************************
2023      * Determine if function's variables are referenced by a function
2024      * nested within it.
2025      */
2026     final bool hasNestedFrameRefs()
2027     {
2028         if (closureVars.dim)
2029             return true;
2030 
2031         /* If a virtual function has contracts, assume its variables are referenced
2032          * by those contracts, even if they aren't. Because they might be referenced
2033          * by the overridden or overriding function's contracts.
2034          * This can happen because frequire and fensure are implemented as nested functions,
2035          * and they can be called directly by an overriding function and the overriding function's
2036          * context had better match, or
2037          * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
2038          */
2039         if (fdrequire || fdensure)
2040             return true;
2041 
2042         if (foverrides.dim && isVirtualMethod())
2043         {
2044             for (size_t i = 0; i < foverrides.dim; i++)
2045             {
2046                 FuncDeclaration fdv = foverrides[i];
2047                 if (fdv.hasNestedFrameRefs())
2048                     return true;
2049             }
2050         }
2051         return false;
2052     }
2053 
2054     /****************************************************
2055      * Check whether result variable can be built.
2056      * Returns:
2057      *     `true` if the function has a return type that
2058      *     is different from `void`.
2059      */
2060     extern (D) private bool canBuildResultVar()
2061     {
2062         auto f = cast(TypeFunction)type;
2063         return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
2064     }
2065 
2066     /****************************************************
2067      * Declare result variable lazily.
2068      */
2069     extern (D) final void buildResultVar(Scope* sc, Type tret)
2070     {
2071         if (!vresult)
2072         {
2073             Loc loc = fensure ? fensure.loc : this.loc;
2074 
2075             /* If inferRetType is true, tret may not be a correct return type yet.
2076              * So, in here it may be a temporary type for vresult, and after
2077              * fbody.dsymbolSemantic() running, vresult.type might be modified.
2078              */
2079             vresult = new VarDeclaration(loc, tret, Id.result, null);
2080             vresult.storage_class |= STC.nodtor | STC.temp;
2081             if (!isVirtual())
2082                 vresult.storage_class |= STC.const_;
2083             vresult.storage_class |= STC.result;
2084 
2085             // set before the semantic() for checkNestedReference()
2086             vresult.parent = this;
2087         }
2088 
2089         if (sc && vresult.semanticRun == PASS.init)
2090         {
2091             TypeFunction tf = type.toTypeFunction();
2092             if (tf.isref)
2093                 vresult.storage_class |= STC.ref_;
2094             vresult.type = tret;
2095 
2096             vresult.dsymbolSemantic(sc);
2097 
2098             if (!sc.insert(vresult))
2099                 error("out result %s is already defined", vresult.toChars());
2100             assert(vresult.parent == this);
2101         }
2102     }
2103 
2104     /****************************************************
2105      * Merge into this function the 'in' contracts of all it overrides.
2106      * 'in's are OR'd together, i.e. only one of them needs to pass.
2107      */
2108     extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
2109     {
2110         /* If a base function and its override both have an IN contract, then
2111          * only one of them needs to succeed. This is done by generating:
2112          *
2113          * void derived.in() {
2114          *  try {
2115          *    base.in();
2116          *  }
2117          *  catch () {
2118          *    ... body of derived.in() ...
2119          *  }
2120          * }
2121          *
2122          * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2123          * If base.in() throws, then derived.in()'s body is executed.
2124          */
2125 
2126         foreach (fdv; foverrides)
2127         {
2128             /* The semantic pass on the contracts of the overridden functions must
2129              * be completed before code generation occurs.
2130              * https://issues.dlang.org/show_bug.cgi?id=3602
2131              */
2132             if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2133             {
2134                 assert(fdv._scope);
2135                 Scope* sc = fdv._scope.push();
2136                 sc.stc &= ~STC.override_;
2137                 fdv.semantic3(sc);
2138                 sc.pop();
2139             }
2140 
2141             sf = fdv.mergeFrequire(sf, params);
2142             if (sf && fdv.fdrequire)
2143             {
2144                 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2145                 /* Make the call:
2146                  *   try { __require(params); }
2147                  *   catch (Throwable) { frequire; }
2148                  */
2149                 params = Expression.arraySyntaxCopy(params);
2150                 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2151                 Statement s2 = new ExpStatement(loc, e);
2152 
2153                 auto c = new Catch(loc, getThrowable(), null, sf);
2154                 c.internalCatch = true;
2155                 auto catches = new Catches();
2156                 catches.push(c);
2157                 sf = new TryCatchStatement(loc, s2, catches);
2158             }
2159             else
2160                 return null;
2161         }
2162         return sf;
2163     }
2164 
2165     /****************************************************
2166      * Determine whether an 'out' contract is declared inside
2167      * the given function or any of its overrides.
2168      * Params:
2169      *      fd = the function to search
2170      * Returns:
2171      *      true    found an 'out' contract
2172      */
2173     static bool needsFensure(FuncDeclaration fd)
2174     {
2175         if (fd.fensures)
2176             return true;
2177 
2178         foreach (fdv; fd.foverrides)
2179         {
2180             if (needsFensure(fdv))
2181                 return true;
2182         }
2183         return false;
2184     }
2185 
2186     /****************************************************
2187      * Rewrite contracts as statements.
2188      */
2189     final void buildEnsureRequire()
2190     {
2191 
2192         if (frequires)
2193         {
2194             /*   in { statements1... }
2195              *   in { statements2... }
2196              *   ...
2197              * becomes:
2198              *   in { { statements1... } { statements2... } ... }
2199              */
2200             assert(frequires.dim);
2201             auto loc = (*frequires)[0].loc;
2202             auto s = new Statements;
2203             foreach (r; *frequires)
2204             {
2205                 s.push(new ScopeStatement(r.loc, r, r.loc));
2206             }
2207             frequire = new CompoundStatement(loc, s);
2208         }
2209 
2210         if (fensures)
2211         {
2212             /*   out(id1) { statements1... }
2213              *   out(id2) { statements2... }
2214              *   ...
2215              * becomes:
2216              *   out(__result) { { ref id1 = __result; { statements1... } }
2217              *                   { ref id2 = __result; { statements2... } } ... }
2218              */
2219             assert(fensures.dim);
2220             auto loc = (*fensures)[0].ensure.loc;
2221             auto s = new Statements;
2222             foreach (r; *fensures)
2223             {
2224                 if (r.id && canBuildResultVar())
2225                 {
2226                     auto rloc = r.ensure.loc;
2227                     auto resultId = new IdentifierExp(rloc, Id.result);
2228                     auto init = new ExpInitializer(rloc, resultId);
2229                     auto stc = STC.ref_ | STC.temp | STC.result;
2230                     auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
2231                     auto sdecl = new ExpStatement(rloc, decl);
2232                     s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
2233                 }
2234                 else
2235                 {
2236                     s.push(r.ensure);
2237                 }
2238             }
2239             fensure = new CompoundStatement(loc, s);
2240         }
2241 
2242         if (!isVirtual())
2243             return;
2244 
2245         /* Rewrite contracts as nested functions, then call them. Doing it as nested
2246          * functions means that overriding functions can call them.
2247          */
2248         TypeFunction f = cast(TypeFunction) type;
2249 
2250         /* Make a copy of the parameters and make them all ref */
2251         static Parameters* toRefCopy(Parameters* params)
2252         {
2253             auto result = new Parameters();
2254 
2255             int toRefDg(size_t n, Parameter p)
2256             {
2257                 p = p.syntaxCopy();
2258                 if (!(p.storageClass & STC.lazy_))
2259                     p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
2260                 p.defaultArg = null; // won't be the same with ref
2261                 result.push(p);
2262                 return 0;
2263             }
2264 
2265             Parameter._foreach(params, &toRefDg);
2266             return result;
2267         }
2268 
2269         if (frequire)
2270         {
2271             /*   in { ... }
2272              * becomes:
2273              *   void __require(ref params) { ... }
2274              *   __require(params);
2275              */
2276             Loc loc = frequire.loc;
2277             fdrequireParams = new Expressions();
2278             if (parameters)
2279             {
2280                 foreach (vd; *parameters)
2281                     fdrequireParams.push(new VarExp(loc, vd));
2282             }
2283             auto fo = cast(TypeFunction)(originalType ? originalType : f);
2284             auto fparams = toRefCopy(fo.parameterList.parameters);
2285             auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2286             tf.isnothrow = f.isnothrow;
2287             tf.isnogc = f.isnogc;
2288             tf.purity = f.purity;
2289             tf.trust = f.trust;
2290             auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
2291             fd.fbody = frequire;
2292             Statement s1 = new ExpStatement(loc, fd);
2293             Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
2294             Statement s2 = new ExpStatement(loc, e);
2295             frequire = new CompoundStatement(loc, s1, s2);
2296             fdrequire = fd;
2297         }
2298 
2299         /* We need to set fdensureParams here and not in the block below to
2300          * have the parameters available when calling a base class ensure(),
2301          * even if this function doesn't have an out contract.
2302          */
2303         fdensureParams = new Expressions();
2304         if (canBuildResultVar())
2305             fdensureParams.push(new IdentifierExp(loc, Id.result));
2306         if (parameters)
2307         {
2308             foreach (vd; *parameters)
2309                 fdensureParams.push(new VarExp(loc, vd));
2310         }
2311 
2312         if (fensure)
2313         {
2314             /*   out (result) { ... }
2315              * becomes:
2316              *   void __ensure(ref tret result, ref params) { ... }
2317              *   __ensure(result, params);
2318              */
2319             Loc loc = fensure.loc;
2320             auto fparams = new Parameters();
2321             if (canBuildResultVar())
2322             {
2323                 Parameter p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
2324                 fparams.push(p);
2325             }
2326             auto fo = cast(TypeFunction)(originalType ? originalType : f);
2327             fparams.pushSlice((*toRefCopy(fo.parameterList.parameters))[]);
2328             auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2329             tf.isnothrow = f.isnothrow;
2330             tf.isnogc = f.isnogc;
2331             tf.purity = f.purity;
2332             tf.trust = f.trust;
2333             auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
2334             fd.fbody = fensure;
2335             Statement s1 = new ExpStatement(loc, fd);
2336             Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
2337             Statement s2 = new ExpStatement(loc, e);
2338             fensure = new CompoundStatement(loc, s1, s2);
2339             fdensure = fd;
2340         }
2341     }
2342 
2343     /****************************************************
2344      * Merge into this function the 'out' contracts of all it overrides.
2345      * 'out's are AND'd together, i.e. all of them need to pass.
2346      */
2347     extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
2348     {
2349         /* Same comments as for mergeFrequire(), except that we take care
2350          * of generating a consistent reference to the 'result' local by
2351          * explicitly passing 'result' to the nested function as a reference
2352          * argument.
2353          * This won't work for the 'this' parameter as it would require changing
2354          * the semantic code for the nested function so that it looks on the parameter
2355          * list for the 'this' pointer, something that would need an unknown amount
2356          * of tweaking of various parts of the compiler that I'd rather leave alone.
2357          */
2358         foreach (fdv; foverrides)
2359         {
2360             /* The semantic pass on the contracts of the overridden functions must
2361              * be completed before code generation occurs.
2362              * https://issues.dlang.org/show_bug.cgi?id=3602 and
2363              * https://issues.dlang.org/show_bug.cgi?id=5230
2364              */
2365             if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
2366             {
2367                 assert(fdv._scope);
2368                 Scope* sc = fdv._scope.push();
2369                 sc.stc &= ~STC.override_;
2370                 fdv.semantic3(sc);
2371                 sc.pop();
2372             }
2373 
2374             sf = fdv.mergeFensure(sf, oid, params);
2375             if (fdv.fdensure)
2376             {
2377                 //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2378                 // Make the call: __ensure(result, params)
2379                 params = Expression.arraySyntaxCopy(params);
2380                 if (canBuildResultVar())
2381                 {
2382                     Type t1 = fdv.type.nextOf().toBasetype();
2383                     Type t2 = this.type.nextOf().toBasetype();
2384                     if (t1.isBaseOf(t2, null))
2385                     {
2386                         /* Making temporary reference variable is necessary
2387                          * in covariant return.
2388                          * https://issues.dlang.org/show_bug.cgi?id=5204
2389                          * https://issues.dlang.org/show_bug.cgi?id=10479
2390                          */
2391                         Expression* eresult = &(*params)[0];
2392                         auto ei = new ExpInitializer(Loc.initial, *eresult);
2393                         auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
2394                         v.storage_class |= STC.temp;
2395                         auto de = new DeclarationExp(Loc.initial, v);
2396                         auto ve = new VarExp(Loc.initial, v);
2397                         *eresult = new CommaExp(Loc.initial, de, ve);
2398                     }
2399                 }
2400                 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
2401                 Statement s2 = new ExpStatement(loc, e);
2402 
2403                 if (sf)
2404                 {
2405                     sf = new CompoundStatement(sf.loc, s2, sf);
2406                 }
2407                 else
2408                     sf = s2;
2409             }
2410         }
2411         return sf;
2412     }
2413 
2414     /*********************************************
2415      * Returns: the function's parameter list, and whether
2416      * it is variadic or not.
2417      */
2418     final ParameterList getParameterList()
2419     {
2420         if (type)
2421         {
2422             TypeFunction fdtype = type.isTypeFunction();
2423             return fdtype.parameterList;
2424         }
2425 
2426         return ParameterList(null, VarArg.none);
2427     }
2428 
2429     /**********************************
2430      * Generate a FuncDeclaration for a runtime library function.
2431      */
2432     static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
2433     {
2434         return genCfunc(fparams, treturn, Identifier.idPool(name, cast(uint)strlen(name)), stc);
2435     }
2436 
2437     static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
2438     {
2439         FuncDeclaration fd;
2440         TypeFunction tf;
2441         Dsymbol s;
2442         __gshared DsymbolTable st = null;
2443 
2444         //printf("genCfunc(name = '%s')\n", id.toChars());
2445         //printf("treturn\n\t"); treturn.print();
2446 
2447         // See if already in table
2448         if (!st)
2449             st = new DsymbolTable();
2450         s = st.lookup(id);
2451         if (s)
2452         {
2453             fd = s.isFuncDeclaration();
2454             assert(fd);
2455             assert(fd.type.nextOf().equals(treturn));
2456         }
2457         else
2458         {
2459             tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc);
2460             fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf);
2461             fd.protection = Prot(Prot.Kind.public_);
2462             fd.linkage = LINK.c;
2463 
2464             st.insert(fd);
2465         }
2466         return fd;
2467     }
2468 
2469     /******************
2470      * Check parameters and return type of D main() function.
2471      * Issue error messages.
2472      */
2473     extern (D) final void checkDmain()
2474     {
2475         TypeFunction tf = type.toTypeFunction();
2476         const nparams = tf.parameterList.length;
2477         bool argerr;
2478         if (nparams == 1)
2479         {
2480             auto fparam0 = tf.parameterList[0];
2481             auto t = fparam0.type.toBasetype();
2482             if (t.ty != Tarray ||
2483                 t.nextOf().ty != Tarray ||
2484                 t.nextOf().nextOf().ty != Tchar ||
2485                 fparam0.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
2486             {
2487                 argerr = true;
2488             }
2489         }
2490 
2491         if (!tf.nextOf())
2492             error("must return `int` or `void`");
2493         else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid)
2494             error("must return `int` or `void`, not `%s`", tf.nextOf().toChars());
2495         else if (tf.parameterList.varargs || nparams >= 2 || argerr)
2496             error("parameters must be `main()` or `main(string[] args)`");
2497     }
2498 
2499     /***********************************************
2500      * Check all return statements for a function to verify that returning
2501      * using NRVO is possible.
2502      *
2503      * Returns:
2504      *      true if the result cannot be returned by hidden reference.
2505      */
2506     final bool checkNrvo()
2507     {
2508         if (!nrvo_can)
2509             return true;
2510 
2511         if (returns is null)
2512             return true;
2513 
2514         auto tf = type.toTypeFunction();
2515         if (tf.isref)
2516             return true;
2517 
2518         foreach (rs; *returns)
2519         {
2520             if (auto ve = rs.exp.isVarExp())
2521             {
2522                 auto v = ve.var.isVarDeclaration();
2523                 if (!v || v.isOut() || v.isRef())
2524                     return true;
2525                 else if (nrvo_var is null)
2526                 {
2527                     if (!v.isDataseg() && !v.isParameter() && v.toParent2() == this)
2528                     {
2529                         //printf("Setting nrvo to %s\n", v.toChars());
2530                         nrvo_var = v;
2531                     }
2532                     else
2533                         return true;
2534                 }
2535                 else if (nrvo_var != v)
2536                     return true;
2537             }
2538             else //if (!exp.isLvalue())    // keep NRVO-ability
2539                 return true;
2540         }
2541         return false;
2542     }
2543 
2544     override final inout(FuncDeclaration) isFuncDeclaration() inout
2545     {
2546         return this;
2547     }
2548 
2549     inout(FuncDeclaration) toAliasFunc() inout
2550     {
2551         return this;
2552     }
2553 
2554     override void accept(Visitor v)
2555     {
2556         v.visit(this);
2557     }
2558 }
2559 
2560 /********************************************************
2561  * Generate Expression to call the invariant.
2562  * Input:
2563  *      ad      aggregate with the invariant
2564  *      vthis   variable with 'this'
2565  * Returns:
2566  *      void expression that calls the invariant
2567  */
2568 Expression addInvariant(const ref Loc loc, Scope* sc, AggregateDeclaration ad, VarDeclaration vthis)
2569 {
2570     Expression e = null;
2571     // Call invariant directly only if it exists
2572     FuncDeclaration inv = ad.inv;
2573     ClassDeclaration cd = ad.isClassDeclaration();
2574 
2575     while (!inv && cd)
2576     {
2577         cd = cd.baseClass;
2578         if (!cd)
2579             break;
2580         inv = cd.inv;
2581     }
2582     if (inv)
2583     {
2584         version (all)
2585         {
2586             // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
2587             // For the correct mangling,
2588             // run attribute inference on inv if needed.
2589             inv.functionSemantic();
2590         }
2591 
2592         //e = new DsymbolExp(Loc.initial, inv);
2593         //e = new CallExp(Loc.initial, e);
2594         //e = e.semantic(sc2);
2595 
2596         /* https://issues.dlang.org/show_bug.cgi?id=13113
2597          * Currently virtual invariant calls completely
2598          * bypass attribute enforcement.
2599          * Change the behavior of pre-invariant call by following it.
2600          */
2601         e = new ThisExp(Loc.initial);
2602         e.type = ad.type.addMod(vthis.type.mod);
2603         e = new DotVarExp(Loc.initial, e, inv, false);
2604         e.type = inv.type;
2605         e = new CallExp(Loc.initial, e);
2606         e.type = Type.tvoid;
2607     }
2608     return e;
2609 }
2610 
2611 /***************************************************
2612  * Visit each overloaded function/template in turn, and call dg(s) on it.
2613  * Exit when no more, or dg(s) returns nonzero.
2614  *
2615  * Params:
2616  *  fstart = symbol to start from
2617  *  dg = the delegate to be called on the overload
2618  *  sc = context used to check if symbol is accessible (and therefore visible),
2619  *       can be null
2620  *
2621  * Returns:
2622  *      ==0     continue
2623  *      !=0     done (and the return value from the last dg() call)
2624  */
2625 extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
2626 {
2627     Dsymbol next;
2628     for (auto d = fstart; d; d = next)
2629     {
2630         import dmd.access : checkSymbolAccess;
2631         if (auto od = d.isOverDeclaration())
2632         {
2633             if (od.hasOverloads)
2634             {
2635                 /* The scope is needed here to check whether a function in
2636                    an overload set was added by means of a private alias (or a
2637                    selective import). If the scope where the alias is created
2638                    is imported somewhere, the overload set is visible, but the private
2639                    alias is not.
2640                  */
2641                 if (sc)
2642                 {
2643                     if (checkSymbolAccess(sc, od))
2644                     {
2645                         if (int r = overloadApply(od.aliassym, dg, sc))
2646                             return r;
2647                     }
2648                 }
2649                 else if (int r = overloadApply(od.aliassym, dg, sc))
2650                     return r;
2651             }
2652             else
2653             {
2654                 if (int r = dg(od.aliassym))
2655                     return r;
2656             }
2657             next = od.overnext;
2658         }
2659         else if (auto fa = d.isFuncAliasDeclaration())
2660         {
2661             if (fa.hasOverloads)
2662             {
2663                 if (int r = overloadApply(fa.funcalias, dg, sc))
2664                     return r;
2665             }
2666             else if (auto fd = fa.toAliasFunc())
2667             {
2668                 if (int r = dg(fd))
2669                     return r;
2670             }
2671             else
2672             {
2673                 d.error("is aliased to a function");
2674                 break;
2675             }
2676             next = fa.overnext;
2677         }
2678         else if (auto ad = d.isAliasDeclaration())
2679         {
2680             if (sc)
2681             {
2682                 if (checkSymbolAccess(sc, ad))
2683                     next = ad.toAlias();
2684             }
2685             else
2686                next = ad.toAlias();
2687             if (next == ad)
2688                 break;
2689             if (next == fstart)
2690                 break;
2691         }
2692         else if (auto td = d.isTemplateDeclaration())
2693         {
2694             if (int r = dg(td))
2695                 return r;
2696             next = td.overnext;
2697         }
2698         else if (auto fd = d.isFuncDeclaration())
2699         {
2700             if (int r = dg(fd))
2701                 return r;
2702             next = fd.overnext;
2703         }
2704         else
2705         {
2706             d.error("is aliased to a function");
2707             break;
2708             // BUG: should print error message?
2709         }
2710     }
2711     return 0;
2712 }
2713 
2714 /**
2715 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
2716 mismatching modifiers to `buf`.
2717 
2718 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
2719 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
2720 
2721 Params:
2722     buf = output buffer to write to
2723     lhsMod = modifier on the left-hand side
2724     lhsMod = modifier on the right-hand side
2725 
2726 Returns:
2727 
2728 A tuple with `isMutable` and `isNotShared` set
2729 if the `lhsMod` is missing those modifiers (compared to rhs).
2730 */
2731 auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod)
2732 {
2733     static struct Mismatches
2734     {
2735         bool isNotShared;
2736         bool isMutable;
2737     }
2738 
2739     Mismatches mismatches;
2740 
2741     bool bothMutable = ((lhsMod & rhsMod) == 0);
2742     bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0;
2743     bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_);
2744 
2745     if (lhsMod & MODFlags.shared_)
2746         buf.writestring("`shared` ");
2747     else if (sharedMismatch && !(lhsMod & MODFlags.immutable_))
2748     {
2749         buf.writestring("non-shared ");
2750         mismatches.isNotShared = true;
2751     }
2752 
2753     if (bothMutable && sharedMismatchOnly)
2754     {
2755     }
2756     else if (lhsMod & MODFlags.immutable_)
2757         buf.writestring("`immutable` ");
2758     else if (lhsMod & MODFlags.const_)
2759         buf.writestring("`const` ");
2760     else if (lhsMod & MODFlags.wild)
2761         buf.writestring("`inout` ");
2762     else
2763     {
2764         buf.writestring("mutable ");
2765         mismatches.isMutable = true;
2766     }
2767 
2768     return mismatches;
2769 }
2770 
2771 ///
2772 unittest
2773 {
2774     OutBuffer buf;
2775     auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0);
2776     assert(buf[] == "`shared` ");
2777     assert(!mismatches.isNotShared);
2778 
2779     buf.setsize(0);
2780     mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_);
2781     assert(buf[] == "non-shared ");
2782     assert(mismatches.isNotShared);
2783 
2784     buf.setsize(0);
2785     mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0);
2786     assert(buf[] == "`const` ");
2787     assert(!mismatches.isMutable);
2788 
2789     buf.setsize(0);
2790     mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_);
2791     assert(buf[] == "mutable ");
2792     assert(mismatches.isMutable);
2793 }
2794 
2795 private const(char)* prependSpace(const(char)* str)
2796 {
2797     if (!str || !*str) return "";
2798 
2799     return (" " ~ str.toDString() ~ "\0").ptr;
2800 }
2801 
2802 /// Flag used by $(LREF resolveFuncCall).
2803 enum FuncResolveFlag : ubyte
2804 {
2805     standard = 0,       /// issue error messages, solve the call.
2806     quiet = 1,          /// do not issue error message on no match, just return `null`.
2807     overloadOnly = 2,   /// only resolve overloads.
2808 }
2809 
2810 /*******************************************
2811  * Given a symbol that could be either a FuncDeclaration or
2812  * a function template, resolve it to a function symbol.
2813  * Params:
2814  *      loc =           instantiation location
2815  *      sc =            instantiation scope
2816  *      s =             instantiation symbol
2817  *      tiargs =        initial list of template arguments
2818  *      tthis =         if !NULL, the `this` argument type
2819  *      fargs =         arguments to function
2820  *      flags =         see $(LREF FuncResolveFlag).
2821  * Returns:
2822  *      if match is found, then function symbol, else null
2823  */
2824 FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
2825     Objects* tiargs, Type tthis, Expressions* fargs, FuncResolveFlag flags)
2826 {
2827     if (!s)
2828         return null; // no match
2829 
2830     version (none)
2831     {
2832         printf("resolveFuncCall('%s')\n", s.toChars());
2833         if (tthis)
2834             printf("\tthis: %s\n", tthis.toChars());
2835         if (fargs)
2836         {
2837             for (size_t i = 0; i < fargs.dim; i++)
2838             {
2839                 Expression arg = (*fargs)[i];
2840                 assert(arg.type);
2841                 printf("\t%s: ", arg.toChars());
2842                 arg.type.print();
2843             }
2844         }
2845     }
2846 
2847     if (tiargs && arrayObjectIsError(tiargs) ||
2848         fargs && arrayObjectIsError(cast(Objects*)fargs))
2849     {
2850         return null;
2851     }
2852 
2853     MatchAccumulator m;
2854     functionResolve(m, s, loc, sc, tiargs, tthis, fargs, null);
2855     auto orig_s = s;
2856 
2857     if (m.last > MATCH.nomatch && m.lastf)
2858     {
2859         if (m.count == 1) // exactly one match
2860         {
2861             if (!(flags & FuncResolveFlag.quiet))
2862                 m.lastf.functionSemantic();
2863             return m.lastf;
2864         }
2865         if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
2866         {
2867             return m.lastf;
2868         }
2869     }
2870 
2871     /* Failed to find a best match.
2872      * Do nothing or print error.
2873      */
2874     if (m.last <= MATCH.nomatch)
2875     {
2876         // error was caused on matched function, not on the matching itself,
2877         // so return the function to produce a better diagnostic
2878         if (m.count == 1)
2879             return m.lastf;
2880     }
2881 
2882     // We are done at this point, as the rest of this function generate
2883     // a diagnostic on invalid match
2884     if (flags & FuncResolveFlag.quiet)
2885         return null;
2886 
2887     auto fd = s.isFuncDeclaration();
2888     auto od = s.isOverDeclaration();
2889     auto td = s.isTemplateDeclaration();
2890     if (td && td.funcroot)
2891         s = fd = td.funcroot;
2892 
2893     OutBuffer tiargsBuf;
2894     arrayObjectsToBuffer(&tiargsBuf, tiargs);
2895 
2896     OutBuffer fargsBuf;
2897     fargsBuf.writeByte('(');
2898     argExpTypesToCBuffer(&fargsBuf, fargs);
2899     fargsBuf.writeByte(')');
2900     if (tthis)
2901         tthis.modToBuffer(&fargsBuf);
2902 
2903     // The call is ambiguous
2904     if (m.lastf && m.nextf)
2905     {
2906         TypeFunction tf1 = m.lastf.type.toTypeFunction();
2907         TypeFunction tf2 = m.nextf.type.toTypeFunction();
2908         const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
2909         const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
2910 
2911         const(char)* mod1 = prependSpace(MODtoChars(tf1.mod));
2912         const(char)* mod2 = prependSpace(MODtoChars(tf2.mod));
2913 
2914         .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s:     `%s%s%s`\nand:\n%s:     `%s%s%s`",
2915             s.parent.toPrettyChars(), s.ident.toChars(),
2916             fargsBuf.peekChars(),
2917             m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1,
2918             m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2);
2919         return null;
2920     }
2921 
2922     // no match, generate an error messages
2923     if (!fd)
2924     {
2925         // all of overloads are templates
2926         if (td)
2927         {
2928             .error(loc, "%s `%s.%s` cannot deduce function from argument types `!(%s)%s`, candidates are:",
2929                    td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
2930                    tiargsBuf.peekChars(), fargsBuf.peekChars());
2931 
2932             printCandidates(loc, td, sc.isDeprecated());
2933             return null;
2934         }
2935         /* This case happens when several ctors are mixed in an agregate.
2936            A (bad) error message is already generated in overloadApply().
2937            see https://issues.dlang.org/show_bug.cgi?id=19729
2938         */
2939         if (!od)
2940             return null;
2941     }
2942 
2943     if (od)
2944     {
2945         .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
2946                od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
2947         return null;
2948     }
2949 
2950     // remove when deprecation period of class allocators and deallocators is over
2951     if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
2952         return null;
2953 
2954     bool hasOverloads = fd.overnext !is null;
2955     auto tf = fd.type.toTypeFunction();
2956     if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch
2957     {
2958         OutBuffer thisBuf, funcBuf;
2959         MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
2960         auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
2961         if (hasOverloads)
2962         {
2963             .error(loc, "none of the overloads of `%s` are callable using a %sobject, candidates are:",
2964                    fd.ident.toChars(), thisBuf.peekChars());
2965             printCandidates(loc, fd, sc.isDeprecated());
2966             return null;
2967         }
2968 
2969         const(char)* failMessage;
2970         functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
2971         if (failMessage)
2972         {
2973             .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
2974                    fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
2975                    tf.modToChars(), fargsBuf.peekChars());
2976             errorSupplemental(loc, failMessage);
2977             return null;
2978         }
2979 
2980         auto fullFdPretty = fd.toPrettyChars();
2981         .error(loc, "%smethod `%s` is not callable using a %sobject",
2982                funcBuf.peekChars(), fullFdPretty, thisBuf.peekChars());
2983 
2984         if (mismatches.isNotShared)
2985             .errorSupplemental(loc, "Consider adding `shared` to %s", fullFdPretty);
2986         else if (mismatches.isMutable)
2987             .errorSupplemental(loc, "Consider adding `const` or `inout` to %s", fullFdPretty);
2988         return null;
2989     }
2990 
2991     //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
2992     if (hasOverloads)
2993     {
2994         .error(loc, "none of the overloads of `%s` are callable using argument types `%s`, candidates are:",
2995                fd.toChars(), fargsBuf.peekChars());
2996         printCandidates(loc, fd, sc.isDeprecated());
2997         return null;
2998     }
2999 
3000     .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3001            fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3002            tf.modToChars(), fargsBuf.peekChars());
3003     // re-resolve to check for supplemental message
3004     const(char)* failMessage;
3005     functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
3006     if (failMessage)
3007         errorSupplemental(loc, failMessage);
3008     return null;
3009 }
3010 
3011 /*******************************************
3012  * Prints template and function overload candidates as supplemental errors.
3013  * Params:
3014  *      loc =            instantiation location
3015  *      declaration =    the declaration to print overload candidates for
3016  *      showDeprecated = If `false`, `deprecated` function won't be shown
3017  */
3018 private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
3019 if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
3020 {
3021     // max num of overloads to print (-v overrides this).
3022     enum int DisplayLimit = 5;
3023     int displayed;
3024     const(char)* constraintsTip;
3025 
3026     overloadApply(declaration, (Dsymbol s)
3027     {
3028         Dsymbol nextOverload;
3029 
3030         if (auto fd = s.isFuncDeclaration())
3031         {
3032             // Don't print overloads which have errors.
3033             // Not that if the whole overload set has errors, we'll never reach
3034             // this point so there's no risk of printing no candidate
3035             if (fd.errors || fd.type.ty == Terror)
3036                 return 0;
3037             // Don't print disabled functions, or `deprecated` outside of deprecated scope
3038             if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
3039                 return 0;
3040 
3041             auto tf = cast(TypeFunction) fd.type;
3042             .errorSupplemental(fd.loc, "`%s%s`", fd.toPrettyChars(),
3043                 parametersTypeToChars(tf.parameterList));
3044             nextOverload = fd.overnext;
3045         }
3046         else if (auto td = s.isTemplateDeclaration())
3047         {
3048             import dmd.staticcond;
3049 
3050             const tmsg = td.toCharsNoConstraints();
3051             const cmsg = td.getConstraintEvalError(constraintsTip);
3052             if (cmsg)
3053                 .errorSupplemental(td.loc, "`%s`\n%s", tmsg, cmsg);
3054             else
3055                 .errorSupplemental(td.loc, "`%s`", tmsg);
3056             nextOverload = td.overnext;
3057         }
3058 
3059         if (global.params.verbose || ++displayed < DisplayLimit)
3060             return 0;
3061 
3062         // Too many overloads to sensibly display.
3063         // Just show count of remaining overloads.
3064         int num = 0;
3065         overloadApply(nextOverload, (s) { ++num; return 0; });
3066 
3067         if (num > 0)
3068             .errorSupplemental(loc, "... (%d more, -v to show) ...", num);
3069         return 1;   // stop iterating
3070     });
3071 
3072     // Nothing was displayed, all overloads are either disabled or deprecated
3073     if (!displayed)
3074         .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
3075     // should be only in verbose mode
3076     if (constraintsTip)
3077         .tip(constraintsTip);
3078 }
3079 
3080 /**************************************
3081  * Returns an indirect type one step from t.
3082  */
3083 Type getIndirection(Type t)
3084 {
3085     t = t.baseElemOf();
3086     if (t.ty == Tarray || t.ty == Tpointer)
3087         return t.nextOf().toBasetype();
3088     if (t.ty == Taarray || t.ty == Tclass)
3089         return t;
3090     if (t.ty == Tstruct)
3091         return t.hasPointers() ? t : null; // TODO
3092 
3093     // should consider TypeDelegate?
3094     return null;
3095 }
3096 
3097 /**************************************
3098  * Performs type-based alias analysis between a newly created value and a pre-
3099  * existing memory reference:
3100  *
3101  * Assuming that a reference A to a value of type `ta` was available to the code
3102  * that created a reference B to a value of type `tb`, it returns whether B
3103  * might alias memory reachable from A based on the types involved (either
3104  * directly or via any number of indirections in either A or B).
3105  *
3106  * This relation is not symmetric in the two arguments. For example, a
3107  * a `const(int)` reference can point to a pre-existing `int`, but not the other
3108  * way round.
3109  *
3110  * Examples:
3111  *
3112  *      ta,           tb,               result
3113  *      `const(int)`, `int`,            `false`
3114  *      `int`,        `const(int)`,     `true`
3115  *      `int`,        `immutable(int)`, `false`
3116  *      const(immutable(int)*), immutable(int)*, false   // BUG: returns true
3117  *
3118  * Params:
3119  *      ta = value type being referred to
3120  *      tb = referred to value type that could be constructed from ta
3121  *
3122  * Returns:
3123  *      true if reference to `tb` is isolated from reference to `ta`
3124  */
3125 private bool traverseIndirections(Type ta, Type tb)
3126 {
3127     //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
3128 
3129     /* Threaded list of aggregate types already examined,
3130      * used to break cycles.
3131      * Cycles in type graphs can only occur with aggregates.
3132      */
3133     static struct Ctxt
3134     {
3135         Ctxt* prev;
3136         Type type;      // an aggregate type
3137     }
3138 
3139     static bool traverse(Type ta, Type tb, Ctxt* ctxt, bool reversePass)
3140     {
3141         //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
3142         ta = ta.baseElemOf();
3143         tb = tb.baseElemOf();
3144 
3145         // First, check if the pointed-to types are convertible to each other such
3146         // that they might alias directly.
3147         static bool mayAliasDirect(Type source, Type target)
3148         {
3149             return
3150                 // if source is the same as target or can be const-converted to target
3151                 source.constConv(target) != MATCH.nomatch ||
3152                 // if target is void and source can be const-converted to target
3153                 (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
3154         }
3155 
3156         if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
3157         {
3158             //printf(" true  mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3159             return false;
3160         }
3161         if (ta.nextOf() && ta.nextOf() == tb.nextOf())
3162         {
3163              //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3164              return true;
3165         }
3166 
3167         if (tb.ty == Tclass || tb.ty == Tstruct)
3168         {
3169             for (Ctxt* c = ctxt; c; c = c.prev)
3170                 if (tb == c.type)
3171                     return true;
3172             Ctxt c;
3173             c.prev = ctxt;
3174             c.type = tb;
3175 
3176             /* Traverse the type of each field of the aggregate
3177              */
3178             AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
3179             foreach (v; sym.fields)
3180             {
3181                 Type tprmi = v.type.addMod(tb.mod);
3182                 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
3183                 if (!traverse(ta, tprmi, &c, reversePass))
3184                     return false;
3185             }
3186         }
3187         else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
3188         {
3189             Type tind = tb.nextOf();
3190             if (!traverse(ta, tind, ctxt, reversePass))
3191                 return false;
3192         }
3193         else if (tb.hasPointers())
3194         {
3195             // BUG: consider the context pointer of delegate types
3196             return false;
3197         }
3198 
3199         // Still no match, so try breaking up ta if we have not done so yet.
3200         if (!reversePass)
3201             return traverse(tb, ta, ctxt, true);
3202 
3203         return true;
3204     }
3205 
3206     // To handle arbitrary levels of indirections in both parameters, we
3207     // recursively descend into aggregate members/levels of indirection in both
3208     // `ta` and `tb` while avoiding cycles. Start with the original types.
3209     const result = traverse(ta, tb, null, false);
3210     //printf("  returns %d\n", result);
3211     return result;
3212 }
3213 
3214 /* For all functions between outerFunc and f, mark them as needing
3215  * a closure.
3216  */
3217 private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc)
3218 {
3219     for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc))
3220     {
3221         FuncDeclaration fy = sx.isFuncDeclaration();
3222         if (fy && fy.closureVars.dim)
3223         {
3224             /* fy needs a closure if it has closureVars[],
3225              * because the frame pointer in the closure will be accessed.
3226              */
3227             fy.requiresClosure = true;
3228         }
3229     }
3230 }
3231 
3232 /********
3233  * Given a nested function f inside a function outerFunc, check
3234  * if any sibling callers of f have escaped. If so, mark
3235  * all the enclosing functions as needing closures.
3236  * This is recursive: we need to check the callers of our siblings.
3237  * Note that nested functions can only call lexically earlier nested
3238  * functions, so loops are impossible.
3239  * Params:
3240  *      f = inner function (nested within outerFunc)
3241  *      outerFunc = outer function
3242  *      p = for internal recursion use
3243  * Returns:
3244  *      true if any closures were needed
3245  */
3246 private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
3247 {
3248     static struct PrevSibling
3249     {
3250         PrevSibling* p;
3251         FuncDeclaration f;
3252     }
3253 
3254     PrevSibling ps;
3255     ps.p = cast(PrevSibling*)p;
3256     ps.f = f;
3257 
3258     //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
3259     bool bAnyClosures = false;
3260     for (size_t i = 0; i < f.siblingCallers.dim; ++i)
3261     {
3262         FuncDeclaration g = f.siblingCallers[i];
3263         if (g.isThis() || g.tookAddressOf)
3264         {
3265             markAsNeedingClosure(g, outerFunc);
3266             bAnyClosures = true;
3267         }
3268 
3269         for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc))
3270         {
3271             // A parent of the sibling had its address taken.
3272             // Assume escaping of parent affects its children, so needs propagating.
3273             // see https://issues.dlang.org/show_bug.cgi?id=19679
3274             FuncDeclaration parentFunc = parent.isFuncDeclaration;
3275             if (parentFunc && parentFunc.tookAddressOf)
3276             {
3277                 markAsNeedingClosure(parentFunc, outerFunc);
3278                 bAnyClosures = true;
3279             }
3280         }
3281 
3282         PrevSibling* prev = cast(PrevSibling*)p;
3283         while (1)
3284         {
3285             if (!prev)
3286             {
3287                 bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
3288                 break;
3289             }
3290             if (prev.f == g)
3291                 break;
3292             prev = prev.p;
3293         }
3294     }
3295     //printf("\t%d\n", bAnyClosures);
3296     return bAnyClosures;
3297 }
3298 
3299 /***********************************************************
3300  * Used as a way to import a set of functions from another scope into this one.
3301  */
3302 extern (C++) final class FuncAliasDeclaration : FuncDeclaration
3303 {
3304     FuncDeclaration funcalias;
3305     bool hasOverloads;
3306 
3307     extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true)
3308     {
3309         super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type);
3310         assert(funcalias != this);
3311         this.funcalias = funcalias;
3312 
3313         this.hasOverloads = hasOverloads;
3314         if (hasOverloads)
3315         {
3316             if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration())
3317                 this.hasOverloads = fad.hasOverloads;
3318         }
3319         else
3320         {
3321             // for internal use
3322             assert(!funcalias.isFuncAliasDeclaration());
3323             this.hasOverloads = false;
3324         }
3325         userAttribDecl = funcalias.userAttribDecl;
3326     }
3327 
3328     override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
3329     {
3330         return this;
3331     }
3332 
3333     override const(char)* kind() const
3334     {
3335         return "function alias";
3336     }
3337 
3338     override inout(FuncDeclaration) toAliasFunc() inout
3339     {
3340         return funcalias.toAliasFunc();
3341     }
3342 
3343     override void accept(Visitor v)
3344     {
3345         v.visit(this);
3346     }
3347 }
3348 
3349 /***********************************************************
3350  */
3351 extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
3352 {
3353     TOK tok;        // TOK.function_ or TOK.delegate_
3354     Type treq;      // target of return type inference
3355 
3356     // backend
3357     bool deferToObj;
3358 
3359     extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null)
3360     {
3361         super(loc, endloc, null, STC.undefined_, type);
3362         this.ident = id ? id : Id.empty;
3363         this.tok = tok;
3364         this.fes = fes;
3365         // Always infer scope for function literals
3366         // See https://issues.dlang.org/show_bug.cgi?id=20362
3367         this.flags |= FUNCFLAG.inferScope;
3368         //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
3369     }
3370 
3371     override Dsymbol syntaxCopy(Dsymbol s)
3372     {
3373         //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
3374         assert(!s);
3375         auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident);
3376         f.treq = treq; // don't need to copy
3377         return FuncDeclaration.syntaxCopy(f);
3378     }
3379 
3380     override bool isNested() const
3381     {
3382         //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
3383         return (tok != TOK.function_) && !isThis();
3384     }
3385 
3386     override inout(AggregateDeclaration) isThis() inout
3387     {
3388         return tok == TOK.delegate_ ? super.isThis() : null;
3389     }
3390 
3391     override bool isVirtual() const
3392     {
3393         return false;
3394     }
3395 
3396     override bool addPreInvariant()
3397     {
3398         return false;
3399     }
3400 
3401     override bool addPostInvariant()
3402     {
3403         return false;
3404     }
3405 
3406     /*******************************
3407      * Modify all expression type of return statements to tret.
3408      *
3409      * On function literals, return type may be modified based on the context type
3410      * after its semantic3 is done, in FuncExp::implicitCastTo.
3411      *
3412      *  A function() dg = (){ return new B(); } // OK if is(B : A) == true
3413      *
3414      * If B to A conversion is convariant that requires offseet adjusting,
3415      * all return statements should be adjusted to return expressions typed A.
3416      */
3417     void modifyReturns(Scope* sc, Type tret)
3418     {
3419         import dmd.statement_rewrite_walker;
3420 
3421         extern (C++) final class RetWalker : StatementRewriteWalker
3422         {
3423             alias visit = typeof(super).visit;
3424         public:
3425             Scope* sc;
3426             Type tret;
3427             FuncLiteralDeclaration fld;
3428 
3429             override void visit(ReturnStatement s)
3430             {
3431                 Expression exp = s.exp;
3432                 if (exp && !exp.type.equals(tret))
3433                 {
3434                     s.exp = exp.castTo(sc, tret);
3435                 }
3436             }
3437         }
3438 
3439         if (semanticRun < PASS.semantic3done)
3440             return;
3441 
3442         if (fes)
3443             return;
3444 
3445         scope RetWalker w = new RetWalker();
3446         w.sc = sc;
3447         w.tret = tret;
3448         w.fld = this;
3449         fbody.accept(w);
3450 
3451         // Also update the inferred function type to match the new return type.
3452         // This is required so the code generator does not try to cast the
3453         // modified returns back to the original type.
3454         if (inferRetType && type.nextOf() != tret)
3455             type.toTypeFunction().next = tret;
3456     }
3457 
3458     override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
3459     {
3460         return this;
3461     }
3462 
3463     override const(char)* kind() const
3464     {
3465         // GCC requires the (char*) casts
3466         return (tok != TOK.function_) ? "delegate" : "function";
3467     }
3468 
3469     override const(char)* toPrettyChars(bool QualifyTypes = false)
3470     {
3471         if (parent)
3472         {
3473             TemplateInstance ti = parent.isTemplateInstance();
3474             if (ti)
3475                 return ti.tempdecl.toPrettyChars(QualifyTypes);
3476         }
3477         return Dsymbol.toPrettyChars(QualifyTypes);
3478     }
3479 
3480     override void accept(Visitor v)
3481     {
3482         v.visit(this);
3483     }
3484 }
3485 
3486 /***********************************************************
3487  */
3488 extern (C++) final class CtorDeclaration : FuncDeclaration
3489 {
3490     bool isCpCtor;
3491     extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
3492     {
3493         super(loc, endloc, Id.ctor, stc, type);
3494         this.isCpCtor = isCpCtor;
3495         //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars());
3496     }
3497 
3498     override Dsymbol syntaxCopy(Dsymbol s)
3499     {
3500         assert(!s);
3501         auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy());
3502         return FuncDeclaration.syntaxCopy(f);
3503     }
3504 
3505     override const(char)* kind() const
3506     {
3507         return isCpCtor ? "copy constructor" : "constructor";
3508     }
3509 
3510     override const(char)* toChars() const
3511     {
3512         return "this";
3513     }
3514 
3515     override bool isVirtual() const
3516     {
3517         return false;
3518     }
3519 
3520     override bool addPreInvariant()
3521     {
3522         return false;
3523     }
3524 
3525     override bool addPostInvariant()
3526     {
3527         return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3528     }
3529 
3530     override inout(CtorDeclaration) isCtorDeclaration() inout
3531     {
3532         return this;
3533     }
3534 
3535     override void accept(Visitor v)
3536     {
3537         v.visit(this);
3538     }
3539 }
3540 
3541 /***********************************************************
3542  */
3543 extern (C++) final class PostBlitDeclaration : FuncDeclaration
3544 {
3545     extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
3546     {
3547         super(loc, endloc, id, stc, null);
3548     }
3549 
3550     override Dsymbol syntaxCopy(Dsymbol s)
3551     {
3552         assert(!s);
3553         auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
3554         return FuncDeclaration.syntaxCopy(dd);
3555     }
3556 
3557     override bool isVirtual() const
3558     {
3559         return false;
3560     }
3561 
3562     override bool addPreInvariant()
3563     {
3564         return false;
3565     }
3566 
3567     override bool addPostInvariant()
3568     {
3569         return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3570     }
3571 
3572     override bool overloadInsert(Dsymbol s)
3573     {
3574         return false; // cannot overload postblits
3575     }
3576 
3577     override inout(PostBlitDeclaration) isPostBlitDeclaration() inout
3578     {
3579         return this;
3580     }
3581 
3582     override void accept(Visitor v)
3583     {
3584         v.visit(this);
3585     }
3586 }
3587 
3588 /***********************************************************
3589  */
3590 extern (C++) final class DtorDeclaration : FuncDeclaration
3591 {
3592     extern (D) this(const ref Loc loc, const ref Loc endloc)
3593     {
3594         super(loc, endloc, Id.dtor, STC.undefined_, null);
3595     }
3596 
3597     extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
3598     {
3599         super(loc, endloc, id, stc, null);
3600     }
3601 
3602     override Dsymbol syntaxCopy(Dsymbol s)
3603     {
3604         assert(!s);
3605         auto dd = new DtorDeclaration(loc, endloc, storage_class, ident);
3606         return FuncDeclaration.syntaxCopy(dd);
3607     }
3608 
3609     override const(char)* kind() const
3610     {
3611         return "destructor";
3612     }
3613 
3614     override const(char)* toChars() const
3615     {
3616         return "~this";
3617     }
3618 
3619     override bool isVirtual() const
3620     {
3621         // D dtor's don't get put into the vtbl[]
3622         // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
3623         return vtblIndex != -1;
3624     }
3625 
3626     override bool addPreInvariant()
3627     {
3628         return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3629     }
3630 
3631     override bool addPostInvariant()
3632     {
3633         return false;
3634     }
3635 
3636     override bool overloadInsert(Dsymbol s)
3637     {
3638         return false; // cannot overload destructors
3639     }
3640 
3641     override inout(DtorDeclaration) isDtorDeclaration() inout
3642     {
3643         return this;
3644     }
3645 
3646     override void accept(Visitor v)
3647     {
3648         v.visit(this);
3649     }
3650 }
3651 
3652 /***********************************************************
3653  */
3654 extern (C++) class StaticCtorDeclaration : FuncDeclaration
3655 {
3656     extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3657     {
3658         super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null);
3659     }
3660 
3661     extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
3662     {
3663         super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
3664     }
3665 
3666     override Dsymbol syntaxCopy(Dsymbol s)
3667     {
3668         assert(!s);
3669         auto scd = new StaticCtorDeclaration(loc, endloc, storage_class);
3670         return FuncDeclaration.syntaxCopy(scd);
3671     }
3672 
3673     override final inout(AggregateDeclaration) isThis() inout
3674     {
3675         return null;
3676     }
3677 
3678     override final bool isVirtual() const
3679     {
3680         return false;
3681     }
3682 
3683     override final bool addPreInvariant()
3684     {
3685         return false;
3686     }
3687 
3688     override final bool addPostInvariant()
3689     {
3690         return false;
3691     }
3692 
3693     override final bool hasStaticCtorOrDtor()
3694     {
3695         return true;
3696     }
3697 
3698     override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout
3699     {
3700         return this;
3701     }
3702 
3703     override void accept(Visitor v)
3704     {
3705         v.visit(this);
3706     }
3707 }
3708 
3709 /***********************************************************
3710  */
3711 extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
3712 {
3713     extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3714     {
3715         super(loc, endloc, "_sharedStaticCtor", stc);
3716     }
3717 
3718     override Dsymbol syntaxCopy(Dsymbol s)
3719     {
3720         assert(!s);
3721         auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
3722         return FuncDeclaration.syntaxCopy(scd);
3723     }
3724 
3725     override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
3726     {
3727         return this;
3728     }
3729 
3730     override void accept(Visitor v)
3731     {
3732         v.visit(this);
3733     }
3734 }
3735 
3736 /***********************************************************
3737  */
3738 extern (C++) class StaticDtorDeclaration : FuncDeclaration
3739 {
3740     VarDeclaration vgate; // 'gate' variable
3741 
3742     extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3743     {
3744         super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null);
3745     }
3746 
3747     extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
3748     {
3749         super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
3750     }
3751 
3752     override Dsymbol syntaxCopy(Dsymbol s)
3753     {
3754         assert(!s);
3755         auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
3756         return FuncDeclaration.syntaxCopy(sdd);
3757     }
3758 
3759     override final inout(AggregateDeclaration) isThis() inout
3760     {
3761         return null;
3762     }
3763 
3764     override final bool isVirtual() const
3765     {
3766         return false;
3767     }
3768 
3769     override final bool hasStaticCtorOrDtor()
3770     {
3771         return true;
3772     }
3773 
3774     override final bool addPreInvariant()
3775     {
3776         return false;
3777     }
3778 
3779     override final bool addPostInvariant()
3780     {
3781         return false;
3782     }
3783 
3784     override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
3785     {
3786         return this;
3787     }
3788 
3789     override void accept(Visitor v)
3790     {
3791         v.visit(this);
3792     }
3793 }
3794 
3795 /***********************************************************
3796  */
3797 extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
3798 {
3799     extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3800     {
3801         super(loc, endloc, "_sharedStaticDtor", stc);
3802     }
3803 
3804     override Dsymbol syntaxCopy(Dsymbol s)
3805     {
3806         assert(!s);
3807         auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
3808         return FuncDeclaration.syntaxCopy(sdd);
3809     }
3810 
3811     override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
3812     {
3813         return this;
3814     }
3815 
3816     override void accept(Visitor v)
3817     {
3818         v.visit(this);
3819     }
3820 }
3821 
3822 /***********************************************************
3823  */
3824 extern (C++) final class InvariantDeclaration : FuncDeclaration
3825 {
3826     extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
3827     {
3828         super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
3829         this.fbody = fbody;
3830     }
3831 
3832     override Dsymbol syntaxCopy(Dsymbol s)
3833     {
3834         assert(!s);
3835         auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null);
3836         return FuncDeclaration.syntaxCopy(id);
3837     }
3838 
3839     override bool isVirtual() const
3840     {
3841         return false;
3842     }
3843 
3844     override bool addPreInvariant()
3845     {
3846         return false;
3847     }
3848 
3849     override bool addPostInvariant()
3850     {
3851         return false;
3852     }
3853 
3854     override inout(InvariantDeclaration) isInvariantDeclaration() inout
3855     {
3856         return this;
3857     }
3858 
3859     override void accept(Visitor v)
3860     {
3861         v.visit(this);
3862     }
3863 }
3864 
3865 
3866 /***********************************************************
3867  */
3868 extern (C++) final class UnitTestDeclaration : FuncDeclaration
3869 {
3870     char* codedoc;      // for documented unittest
3871 
3872     // toObjFile() these nested functions after this one
3873     FuncDeclarations deferredNested;
3874 
3875     extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
3876     {
3877         super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null);
3878         this.codedoc = codedoc;
3879     }
3880 
3881     override Dsymbol syntaxCopy(Dsymbol s)
3882     {
3883         assert(!s);
3884         auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
3885         return FuncDeclaration.syntaxCopy(utd);
3886     }
3887 
3888     override inout(AggregateDeclaration) isThis() inout
3889     {
3890         return null;
3891     }
3892 
3893     override bool isVirtual() const
3894     {
3895         return false;
3896     }
3897 
3898     override bool addPreInvariant()
3899     {
3900         return false;
3901     }
3902 
3903     override bool addPostInvariant()
3904     {
3905         return false;
3906     }
3907 
3908     override inout(UnitTestDeclaration) isUnitTestDeclaration() inout
3909     {
3910         return this;
3911     }
3912 
3913     override void accept(Visitor v)
3914     {
3915         v.visit(this);
3916     }
3917 }
3918 
3919 /***********************************************************
3920  */
3921 extern (C++) final class NewDeclaration : FuncDeclaration
3922 {
3923     Parameters* parameters;
3924     VarArg varargs;
3925 
3926     extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Parameters* fparams, VarArg varargs)
3927     {
3928         super(loc, endloc, Id.classNew, STC.static_ | stc, null);
3929         this.parameters = fparams;
3930         this.varargs = varargs;
3931     }
3932 
3933     override Dsymbol syntaxCopy(Dsymbol s)
3934     {
3935         assert(!s);
3936         auto f = new NewDeclaration(loc, endloc, storage_class, Parameter.arraySyntaxCopy(parameters), varargs);
3937         return FuncDeclaration.syntaxCopy(f);
3938     }
3939 
3940     override const(char)* kind() const
3941     {
3942         return "allocator";
3943     }
3944 
3945     override bool isVirtual() const
3946     {
3947         return false;
3948     }
3949 
3950     override bool addPreInvariant()
3951     {
3952         return false;
3953     }
3954 
3955     override bool addPostInvariant()
3956     {
3957         return false;
3958     }
3959 
3960     override inout(NewDeclaration) isNewDeclaration() inout
3961     {
3962         return this;
3963     }
3964 
3965     override void accept(Visitor v)
3966     {
3967         v.visit(this);
3968     }
3969 }