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