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