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