<
1
/**
2
 * Defines a function declaration.
3
 *
4
 * Includes:
5
 * - function/delegate literals
6
 * - function aliases
7
 * - (static/shared) constructors/destructors/post-blits
8
 * - `invariant`
9
 * - `unittest`
10
 *
11
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
12
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
13
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
14
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d)
15
 * Documentation:  https://dlang.org/phobos/dmd_func.html
16
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d
17
 */
18

19
module dmd.func;
20

21
import core.stdc.stdio;
22
import core.stdc.string;
23
import dmd.aggregate;
24
import dmd.arraytypes;
25
import dmd.blockexit;
26
import dmd.gluelayer;
27
import dmd.dclass;
28
import dmd.declaration;
29
import dmd.delegatize;
30
import dmd.dinterpret;
31
import dmd.dmodule;
32
import dmd.dscope;
33
import dmd.dstruct;
34
import dmd.dsymbol;
35
import dmd.dsymbolsem;
36
import dmd.dtemplate;
37
import dmd.errors;
38
import dmd.escape;
39
import dmd.expression;
40
import dmd.globals;
41
import dmd.hdrgen;
42
import dmd.id;
43
import dmd.identifier;
44
import dmd.init;
45
import dmd.mtype;
46
import dmd.objc;
47
import dmd.root.outbuffer;
48
import dmd.root.rootobject;
49
import dmd.root.string;
50
import dmd.root.stringtable;
51
import dmd.semantic2;
52
import dmd.semantic3;
53
import dmd.statement_rewrite_walker;
54
import dmd.statement;
55
import dmd.statementsem;
56
import dmd.tokens;
57
import dmd.visitor;
58

59
/// Inline Status
60
enum ILS : int
61
{
62
    uninitialized,       /// not computed yet
63
    no,                  /// cannot inline
64
    yes,                 /// can inline
65
}
66

67
enum BUILTIN : byte
68
{
69
    unknown = -1,    /// not known if this is a builtin
70
    unimp,           /// this is not a builtin
71
    gcc,             /// this is a GCC builtin
72
    llvm,            /// this is an LLVM builtin
73
    sin,
74
    cos,
75
    tan,
76
    sqrt,
77
    fabs,
78
    ldexp,
79
    log,
80
    log2,
81
    log10,
82
    exp,
83
    expm1,
84
    exp2,
85
    round,
86
    floor,
87
    ceil,
88
    trunc,
89
    copysign,
90
    pow,
91
    fmin,
92
    fmax,
93
    fma,
94
    isnan,
95
    isinfinity,
96
    isfinite,
97
    bsf,
98
    bsr,
99
    bswap,
100
    popcnt,
101
    yl2x,
102
    yl2xp1,
103
    toPrecFloat,
104
    toPrecDouble,
105
    toPrecReal
106
}
107

108
/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
109
 */
110
extern (C++) final class NrvoWalker : StatementRewriteWalker
111
{
112
    alias visit = typeof(super).visit;
113
public:
114
    FuncDeclaration fd;
115
    Scope* sc;
116

117
    override void visit(ReturnStatement s)
118
    {
119
        // See if all returns are instead to be replaced with a goto returnLabel;
120 1
        if (fd.returnLabel)
121
        {
122
            /* Rewrite:
123
             *  return exp;
124
             * as:
125
             *  vresult = exp; goto Lresult;
126
             */
127 1
            auto gs = new GotoStatement(s.loc, Id.returnLabel);
128 1
            gs.label = fd.returnLabel;
129

130 1
            Statement s1 = gs;
131 1
            if (s.exp)
132 1
                s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
133

134 1
            replaceCurrent(s1);
135
        }
136
    }
137

138
    override void visit(TryFinallyStatement s)
139
    {
140 1
        DtorExpStatement des;
141 1
        if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
142 1
            fd.nrvo_var == des.var)
143
        {
144 1
            if (!(global.params.useExceptions && ClassDeclaration.throwable))
145
            {
146
                /* Don't need to call destructor at all, since it is nrvo
147
                 */
148 1
                replaceCurrent(s._body);
149 1
                s._body.accept(this);
150 1
                return;
151
            }
152

153
            /* Normally local variable dtors are called regardless exceptions.
154
             * But for nrvo_var, its dtor should be called only when exception is thrown.
155
             *
156
             * Rewrite:
157
             *      try { s.body; } finally { nrvo_var.edtor; }
158
             *      // equivalent with:
159
             *      //    s.body; scope(exit) nrvo_var.edtor;
160
             * as:
161
             *      try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
162
             *      // equivalent with:
163
             *      //    s.body; scope(failure) nrvo_var.edtor;
164
             */
165 1
            Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
166 1
            Identifier id = Identifier.generateId("__o");
167

168 1
            Statement handler = new PeelStatement(sexception);
169 1
            if (sexception.blockExit(fd, false) & BE.fallthru)
170
            {
171 1
                auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
172 1
                ts.internalThrow = true;
173 1
                handler = new CompoundStatement(Loc.initial, handler, ts);
174
            }
175

176 1
            auto catches = new Catches();
177 1
            auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
178 1
            ctch.internalCatch = true;
179 1
            ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
180 1
            catches.push(ctch);
181

182 1
            Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
183 1
            fd.eh_none = false;
184 1
            replaceCurrent(s2);
185 1
            s2.accept(this);
186
        }
187
        else
188 1
            StatementRewriteWalker.visit(s);
189
    }
190
}
191

192
enum FUNCFLAG : uint
193
{
194
    purityInprocess  = 1,      /// working on determining purity
195
    safetyInprocess  = 2,      /// working on determining safety
196
    nothrowInprocess = 4,      /// working on determining nothrow
197
    nogcInprocess    = 8,      /// working on determining @nogc
198
    returnInprocess  = 0x10,   /// working on inferring 'return' for parameters
199
    inlineScanned    = 0x20,   /// function has been scanned for inline possibilities
200
    inferScope       = 0x40,   /// infer 'scope' for parameters
201
    hasCatches       = 0x80,   /// function has try-catch statements
202
    compileTimeOnly  = 0x100,  /// is a compile time only function; no code will be generated for it
203
    printf           = 0x200,  /// is a printf-like function
204
    scanf            = 0x400,  /// is a scanf-like function
205
}
206

207
/***********************************************************
208
 * Tuple of result identifier (possibly null) and statement.
209
 * This is used to store out contracts: out(id){ ensure }
210
 */
211
extern (C++) struct Ensure
212
{
213
    Identifier id;
214
    Statement ensure;
215

216
    Ensure syntaxCopy()
217
    {
218 1
        return Ensure(id, ensure.syntaxCopy());
219
    }
220

221
    /*****************************************
222
     * Do syntax copy of an array of Ensure's.
223
     */
224
    static Ensures* arraySyntaxCopy(Ensures* a)
225
    {
226 1
        Ensures* b = null;
227 1
        if (a)
228
        {
229 1
            b = a.copy();
230 1
            foreach (i, e; *a)
231
            {
232 1
                (*b)[i] = e.syntaxCopy();
233
            }
234
        }
235 1
        return b;
236
    }
237

238
}
239

240
/***********************************************************
241
 */
242
extern (C++) class FuncDeclaration : Declaration
243
{
244
    Statements* frequires;              /// in contracts
245
    Ensures* fensures;                  /// out contracts
246
    Statement frequire;                 /// lowered in contract
247
    Statement fensure;                  /// lowered out contract
248
    Statement fbody;                    /// function body
249

250
    FuncDeclarations foverrides;        /// functions this function overrides
251
    FuncDeclaration fdrequire;          /// function that does the in contract
252
    FuncDeclaration fdensure;           /// function that does the out contract
253

254
    Expressions* fdrequireParams;       /// argument list for __require
255
    Expressions* fdensureParams;        /// argument list for __ensure
256

257
    const(char)* mangleString;          /// mangled symbol created from mangleExact()
258

259
    VarDeclaration vresult;             /// result variable for out contracts
260
    LabelDsymbol returnLabel;           /// where the return goes
261

262
    // used to prevent symbols in different
263
    // scopes from having the same name
264
    DsymbolTable localsymtab;
265
    VarDeclaration vthis;               /// 'this' parameter (member and nested)
266
    bool isThis2;                       /// has a dual-context 'this' parameter
267
    VarDeclaration v_arguments;         /// '_arguments' parameter
268
    ObjcSelector* selector;             /// Objective-C method selector (member function only)
269
    VarDeclaration selectorParameter;   /// Objective-C implicit selector parameter
270

271
    VarDeclaration v_argptr;            /// '_argptr' variable
272
    VarDeclarations* parameters;        /// Array of VarDeclaration's for parameters
273
    DsymbolTable labtab;                /// statement label symbol table
274
    Dsymbol overnext;                   /// next in overload list
275
    FuncDeclaration overnext0;          /// next in overload list (only used during IFTI)
276
    Loc endloc;                         /// location of closing curly bracket
277
    int vtblIndex = -1;                 /// for member functions, index into vtbl[]
278
    bool naked;                         /// true if naked
279
    bool generated;                     /// true if function was generated by the compiler rather than
280
                                        /// supplied by the user
281
    bool hasAlwaysInlines;              /// contains references to functions that must be inlined
282
    ubyte isCrtCtorDtor;                /// has attribute pragma(crt_constructor(1)/crt_destructor(2))
283
                                        /// not set before the glue layer
284

285
    ILS inlineStatusStmt = ILS.uninitialized;
286
    ILS inlineStatusExp = ILS.uninitialized;
287
    PINLINE inlining = PINLINE.default_;
288

289
    int inlineNest;                     /// !=0 if nested inline
290
    bool eh_none;                       /// true if no exception unwinding is needed
291

292
    bool semantic3Errors;               /// true if errors in semantic3 this function's frame ptr
293
    ForeachStatement fes;               /// if foreach body, this is the foreach
294
    BaseClass* interfaceVirtual;        /// if virtual, but only appears in base interface vtbl[]
295
    bool introducing;                   /// true if 'introducing' function
296
    /** if !=NULL, then this is the type
297
    of the 'introducing' function
298
    this one is overriding
299
    */
300
    Type tintro;
301

302
    bool inferRetType;                  /// true if return type is to be inferred
303
    StorageClass storage_class2;        /// storage class for template onemember's
304

305
    // Things that should really go into Scope
306

307
    /// 1 if there's a return exp; statement
308
    /// 2 if there's a throw statement
309
    /// 4 if there's an assert(0)
310
    /// 8 if there's inline asm
311
    /// 16 if there are multiple return statements
312
    int hasReturnExp;
313

314
    // Support for NRVO (named return value optimization)
315
    bool nrvo_can = true;               /// true means we can do NRVO
316
    VarDeclaration nrvo_var;            /// variable to replace with shidden
317
    Symbol* shidden;                    /// hidden pointer passed to function
318

319
    ReturnStatements* returns;
320

321
    GotoStatements* gotos;              /// Gotos with forward references
322

323
    /// set if this is a known, builtin function we can evaluate at compile time
324
    BUILTIN builtin = BUILTIN.unknown;
325

326
    /// set if someone took the address of this function
327
    int tookAddressOf;
328

329
    bool requiresClosure;               // this function needs a closure
330

331
    /** local variables in this function which are referenced by nested functions
332
     * (They'll get put into the "closure" for this function.)
333
     */
334
    VarDeclarations closureVars;
335

336
    /** Outer variables which are referenced by this nested function
337
     * (the inverse of closureVars)
338
     */
339
    VarDeclarations outerVars;
340

341
    /// Sibling nested functions which called this one
342
    FuncDeclarations siblingCallers;
343

344
    FuncDeclarations *inlinedNestedCallees;
345

346
    uint flags;                        /// FUNCFLAG.xxxxx
347

348 1
    extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type)
349
    {
350 1
        super(loc, ident);
351
        //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type);
352
        //printf("storage_class = x%x\n", storage_class);
353 1
        this.storage_class = storage_class;
354 1
        this.type = type;
355 1
        if (type)
356
        {
357
            // Normalize storage_class, because function-type related attributes
358
            // are already set in the 'type' in parsing phase.
359 1
            this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
360
        }
361 1
        this.endloc = endloc;
362
        /* The type given for "infer the return type" is a TypeFunction with
363
         * NULL for the return type.
364
         */
365 1
        inferRetType = (type && type.nextOf() is null);
366
    }
367

368
    static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type)
369
    {
370 0
        return new FuncDeclaration(loc, endloc, id, storage_class, type);
371
    }
372

373
    override Dsymbol syntaxCopy(Dsymbol s)
374
    {
375
        //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
376 1
        FuncDeclaration f = s ? cast(FuncDeclaration)s : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy());
377 1
        f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
378 1
        f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
379 1
        f.fbody = fbody ? fbody.syntaxCopy() : null;
380 1
        return f;
381
    }
382

383
    /****************************************************
384
     * Resolve forward reference of function signature -
385
     * parameter types, return type, and attributes.
386
     * Returns false if any errors exist in the signature.
387
     */
388
    final bool functionSemantic()
389
    {
390 1
        if (!_scope)
391 1
            return !errors;
392

393 1
        this.cppnamespace = _scope.namespace;
394

395 1
        if (!originalType) // semantic not yet run
396
        {
397 1
            TemplateInstance spec = isSpeculative();
398 1
            uint olderrs = global.errors;
399 1
            uint oldgag = global.gag;
400 1
            if (global.gag && !spec)
401 1
                global.gag = 0;
402 1
            dsymbolSemantic(this, _scope);
403 1
            global.gag = oldgag;
404 1
            if (spec && global.errors != olderrs)
405 0
                spec.errors = (global.errors - olderrs != 0);
406 1
            if (olderrs != global.errors) // if errors compiling this function
407 1
                return false;
408
        }
409

410
        // if inferring return type, sematic3 needs to be run
411
        // - When the function body contains any errors, we cannot assume
412
        //   the inferred return type is valid.
413
        //   So, the body errors should become the function signature error.
414 1
        if (inferRetType && type && !type.nextOf())
415 1
            return functionSemantic3();
416

417 1
        TemplateInstance ti;
418 1
        if (isInstantiated() && !isVirtualMethod() &&
419 1
            ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident))
420
        {
421 1
            AggregateDeclaration ad = isMemberLocal();
422 1
            if (ad && ad.sizeok != Sizeok.done)
423
            {
424
                /* Currently dmd cannot resolve forward references per methods,
425
                 * then setting SIZOKfwd is too conservative and would break existing code.
426
                 * So, just stop method attributes inference until ad.dsymbolSemantic() done.
427
                 */
428
                //ad.sizeok = Sizeok.fwd;
429
            }
430
            else
431 1
                return functionSemantic3() || !errors;
432
        }
433

434 1
        if (storage_class & STC.inference)
435 1
            return functionSemantic3() || !errors;
436

437 1
        return !errors;
438
    }
439

440
    /****************************************************
441
     * Resolve forward reference of function body.
442
     * Returns false if any errors exist in the body.
443
     */
444
    final bool functionSemantic3()
445
    {
446 1
        if (semanticRun < PASS.semantic3 && _scope)
447
        {
448
            /* Forward reference - we need to run semantic3 on this function.
449
             * If errors are gagged, and it's not part of a template instance,
450
             * we need to temporarily ungag errors.
451
             */
452 1
            TemplateInstance spec = isSpeculative();
453 1
            uint olderrs = global.errors;
454 1
            uint oldgag = global.gag;
455 1
            if (global.gag && !spec)
456 1
                global.gag = 0;
457 1
            semantic3(this, _scope);
458 1
            global.gag = oldgag;
459

460
            // If it is a speculatively-instantiated template, and errors occur,
461
            // we need to mark the template as having errors.
462 1
            if (spec && global.errors != olderrs)
463 1
                spec.errors = (global.errors - olderrs != 0);
464 1
            if (olderrs != global.errors) // if errors compiling this function
465 1
                return false;
466
        }
467

468 1
        return !errors && !semantic3Errors;
469
    }
470

471
    /****************************************************
472
     * Check that this function type is properly resolved.
473
     * If not, report "forward reference error" and return true.
474
     */
475
    extern (D) final bool checkForwardRef(const ref Loc loc)
476
    {
477 1
        if (!functionSemantic())
478 0
            return true;
479

480
        /* No deco means the functionSemantic() call could not resolve
481
         * forward referenes in the type of this function.
482
         */
483 1
        if (!type.deco)
484
        {
485 1
            bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3);
486 1
            .error(loc, "forward reference to %s`%s`",
487 1
                (inSemantic3 ? "inferred return type of function " : "").ptr,
488
                toChars());
489 1
            return true;
490
        }
491 1
        return false;
492
    }
493

494
    // called from semantic3
495
    /**
496
     * Creates and returns the hidden parameters for this function declaration.
497
     *
498
     * Hidden parameters include the `this` parameter of a class, struct or
499
     * nested function and the selector parameter for Objective-C methods.
500
     */
501
    extern (D) final void declareThis(Scope* sc)
502
    {
503 1
        isThis2 = toParent2() != toParentLocal();
504 1
        auto ad = isThis();
505 1
        if (!isThis2 && !ad && !isNested())
506
        {
507 1
            vthis = null;
508 1
            selectorParameter = null;
509 1
            return;
510
        }
511

512
        Type addModStc(Type t)
513
        {
514 1
            return t.addMod(type.mod).addStorageClass(storage_class);
515
        }
516

517 1
        if (isThis2 || isNested())
518
        {
519
            /* The 'this' for a nested function is the link to the
520
             * enclosing function's stack frame.
521
             * Note that nested functions and member functions are disjoint.
522
             */
523 1
            Type tthis = addModStc(isThis2 ?
524 1
                                   Type.tvoidptr.sarrayOf(2).pointerTo() :
525 1
                                   Type.tvoid.pointerTo());
526 1
            vthis = new VarDeclaration(loc, tthis, isThis2 ? Id.this2 : Id.capture, null);
527 1
            vthis.storage_class |= STC.parameter | STC.nodtor;
528
        }
529 1
        else if (ad)
530
        {
531 1
            Type thandle = addModStc(ad.handleType());
532 1
            vthis = new ThisDeclaration(loc, thandle);
533 1
            vthis.storage_class |= STC.parameter;
534 1
            if (thandle.ty == Tstruct)
535
            {
536 1
                vthis.storage_class |= STC.ref_;
537
                // if member function is marked 'inout', then 'this' is 'return ref'
538 1
                if (type.ty == Tfunction && (cast(TypeFunction)type).isInOutQual())
539 1
                    vthis.storage_class |= STC.return_;
540
            }
541
        }
542

543 1
        if (type.ty == Tfunction)
544
        {
545 1
            TypeFunction tf = cast(TypeFunction)type;
546 1
            if (tf.isreturn)
547 1
                vthis.storage_class |= STC.return_;
548 1
            if (tf.isScopeQual)
549 1
                vthis.storage_class |= STC.scope_;
550
        }
551 1
        if (flags & FUNCFLAG.inferScope && !(vthis.storage_class & STC.scope_))
552 1
            vthis.storage_class |= STC.maybescope;
553

554 1
        vthis.dsymbolSemantic(sc);
555 1
        if (!sc.insert(vthis))
556 0
            assert(0);
557 1
        vthis.parent = this;
558 1
        if (ad)
559 1
            selectorParameter = objc.createSelectorParameter(this, sc);
560
    }
561

562
    override final bool equals(const RootObject o) const
563
    {
564 1
        if (this == o)
565 1
            return true;
566

567 1
        if (auto s = isDsymbol(o))
568
        {
569 1
            auto fd1 = this;
570 1
            auto fd2 = s.isFuncDeclaration();
571 1
            if (!fd2)
572 0
                return false;
573

574 1
            auto fa1 = fd1.isFuncAliasDeclaration();
575 1
            auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
576

577 1
            auto fa2 = fd2.isFuncAliasDeclaration();
578 1
            auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
579

580 1
            if (fa1 && fa2)
581
            {
582 1
                return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
583
            }
584

585 1
            bool b1 = fa1 !is null;
586 1
            if (b1 && faf1.isUnique() && !fa1.hasOverloads)
587 0
                b1 = false;
588

589 1
            bool b2 = fa2 !is null;
590 1
            if (b2 && faf2.isUnique() && !fa2.hasOverloads)
591 0
                b2 = false;
592

593 1
            if (b1 != b2)
594 1
                return false;
595

596 1
            return faf1.toParent().equals(faf2.toParent()) &&
597 1
                   faf1.ident.equals(faf2.ident) &&
598 1
                   faf1.type.equals(faf2.type);
599
        }
600 0
        return false;
601
    }
602

603
    /****************************************************
604
     * Determine if 'this' overrides fd.
605
     * Return !=0 if it does.
606
     */
607
    final int overrides(FuncDeclaration fd)
608
    {
609 1
        int result = 0;
610 1
        if (fd.ident == ident)
611
        {
612 1
            int cov = type.covariant(fd.type);
613 1
            if (cov)
614
            {
615 1
                ClassDeclaration cd1 = toParent().isClassDeclaration();
616 1
                ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
617 1
                if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
618 1
                    result = 1;
619
            }
620
        }
621 1
        return result;
622
    }
623

624
    /*************************************************
625
     * Find index of function in vtbl[0..dim] that
626
     * this function overrides.
627
     * Prefer an exact match to a covariant one.
628
     * Params:
629
     *      vtbl     = vtable to use
630
     *      dim      = maximal vtable dimension
631
     * Returns:
632
     *      -1      didn't find one
633
     *      -2      can't determine because of forward references
634
     */
635
    final int findVtblIndex(Dsymbols* vtbl, int dim)
636
    {
637
        //printf("findVtblIndex() %s\n", toChars());
638 1
        FuncDeclaration mismatch = null;
639 1
        StorageClass mismatchstc = 0;
640 1
        int mismatchvi = -1;
641 1
        int exactvi = -1;
642 1
        int bestvi = -1;
643 1
        for (int vi = 0; vi < dim; vi++)
644
        {
645 1
            FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration();
646 1
            if (fdv && fdv.ident == ident)
647
            {
648 1
                if (type.equals(fdv.type)) // if exact match
649
                {
650 1
                    if (fdv.parent.isClassDeclaration())
651
                    {
652 1
                        if (fdv.isFuture())
653
                        {
654 1
                            bestvi = vi;
655 1
                            continue;           // keep looking
656
                        }
657 1
                        return vi; // no need to look further
658
                    }
659

660 1
                    if (exactvi >= 0)
661
                    {
662 1
                        error("cannot determine overridden function");
663 1
                        return exactvi;
664
                    }
665 1
                    exactvi = vi;
666 1
                    bestvi = vi;
667 1
                    continue;
668
                }
669

670 1
                StorageClass stc = 0;
671 1
                int cov = type.covariant(fdv.type, &stc);
672
                //printf("\tbaseclass cov = %d\n", cov);
673 1
                switch (cov)
674
                {
675 1
                case 0:
676
                    // types are distinct
677 1
                    break;
678

679 1
                case 1:
680 1
                    bestvi = vi; // covariant, but not identical
681 1
                    break;
682
                    // keep looking for an exact match
683

684 1
                case 2:
685 1
                    mismatchvi = vi;
686 1
                    mismatchstc = stc;
687 1
                    mismatch = fdv; // overrides, but is not covariant
688 1
                    break;
689
                    // keep looking for an exact match
690

691 0
                case 3:
692 0
                    return -2; // forward references
693

694 0
                default:
695 0
                    assert(0);
696
                }
697
            }
698
        }
699 1
        if (bestvi == -1 && mismatch)
700
        {
701
            //type.print();
702
            //mismatch.type.print();
703
            //printf("%s %s\n", type.deco, mismatch.type.deco);
704
            //printf("stc = %llx\n", mismatchstc);
705 1
            if (mismatchstc)
706
            {
707
                // Fix it by modifying the type to add the storage classes
708 1
                type = type.addStorageClass(mismatchstc);
709 1
                bestvi = mismatchvi;
710
            }
711
        }
712 1
        return bestvi;
713
    }
714

715
    /*********************************
716
     * If function a function in a base class,
717
     * return that base class.
718
     * Returns:
719
     *  base class if overriding, null if not
720
     */
721
    final BaseClass* overrideInterface()
722
    {
723 0
        if (ClassDeclaration cd = toParent2().isClassDeclaration())
724
        {
725 0
            foreach (b; cd.interfaces)
726
            {
727 0
                auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim);
728 0
                if (v >= 0)
729 0
                    return b;
730
            }
731
        }
732 0
        return null;
733
    }
734

735
    /****************************************************
736
     * Overload this FuncDeclaration with the new one f.
737
     * Return true if successful; i.e. no conflict.
738
     */
739
    override bool overloadInsert(Dsymbol s)
740
    {
741
        //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
742 1
        assert(s != this);
743 1
        AliasDeclaration ad = s.isAliasDeclaration();
744 1
        if (ad)
745
        {
746 1
            if (overnext)
747 0
                return overnext.overloadInsert(ad);
748 1
            if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof)
749
            {
750
                //printf("\tad = '%s'\n", ad.type.toChars());
751 1
                return false;
752
            }
753 1
            overnext = ad;
754
            //printf("\ttrue: no conflict\n");
755 1
            return true;
756
        }
757 1
        TemplateDeclaration td = s.isTemplateDeclaration();
758 1
        if (td)
759
        {
760 1
            if (!td.funcroot)
761 1
                td.funcroot = this;
762 1
            if (overnext)
763 1
                return overnext.overloadInsert(td);
764 1
            overnext = td;
765 1
            return true;
766
        }
767 1
        FuncDeclaration fd = s.isFuncDeclaration();
768 1
        if (!fd)
769 0
            return false;
770

771
        version (none)
772
        {
773
            /* Disable this check because:
774
             *  const void foo();
775
             * semantic() isn't run yet on foo(), so the const hasn't been
776
             * applied yet.
777
             */
778
            if (type)
779
            {
780
                printf("type = %s\n", type.toChars());
781
                printf("fd.type = %s\n", fd.type.toChars());
782
            }
783
            // fd.type can be NULL for overloaded constructors
784
            if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
785
            {
786
                //printf("\tfalse: conflict %s\n", kind());
787
                return false;
788
            }
789
        }
790

791 1
        if (overnext)
792
        {
793 1
            td = overnext.isTemplateDeclaration();
794 1
            if (td)
795 1
                fd.overloadInsert(td);
796
            else
797 1
                return overnext.overloadInsert(fd);
798
        }
799 1
        overnext = fd;
800
        //printf("\ttrue: no conflict\n");
801 1
        return true;
802
    }
803

804
    /********************************************
805
     * Find function in overload list that exactly matches t.
806
     */
807
    extern (D) final FuncDeclaration overloadExactMatch(Type t)
808
    {
809 1
        FuncDeclaration fd;
810 1
        overloadApply(this, (Dsymbol s)
811
        {
812 1
            auto f = s.isFuncDeclaration();
813 1
            if (!f)
814 1
                return 0;
815 1
            if (t.equals(f.type))
816
            {
817 1
                fd = f;
818 1
                return 1;
819
            }
820

821
            /* Allow covariant matches, as long as the return type
822
             * is just a const conversion.
823
             * This allows things like pure functions to match with an impure function type.
824
             */
825 1
            if (t.ty == Tfunction)
826
            {
827 1
                auto tf = cast(TypeFunction)f.type;
828 1
                if (tf.covariant(t) == 1 &&
829 1
                    tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
830
                {
831 1
                    fd = f;
832 1
                    return 1;
833
                }
834
            }
835 1
            return 0;
836
        });
837 1
        return fd;
838
    }
839

840
    /********************************************
841
     * Find function in overload list that matches to the 'this' modifier.
842
     * There's four result types.
843
     *
844
     * 1. If the 'tthis' matches only one candidate, it's an "exact match".
845
     *    Returns the function and 'hasOverloads' is set to false.
846
     *      eg. If 'tthis" is mutable and there's only one mutable method.
847
     * 2. If there's two or more match candidates, but a candidate function will be
848
     *    a "better match".
849
     *    Returns the better match function but 'hasOverloads' is set to true.
850
     *      eg. If 'tthis' is mutable, and there's both mutable and const methods,
851
     *          the mutable method will be a better match.
852
     * 3. If there's two or more match candidates, but there's no better match,
853
     *    Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
854
     *      eg. If 'tthis' is mutable, and there's two or more mutable methods.
855
     * 4. If there's no candidates, it's "no match" and returns null with error report.
856
     *      e.g. If 'tthis' is const but there's no const methods.
857
     */
858
    extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
859
    {
860
        //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
861 1
        MatchAccumulator m;
862 1
        overloadApply(this, (Dsymbol s)
863
        {
864 1
            auto f = s.isFuncDeclaration();
865 1
            if (!f || f == m.lastf) // skip duplicates
866 0
                return 0;
867

868 1
            auto tf = f.type.toTypeFunction();
869
            //printf("tf = %s\n", tf.toChars());
870

871 1
            MATCH match;
872 1
            if (tthis) // non-static functions are preferred than static ones
873
            {
874 1
                if (f.needThis())
875 1
                    match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
876
                else
877 0
                    match = MATCH.constant; // keep static function in overload candidates
878
            }
879
            else // static functions are preferred than non-static ones
880
            {
881 0
                if (f.needThis())
882 0
                    match = MATCH.convert;
883
                else
884 0
                    match = MATCH.exact;
885
            }
886 1
            if (match == MATCH.nomatch)
887 1
                return 0;
888

889 1
            if (match > m.last) goto LcurrIsBetter;
890 1
            if (match < m.last) goto LlastIsBetter;
891

892
            // See if one of the matches overrides the other.
893 0
            if (m.lastf.overrides(f)) goto LlastIsBetter;
894 0
            if (f.overrides(m.lastf)) goto LcurrIsBetter;
895

896
            //printf("\tambiguous\n");
897 0
            m.nextf = f;
898 0
            m.count++;
899 0
            return 0;
900

901
        LlastIsBetter:
902
            //printf("\tlastbetter\n");
903 1
            m.count++; // count up
904 1
            return 0;
905

906
        LcurrIsBetter:
907
            //printf("\tisbetter\n");
908 1
            if (m.last <= MATCH.convert)
909
            {
910
                // clear last secondary matching
911 1
                m.nextf = null;
912 1
                m.count = 0;
913
            }
914 1
            m.last = match;
915 1
            m.lastf = f;
916 1
            m.count++; // count up
917 1
            return 0;
918
        });
919

920 1
        if (m.count == 1)       // exact match
921
        {
922 1
            hasOverloads = false;
923
        }
924 1
        else if (m.count > 1)   // better or ambiguous match
925
        {
926 1
            hasOverloads = true;
927
        }
928
        else                    // no match
929
        {
930 1
            hasOverloads = true;
931 1
            auto tf = this.type.toTypeFunction();
932 1
            assert(tthis);
933 1
            assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
934
            {
935 1
                OutBuffer thisBuf, funcBuf;
936 1
                MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
937 1
                MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
938 1
                .error(loc, "%smethod %s is not callable using a %sobject",
939
                    funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
940
            }
941
        }
942 1
        return m.lastf;
943
    }
944

945
    /********************************************
946
     * find function template root in overload list
947
     */
948
    extern (D) final TemplateDeclaration findTemplateDeclRoot()
949
    {
950 1
        FuncDeclaration f = this;
951 1
        while (f && f.overnext)
952
        {
953
            //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
954 1
            TemplateDeclaration td = f.overnext.isTemplateDeclaration();
955 1
            if (td)
956 1
                return td;
957 1
            f = f.overnext.isFuncDeclaration();
958
        }
959 1
        return null;
960
    }
961

962
    /********************************************
963
     * Returns true if function was declared
964
     * directly or indirectly in a unittest block
965
     */
966
    final bool inUnittest()
967
    {
968 1
        Dsymbol f = this;
969
        do
970
        {
971 1
            if (f.isUnitTestDeclaration())
972 0
                return true;
973 1
            f = f.toParent();
974
        }
975 1
        while (f);
976 1
        return false;
977
    }
978

979
    /*************************************
980
     * Determine partial specialization order of 'this' vs g.
981
     * This is very similar to TemplateDeclaration::leastAsSpecialized().
982
     * Returns:
983
     *      match   'this' is at least as specialized as g
984
     *      0       g is more specialized than 'this'
985
     */
986
    final MATCH leastAsSpecialized(FuncDeclaration g)
987
    {
988
        enum LOG_LEASTAS = 0;
989
        static if (LOG_LEASTAS)
990
        {
991
            printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars());
992
            printf("%s, %s\n", type.toChars(), g.type.toChars());
993
        }
994

995
        /* This works by calling g() with f()'s parameters, and
996
         * if that is possible, then f() is at least as specialized
997
         * as g() is.
998
         */
999

1000 1
        TypeFunction tf = type.toTypeFunction();
1001 1
        TypeFunction tg = g.type.toTypeFunction();
1002

1003
        /* If both functions have a 'this' pointer, and the mods are not
1004
         * the same and g's is not const, then this is less specialized.
1005
         */
1006 1
        if (needThis() && g.needThis() && tf.mod != tg.mod)
1007
        {
1008 1
            if (isCtorDeclaration())
1009
            {
1010 1
                if (!MODimplicitConv(tg.mod, tf.mod))
1011 1
                    return MATCH.nomatch;
1012
            }
1013
            else
1014
            {
1015 1
                if (!MODimplicitConv(tf.mod, tg.mod))
1016 1
                    return MATCH.nomatch;
1017
            }
1018
        }
1019

1020
        /* Create a dummy array of arguments out of the parameters to f()
1021
         */
1022 1
        Expressions args;
1023 1
        foreach (u, p; tf.parameterList)
1024
        {
1025 1
            Expression e;
1026 1
            if (p.isReference())
1027
            {
1028 1
                e = new IdentifierExp(Loc.initial, p.ident);
1029 1
                e.type = p.type;
1030
            }
1031
            else
1032 1
                e = p.type.defaultInitLiteral(Loc.initial);
1033 1
            args.push(e);
1034
        }
1035

1036 1
        MATCH m = tg.callMatch(null, args[], 1);
1037 1
        if (m > MATCH.nomatch)
1038
        {
1039
            /* A variadic parameter list is less specialized than a
1040
             * non-variadic one.
1041
             */
1042 1
            if (tf.parameterList.varargs && !tg.parameterList.varargs)
1043 1
                goto L1; // less specialized
1044

1045
            static if (LOG_LEASTAS)
1046
            {
1047
                printf("  matches %d, so is least as specialized\n", m);
1048
            }
1049 1
            return m;
1050
        }
1051
    L1:
1052
        static if (LOG_LEASTAS)
1053
        {
1054
            printf("  doesn't match, so is not as specialized\n");
1055
        }
1056 1
        return MATCH.nomatch;
1057
    }
1058

1059
    /********************************
1060
     * Labels are in a separate scope, one per function.
1061
     */
1062
    final LabelDsymbol searchLabel(Identifier ident)
1063
    {
1064 1
        Dsymbol s;
1065 1
        if (!labtab)
1066 1
            labtab = new DsymbolTable(); // guess we need one
1067

1068 1
        s = labtab.lookup(ident);
1069 1
        if (!s)
1070
        {
1071 1
            s = new LabelDsymbol(ident);
1072 1
            labtab.insert(s);
1073
        }
1074 1
        return cast(LabelDsymbol)s;
1075
    }
1076

1077
    /*****************************************
1078
     * Determine lexical level difference from `this` to nested function `fd`.
1079
     * Params:
1080
     *      fd = target of call
1081
     *      intypeof = !=0 if inside typeof
1082
     * Returns:
1083
     *      0       same level
1084
     *      >0      decrease nesting by number
1085
     *      -1      increase nesting by 1 (`fd` is nested within `this`)
1086
     *      LevelError  error, `this` cannot call `fd`
1087
     */
1088
    final int getLevel(FuncDeclaration fd, int intypeof)
1089
    {
1090
        //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
1091 1
        Dsymbol fdparent = fd.toParent2();
1092 1
        if (fdparent == this)
1093 0
            return -1;
1094

1095 1
        Dsymbol s = this;
1096 1
        int level = 0;
1097 1
        while (fd != s && fdparent != s.toParent2())
1098
        {
1099
            //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
1100 1
            if (auto thisfd = s.isFuncDeclaration())
1101
            {
1102 1
                if (!thisfd.isNested() && !thisfd.vthis && !intypeof)
1103 1
                    return LevelError;
1104
            }
1105
            else
1106
            {
1107 1
                if (auto thiscd = s.isAggregateDeclaration())
1108
                {
1109
                    /* AggregateDeclaration::isNested returns true only when
1110
                     * it has a hidden pointer.
1111
                     * But, calling the function belongs unrelated lexical scope
1112
                     * is still allowed inside typeof.
1113
                     *
1114
                     * struct Map(alias fun) {
1115
                     *   typeof({ return fun(); }) RetType;
1116
                     *   // No member function makes Map struct 'not nested'.
1117
                     * }
1118
                     */
1119 1
                    if (!thiscd.isNested() && !intypeof)
1120 0
                        return LevelError;
1121
                }
1122
                else
1123 1
                    return LevelError;
1124
            }
1125

1126 1
            s = s.toParentP(fd);
1127 1
            assert(s);
1128 1
            level++;
1129
        }
1130 1
        return level;
1131
    }
1132

1133
    /***********************************
1134
     * Determine lexical level difference from `this` to nested function `fd`.
1135
     * Issue error if `this` cannot call `fd`.
1136
     * Params:
1137
     *      loc = location for error messages
1138
     *      sc = context
1139
     *      fd = target of call
1140
     * Returns:
1141
     *      0       same level
1142
     *      >0      decrease nesting by number
1143
     *      -1      increase nesting by 1 (`fd` is nested within 'this')
1144
     *      LevelError  error
1145
     */
1146
    final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd)
1147
    {
1148 1
        int level = getLevel(fd, sc.intypeof);
1149 1
        if (level != LevelError)
1150 1
            return level;
1151

1152
        // Don't give error if in template constraint
1153 1
        if (!(sc.flags & SCOPE.constraint))
1154
        {
1155 1
            const(char)* xstatic = isStatic() ? "static " : "";
1156
            // better diagnostics for static functions
1157 1
            .error(loc, "%s%s %s cannot access frame of function %s",
1158
                xstatic, kind(), toPrettyChars(), fd.toPrettyChars());
1159 1
            return LevelError;
1160
        }
1161 1
        return 1;
1162
    }
1163

1164
    enum LevelError = -2;
1165

1166
    override const(char)* toPrettyChars(bool QualifyTypes = false)
1167
    {
1168 1
        if (isMain())
1169 1
            return "D main";
1170
        else
1171 1
            return Dsymbol.toPrettyChars(QualifyTypes);
1172
    }
1173

1174
    /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
1175
    final const(char)* toFullSignature()
1176
    {
1177 1
        OutBuffer buf;
1178 1
        functionToBufferWithIdent(type.toTypeFunction(), &buf, toChars());
1179 1
        return buf.extractChars();
1180
    }
1181

1182
    final bool isMain() const
1183
    {
1184 1
        return ident == Id.main && linkage != LINK.c && !isMember() && !isNested();
1185
    }
1186

1187
    final bool isCMain() const
1188
    {
1189 1
        return ident == Id.main && linkage == LINK.c && !isMember() && !isNested();
1190
    }
1191

1192
    final bool isWinMain() const
1193
    {
1194
        //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1195
        version (none)
1196
        {
1197
            bool x = ident == Id.WinMain && linkage != LINK.c && !isMember();
1198
            printf("%s\n", x ? "yes" : "no");
1199
            return x;
1200
        }
1201
        else
1202
        {
1203 1
            return ident == Id.WinMain && linkage != LINK.c && !isMember();
1204
        }
1205
    }
1206

1207
    final bool isDllMain() const
1208
    {
1209 1
        return ident == Id.DllMain && linkage != LINK.c && !isMember();
1210
    }
1211

1212
    final bool isRtInit() const
1213
    {
1214 1
        return ident == Id.rt_init && linkage == LINK.c && !isMember() && !isNested();
1215
    }
1216

1217
    override final bool isExport() const
1218
    {
1219 1
        return protection.kind == Prot.Kind.export_;
1220
    }
1221

1222
    override final bool isImportedSymbol() const
1223
    {
1224
        //printf("isImportedSymbol()\n");
1225
        //printf("protection = %d\n", protection);
1226 1
        return (protection.kind == Prot.Kind.export_) && !fbody;
1227
    }
1228

1229
    override final bool isCodeseg() const pure nothrow @nogc @safe
1230
    {
1231 1
        return true; // functions are always in the code segment
1232
    }
1233

1234
    override final bool isOverloadable() const
1235
    {
1236 1
        return true; // functions can be overloaded
1237
    }
1238

1239
    /***********************************
1240
     * Override so it can work even if semantic() hasn't yet
1241
     * been run.
1242
     */
1243
    override final bool isAbstract()
1244
    {
1245 1
        if (storage_class & STC.abstract_)
1246 1
            return true;
1247 1
        if (semanticRun >= PASS.semanticdone)
1248 1
            return false;
1249

1250 1
        if (_scope)
1251
        {
1252 1
           if (_scope.stc & STC.abstract_)
1253 0
                return true;
1254 1
           parent = _scope.parent;
1255 1
           Dsymbol parent = toParent();
1256 1
           if (parent.isInterfaceDeclaration())
1257 0
                return true;
1258
        }
1259 1
        return false;
1260
    }
1261

1262
    /**********************************
1263
     * Decide if attributes for this function can be inferred from examining
1264
     * the function body.
1265
     * Returns:
1266
     *  true if can
1267
     */
1268
    final bool canInferAttributes(Scope* sc)
1269
    {
1270 1
        if (!fbody)
1271 1
            return false;
1272

1273 1
        if (isVirtualMethod())
1274 1
            return false;               // since they may be overridden
1275

1276 1
        if (sc.func &&
1277
            /********** this is for backwards compatibility for the moment ********/
1278 1
            (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
1279 1
            return true;
1280

1281 1
        if (isFuncLiteralDeclaration() ||               // externs are not possible with literals
1282 1
            (storage_class & STC.inference) ||           // do attribute inference
1283 1
            (inferRetType && !isCtorDeclaration()))
1284 1
            return true;
1285

1286 1
        if (isInstantiated())
1287
        {
1288 1
            auto ti = parent.isTemplateInstance();
1289 1
            if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
1290 1
                return true;
1291
        }
1292

1293 1
        return false;
1294
    }
1295

1296
    /*****************************************
1297
     * Initialize for inferring the attributes of this function.
1298
     */
1299
    final void initInferAttributes()
1300
    {
1301
        //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1302 1
        TypeFunction tf = type.toTypeFunction();
1303 1
        if (tf.purity == PURE.impure) // purity not specified
1304 1
            flags |= FUNCFLAG.purityInprocess;
1305

1306 1
        if (tf.trust == TRUST.default_)
1307 1
            flags |= FUNCFLAG.safetyInprocess;
1308

1309 1
        if (!tf.isnothrow)
1310 1
            flags |= FUNCFLAG.nothrowInprocess;
1311

1312 1
        if (!tf.isnogc)
1313 1
            flags |= FUNCFLAG.nogcInprocess;
1314

1315 1
        if (!isVirtual() || introducing)
1316 1
            flags |= FUNCFLAG.returnInprocess;
1317

1318
        // Initialize for inferring STC.scope_
1319 1
        if (global.params.vsafe)
1320 1
            flags |= FUNCFLAG.inferScope;
1321
    }
1322

1323
    final PURE isPure()
1324
    {
1325
        //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1326 1
        TypeFunction tf = type.toTypeFunction();
1327 1
        if (flags & FUNCFLAG.purityInprocess)
1328 1
            setImpure();
1329 1
        if (tf.purity == PURE.fwdref)
1330 1
            tf.purityLevel();
1331 1
        PURE purity = tf.purity;
1332 1
        if (purity > PURE.weak && isNested())
1333 1
            purity = PURE.weak;
1334 1
        if (purity > PURE.weak && needThis())
1335
        {
1336
            // The attribute of the 'this' reference affects purity strength
1337 1
            if (type.mod & MODFlags.immutable_)
1338
            {
1339
            }
1340 1
            else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
1341 1
                purity = PURE.const_;
1342
            else
1343 1
                purity = PURE.weak;
1344
        }
1345 1
        tf.purity = purity;
1346
        // ^ This rely on the current situation that every FuncDeclaration has a
1347
        //   unique TypeFunction.
1348 1
        return purity;
1349
    }
1350

1351
    final PURE isPureBypassingInference()
1352
    {
1353 1
        if (flags & FUNCFLAG.purityInprocess)
1354 1
            return PURE.fwdref;
1355
        else
1356 1
            return isPure();
1357
    }
1358

1359
    /**************************************
1360
     * The function is doing something impure,
1361
     * so mark it as impure.
1362
     * If there's a purity error, return true.
1363
     */
1364
    extern (D) final bool setImpure()
1365
    {
1366 1
        if (flags & FUNCFLAG.purityInprocess)
1367
        {
1368 1
            flags &= ~FUNCFLAG.purityInprocess;
1369 1
            if (fes)
1370 1
                fes.func.setImpure();
1371
        }
1372 1
        else if (isPure())
1373 1
            return true;
1374 1
        return false;
1375
    }
1376

1377
    final bool isSafe()
1378
    {
1379 1
        if (flags & FUNCFLAG.safetyInprocess)
1380 1
            setUnsafe();
1381 1
        return type.toTypeFunction().trust == TRUST.safe;
1382
    }
1383

1384
    final bool isSafeBypassingInference()
1385
    {
1386 1
        return !(flags & FUNCFLAG.safetyInprocess) && isSafe();
1387
    }
1388

1389
    final bool isTrusted()
1390
    {
1391 1
        if (flags & FUNCFLAG.safetyInprocess)
1392 0
            setUnsafe();
1393 1
        return type.toTypeFunction().trust == TRUST.trusted;
1394
    }
1395

1396
    /**************************************
1397
     * The function is doing something unsafe,
1398
     * so mark it as unsafe.
1399
     * If there's a safe error, return true.
1400
     */
1401
    extern (D) final bool setUnsafe()
1402
    {
1403 1
        if (flags & FUNCFLAG.safetyInprocess)
1404
        {
1405 1
            flags &= ~FUNCFLAG.safetyInprocess;
1406 1
            type.toTypeFunction().trust = TRUST.system;
1407 1
            if (fes)
1408 1
                fes.func.setUnsafe();
1409
        }
1410 1
        else if (isSafe())
1411 1
            return true;
1412 1
        return false;
1413
    }
1414

1415
    final bool isNogc()
1416
    {
1417
        //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1418 1
        if (flags & FUNCFLAG.nogcInprocess)
1419 1
            setGC();
1420 1
        return type.toTypeFunction().isnogc;
1421
    }
1422

1423
    final bool isNogcBypassingInference()
1424
    {
1425 1
        return !(flags & FUNCFLAG.nogcInprocess) && isNogc();
1426
    }
1427

1428
    /**************************************
1429
     * The function is doing something that may allocate with the GC,
1430
     * so mark it as not nogc (not no-how).
1431
     * Returns:
1432
     *      true if function is marked as @nogc, meaning a user error occurred
1433
     */
1434
    extern (D) final bool setGC()
1435
    {
1436
        //printf("setGC() %s\n", toChars());
1437 1
        if (flags & FUNCFLAG.nogcInprocess && semanticRun < PASS.semantic3 && _scope)
1438
        {
1439 1
            this.semantic2(_scope);
1440 1
            this.semantic3(_scope);
1441
        }
1442

1443 1
        if (flags & FUNCFLAG.nogcInprocess)
1444
        {
1445 1
            flags &= ~FUNCFLAG.nogcInprocess;
1446 1
            type.toTypeFunction().isnogc = false;
1447 1
            if (fes)
1448 1
                fes.func.setGC();
1449
        }
1450 1
        else if (isNogc())
1451 1
            return true;
1452 1
        return false;
1453
    }
1454

1455
    extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
1456
    {
1457 1
        if (!global.params.vgc)
1458 1
            return;
1459

1460 1
        Module m = getModule();
1461 1
        if (m && m.isRoot() && !inUnittest())
1462
        {
1463 1
            message(loc, "vgc: %s", warn);
1464
        }
1465
    }
1466

1467
    /********************************************
1468
     * See if pointers from function parameters, mutable globals, or uplevel functions
1469
     * could leak into return value.
1470
     * Returns:
1471
     *   true if the function return value is isolated from
1472
     *   any inputs to the function
1473
     */
1474
    extern (D) final bool isReturnIsolated()
1475
    {
1476
        //printf("isReturnIsolated(this: %s)\n", this.toChars);
1477 1
        TypeFunction tf = type.toTypeFunction();
1478 1
        assert(tf.next);
1479

1480 1
        Type treti = tf.next;
1481 1
        if (tf.isref)
1482 1
            return isTypeIsolatedIndirect(treti);              // check influence from parameters
1483

1484 1
        return isTypeIsolated(treti);
1485
    }
1486

1487
    /********************
1488
     * See if pointers from function parameters, mutable globals, or uplevel functions
1489
     * could leak into type `t`.
1490
     * Params:
1491
     *   t = type to check if it is isolated
1492
     * Returns:
1493
     *   true if `t` is isolated from
1494
     *   any inputs to the function
1495
     */
1496
    extern (D) final bool isTypeIsolated(Type t)
1497
    {
1498 1
        StringTable!Type parentTypes;
1499 1
        parentTypes._init();
1500 1
        return isTypeIsolated(t, parentTypes);
1501
    }
1502

1503
    ///ditto
1504
    extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
1505
    {
1506
        //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
1507

1508 1
        t = t.baseElemOf();
1509 1
        switch (t.ty)
1510
        {
1511 1
            case Tarray:
1512 1
            case Tpointer:
1513 1
                return isTypeIsolatedIndirect(t.nextOf()); // go down one level
1514

1515 0
            case Taarray:
1516 1
            case Tclass:
1517 1
                return isTypeIsolatedIndirect(t);
1518

1519 1
            case Tstruct:
1520
                /* Drill down and check the struct's fields
1521
                 */
1522 1
                auto sym = t.toDsymbol(null).isStructDeclaration();
1523 1
                const tName = t.toChars.toDString;
1524 1
                const entry = parentTypes.insert(tName, t);
1525 1
                if (entry == null)
1526
                {
1527
                    //we've already seen this type in a parent, not isolated
1528 1
                    return false;
1529
                }
1530 1
                foreach (v; sym.fields)
1531
                {
1532 1
                    Type tmi = v.type.addMod(t.mod);
1533
                    //printf("\tt = %s, v: %s, vtype: %s,  tmi = %s\n",
1534
                    //       t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
1535 1
                    if (!isTypeIsolated(tmi, parentTypes))
1536 1
                        return false;
1537
                }
1538 1
                return true;
1539

1540 1
            default:
1541 1
                return true;
1542
        }
1543
    }
1544

1545
    /********************************************
1546
     * Params:
1547
     *    t = type of object to test one level of indirection down
1548
     * Returns:
1549
     *    true if an object typed `t` has no indirections
1550
     *    which could have come from the function's parameters, mutable
1551
     *    globals, or uplevel functions.
1552
     */
1553
    private bool isTypeIsolatedIndirect(Type t)
1554
    {
1555
        //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1556 1
        assert(t);
1557

1558
        /* Since `t` is one level down from an indirection, it could pick
1559
         * up a reference to a mutable global or an outer function, so
1560
         * return false.
1561
         */
1562 1
        if (!isPureBypassingInference() || isNested())
1563 1
            return false;
1564

1565 1
        TypeFunction tf = type.toTypeFunction();
1566

1567
        //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1568

1569 1
        foreach (i, fparam; tf.parameterList)
1570
        {
1571 1
            Type tp = fparam.type;
1572 1
            if (!tp)
1573
                continue;
1574

1575 1
            if (fparam.storageClass & (STC.lazy_ | STC.out_ | STC.ref_))
1576
            {
1577 1
                if (!traverseIndirections(tp, t))
1578 1
                    return false;
1579
                continue;
1580
            }
1581

1582
            /* Goes down one level of indirection, then calls traverseIndirection() on
1583
             * the result.
1584
             * Returns:
1585
             *  true if t is isolated from tp
1586
             */
1587
            static bool traverse(Type tp, Type t)
1588
            {
1589 1
                tp = tp.baseElemOf();
1590 1
                switch (tp.ty)
1591
                {
1592 1
                    case Tarray:
1593 1
                    case Tpointer:
1594 1
                        return traverseIndirections(tp.nextOf(), t);
1595

1596 0
                    case Taarray:
1597 1
                    case Tclass:
1598 1
                        return traverseIndirections(tp, t);
1599

1600 1
                    case Tstruct:
1601
                        /* Drill down and check the struct's fields
1602
                         */
1603 1
                        auto sym = tp.toDsymbol(null).isStructDeclaration();
1604 1
                        foreach (v; sym.fields)
1605
                        {
1606 1
                            Type tprmi = v.type.addMod(tp.mod);
1607
                            //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1608 1
                            if (!traverse(tprmi, t))
1609 1
                                return false;
1610
                        }
1611 1
                        return true;
1612

1613 1
                    default:
1614 1
                        return true;
1615
                }
1616
            }
1617

1618 1
            if (!traverse(tp, t))
1619 1
                return false;
1620
        }
1621
        // The 'this' reference is a parameter, too
1622 1
        if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
1623
        {
1624 1
            Type tthis = ad.getType().addMod(tf.mod);
1625
            //printf("\ttthis = %s\n", tthis.toChars());
1626 1
            if (!traverseIndirections(tthis, t))
1627 1
                return false;
1628
        }
1629

1630 1
        return true;
1631
    }
1632

1633
    /****************************************
1634
     * Determine if function needs a static frame pointer.
1635
     * Returns:
1636
     *  `true` if function is really nested within other function.
1637
     * Contracts:
1638
     *  If isNested() returns true, isThis() should return false,
1639
     *  unless the function needs a dual-context pointer.
1640
     */
1641
    bool isNested() const
1642
    {
1643 1
        auto f = toAliasFunc();
1644
        //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1645 1
        return ((f.storage_class & STC.static_) == 0) &&
1646 1
                (f.linkage == LINK.d) &&
1647 1
                (f.toParent2().isFuncDeclaration() !is null ||
1648 1
                 f.toParent2() !is f.toParentLocal());
1649
    }
1650

1651
    /****************************************
1652
     * Determine if function is a non-static member function
1653
     * that has an implicit 'this' expression.
1654
     * Returns:
1655
     *  The aggregate it is a member of, or null.
1656
     * Contracts:
1657
     *  Both isThis() and isNested() should return true if function needs a dual-context pointer,
1658
     *  otherwise if isThis() returns true, isNested() should return false.
1659
     */
1660
    override inout(AggregateDeclaration) isThis() inout
1661
    {
1662
        //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1663 1
        auto ad = (storage_class & STC.static_) ? objc.isThis(this) : isMemberLocal();
1664
        //printf("-FuncDeclaration::isThis() %p\n", ad);
1665 1
        return ad;
1666
    }
1667

1668
    override final bool needThis()
1669
    {
1670
        //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1671 1
        return toAliasFunc().isThis() !is null;
1672
    }
1673

1674
    // Determine if a function is pedantically virtual
1675
    final bool isVirtualMethod()
1676
    {
1677 1
        if (toAliasFunc() != this)
1678 1
            return toAliasFunc().isVirtualMethod();
1679

1680
        //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1681 1
        if (!isVirtual())
1682 1
            return false;
1683
        // If it's a final method, and does not override anything, then it is not virtual
1684 1
        if (isFinalFunc() && foverrides.dim == 0)
1685
        {
1686 1
            return false;
1687
        }
1688 1
        return true;
1689
    }
1690

1691
    // Determine if function goes into virtual function pointer table
1692
    bool isVirtual() const
1693
    {
1694 1
        if (toAliasFunc() != this)
1695 1
            return toAliasFunc().isVirtual();
1696

1697 1
        auto p = toParent();
1698

1699 1
        if (!isMember || !p.isClassDeclaration)
1700 1
            return false;
1701
                                                             // https://issues.dlang.org/show_bug.cgi?id=19654
1702 1
        if (p.isClassDeclaration.classKind == ClassKind.objc && !p.isInterfaceDeclaration)
1703 0
            return objc.isVirtual(this);
1704

1705
        version (none)
1706
        {
1707
            printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1708
            printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == Prot.Kind.private_, isCtorDeclaration(), linkage != LINK.d);
1709
            printf("result is %d\n", isMember() && !(isStatic() || protection == Prot.Kind.private_ || protection == Prot.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()));
1710
        }
1711 1
        return !(isStatic() || protection.kind == Prot.Kind.private_ || protection.kind == Prot.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc());
1712
    }
1713

1714
    final bool isFinalFunc() const
1715
    {
1716 1
        if (toAliasFunc() != this)
1717 1
            return toAliasFunc().isFinalFunc();
1718

1719
        version (none)
1720
        {{
1721
            auto cd = toParent().isClassDeclaration();
1722
            printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal());
1723
            printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_));
1724
            printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_)));
1725
            if (cd)
1726
                printf("\tmember of %s\n", cd.toChars());
1727
        }}
1728 1
        if (!isMember())
1729 0
            return false;
1730 1
        if (Declaration.isFinal())
1731 1
            return true;
1732 1
        auto cd = toParent().isClassDeclaration();
1733 1
        return (cd !is null) && (cd.storage_class & STC.final_);
1734
    }
1735

1736
    bool addPreInvariant()
1737
    {
1738 1
        auto ad = isThis();
1739 1
        ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1740 1
        return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (protection.kind == Prot.Kind.protected_ || protection.kind == Prot.Kind.public_ || protection.kind == Prot.Kind.export_) && !naked);
1741
    }
1742

1743
    bool addPostInvariant()
1744
    {
1745 1
        auto ad = isThis();
1746 1
        ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1747 1
        return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (protection.kind == Prot.Kind.protected_ || protection.kind == Prot.Kind.public_ || protection.kind == Prot.Kind.export_) && !naked);
1748
    }
1749

1750
    override const(char)* kind() const
1751
    {
1752 1
        return generated ? "generated function" : "function";
1753
    }
1754

1755
    /********************************************
1756
     * Returns:
1757
     *  true if there are no overloads of this function
1758
     */
1759
    final bool isUnique() const
1760
    {
1761 1
        bool result = false;
1762 1
        overloadApply(cast() this, (Dsymbol s)
1763
        {
1764 1
            auto f = s.isFuncDeclaration();
1765 1
            if (!f)
1766 1
                return 0;
1767 1
            if (result)
1768
            {
1769 1
                result = false;
1770 1
                return 1; // ambiguous, done
1771
            }
1772
            else
1773
            {
1774 1
                result = true;
1775 1
                return 0;
1776
            }
1777
        });
1778 1
        return result;
1779
    }
1780

1781
    /*********************************************
1782
     * In the current function, we are calling 'this' function.
1783
     * 1. Check to see if the current function can call 'this' function, issue error if not.
1784
     * 2. If the current function is not the parent of 'this' function, then add
1785
     *    the current function to the list of siblings of 'this' function.
1786
     * 3. If the current function is a literal, and it's accessing an uplevel scope,
1787
     *    then mark it as a delegate.
1788
     * Returns true if error occurs.
1789
     */
1790
    extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
1791
    {
1792
        //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
1793

1794 1
        if (auto fld = this.isFuncLiteralDeclaration())
1795
        {
1796 1
            if (fld.tok == TOK.reserved)
1797
            {
1798 1
                fld.tok = TOK.function_;
1799 1
                fld.vthis = null;
1800
            }
1801
        }
1802

1803 1
        if (!parent || parent == sc.parent)
1804 1
            return false;
1805 1
        if (ident == Id.require || ident == Id.ensure)
1806 1
            return false;
1807 1
        if (!isThis() && !isNested())
1808 1
            return false;
1809

1810
        // The current function
1811 1
        FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
1812 1
        if (!fdthis)
1813 1
            return false; // out of function scope
1814

1815 1
        Dsymbol p = toParentLocal();
1816 1
        Dsymbol p2 = toParent2();
1817

1818
        // Function literals from fdthis to p must be delegates
1819 1
        ensureStaticLinkTo(fdthis, p);
1820 1
        if (p != p2)
1821 1
            ensureStaticLinkTo(fdthis, p2);
1822

1823 1
        if (isNested())
1824
        {
1825
            // The function that this function is in
1826
            bool checkEnclosing(FuncDeclaration fdv)
1827
            {
1828 1
                if (!fdv)
1829 1
                    return false;
1830 1
                if (fdv == fdthis)
1831 1
                    return false;
1832

1833
                //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
1834
                //printf("fdv  = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
1835
                //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
1836

1837
                // Add this function to the list of those which called us
1838 1
                if (fdthis != this)
1839
                {
1840 1
                    bool found = false;
1841 1
                    for (size_t i = 0; i < siblingCallers.dim; ++i)
1842
                    {
1843 1
                        if (siblingCallers[i] == fdthis)
1844 1
                            found = true;
1845
                    }
1846 1
                    if (!found)
1847
                    {
1848
                        //printf("\tadding sibling %s\n", fdthis.toPrettyChars());
1849 1
                        if (!sc.intypeof && !(sc.flags & SCOPE.compile))
1850 1
                            siblingCallers.push(fdthis);
1851
                    }
1852
                }
1853

1854 1
                const lv = fdthis.getLevelAndCheck(loc, sc, fdv);
1855 1
                if (lv == LevelError)
1856 1
                    return true; // error
1857 1
                if (lv == -1)
1858 0
                    return false; // downlevel call
1859 1
                if (lv == 0)
1860 1
                    return false; // same level call
1861

1862 1
                return false; // Uplevel call
1863
            }
1864

1865 1
            if (checkEnclosing(p.isFuncDeclaration()))
1866 1
                return true;
1867 1
            if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
1868 0
                return true;
1869
        }
1870 1
        return false;
1871
    }
1872

1873
    /*******************************
1874
     * Look at all the variables in this function that are referenced
1875
     * by nested functions, and determine if a closure needs to be
1876
     * created for them.
1877
     */
1878
    final bool needsClosure()
1879
    {
1880
        /* Need a closure for all the closureVars[] if any of the
1881
         * closureVars[] are accessed by a
1882
         * function that escapes the scope of this function.
1883
         * We take the conservative approach and decide that a function needs
1884
         * a closure if it:
1885
         * 1) is a virtual function
1886
         * 2) has its address taken
1887
         * 3) has a parent that escapes
1888
         * 4) calls another nested function that needs a closure
1889
         *
1890
         * Note that since a non-virtual function can be called by
1891
         * a virtual one, if that non-virtual function accesses a closure
1892
         * var, the closure still has to be taken. Hence, we check for isThis()
1893
         * instead of isVirtual(). (thanks to David Friedman)
1894
         *
1895
         * When the function returns a local struct or class, `requiresClosure`
1896
         * is already set to `true` upon entering this function when the
1897
         * struct/class refers to a local variable and a closure is needed.
1898
         */
1899

1900
        //printf("FuncDeclaration::needsClosure() %s\n", toChars());
1901

1902 1
        if (requiresClosure)
1903 1
            goto Lyes;
1904

1905 1
        for (size_t i = 0; i < closureVars.dim; i++)
1906
        {
1907 1
            VarDeclaration v = closureVars[i];
1908
            //printf("\tv = %s\n", v.toChars());
1909

1910 1
            for (size_t j = 0; j < v.nestedrefs.dim; j++)
1911
            {
1912 1
                FuncDeclaration f = v.nestedrefs[j];
1913 1
                assert(f != this);
1914

1915
                /* __require and __ensure will always get called directly,
1916
                 * so they never make outer functions closure.
1917
                 */
1918 1
                if (f.ident == Id.require || f.ident == Id.ensure)
1919 1
                    continue;
1920

1921
                //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
1922

1923
                /* Look to see if f escapes. We consider all parents of f within
1924
                 * this, and also all siblings which call f; if any of them escape,
1925
                 * so does f.
1926
                 * Mark all affected functions as requiring closures.
1927
                 */
1928 1
                for (Dsymbol s = f; s && s != this; s = s.toParentP(this))
1929
                {
1930 1
                    FuncDeclaration fx = s.isFuncDeclaration();
1931 1
                    if (!fx)
1932 1
                        continue;
1933 1
                    if (fx.isThis() || fx.tookAddressOf)
1934
                    {
1935
                        //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
1936

1937
                        /* Mark as needing closure any functions between this and f
1938
                         */
1939 1
                        markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this);
1940

1941 1
                        requiresClosure = true;
1942
                    }
1943

1944
                    /* We also need to check if any sibling functions that
1945
                     * called us, have escaped. This is recursive: we need
1946
                     * to check the callers of our siblings.
1947
                     */
1948 1
                    if (checkEscapingSiblings(fx, this))
1949 1
                        requiresClosure = true;
1950

1951
                    /* https://issues.dlang.org/show_bug.cgi?id=12406
1952
                     * Iterate all closureVars to mark all descendant
1953
                     * nested functions that access to the closing context of this function.
1954
                     */
1955
                }
1956
            }
1957
        }
1958 1
        if (requiresClosure)
1959 1
            goto Lyes;
1960

1961 1
        return false;
1962

1963
    Lyes:
1964
        //printf("\tneeds closure\n");
1965 1
        return true;
1966
    }
1967

1968
    /***********************************************
1969
     * Check that the function contains any closure.
1970
     * If it's @nogc, report suitable errors.
1971
     * This is mostly consistent with FuncDeclaration::needsClosure().
1972
     *
1973
     * Returns:
1974
     *      true if any errors occur.
1975
     */
1976
    extern (D) final bool checkClosure()
1977
    {
1978 1
        if (!needsClosure())
1979 1
            return false;
1980

1981 1
        if (setGC())
1982
        {
1983 1
            error("is `@nogc` yet allocates closures with the GC");
1984 1
            if (global.gag)     // need not report supplemental errors
1985 0
                return true;
1986
        }
1987
        else
1988
        {
1989 1
            printGCUsage(loc, "using closure causes GC allocation");
1990 1
            return false;
1991
        }
1992

1993 1
        FuncDeclarations a;
1994 1
        foreach (v; closureVars)
1995
        {
1996 1
            foreach (f; v.nestedrefs)
1997
            {
1998 1
                assert(f !is this);
1999

2000
            LcheckAncestorsOfANestedRef:
2001 1
                for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
2002
                {
2003 1
                    auto fx = s.isFuncDeclaration();
2004 1
                    if (!fx)
2005 0
                        continue;
2006 1
                    if (fx.isThis() ||
2007 1
                        fx.tookAddressOf ||
2008 0
                        checkEscapingSiblings(fx, this))
2009
                    {
2010 1
                        foreach (f2; a)
2011
                        {
2012 1
                            if (f2 == f)
2013 0
                                break LcheckAncestorsOfANestedRef;
2014
                        }
2015 1
                        a.push(f);
2016 1
                        .errorSupplemental(f.loc, "%s closes over variable %s at %s",
2017
                            f.toPrettyChars(), v.toChars(), v.loc.toChars());
2018 1
                        break LcheckAncestorsOfANestedRef;
2019
                    }
2020
                }
2021
            }
2022
        }
2023

2024 1
        return true;
2025
    }
2026

2027
    /***********************************************
2028
     * Determine if function's variables are referenced by a function
2029
     * nested within it.
2030
     */
2031
    final bool hasNestedFrameRefs()
2032
    {
2033 1
        if (closureVars.dim)
2034 1
            return true;
2035

2036
        /* If a virtual function has contracts, assume its variables are referenced
2037
         * by those contracts, even if they aren't. Because they might be referenced
2038
         * by the overridden or overriding function's contracts.
2039
         * This can happen because frequire and fensure are implemented as nested functions,
2040
         * and they can be called directly by an overriding function and the overriding function's
2041
         * context had better match, or
2042
         * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
2043
         */
2044 1
        if (fdrequire || fdensure)
2045 1
            return true;
2046

2047 1
        if (foverrides.dim && isVirtualMethod())
2048
        {
2049 1
            for (size_t i = 0; i < foverrides.dim; i++)
2050
            {
2051 1
                FuncDeclaration fdv = foverrides[i];
2052 1
                if (fdv.hasNestedFrameRefs())
2053 1
                    return true;
2054
            }
2055
        }
2056 1
        return false;
2057
    }
2058

2059
    /****************************************************
2060
     * Check whether result variable can be built.
2061
     * Returns:
2062
     *     `true` if the function has a return type that
2063
     *     is different from `void`.
2064
     */
2065
    extern (D) private bool canBuildResultVar()
2066
    {
2067 1
        auto f = cast(TypeFunction)type;
2068 1
        return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
2069
    }
2070

2071
    /****************************************************
2072
     * Declare result variable lazily.
2073
     */
2074
    extern (D) final void buildResultVar(Scope* sc, Type tret)
2075
    {
2076 1
        if (!vresult)
2077
        {
2078 1
            Loc loc = fensure ? fensure.loc : this.loc;
2079

2080
            /* If inferRetType is true, tret may not be a correct return type yet.
2081
             * So, in here it may be a temporary type for vresult, and after
2082
             * fbody.dsymbolSemantic() running, vresult.type might be modified.
2083
             */
2084 1
            vresult = new VarDeclaration(loc, tret, Id.result, null);
2085 1
            vresult.storage_class |= STC.nodtor | STC.temp;
2086 1
            if (!isVirtual())
2087 1
                vresult.storage_class |= STC.const_;
2088 1
            vresult.storage_class |= STC.result;
2089

2090
            // set before the semantic() for checkNestedReference()
2091 1
            vresult.parent = this;
2092
        }
2093

2094 1
        if (sc && vresult.semanticRun == PASS.init)
2095
        {
2096 1
            TypeFunction tf = type.toTypeFunction();
2097 1
            if (tf.isref)
2098 1
                vresult.storage_class |= STC.ref_;
2099 1
            vresult.type = tret;
2100

2101 1
            vresult.dsymbolSemantic(sc);
2102

2103 1
            if (!sc.insert(vresult))
2104 0
                error("out result %s is already defined", vresult.toChars());
2105 1
            assert(vresult.parent == this);
2106
        }
2107
    }
2108

2109
    /****************************************************
2110
     * Merge into this function the 'in' contracts of all it overrides.
2111
     * 'in's are OR'd together, i.e. only one of them needs to pass.
2112
     */
2113
    extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
2114
    {
2115
        /* If a base function and its override both have an IN contract, then
2116
         * only one of them needs to succeed. This is done by generating:
2117
         *
2118
         * void derived.in() {
2119
         *  try {
2120
         *    base.in();
2121
         *  }
2122
         *  catch () {
2123
         *    ... body of derived.in() ...
2124
         *  }
2125
         * }
2126
         *
2127
         * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2128
         * If base.in() throws, then derived.in()'s body is executed.
2129
         */
2130

2131 1
        foreach (fdv; foverrides)
2132
        {
2133
            /* The semantic pass on the contracts of the overridden functions must
2134
             * be completed before code generation occurs.
2135
             * https://issues.dlang.org/show_bug.cgi?id=3602
2136
             */
2137 1
            if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2138
            {
2139 1
                assert(fdv._scope);
2140 1
                Scope* sc = fdv._scope.push();
2141 1
                sc.stc &= ~STC.override_;
2142 1
                fdv.semantic3(sc);
2143 1
                sc.pop();
2144
            }
2145

2146 1
            sf = fdv.mergeFrequire(sf, params);
2147 1
            if (sf && fdv.fdrequire)
2148
            {
2149
                //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2150
                /* Make the call:
2151
                 *   try { __require(params); }
2152
                 *   catch (Throwable) { frequire; }
2153
                 */
2154 1
                params = Expression.arraySyntaxCopy(params);
2155 1
                Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2156 1
                Statement s2 = new ExpStatement(loc, e);
2157

2158 1
                auto c = new Catch(loc, getThrowable(), null, sf);
2159 1
                c.internalCatch = true;
2160 1
                auto catches = new Catches();
2161 1
                catches.push(c);
2162 1
                sf = new TryCatchStatement(loc, s2, catches);
2163
            }
2164
            else
2165 1
                return null;
2166
        }
2167 1
        return sf;
2168
    }
2169

2170
    /****************************************************
2171
     * Determine whether an 'out' contract is declared inside
2172
     * the given function or any of its overrides.
2173
     * Params:
2174
     *      fd = the function to search
2175
     * Returns:
2176
     *      true    found an 'out' contract
2177
     */
2178
    static bool needsFensure(FuncDeclaration fd)
2179
    {
2180 1
        if (fd.fensures)
2181 1
            return true;
2182

2183 1
        foreach (fdv; fd.foverrides)
2184
        {
2185 1
            if (needsFensure(fdv))
2186 1
                return true;
2187
        }
2188 1
        return false;
2189
    }
2190

2191
    /****************************************************
2192
     * Rewrite contracts as statements.
2193
     */
2194
    final void buildEnsureRequire()
2195
    {
2196

2197 1
        if (frequires)
2198
        {
2199
            /*   in { statements1... }
2200
             *   in { statements2... }
2201
             *   ...
2202
             * becomes:
2203
             *   in { { statements1... } { statements2... } ... }
2204
             */
2205 1
            assert(frequires.dim);
2206 1
            auto loc = (*frequires)[0].loc;
2207 1
            auto s = new Statements;
2208 1
            foreach (r; *frequires)
2209
            {
2210 1
                s.push(new ScopeStatement(r.loc, r, r.loc));
2211
            }
2212 1
            frequire = new CompoundStatement(loc, s);
2213
        }
2214

2215 1
        if (fensures)
2216
        {
2217
            /*   out(id1) { statements1... }
2218
             *   out(id2) { statements2... }
2219
             *   ...
2220
             * becomes:
2221
             *   out(__result) { { ref id1 = __result; { statements1... } }
2222
             *                   { ref id2 = __result; { statements2... } } ... }
2223
             */
2224 1
            assert(fensures.dim);
2225 1
            auto loc = (*fensures)[0].ensure.loc;
2226 1
            auto s = new Statements;
2227 1
            foreach (r; *fensures)
2228
            {
2229 1
                if (r.id && canBuildResultVar())
2230
                {
2231 1
                    auto rloc = r.ensure.loc;
2232 1
                    auto resultId = new IdentifierExp(rloc, Id.result);
2233 1
                    auto init = new ExpInitializer(rloc, resultId);
2234 1
                    auto stc = STC.ref_ | STC.temp | STC.result;
2235 1
                    auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
2236 1
                    auto sdecl = new ExpStatement(rloc, decl);
2237 1
                    s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
2238
                }
2239
                else
2240
                {
2241 1
                    s.push(r.ensure);
2242
                }
2243
            }
2244 1
            fensure = new CompoundStatement(loc, s);
2245
        }
2246

2247 1
        if (!isVirtual())
2248 1
            return;
2249

2250
        /* Rewrite contracts as nested functions, then call them. Doing it as nested
2251
         * functions means that overriding functions can call them.
2252
         */
2253 1
        TypeFunction f = cast(TypeFunction) type;
2254

2255
        /* Make a copy of the parameters and make them all ref */
2256
        static Parameters* toRefCopy(ParameterList parameterList)
2257
        {
2258 1
            auto result = new Parameters();
2259

2260 1
            foreach (n, p; parameterList)
2261
            {
2262 1
                p = p.syntaxCopy();
2263 1
                if (!(p.storageClass & STC.lazy_))
2264 1
                    p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
2265 1
                p.defaultArg = null; // won't be the same with ref
2266 1
                result.push(p);
2267
            }
2268

2269 1
            return result;
2270
        }
2271

2272 1
        if (frequire)
2273
        {
2274
            /*   in { ... }
2275
             * becomes:
2276
             *   void __require(ref params) { ... }
2277
             *   __require(params);
2278
             */
2279 1
            Loc loc = frequire.loc;
2280 1
            fdrequireParams = new Expressions();
2281 1
            if (parameters)
2282
            {
2283 1
                foreach (vd; *parameters)
2284 1
                    fdrequireParams.push(new VarExp(loc, vd));
2285
            }
2286 1
            auto fo = cast(TypeFunction)(originalType ? originalType : f);
2287 1
            auto fparams = toRefCopy(fo.parameterList);
2288 1
            auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2289 1
            tf.isnothrow = f.isnothrow;
2290 1
            tf.isnogc = f.isnogc;
2291 1
            tf.purity = f.purity;
2292 1
            tf.trust = f.trust;
2293 1
            auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
2294 1
            fd.fbody = frequire;
2295 1
            Statement s1 = new ExpStatement(loc, fd);
2296 1
            Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
2297 1
            Statement s2 = new ExpStatement(loc, e);
2298 1
            frequire = new CompoundStatement(loc, s1, s2);
2299 1
            fdrequire = fd;
2300
        }
2301

2302
        /* We need to set fdensureParams here and not in the block below to
2303
         * have the parameters available when calling a base class ensure(),
2304
         * even if this function doesn't have an out contract.
2305
         */
2306 1
        fdensureParams = new Expressions();
2307 1
        if (canBuildResultVar())
2308 1
            fdensureParams.push(new IdentifierExp(loc, Id.result));
2309 1
        if (parameters)
2310
        {
2311 1
            foreach (vd; *parameters)
2312 1
                fdensureParams.push(new VarExp(loc, vd));
2313
        }
2314

2315 1
        if (fensure)
2316
        {
2317
            /*   out (result) { ... }
2318
             * becomes:
2319
             *   void __ensure(ref tret result, ref params) { ... }
2320
             *   __ensure(result, params);
2321
             */
2322 1
            Loc loc = fensure.loc;
2323 1
            auto fparams = new Parameters();
2324 1
            if (canBuildResultVar())
2325
            {
2326 1
                Parameter p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
2327 1
                fparams.push(p);
2328
            }
2329 1
            auto fo = cast(TypeFunction)(originalType ? originalType : f);
2330 1
            fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
2331 1
            auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2332 1
            tf.isnothrow = f.isnothrow;
2333 1
            tf.isnogc = f.isnogc;
2334 1
            tf.purity = f.purity;
2335 1
            tf.trust = f.trust;
2336 1
            auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
2337 1
            fd.fbody = fensure;
2338 1
            Statement s1 = new ExpStatement(loc, fd);
2339 1
            Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
2340 1
            Statement s2 = new ExpStatement(loc, e);
2341 1
            fensure = new CompoundStatement(loc, s1, s2);
2342 1
            fdensure = fd;
2343
        }
2344
    }
2345

2346
    /****************************************************
2347
     * Merge into this function the 'out' contracts of all it overrides.
2348
     * 'out's are AND'd together, i.e. all of them need to pass.
2349
     */
2350
    extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
2351
    {
2352
        /* Same comments as for mergeFrequire(), except that we take care
2353
         * of generating a consistent reference to the 'result' local by
2354
         * explicitly passing 'result' to the nested function as a reference
2355
         * argument.
2356
         * This won't work for the 'this' parameter as it would require changing
2357
         * the semantic code for the nested function so that it looks on the parameter
2358
         * list for the 'this' pointer, something that would need an unknown amount
2359
         * of tweaking of various parts of the compiler that I'd rather leave alone.
2360
         */
2361 1
        foreach (fdv; foverrides)
2362
        {
2363
            /* The semantic pass on the contracts of the overridden functions must
2364
             * be completed before code generation occurs.
2365
             * https://issues.dlang.org/show_bug.cgi?id=3602 and
2366
             * https://issues.dlang.org/show_bug.cgi?id=5230
2367
             */
2368 1
            if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
2369
            {
2370 1
                assert(fdv._scope);
2371 1
                Scope* sc = fdv._scope.push();
2372 1
                sc.stc &= ~STC.override_;
2373 1
                fdv.semantic3(sc);
2374 1
                sc.pop();
2375
            }
2376

2377 1
            sf = fdv.mergeFensure(sf, oid, params);
2378 1
            if (fdv.fdensure)
2379
            {
2380
                //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2381
                // Make the call: __ensure(result, params)
2382 1
                params = Expression.arraySyntaxCopy(params);
2383 1
                if (canBuildResultVar())
2384
                {
2385 1
                    Type t1 = fdv.type.nextOf().toBasetype();
2386 1
                    Type t2 = this.type.nextOf().toBasetype();
2387 1
                    if (t1.isBaseOf(t2, null))
2388
                    {
2389
                        /* Making temporary reference variable is necessary
2390
                         * in covariant return.
2391
                         * https://issues.dlang.org/show_bug.cgi?id=5204
2392
                         * https://issues.dlang.org/show_bug.cgi?id=10479
2393
                         */
2394 1
                        Expression* eresult = &(*params)[0];
2395 1
                        auto ei = new ExpInitializer(Loc.initial, *eresult);
2396 1
                        auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
2397 1
                        v.storage_class |= STC.temp;
2398 1
                        auto de = new DeclarationExp(Loc.initial, v);
2399 1
                        auto ve = new VarExp(Loc.initial, v);
2400 1
                        *eresult = new CommaExp(Loc.initial, de, ve);
2401
                    }
2402
                }
2403 1
                Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
2404 1
                Statement s2 = new ExpStatement(loc, e);
2405

2406 1
                if (sf)
2407
                {
2408 1
                    sf = new CompoundStatement(sf.loc, s2, sf);
2409
                }
2410
                else
2411 1
                    sf = s2;
2412
            }
2413
        }
2414 1
        return sf;
2415
    }
2416

2417
    /*********************************************
2418
     * Returns: the function's parameter list, and whether
2419
     * it is variadic or not.
2420
     */
2421
    final ParameterList getParameterList()
2422
    {
2423 1
        if (type)
2424
        {
2425 1
            TypeFunction fdtype = type.isTypeFunction();
2426 1
            return fdtype.parameterList;
2427
        }
2428

2429 0
        return ParameterList(null, VarArg.none);
2430
    }
2431

2432
    /**********************************
2433
     * Generate a FuncDeclaration for a runtime library function.
2434
     */
2435
    static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
2436
    {
2437 1
        return genCfunc(fparams, treturn, Identifier.idPool(name, cast(uint)strlen(name)), stc);
2438
    }
2439

2440
    static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
2441
    {
2442 1
        FuncDeclaration fd;
2443 1
        TypeFunction tf;
2444 1
        Dsymbol s;
2445 1
        __gshared DsymbolTable st = null;
2446

2447
        //printf("genCfunc(name = '%s')\n", id.toChars());
2448
        //printf("treturn\n\t"); treturn.print();
2449

2450
        // See if already in table
2451 1
        if (!st)
2452 1
            st = new DsymbolTable();
2453 1
        s = st.lookup(id);
2454 1
        if (s)
2455
        {
2456 1
            fd = s.isFuncDeclaration();
2457 1
            assert(fd);
2458 1
            assert(fd.type.nextOf().equals(treturn));
2459
        }
2460
        else
2461
        {
2462 1
            tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc);
2463 1
            fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf);
2464 1
            fd.protection = Prot(Prot.Kind.public_);
2465 1
            fd.linkage = LINK.c;
2466

2467 1
            st.insert(fd);
2468
        }
2469 1
        return fd;
2470
    }
2471

2472
    /******************
2473
     * Check parameters and return type of D main() function.
2474
     * Issue error messages.
2475
     */
2476
    extern (D) final void checkDmain()
2477
    {
2478 1
        TypeFunction tf = type.toTypeFunction();
2479 1
        const nparams = tf.parameterList.length;
2480 1
        bool argerr;
2481 1
        if (nparams == 1)
2482
        {
2483 1
            auto fparam0 = tf.parameterList[0];
2484 1
            auto t = fparam0.type.toBasetype();
2485 1
            if (t.ty != Tarray ||
2486 1
                t.nextOf().ty != Tarray ||
2487 1
                t.nextOf().nextOf().ty != Tchar ||
2488 1
                fparam0.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
2489
            {
2490 1
                argerr = true;
2491
            }
2492
        }
2493

2494 1
        if (!tf.nextOf())
2495 1
            error("must return `int` or `void`");
2496 1
        else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid)
2497 0
            error("must return `int` or `void`, not `%s`", tf.nextOf().toChars());
2498 1
        else if (tf.parameterList.varargs || nparams >= 2 || argerr)
2499 1
            error("parameters must be `main()` or `main(string[] args)`");
2500
    }
2501

2502
    /***********************************************
2503
     * Check all return statements for a function to verify that returning
2504
     * using NRVO is possible.
2505
     *
2506
     * Returns:
2507
     *      true if the result cannot be returned by hidden reference.
2508
     */
2509
    final bool checkNrvo()
2510
    {
2511 1
        if (!nrvo_can)
2512 0
            return true;
2513

2514 1
        if (returns is null)
2515 1
            return true;
2516

2517 1
        auto tf = type.toTypeFunction();
2518 1
        if (tf.isref)
2519 0
            return true;
2520

2521 1
        foreach (rs; *returns)
2522
        {
2523 1
            if (auto ve = rs.exp.isVarExp())
2524
            {
2525 1
                auto v = ve.var.isVarDeclaration();
2526 1
                if (!v || v.isOut() || v.isRef())
2527 0
                    return true;
2528 1
                else if (nrvo_var is null)
2529
                {
2530 1
                    if (!v.isDataseg() && !v.isParameter() && v.toParent2() == this)
2531
                    {
2532
                        //printf("Setting nrvo to %s\n", v.toChars());
2533 1
                        nrvo_var = v;
2534
                    }
2535
                    else
2536 1
                        return true;
2537
                }
2538 1
                else if (nrvo_var != v)
2539 1
                    return true;
2540
            }
2541
            else //if (!exp.isLvalue())    // keep NRVO-ability
2542 1
                return true;
2543
        }
2544 1
        return false;
2545
    }
2546

2547
    override final inout(FuncDeclaration) isFuncDeclaration() inout
2548
    {
2549 1
        return this;
2550
    }
2551

2552
    inout(FuncDeclaration) toAliasFunc() inout
2553
    {
2554 1
        return this;
2555
    }
2556

2557
    override void accept(Visitor v)
2558
    {
2559 1
        v.visit(this);
2560
    }
2561
}
2562

2563
/********************************************************
2564
 * Generate Expression to call the invariant.
2565
 * Input:
2566
 *      ad      aggregate with the invariant
2567
 *      vthis   variable with 'this'
2568
 * Returns:
2569
 *      void expression that calls the invariant
2570
 */
2571
Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
2572
{
2573 1
    Expression e = null;
2574
    // Call invariant directly only if it exists
2575 1
    FuncDeclaration inv = ad.inv;
2576 1
    ClassDeclaration cd = ad.isClassDeclaration();
2577

2578 1
    while (!inv && cd)
2579
    {
2580 1
        cd = cd.baseClass;
2581 1
        if (!cd)
2582 1
            break;
2583 1
        inv = cd.inv;
2584
    }
2585 1
    if (inv)
2586
    {
2587
        version (all)
2588
        {
2589
            // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
2590
            // For the correct mangling,
2591
            // run attribute inference on inv if needed.
2592 1
            inv.functionSemantic();
2593
        }
2594

2595
        //e = new DsymbolExp(Loc.initial, inv);
2596
        //e = new CallExp(Loc.initial, e);
2597
        //e = e.semantic(sc2);
2598

2599
        /* https://issues.dlang.org/show_bug.cgi?id=13113
2600
         * Currently virtual invariant calls completely
2601
         * bypass attribute enforcement.
2602
         * Change the behavior of pre-invariant call by following it.
2603
         */
2604 1
        e = new ThisExp(Loc.initial);
2605 1
        e.type = ad.type.addMod(vthis.type.mod);
2606 1
        e = new DotVarExp(Loc.initial, e, inv, false);
2607 1
        e.type = inv.type;
2608 1
        e = new CallExp(Loc.initial, e);
2609 1
        e.type = Type.tvoid;
2610
    }
2611 1
    return e;
2612
}
2613

2614
/***************************************************
2615
 * Visit each overloaded function/template in turn, and call dg(s) on it.
2616
 * Exit when no more, or dg(s) returns nonzero.
2617
 *
2618
 * Params:
2619
 *  fstart = symbol to start from
2620
 *  dg = the delegate to be called on the overload
2621
 *  sc = context used to check if symbol is accessible (and therefore visible),
2622
 *       can be null
2623
 *
2624
 * Returns:
2625
 *      ==0     continue
2626
 *      !=0     done (and the return value from the last dg() call)
2627
 */
2628
extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
2629
{
2630 1
    Dsymbol next;
2631 1
    for (auto d = fstart; d; d = next)
2632
    {
2633
        import dmd.access : checkSymbolAccess;
2634 1
        if (auto od = d.isOverDeclaration())
2635
        {
2636 1
            if (od.hasOverloads)
2637
            {
2638
                /* The scope is needed here to check whether a function in
2639
                   an overload set was added by means of a private alias (or a
2640
                   selective import). If the scope where the alias is created
2641
                   is imported somewhere, the overload set is visible, but the private
2642
                   alias is not.
2643
                 */
2644 1
                if (sc)
2645
                {
2646 1
                    if (checkSymbolAccess(sc, od))
2647
                    {
2648 1
                        if (int r = overloadApply(od.aliassym, dg, sc))
2649 0
                            return r;
2650
                    }
2651
                }
2652 1
                else if (int r = overloadApply(od.aliassym, dg, sc))
2653 1
                    return r;
2654
            }
2655
            else
2656
            {
2657 0
                if (int r = dg(od.aliassym))
2658 0
                    return r;
2659
            }
2660 1
            next = od.overnext;
2661
        }
2662 1
        else if (auto fa = d.isFuncAliasDeclaration())
2663
        {
2664 1
            if (fa.hasOverloads)
2665
            {
2666 1
                if (int r = overloadApply(fa.funcalias, dg, sc))
2667 1
                    return r;
2668
            }
2669 1
            else if (auto fd = fa.toAliasFunc())
2670
            {
2671 1
                if (int r = dg(fd))
2672 1
                    return r;
2673
            }
2674
            else
2675
            {
2676 0
                d.error("is aliased to a function");
2677 0
                break;
2678
            }
2679 1
            next = fa.overnext;
2680
        }
2681 1
        else if (auto ad = d.isAliasDeclaration())
2682
        {
2683 1
            if (sc)
2684
            {
2685 1
                if (checkSymbolAccess(sc, ad))
2686 1
                    next = ad.toAlias();
2687
            }
2688
            else
2689 1
               next = ad.toAlias();
2690 1
            if (next == ad)
2691 0
                break;
2692 1
            if (next == fstart)
2693 0
                break;
2694
        }
2695 1
        else if (auto td = d.isTemplateDeclaration())
2696
        {
2697 1
            if (int r = dg(td))
2698 1
                return r;
2699 1
            next = td.overnext;
2700
        }
2701 1
        else if (auto fd = d.isFuncDeclaration())
2702
        {
2703 1
            if (int r = dg(fd))
2704 1
                return r;
2705 1
            next = fd.overnext;
2706
        }
2707
        else
2708
        {
2709 1
            d.error("is aliased to a function");
2710 1
            break;
2711
            // BUG: should print error message?
2712
        }
2713
    }
2714 1
    return 0;
2715
}
2716

2717
/**
2718
Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
2719
mismatching modifiers to `buf`.
2720

2721
The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
2722
lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
2723

2724
Params:
2725
    buf = output buffer to write to
2726
    lhsMod = modifier on the left-hand side
2727
    lhsMod = modifier on the right-hand side
2728

2729
Returns:
2730

2731
A tuple with `isMutable` and `isNotShared` set
2732
if the `lhsMod` is missing those modifiers (compared to rhs).
2733
*/
2734
auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod)
2735
{
2736
    static struct Mismatches
2737
    {
2738
        bool isNotShared;
2739
        bool isMutable;
2740
    }
2741

2742 1
    Mismatches mismatches;
2743

2744 1
    bool bothMutable = ((lhsMod & rhsMod) == 0);
2745 1
    bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0;
2746 1
    bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_);
2747

2748 1
    if (lhsMod & MODFlags.shared_)
2749 1
        buf.writestring("`shared` ");
2750 1
    else if (sharedMismatch && !(lhsMod & MODFlags.immutable_))
2751
    {
2752 1
        buf.writestring("non-shared ");
2753 1
        mismatches.isNotShared = true;
2754
    }
2755

2756 1
    if (bothMutable && sharedMismatchOnly)
2757
    {
2758
    }
2759 1
    else if (lhsMod & MODFlags.immutable_)
2760 1
        buf.writestring("`immutable` ");
2761 1
    else if (lhsMod & MODFlags.const_)
2762 1
        buf.writestring("`const` ");
2763 1
    else if (lhsMod & MODFlags.wild)
2764 1
        buf.writestring("`inout` ");
2765
    else
2766
    {
2767 1
        buf.writestring("mutable ");
2768 1
        mismatches.isMutable = true;
2769
    }
2770

2771 1
    return mismatches;
2772
}
2773

2774
///
2775
unittest
2776
{
2777
    OutBuffer buf;
2778
    auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0);
2779
    assert(buf[] == "`shared` ");
2780
    assert(!mismatches.isNotShared);
2781

2782
    buf.setsize(0);
2783
    mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_);
2784
    assert(buf[] == "non-shared ");
2785
    assert(mismatches.isNotShared);
2786

2787
    buf.setsize(0);
2788
    mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0);
2789
    assert(buf[] == "`const` ");
2790
    assert(!mismatches.isMutable);
2791

2792
    buf.setsize(0);
2793
    mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_);
2794
    assert(buf[] == "mutable ");
2795
    assert(mismatches.isMutable);
2796
}
2797

2798
private const(char)* prependSpace(const(char)* str)
2799
{
2800 1
    if (!str || !*str) return "";
2801

2802 1
    return (" " ~ str.toDString() ~ "\0").ptr;
2803
}
2804

2805
/// Flag used by $(LREF resolveFuncCall).
2806
enum FuncResolveFlag : ubyte
2807
{
2808
    standard = 0,       /// issue error messages, solve the call.
2809
    quiet = 1,          /// do not issue error message on no match, just return `null`.
2810
    overloadOnly = 2,   /// only resolve overloads.
2811
}
2812

2813
/*******************************************
2814
 * Given a symbol that could be either a FuncDeclaration or
2815
 * a function template, resolve it to a function symbol.
2816
 * Params:
2817
 *      loc =           instantiation location
2818
 *      sc =            instantiation scope
2819
 *      s =             instantiation symbol
2820
 *      tiargs =        initial list of template arguments
2821
 *      tthis =         if !NULL, the `this` argument type
2822
 *      fargs =         arguments to function
2823
 *      flags =         see $(LREF FuncResolveFlag).
2824
 * Returns:
2825
 *      if match is found, then function symbol, else null
2826
 */
2827
FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
2828
    Objects* tiargs, Type tthis, Expressions* fargs, FuncResolveFlag flags)
2829
{
2830 1
    if (!s)
2831 0
        return null; // no match
2832

2833
    version (none)
2834
    {
2835
        printf("resolveFuncCall('%s')\n", s.toChars());
2836
        if (tthis)
2837
            printf("\tthis: %s\n", tthis.toChars());
2838
        if (fargs)
2839
        {
2840
            for (size_t i = 0; i < fargs.dim; i++)
2841
            {
2842
                Expression arg = (*fargs)[i];
2843
                assert(arg.type);
2844
                printf("\t%s: ", arg.toChars());
2845
                arg.type.print();
2846
            }
2847
        }
2848
    }
2849

2850 1
    if (tiargs && arrayObjectIsError(tiargs) ||
2851 1
        fargs && arrayObjectIsError(cast(Objects*)fargs))
2852
    {
2853 1
        return null;
2854
    }
2855

2856 1
    MatchAccumulator m;
2857 1
    functionResolve(m, s, loc, sc, tiargs, tthis, fargs, null);
2858 1
    auto orig_s = s;
2859

2860 1
    if (m.last > MATCH.nomatch && m.lastf)
2861
    {
2862 1
        if (m.count == 1) // exactly one match
2863
        {
2864 1
            if (!(flags & FuncResolveFlag.quiet))
2865 1
                m.lastf.functionSemantic();
2866 1
            return m.lastf;
2867
        }
2868 1
        if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
2869
        {
2870 1
            return m.lastf;
2871
        }
2872
    }
2873

2874
    /* Failed to find a best match.
2875
     * Do nothing or print error.
2876
     */
2877 1
    if (m.last <= MATCH.nomatch)
2878
    {
2879
        // error was caused on matched function, not on the matching itself,
2880
        // so return the function to produce a better diagnostic
2881 1
        if (m.count == 1)
2882 1
            return m.lastf;
2883
    }
2884

2885
    // We are done at this point, as the rest of this function generate
2886
    // a diagnostic on invalid match
2887 1
    if (flags & FuncResolveFlag.quiet)
2888 1
        return null;
2889

2890 1
    auto fd = s.isFuncDeclaration();
2891 1
    auto od = s.isOverDeclaration();
2892 1
    auto td = s.isTemplateDeclaration();
2893 1
    if (td && td.funcroot)
2894 1
        s = fd = td.funcroot;
2895

2896 1
    OutBuffer tiargsBuf;
2897 1
    arrayObjectsToBuffer(&tiargsBuf, tiargs);
2898

2899 1
    OutBuffer fargsBuf;
2900 1
    fargsBuf.writeByte('(');
2901 1
    argExpTypesToCBuffer(&fargsBuf, fargs);
2902 1
    fargsBuf.writeByte(')');
2903 1
    if (tthis)
2904 1
        tthis.modToBuffer(&fargsBuf);
2905

2906
    // The call is ambiguous
2907 1
    if (m.lastf && m.nextf)
2908
    {
2909 1
        TypeFunction tf1 = m.lastf.type.toTypeFunction();
2910 1
        TypeFunction tf2 = m.nextf.type.toTypeFunction();
2911 1
        const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
2912 1
        const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
2913

2914 1
        const(char)* mod1 = prependSpace(MODtoChars(tf1.mod));
2915 1
        const(char)* mod2 = prependSpace(MODtoChars(tf2.mod));
2916

2917 1
        .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s:     `%s%s%s`\nand:\n%s:     `%s%s%s`",
2918
            s.parent.toPrettyChars(), s.ident.toChars(),
2919
            fargsBuf.peekChars(),
2920
            m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1,
2921
            m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2);
2922 1
        return null;
2923
    }
2924

2925
    // no match, generate an error messages
2926 1
    if (!fd)
2927
    {
2928
        // all of overloads are templates
2929 1
        if (td)
2930
        {
2931 1
            .error(loc, "%s `%s.%s` cannot deduce function from argument types `!(%s)%s`, candidates are:",
2932
                   td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
2933
                   tiargsBuf.peekChars(), fargsBuf.peekChars());
2934

2935 1
            printCandidates(loc, td, sc.isDeprecated());
2936 1
            return null;
2937
        }
2938
        /* This case happens when several ctors are mixed in an agregate.
2939
           A (bad) error message is already generated in overloadApply().
2940
           see https://issues.dlang.org/show_bug.cgi?id=19729
2941
        */
2942 1
        if (!od)
2943 1
            return null;
2944
    }
2945

2946 1
    if (od)
2947
    {
2948 1
        .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
2949
               od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
2950 1
        return null;
2951
    }
2952

2953
    // remove when deprecation period of class allocators and deallocators is over
2954 1
    if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
2955 1
        return null;
2956

2957 1
    bool hasOverloads = fd.overnext !is null;
2958 1
    auto tf = fd.type.toTypeFunction();
2959 1
    if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch
2960
    {
2961 1
        OutBuffer thisBuf, funcBuf;
2962 1
        MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
2963 1
        auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
2964 1
        if (hasOverloads)
2965
        {
2966 1
            .error(loc, "none of the overloads of `%s` are callable using a %sobject, candidates are:",
2967
                   fd.ident.toChars(), thisBuf.peekChars());
2968 1
            printCandidates(loc, fd, sc.isDeprecated());
2969 1
            return null;
2970
        }
2971

2972 1
        const(char)* failMessage;
2973 1
        functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
2974 1
        if (failMessage)
2975
        {
2976 1
            .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
2977
                   fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
2978
                   tf.modToChars(), fargsBuf.peekChars());
2979 1
            errorSupplemental(loc, failMessage);
2980 1
            return null;
2981
        }
2982

2983 1
        auto fullFdPretty = fd.toPrettyChars();
2984 1
        .error(loc, "%smethod `%s` is not callable using a %sobject",
2985
               funcBuf.peekChars(), fullFdPretty, thisBuf.peekChars());
2986

2987 1
        if (mismatches.isNotShared)
2988 1
            .errorSupplemental(loc, "Consider adding `shared` to %s", fullFdPretty);
2989 1
        else if (mismatches.isMutable)
2990 1
            .errorSupplemental(loc, "Consider adding `const` or `inout` to %s", fullFdPretty);
2991 1
        return null;
2992
    }
2993

2994
    //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
2995 1
    if (hasOverloads)
2996
    {
2997 1
        .error(loc, "none of the overloads of `%s` are callable using argument types `%s`, candidates are:",
2998
               fd.toChars(), fargsBuf.peekChars());
2999 1
        printCandidates(loc, fd, sc.isDeprecated());
3000 1
        return null;
3001
    }
3002

3003 1
    .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3004
           fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3005
           tf.modToChars(), fargsBuf.peekChars());
3006
    // re-resolve to check for supplemental message
3007 1
    const(char)* failMessage;
3008 1
    functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
3009 1
    if (failMessage)
3010 1
        errorSupplemental(loc, failMessage);
3011 1
    return null;
3012
}
3013

3014
/*******************************************
3015
 * Prints template and function overload candidates as supplemental errors.
3016
 * Params:
3017
 *      loc =            instantiation location
3018
 *      declaration =    the declaration to print overload candidates for
3019
 *      showDeprecated = If `false`, `deprecated` function won't be shown
3020
 */
3021
private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
3022
if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
3023
{
3024
    // max num of overloads to print (-v overrides this).
3025
    enum int DisplayLimit = 5;
3026 1
    int displayed;
3027 1
    const(char)* constraintsTip;
3028

3029 1
    overloadApply(declaration, (Dsymbol s)
3030
    {
3031 1
        Dsymbol nextOverload;
3032

3033 1
        if (auto fd = s.isFuncDeclaration())
3034
        {
3035
            // Don't print overloads which have errors.
3036
            // Not that if the whole overload set has errors, we'll never reach
3037
            // this point so there's no risk of printing no candidate
3038 1
            if (fd.errors || fd.type.ty == Terror)
3039 1
                return 0;
3040
            // Don't print disabled functions, or `deprecated` outside of deprecated scope
3041 1
            if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
3042 1
                return 0;
3043

3044 1
            auto tf = cast(TypeFunction) fd.type;
3045 1
            .errorSupplemental(fd.loc, "`%s%s`", fd.toPrettyChars(),
3046
                parametersTypeToChars(tf.parameterList));
3047 1
            nextOverload = fd.overnext;
3048
        }
3049 1
        else if (auto td = s.isTemplateDeclaration())
3050
        {
3051
            import dmd.staticcond;
3052

3053 1
            const tmsg = td.toCharsNoConstraints();
3054 1
            const cmsg = td.getConstraintEvalError(constraintsTip);
3055 1
            if (cmsg)
3056 1
                .errorSupplemental(td.loc, "`%s`\n%s", tmsg, cmsg);
3057
            else
3058 1
                .errorSupplemental(td.loc, "`%s`", tmsg);
3059 1
            nextOverload = td.overnext;
3060
        }
3061

3062 1
        if (global.params.verbose || ++displayed < DisplayLimit)
3063 1
            return 0;
3064

3065
        // Too many overloads to sensibly display.
3066
        // Just show count of remaining overloads.
3067 1
        int num = 0;
3068 1
        overloadApply(nextOverload, (s) { ++num; return 0; });
3069

3070 1
        if (num > 0)
3071 1
            .errorSupplemental(loc, "... (%d more, -v to show) ...", num);
3072 1
        return 1;   // stop iterating
3073
    });
3074

3075
    // Nothing was displayed, all overloads are either disabled or deprecated
3076 1
    if (!displayed)
3077 1
        .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
3078
    // should be only in verbose mode
3079 1
    if (constraintsTip)
3080 1
        .tip(constraintsTip);
3081
}
3082

3083
/**************************************
3084
 * Returns an indirect type one step from t.
3085
 */
3086
Type getIndirection(Type t)
3087
{
3088 1
    t = t.baseElemOf();
3089 1
    if (t.ty == Tarray || t.ty == Tpointer)
3090 1
        return t.nextOf().toBasetype();
3091 1
    if (t.ty == Taarray || t.ty == Tclass)
3092 1
        return t;
3093 1
    if (t.ty == Tstruct)
3094 1
        return t.hasPointers() ? t : null; // TODO
3095

3096
    // should consider TypeDelegate?
3097 0
    return null;
3098
}
3099

3100
/**************************************
3101
 * Performs type-based alias analysis between a newly created value and a pre-
3102
 * existing memory reference:
3103