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