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