d: Merge upstream dmd 3982604c5, druntime bc58b1e9, phobos 12329adb6.
[official-gcc.git] / gcc / d / dmd / func.d
blobda33587fc88a802718c5945e3abd85ceb37c045d
1 /**
2 * Defines a function declaration.
4 * Includes:
5 * - function/delegate literals
6 * - function aliases
7 * - (static/shared) constructors/destructors/post-blits
8 * - `invariant`
9 * - `unittest`
11 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
12 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
13 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
14 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d)
15 * Documentation: https://dlang.org/phobos/dmd_func.html
16 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d
19 module dmd.func;
21 import core.stdc.stdio;
22 import core.stdc.string;
23 import dmd.aggregate;
24 import dmd.arraytypes;
25 import dmd.astenums;
26 import dmd.blockexit;
27 import dmd.gluelayer;
28 import dmd.dclass;
29 import dmd.declaration;
30 import dmd.delegatize;
31 import dmd.dinterpret;
32 import dmd.dmodule;
33 import dmd.dscope;
34 import dmd.dstruct;
35 import dmd.dsymbol;
36 import dmd.dsymbolsem;
37 import dmd.dtemplate;
38 import dmd.errors;
39 import dmd.escape;
40 import dmd.expression;
41 import dmd.globals;
42 import dmd.hdrgen;
43 import dmd.id;
44 import dmd.identifier;
45 import dmd.init;
46 import dmd.mtype;
47 import dmd.objc;
48 import dmd.root.aav;
49 import dmd.common.outbuffer;
50 import dmd.root.rootobject;
51 import dmd.root.string;
52 import dmd.root.stringtable;
53 import dmd.semantic2;
54 import dmd.semantic3;
55 import dmd.statement_rewrite_walker;
56 import dmd.statement;
57 import dmd.statementsem;
58 import dmd.tokens;
59 import dmd.visitor;
61 /// Inline Status
62 enum ILS : ubyte
64 uninitialized, /// not computed yet
65 no, /// cannot inline
66 yes, /// can inline
69 enum BUILTIN : ubyte
71 unknown = 255, /// not known if this is a builtin
72 unimp = 0, /// this is not a builtin
73 gcc, /// this is a GCC builtin
74 llvm, /// this is an LLVM builtin
75 sin,
76 cos,
77 tan,
78 sqrt,
79 fabs,
80 ldexp,
81 log,
82 log2,
83 log10,
84 exp,
85 expm1,
86 exp2,
87 round,
88 floor,
89 ceil,
90 trunc,
91 copysign,
92 pow,
93 fmin,
94 fmax,
95 fma,
96 isnan,
97 isinfinity,
98 isfinite,
99 bsf,
100 bsr,
101 bswap,
102 popcnt,
103 yl2x,
104 yl2xp1,
105 toPrecFloat,
106 toPrecDouble,
107 toPrecReal
110 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
112 extern (C++) final class NrvoWalker : StatementRewriteWalker
114 alias visit = typeof(super).visit;
115 public:
116 FuncDeclaration fd;
117 Scope* sc;
119 override void visit(ReturnStatement s)
121 // See if all returns are instead to be replaced with a goto returnLabel;
122 if (fd.returnLabel)
124 /* Rewrite:
125 * return exp;
126 * as:
127 * vresult = exp; goto Lresult;
129 auto gs = new GotoStatement(s.loc, Id.returnLabel);
130 gs.label = fd.returnLabel;
132 Statement s1 = gs;
133 if (s.exp)
134 s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
136 replaceCurrent(s1);
140 override void visit(TryFinallyStatement s)
142 DtorExpStatement des;
143 if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
144 fd.nrvo_var == des.var)
146 if (!(global.params.useExceptions && ClassDeclaration.throwable))
148 /* Don't need to call destructor at all, since it is nrvo
150 replaceCurrent(s._body);
151 s._body.accept(this);
152 return;
155 /* Normally local variable dtors are called regardless exceptions.
156 * But for nrvo_var, its dtor should be called only when exception is thrown.
158 * Rewrite:
159 * try { s.body; } finally { nrvo_var.edtor; }
160 * // equivalent with:
161 * // s.body; scope(exit) nrvo_var.edtor;
162 * as:
163 * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
164 * // equivalent with:
165 * // s.body; scope(failure) nrvo_var.edtor;
167 Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
168 Identifier id = Identifier.generateId("__o");
170 Statement handler = new PeelStatement(sexception);
171 if (sexception.blockExit(fd, false) & BE.fallthru)
173 auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
174 ts.internalThrow = true;
175 handler = new CompoundStatement(Loc.initial, handler, ts);
178 auto catches = new Catches();
179 auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
180 ctch.internalCatch = true;
181 ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
182 catches.push(ctch);
184 Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
185 fd.eh_none = false;
186 replaceCurrent(s2);
187 s2.accept(this);
189 else
190 StatementRewriteWalker.visit(s);
194 enum FUNCFLAG : uint
196 purityInprocess = 1, /// working on determining purity
197 safetyInprocess = 2, /// working on determining safety
198 nothrowInprocess = 4, /// working on determining nothrow
199 nogcInprocess = 8, /// working on determining @nogc
200 returnInprocess = 0x10, /// working on inferring 'return' for parameters
201 inlineScanned = 0x20, /// function has been scanned for inline possibilities
202 inferScope = 0x40, /// infer 'scope' for parameters
203 hasCatches = 0x80, /// function has try-catch statements
204 compileTimeOnly = 0x100, /// is a compile time only function; no code will be generated for it
205 printf = 0x200, /// is a printf-like function
206 scanf = 0x400, /// is a scanf-like function
207 noreturn = 0x800, /// the function does not return
210 /***********************************************************
211 * Tuple of result identifier (possibly null) and statement.
212 * This is used to store out contracts: out(id){ ensure }
214 extern (C++) struct Ensure
216 Identifier id;
217 Statement ensure;
219 Ensure syntaxCopy()
221 return Ensure(id, ensure.syntaxCopy());
224 /*****************************************
225 * Do syntax copy of an array of Ensure's.
227 static Ensures* arraySyntaxCopy(Ensures* a)
229 Ensures* b = null;
230 if (a)
232 b = a.copy();
233 foreach (i, e; *a)
235 (*b)[i] = e.syntaxCopy();
238 return b;
243 /***********************************************************
245 extern (C++) class FuncDeclaration : Declaration
247 Statements* frequires; /// in contracts
248 Ensures* fensures; /// out contracts
249 Statement frequire; /// lowered in contract
250 Statement fensure; /// lowered out contract
251 Statement fbody; /// function body
253 FuncDeclarations foverrides; /// functions this function overrides
254 FuncDeclaration fdrequire; /// function that does the in contract
255 FuncDeclaration fdensure; /// function that does the out contract
257 Expressions* fdrequireParams; /// argument list for __require
258 Expressions* fdensureParams; /// argument list for __ensure
260 const(char)* mangleString; /// mangled symbol created from mangleExact()
262 VarDeclaration vresult; /// result variable for out contracts
263 LabelDsymbol returnLabel; /// where the return goes
265 bool[size_t] isTypeIsolatedCache; /// cache for the potentially very expensive isTypeIsolated check
267 // used to prevent symbols in different
268 // scopes from having the same name
269 DsymbolTable localsymtab;
270 VarDeclaration vthis; /// 'this' parameter (member and nested)
271 bool isThis2; /// has a dual-context 'this' parameter
272 VarDeclaration v_arguments; /// '_arguments' parameter
274 VarDeclaration v_argptr; /// '_argptr' variable
275 VarDeclarations* parameters; /// Array of VarDeclaration's for parameters
276 DsymbolTable labtab; /// statement label symbol table
277 Dsymbol overnext; /// next in overload list
278 FuncDeclaration overnext0; /// next in overload list (only used during IFTI)
279 Loc endloc; /// location of closing curly bracket
280 int vtblIndex = -1; /// for member functions, index into vtbl[]
281 bool naked; /// true if naked
282 bool generated; /// true if function was generated by the compiler rather than
283 /// supplied by the user
284 bool hasAlwaysInlines; /// contains references to functions that must be inlined
285 ubyte isCrtCtorDtor; /// has attribute pragma(crt_constructor(1)/crt_destructor(2))
286 /// not set before the glue layer
288 ILS inlineStatusStmt = ILS.uninitialized;
289 ILS inlineStatusExp = ILS.uninitialized;
290 PINLINE inlining = PINLINE.default_;
292 int inlineNest; /// !=0 if nested inline
293 bool eh_none; /// true if no exception unwinding is needed
295 bool semantic3Errors; /// true if errors in semantic3 this function's frame ptr
296 ForeachStatement fes; /// if foreach body, this is the foreach
297 BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[]
298 bool introducing; /// true if 'introducing' function
299 /** if !=NULL, then this is the type
300 of the 'introducing' function
301 this one is overriding
303 Type tintro;
305 bool inferRetType; /// true if return type is to be inferred
306 StorageClass storage_class2; /// storage class for template onemember's
308 // Things that should really go into Scope
310 /// 1 if there's a return exp; statement
311 /// 2 if there's a throw statement
312 /// 4 if there's an assert(0)
313 /// 8 if there's inline asm
314 /// 16 if there are multiple return statements
315 int hasReturnExp;
317 // Support for NRVO (named return value optimization)
318 bool nrvo_can = true; /// true means we can do NRVO
319 VarDeclaration nrvo_var; /// variable to replace with shidden
320 Symbol* shidden; /// hidden pointer passed to function
322 ReturnStatements* returns;
324 GotoStatements* gotos; /// Gotos with forward references
326 /// set if this is a known, builtin function we can evaluate at compile time
327 BUILTIN builtin = BUILTIN.unknown;
329 /// set if someone took the address of this function
330 int tookAddressOf;
332 bool requiresClosure; // this function needs a closure
334 /** local variables in this function which are referenced by nested functions
335 * (They'll get put into the "closure" for this function.)
337 VarDeclarations closureVars;
339 /** Outer variables which are referenced by this nested function
340 * (the inverse of closureVars)
342 VarDeclarations outerVars;
344 /// Sibling nested functions which called this one
345 FuncDeclarations siblingCallers;
347 FuncDeclarations *inlinedNestedCallees;
349 uint flags; /// FUNCFLAG.xxxxx
352 * Data for a function declaration that is needed for the Objective-C
353 * integration.
355 ObjcFuncDeclaration objc;
357 extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false)
359 super(loc, ident);
360 //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type);
361 //printf("storage_class = x%x\n", storage_class);
362 this.storage_class = storage_class;
363 this.type = type;
364 if (type)
366 // Normalize storage_class, because function-type related attributes
367 // are already set in the 'type' in parsing phase.
368 this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
370 this.endloc = endloc;
371 if (noreturn)
372 this.flags |= FUNCFLAG.noreturn;
374 /* The type given for "infer the return type" is a TypeFunction with
375 * NULL for the return type.
377 inferRetType = (type && type.nextOf() is null);
380 static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
382 return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn);
385 override FuncDeclaration syntaxCopy(Dsymbol s)
387 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
388 FuncDeclaration f = s ? cast(FuncDeclaration)s
389 : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), (flags & FUNCFLAG.noreturn) != 0);
390 f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
391 f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
392 f.fbody = fbody ? fbody.syntaxCopy() : null;
393 return f;
396 /****************************************************
397 * Resolve forward reference of function signature -
398 * parameter types, return type, and attributes.
399 * Returns:
400 * false if any errors exist in the signature.
402 final bool functionSemantic()
404 //printf("functionSemantic() %p %s\n", this, toChars());
405 if (!_scope)
406 return !errors;
408 this.cppnamespace = _scope.namespace;
410 if (!originalType) // semantic not yet run
412 TemplateInstance spec = isSpeculative();
413 uint olderrs = global.errors;
414 uint oldgag = global.gag;
415 if (global.gag && !spec)
416 global.gag = 0;
417 dsymbolSemantic(this, _scope);
418 global.gag = oldgag;
419 if (spec && global.errors != olderrs)
420 spec.errors = (global.errors - olderrs != 0);
421 if (olderrs != global.errors) // if errors compiling this function
422 return false;
425 // if inferring return type, sematic3 needs to be run
426 // - When the function body contains any errors, we cannot assume
427 // the inferred return type is valid.
428 // So, the body errors should become the function signature error.
429 if (inferRetType && type && !type.nextOf())
430 return functionSemantic3();
432 TemplateInstance ti;
433 if (isInstantiated() && !isVirtualMethod() &&
434 ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident))
436 AggregateDeclaration ad = isMemberLocal();
437 if (ad && ad.sizeok != Sizeok.done)
439 /* Currently dmd cannot resolve forward references per methods,
440 * then setting SIZOKfwd is too conservative and would break existing code.
441 * So, just stop method attributes inference until ad.dsymbolSemantic() done.
443 //ad.sizeok = Sizeok.fwd;
445 else
446 return functionSemantic3() || !errors;
449 if (storage_class & STC.inference)
450 return functionSemantic3() || !errors;
452 return !errors;
455 /****************************************************
456 * Resolve forward reference of function body.
457 * Returns false if any errors exist in the body.
459 final bool functionSemantic3()
461 if (semanticRun < PASS.semantic3 && _scope)
463 /* Forward reference - we need to run semantic3 on this function.
464 * If errors are gagged, and it's not part of a template instance,
465 * we need to temporarily ungag errors.
467 TemplateInstance spec = isSpeculative();
468 uint olderrs = global.errors;
469 uint oldgag = global.gag;
470 if (global.gag && !spec)
471 global.gag = 0;
472 semantic3(this, _scope);
473 global.gag = oldgag;
475 // If it is a speculatively-instantiated template, and errors occur,
476 // we need to mark the template as having errors.
477 if (spec && global.errors != olderrs)
478 spec.errors = (global.errors - olderrs != 0);
479 if (olderrs != global.errors) // if errors compiling this function
480 return false;
483 return !errors && !semantic3Errors;
486 /****************************************************
487 * Check that this function type is properly resolved.
488 * If not, report "forward reference error" and return true.
490 extern (D) final bool checkForwardRef(const ref Loc loc)
492 if (!functionSemantic())
493 return true;
495 /* No deco means the functionSemantic() call could not resolve
496 * forward referenes in the type of this function.
498 if (!type.deco)
500 bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3);
501 .error(loc, "forward reference to %s`%s`",
502 (inSemantic3 ? "inferred return type of function " : "").ptr,
503 toChars());
504 return true;
506 return false;
509 // called from semantic3
511 * Creates and returns the hidden parameters for this function declaration.
513 * Hidden parameters include the `this` parameter of a class, struct or
514 * nested function and the selector parameter for Objective-C methods.
516 extern (D) final void declareThis(Scope* sc)
518 isThis2 = toParent2() != toParentLocal();
519 auto ad = isThis();
520 if (!isThis2 && !ad && !isNested())
522 vthis = null;
523 objc.selectorParameter = null;
524 return;
527 Type addModStc(Type t)
529 return t.addMod(type.mod).addStorageClass(storage_class);
532 if (isThis2 || isNested())
534 /* The 'this' for a nested function is the link to the
535 * enclosing function's stack frame.
536 * Note that nested functions and member functions are disjoint.
538 Type tthis = addModStc(isThis2 ?
539 Type.tvoidptr.sarrayOf(2).pointerTo() :
540 Type.tvoid.pointerTo());
541 vthis = new VarDeclaration(loc, tthis, isThis2 ? Id.this2 : Id.capture, null);
542 vthis.storage_class |= STC.parameter | STC.nodtor;
544 else if (ad)
546 Type thandle = addModStc(ad.handleType());
547 vthis = new ThisDeclaration(loc, thandle);
548 vthis.storage_class |= STC.parameter;
549 if (thandle.ty == Tstruct)
551 vthis.storage_class |= STC.ref_;
552 // if member function is marked 'inout', then 'this' is 'return ref'
553 if (type.ty == Tfunction && (cast(TypeFunction)type).isInOutQual())
554 vthis.storage_class |= STC.return_;
558 if (auto tf = type.isTypeFunction())
560 if (tf.isreturn)
561 vthis.storage_class |= STC.return_;
562 if (tf.isScopeQual)
563 vthis.storage_class |= STC.scope_;
565 /* Add STC.returnScope like typesem.d does for TypeFunction parameters,
566 * at least it should be the same. At the moment, we'll just
567 * do existing practice. But we should examine how TypeFunction does
568 * it, for consistency.
570 if (!tf.isref && isRefReturnScope(vthis.storage_class))
572 /* if `ref return scope`, evaluate to `ref` `return scope`
574 vthis.storage_class |= STC.returnScope;
577 if (flags & FUNCFLAG.inferScope && !(vthis.storage_class & STC.scope_))
578 vthis.storage_class |= STC.maybescope;
580 vthis.dsymbolSemantic(sc);
581 if (!sc.insert(vthis))
582 assert(0);
583 vthis.parent = this;
584 if (ad)
585 objc.selectorParameter = .objc.createSelectorParameter(this, sc);
588 override final bool equals(const RootObject o) const
590 if (this == o)
591 return true;
593 if (auto s = isDsymbol(o))
595 auto fd1 = this;
596 auto fd2 = s.isFuncDeclaration();
597 if (!fd2)
598 return false;
600 auto fa1 = fd1.isFuncAliasDeclaration();
601 auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
603 auto fa2 = fd2.isFuncAliasDeclaration();
604 auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
606 if (fa1 && fa2)
608 return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
611 bool b1 = fa1 !is null;
612 if (b1 && faf1.isUnique() && !fa1.hasOverloads)
613 b1 = false;
615 bool b2 = fa2 !is null;
616 if (b2 && faf2.isUnique() && !fa2.hasOverloads)
617 b2 = false;
619 if (b1 != b2)
620 return false;
622 return faf1.toParent().equals(faf2.toParent()) &&
623 faf1.ident.equals(faf2.ident) &&
624 faf1.type.equals(faf2.type);
626 return false;
629 /****************************************************
630 * Determine if 'this' overrides fd.
631 * Return !=0 if it does.
633 final int overrides(FuncDeclaration fd)
635 int result = 0;
636 if (fd.ident == ident)
638 const cov = type.covariant(fd.type);
639 if (cov != Covariant.distinct)
641 ClassDeclaration cd1 = toParent().isClassDeclaration();
642 ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
643 if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
644 result = 1;
647 return result;
650 /*************************************************
651 * Find index of function in vtbl[0..dim] that
652 * this function overrides.
653 * Prefer an exact match to a covariant one.
654 * Params:
655 * vtbl = vtable to use
656 * dim = maximal vtable dimension
657 * Returns:
658 * -1 didn't find one
659 * -2 can't determine because of forward references
661 final int findVtblIndex(Dsymbols* vtbl, int dim)
663 //printf("findVtblIndex() %s\n", toChars());
664 FuncDeclaration mismatch = null;
665 StorageClass mismatchstc = 0;
666 int mismatchvi = -1;
667 int exactvi = -1;
668 int bestvi = -1;
669 for (int vi = 0; vi < dim; vi++)
671 FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration();
672 if (fdv && fdv.ident == ident)
674 if (type.equals(fdv.type)) // if exact match
676 if (fdv.parent.isClassDeclaration())
678 if (fdv.isFuture())
680 bestvi = vi;
681 continue; // keep looking
683 return vi; // no need to look further
686 if (exactvi >= 0)
688 error("cannot determine overridden function");
689 return exactvi;
691 exactvi = vi;
692 bestvi = vi;
693 continue;
696 StorageClass stc = 0;
697 const cov = type.covariant(fdv.type, &stc);
698 //printf("\tbaseclass cov = %d\n", cov);
699 final switch (cov)
701 case Covariant.distinct:
702 // types are distinct
703 break;
705 case Covariant.yes:
706 bestvi = vi; // covariant, but not identical
707 break;
708 // keep looking for an exact match
710 case Covariant.no:
711 mismatchvi = vi;
712 mismatchstc = stc;
713 mismatch = fdv; // overrides, but is not covariant
714 break;
715 // keep looking for an exact match
717 case Covariant.fwdref:
718 return -2; // forward references
722 if (bestvi == -1 && mismatch)
724 //type.print();
725 //mismatch.type.print();
726 //printf("%s %s\n", type.deco, mismatch.type.deco);
727 //printf("stc = %llx\n", mismatchstc);
728 if (mismatchstc)
730 // Fix it by modifying the type to add the storage classes
731 type = type.addStorageClass(mismatchstc);
732 bestvi = mismatchvi;
735 return bestvi;
738 /*********************************
739 * If function a function in a base class,
740 * return that base class.
741 * Returns:
742 * base class if overriding, null if not
744 final BaseClass* overrideInterface()
746 for (ClassDeclaration cd = toParent2().isClassDeclaration(); cd; cd = cd.baseClass)
748 foreach (b; cd.interfaces)
750 auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim);
751 if (v >= 0)
752 return b;
755 return null;
758 /****************************************************
759 * Overload this FuncDeclaration with the new one f.
760 * Return true if successful; i.e. no conflict.
762 override bool overloadInsert(Dsymbol s)
764 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
765 assert(s != this);
766 AliasDeclaration ad = s.isAliasDeclaration();
767 if (ad)
769 if (overnext)
770 return overnext.overloadInsert(ad);
771 if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof)
773 //printf("\tad = '%s'\n", ad.type.toChars());
774 return false;
776 overnext = ad;
777 //printf("\ttrue: no conflict\n");
778 return true;
780 TemplateDeclaration td = s.isTemplateDeclaration();
781 if (td)
783 if (!td.funcroot)
784 td.funcroot = this;
785 if (overnext)
786 return overnext.overloadInsert(td);
787 overnext = td;
788 return true;
790 FuncDeclaration fd = s.isFuncDeclaration();
791 if (!fd)
792 return false;
794 version (none)
796 /* Disable this check because:
797 * const void foo();
798 * semantic() isn't run yet on foo(), so the const hasn't been
799 * applied yet.
801 if (type)
803 printf("type = %s\n", type.toChars());
804 printf("fd.type = %s\n", fd.type.toChars());
806 // fd.type can be NULL for overloaded constructors
807 if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
809 //printf("\tfalse: conflict %s\n", kind());
810 return false;
814 if (overnext)
816 td = overnext.isTemplateDeclaration();
817 if (td)
818 fd.overloadInsert(td);
819 else
820 return overnext.overloadInsert(fd);
822 overnext = fd;
823 //printf("\ttrue: no conflict\n");
824 return true;
827 /********************************************
828 * Find function in overload list that exactly matches t.
830 extern (D) final FuncDeclaration overloadExactMatch(Type t)
832 FuncDeclaration fd;
833 overloadApply(this, (Dsymbol s)
835 auto f = s.isFuncDeclaration();
836 if (!f)
837 return 0;
838 if (t.equals(f.type))
840 fd = f;
841 return 1;
844 /* Allow covariant matches, as long as the return type
845 * is just a const conversion.
846 * This allows things like pure functions to match with an impure function type.
848 if (t.ty == Tfunction)
850 auto tf = cast(TypeFunction)f.type;
851 if (tf.covariant(t) == Covariant.yes &&
852 tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
854 fd = f;
855 return 1;
858 return 0;
860 return fd;
863 /********************************************
864 * Find function in overload list that matches to the 'this' modifier.
865 * There's four result types.
867 * 1. If the 'tthis' matches only one candidate, it's an "exact match".
868 * Returns the function and 'hasOverloads' is set to false.
869 * eg. If 'tthis" is mutable and there's only one mutable method.
870 * 2. If there's two or more match candidates, but a candidate function will be
871 * a "better match".
872 * Returns the better match function but 'hasOverloads' is set to true.
873 * eg. If 'tthis' is mutable, and there's both mutable and const methods,
874 * the mutable method will be a better match.
875 * 3. If there's two or more match candidates, but there's no better match,
876 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
877 * eg. If 'tthis' is mutable, and there's two or more mutable methods.
878 * 4. If there's no candidates, it's "no match" and returns null with error report.
879 * e.g. If 'tthis' is const but there's no const methods.
881 extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
883 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
884 MatchAccumulator m;
885 overloadApply(this, (Dsymbol s)
887 auto f = s.isFuncDeclaration();
888 if (!f || f == m.lastf) // skip duplicates
889 return 0;
891 auto tf = f.type.toTypeFunction();
892 //printf("tf = %s\n", tf.toChars());
894 MATCH match;
895 if (tthis) // non-static functions are preferred than static ones
897 if (f.needThis())
898 match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
899 else
900 match = MATCH.constant; // keep static function in overload candidates
902 else // static functions are preferred than non-static ones
904 if (f.needThis())
905 match = MATCH.convert;
906 else
907 match = MATCH.exact;
909 if (match == MATCH.nomatch)
910 return 0;
912 if (match > m.last) goto LcurrIsBetter;
913 if (match < m.last) goto LlastIsBetter;
915 // See if one of the matches overrides the other.
916 if (m.lastf.overrides(f)) goto LlastIsBetter;
917 if (f.overrides(m.lastf)) goto LcurrIsBetter;
919 //printf("\tambiguous\n");
920 m.nextf = f;
921 m.count++;
922 return 0;
924 LlastIsBetter:
925 //printf("\tlastbetter\n");
926 m.count++; // count up
927 return 0;
929 LcurrIsBetter:
930 //printf("\tisbetter\n");
931 if (m.last <= MATCH.convert)
933 // clear last secondary matching
934 m.nextf = null;
935 m.count = 0;
937 m.last = match;
938 m.lastf = f;
939 m.count++; // count up
940 return 0;
943 if (m.count == 1) // exact match
945 hasOverloads = false;
947 else if (m.count > 1) // better or ambiguous match
949 hasOverloads = true;
951 else // no match
953 hasOverloads = true;
954 auto tf = this.type.toTypeFunction();
955 assert(tthis);
956 assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
958 OutBuffer thisBuf, funcBuf;
959 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
960 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
961 .error(loc, "%smethod %s is not callable using a %sobject",
962 funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
965 return m.lastf;
968 /********************************************
969 * find function template root in overload list
971 extern (D) final TemplateDeclaration findTemplateDeclRoot()
973 FuncDeclaration f = this;
974 while (f && f.overnext)
976 //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
977 TemplateDeclaration td = f.overnext.isTemplateDeclaration();
978 if (td)
979 return td;
980 f = f.overnext.isFuncDeclaration();
982 return null;
985 /********************************************
986 * Returns true if function was declared
987 * directly or indirectly in a unittest block
989 final bool inUnittest()
991 Dsymbol f = this;
994 if (f.isUnitTestDeclaration())
995 return true;
996 f = f.toParent();
998 while (f);
999 return false;
1002 /*************************************
1003 * Determine partial specialization order of 'this' vs g.
1004 * This is very similar to TemplateDeclaration::leastAsSpecialized().
1005 * Returns:
1006 * match 'this' is at least as specialized as g
1007 * 0 g is more specialized than 'this'
1009 final MATCH leastAsSpecialized(FuncDeclaration g)
1011 enum LOG_LEASTAS = 0;
1012 static if (LOG_LEASTAS)
1014 printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars());
1015 printf("%s, %s\n", type.toChars(), g.type.toChars());
1018 /* This works by calling g() with f()'s parameters, and
1019 * if that is possible, then f() is at least as specialized
1020 * as g() is.
1023 TypeFunction tf = type.toTypeFunction();
1024 TypeFunction tg = g.type.toTypeFunction();
1026 /* If both functions have a 'this' pointer, and the mods are not
1027 * the same and g's is not const, then this is less specialized.
1029 if (needThis() && g.needThis() && tf.mod != tg.mod)
1031 if (isCtorDeclaration())
1033 if (!MODimplicitConv(tg.mod, tf.mod))
1034 return MATCH.nomatch;
1036 else
1038 if (!MODimplicitConv(tf.mod, tg.mod))
1039 return MATCH.nomatch;
1043 /* Create a dummy array of arguments out of the parameters to f()
1045 Expressions args;
1046 foreach (u, p; tf.parameterList)
1048 Expression e;
1049 if (p.isReference())
1051 e = new IdentifierExp(Loc.initial, p.ident);
1052 e.type = p.type;
1054 else
1055 e = p.type.defaultInitLiteral(Loc.initial);
1056 args.push(e);
1059 MATCH m = tg.callMatch(null, args[], 1);
1060 if (m > MATCH.nomatch)
1062 /* A variadic parameter list is less specialized than a
1063 * non-variadic one.
1065 if (tf.parameterList.varargs && !tg.parameterList.varargs)
1066 goto L1; // less specialized
1068 static if (LOG_LEASTAS)
1070 printf(" matches %d, so is least as specialized\n", m);
1072 return m;
1075 static if (LOG_LEASTAS)
1077 printf(" doesn't match, so is not as specialized\n");
1079 return MATCH.nomatch;
1082 /********************************
1083 * Searches for a label with the given identifier. This function will insert a new
1084 * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
1086 * Params:
1087 * ident = identifier of the requested label
1088 * loc = location used when creating a new `LabelDsymbol`
1090 * Returns: the `LabelDsymbol` for `ident`
1092 final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial)
1094 Dsymbol s;
1095 if (!labtab)
1096 labtab = new DsymbolTable(); // guess we need one
1098 s = labtab.lookup(ident);
1099 if (!s)
1101 s = new LabelDsymbol(ident, loc);
1102 labtab.insert(s);
1104 return cast(LabelDsymbol)s;
1107 /*****************************************
1108 * Determine lexical level difference from `this` to nested function `fd`.
1109 * Params:
1110 * fd = target of call
1111 * intypeof = !=0 if inside typeof
1112 * Returns:
1113 * 0 same level
1114 * >0 decrease nesting by number
1115 * -1 increase nesting by 1 (`fd` is nested within `this`)
1116 * LevelError error, `this` cannot call `fd`
1118 final int getLevel(FuncDeclaration fd, int intypeof)
1120 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
1121 Dsymbol fdparent = fd.toParent2();
1122 if (fdparent == this)
1123 return -1;
1125 Dsymbol s = this;
1126 int level = 0;
1127 while (fd != s && fdparent != s.toParent2())
1129 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
1130 if (auto thisfd = s.isFuncDeclaration())
1132 if (!thisfd.isNested() && !thisfd.vthis && !intypeof)
1133 return LevelError;
1135 else
1137 if (auto thiscd = s.isAggregateDeclaration())
1139 /* AggregateDeclaration::isNested returns true only when
1140 * it has a hidden pointer.
1141 * But, calling the function belongs unrelated lexical scope
1142 * is still allowed inside typeof.
1144 * struct Map(alias fun) {
1145 * typeof({ return fun(); }) RetType;
1146 * // No member function makes Map struct 'not nested'.
1149 if (!thiscd.isNested() && !intypeof)
1150 return LevelError;
1152 else
1153 return LevelError;
1156 s = s.toParentP(fd);
1157 assert(s);
1158 level++;
1160 return level;
1163 /***********************************
1164 * Determine lexical level difference from `this` to nested function `fd`.
1165 * Issue error if `this` cannot call `fd`.
1167 * Params:
1168 * loc = location for error messages
1169 * sc = context
1170 * fd = target of call
1171 * decl = The `Declaration` that triggered this check.
1172 * Used to provide a better error message only.
1173 * Returns:
1174 * 0 same level
1175 * >0 decrease nesting by number
1176 * -1 increase nesting by 1 (`fd` is nested within 'this')
1177 * LevelError error
1179 final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd,
1180 Declaration decl)
1182 int level = getLevel(fd, sc.intypeof);
1183 if (level != LevelError)
1184 return level;
1186 // Don't give error if in template constraint
1187 if (!(sc.flags & SCOPE.constraint))
1189 const(char)* xstatic = isStatic() ? "`static` " : "";
1190 // better diagnostics for static functions
1191 .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
1192 xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(),
1193 fd.toPrettyChars());
1194 .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
1195 return LevelError;
1197 return 1;
1200 enum LevelError = -2;
1202 override const(char)* toPrettyChars(bool QualifyTypes = false)
1204 if (isMain())
1205 return "D main";
1206 else
1207 return Dsymbol.toPrettyChars(QualifyTypes);
1210 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
1211 final const(char)* toFullSignature()
1213 OutBuffer buf;
1214 functionToBufferWithIdent(type.toTypeFunction(), &buf, toChars(), isStatic);
1215 return buf.extractChars();
1218 final bool isMain() const
1220 return ident == Id.main && linkage != LINK.c && !isMember() && !isNested();
1223 final bool isCMain() const
1225 return ident == Id.main && linkage == LINK.c && !isMember() && !isNested();
1228 final bool isWinMain() const
1230 //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1231 version (none)
1233 bool x = ident == Id.WinMain && linkage != LINK.c && !isMember();
1234 printf("%s\n", x ? "yes" : "no");
1235 return x;
1237 else
1239 return ident == Id.WinMain && linkage != LINK.c && !isMember();
1243 final bool isDllMain() const
1245 return ident == Id.DllMain && linkage != LINK.c && !isMember();
1248 final bool isRtInit() const
1250 return ident == Id.rt_init && linkage == LINK.c && !isMember() && !isNested();
1253 override final bool isExport() const
1255 return visibility.kind == Visibility.Kind.export_;
1258 override final bool isImportedSymbol() const
1260 //printf("isImportedSymbol()\n");
1261 //printf("protection = %d\n", visibility);
1262 return (visibility.kind == Visibility.Kind.export_) && !fbody;
1265 override final bool isCodeseg() const pure nothrow @nogc @safe
1267 return true; // functions are always in the code segment
1270 override final bool isOverloadable() const
1272 return true; // functions can be overloaded
1275 /***********************************
1276 * Override so it can work even if semantic() hasn't yet
1277 * been run.
1279 override final bool isAbstract()
1281 if (storage_class & STC.abstract_)
1282 return true;
1283 if (semanticRun >= PASS.semanticdone)
1284 return false;
1286 if (_scope)
1288 if (_scope.stc & STC.abstract_)
1289 return true;
1290 parent = _scope.parent;
1291 Dsymbol parent = toParent();
1292 if (parent.isInterfaceDeclaration())
1293 return true;
1295 return false;
1298 /**********************************
1299 * Decide if attributes for this function can be inferred from examining
1300 * the function body.
1301 * Returns:
1302 * true if can
1304 final bool canInferAttributes(Scope* sc)
1306 if (!fbody)
1307 return false;
1309 if (isVirtualMethod() &&
1311 * https://issues.dlang.org/show_bug.cgi?id=21719
1313 * If we have an auto virtual function we can infer
1314 * the attributes.
1316 !(inferRetType && !isCtorDeclaration()))
1317 return false; // since they may be overridden
1319 if (sc.func &&
1320 /********** this is for backwards compatibility for the moment ********/
1321 (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
1322 return true;
1324 if (isFuncLiteralDeclaration() || // externs are not possible with literals
1325 (storage_class & STC.inference) || // do attribute inference
1326 (inferRetType && !isCtorDeclaration()))
1327 return true;
1329 if (isInstantiated())
1331 auto ti = parent.isTemplateInstance();
1332 if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
1333 return true;
1336 return false;
1339 /*****************************************
1340 * Initialize for inferring the attributes of this function.
1342 final void initInferAttributes()
1344 //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1345 TypeFunction tf = type.toTypeFunction();
1346 if (tf.purity == PURE.impure) // purity not specified
1347 flags |= FUNCFLAG.purityInprocess;
1349 if (tf.trust == TRUST.default_)
1350 flags |= FUNCFLAG.safetyInprocess;
1352 if (!tf.isnothrow)
1353 flags |= FUNCFLAG.nothrowInprocess;
1355 if (!tf.isnogc)
1356 flags |= FUNCFLAG.nogcInprocess;
1358 if (!isVirtual() || introducing)
1359 flags |= FUNCFLAG.returnInprocess;
1361 // Initialize for inferring STC.scope_
1362 if (global.params.useDIP1000 == FeatureState.enabled)
1363 flags |= FUNCFLAG.inferScope;
1366 final PURE isPure()
1368 //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1369 TypeFunction tf = type.toTypeFunction();
1370 if (flags & FUNCFLAG.purityInprocess)
1371 setImpure();
1372 if (tf.purity == PURE.fwdref)
1373 tf.purityLevel();
1374 PURE purity = tf.purity;
1375 if (purity > PURE.weak && isNested())
1376 purity = PURE.weak;
1377 if (purity > PURE.weak && needThis())
1379 // The attribute of the 'this' reference affects purity strength
1380 if (type.mod & MODFlags.immutable_)
1383 else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
1384 purity = PURE.const_;
1385 else
1386 purity = PURE.weak;
1388 tf.purity = purity;
1389 // ^ This rely on the current situation that every FuncDeclaration has a
1390 // unique TypeFunction.
1391 return purity;
1394 final PURE isPureBypassingInference()
1396 if (flags & FUNCFLAG.purityInprocess)
1397 return PURE.fwdref;
1398 else
1399 return isPure();
1402 /**************************************
1403 * The function is doing something impure,
1404 * so mark it as impure.
1405 * If there's a purity error, return true.
1407 extern (D) final bool setImpure()
1409 if (flags & FUNCFLAG.purityInprocess)
1411 flags &= ~FUNCFLAG.purityInprocess;
1412 if (fes)
1413 fes.func.setImpure();
1415 else if (isPure())
1416 return true;
1417 return false;
1420 final bool isSafe()
1422 if (flags & FUNCFLAG.safetyInprocess)
1423 setUnsafe();
1424 return type.toTypeFunction().trust == TRUST.safe;
1427 final bool isSafeBypassingInference()
1429 return !(flags & FUNCFLAG.safetyInprocess) && isSafe();
1432 final bool isTrusted()
1434 if (flags & FUNCFLAG.safetyInprocess)
1435 setUnsafe();
1436 return type.toTypeFunction().trust == TRUST.trusted;
1439 /**************************************
1440 * The function is doing something unsafe,
1441 * so mark it as unsafe.
1442 * If there's a safe error, return true.
1444 extern (D) final bool setUnsafe()
1446 if (flags & FUNCFLAG.safetyInprocess)
1448 flags &= ~FUNCFLAG.safetyInprocess;
1449 type.toTypeFunction().trust = TRUST.system;
1450 if (fes)
1451 fes.func.setUnsafe();
1453 else if (isSafe())
1454 return true;
1455 return false;
1458 final bool isNogc()
1460 //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1461 if (flags & FUNCFLAG.nogcInprocess)
1462 setGC();
1463 return type.toTypeFunction().isnogc;
1466 final bool isNogcBypassingInference()
1468 return !(flags & FUNCFLAG.nogcInprocess) && isNogc();
1471 /**************************************
1472 * The function is doing something that may allocate with the GC,
1473 * so mark it as not nogc (not no-how).
1474 * Returns:
1475 * true if function is marked as @nogc, meaning a user error occurred
1477 extern (D) final bool setGC()
1479 //printf("setGC() %s\n", toChars());
1480 if (flags & FUNCFLAG.nogcInprocess && semanticRun < PASS.semantic3 && _scope)
1482 this.semantic2(_scope);
1483 this.semantic3(_scope);
1486 if (flags & FUNCFLAG.nogcInprocess)
1488 flags &= ~FUNCFLAG.nogcInprocess;
1489 type.toTypeFunction().isnogc = false;
1490 if (fes)
1491 fes.func.setGC();
1493 else if (isNogc())
1494 return true;
1495 return false;
1498 extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
1500 if (!global.params.vgc)
1501 return;
1503 Module m = getModule();
1504 if (m && m.isRoot() && !inUnittest())
1506 message(loc, "vgc: %s", warn);
1510 /********************************************
1511 * See if pointers from function parameters, mutable globals, or uplevel functions
1512 * could leak into return value.
1513 * Returns:
1514 * true if the function return value is isolated from
1515 * any inputs to the function
1517 extern (D) final bool isReturnIsolated()
1519 //printf("isReturnIsolated(this: %s)\n", this.toChars);
1520 TypeFunction tf = type.toTypeFunction();
1521 assert(tf.next);
1523 Type treti = tf.next;
1524 if (tf.isref)
1525 return isTypeIsolatedIndirect(treti); // check influence from parameters
1527 return isTypeIsolated(treti);
1530 /********************
1531 * See if pointers from function parameters, mutable globals, or uplevel functions
1532 * could leak into type `t`.
1533 * Params:
1534 * t = type to check if it is isolated
1535 * Returns:
1536 * true if `t` is isolated from
1537 * any inputs to the function
1539 extern (D) final bool isTypeIsolated(Type t)
1541 StringTable!Type parentTypes;
1542 const uniqueTypeID = t.getUniqueID();
1543 if (uniqueTypeID)
1545 const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
1546 if (cacheResultPtr !is null)
1547 return *cacheResultPtr;
1549 parentTypes._init();
1550 const isIsolated = isTypeIsolated(t, parentTypes);
1551 isTypeIsolatedCache[uniqueTypeID] = isIsolated;
1552 return isIsolated;
1554 else
1556 parentTypes._init();
1557 return isTypeIsolated(t, parentTypes);
1561 ///ditto
1562 extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
1564 //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
1566 t = t.baseElemOf();
1567 switch (t.ty)
1569 case Tarray:
1570 case Tpointer:
1571 return isTypeIsolatedIndirect(t.nextOf()); // go down one level
1573 case Taarray:
1574 case Tclass:
1575 return isTypeIsolatedIndirect(t);
1577 case Tstruct:
1578 /* Drill down and check the struct's fields
1580 auto sym = t.toDsymbol(null).isStructDeclaration();
1581 const tName = t.toChars.toDString;
1582 const entry = parentTypes.insert(tName, t);
1583 if (entry == null)
1585 //we've already seen this type in a parent, not isolated
1586 return false;
1588 foreach (v; sym.fields)
1590 Type tmi = v.type.addMod(t.mod);
1591 //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
1592 // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
1593 if (!isTypeIsolated(tmi, parentTypes))
1594 return false;
1596 return true;
1598 default:
1599 return true;
1603 /********************************************
1604 * Params:
1605 * t = type of object to test one level of indirection down
1606 * Returns:
1607 * true if an object typed `t` has no indirections
1608 * which could have come from the function's parameters, mutable
1609 * globals, or uplevel functions.
1611 private bool isTypeIsolatedIndirect(Type t)
1613 //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1614 assert(t);
1616 /* Since `t` is one level down from an indirection, it could pick
1617 * up a reference to a mutable global or an outer function, so
1618 * return false.
1620 if (!isPureBypassingInference() || isNested())
1621 return false;
1623 TypeFunction tf = type.toTypeFunction();
1625 //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1627 foreach (i, fparam; tf.parameterList)
1629 Type tp = fparam.type;
1630 if (!tp)
1631 continue;
1633 if (fparam.storageClass & (STC.lazy_ | STC.out_ | STC.ref_))
1635 if (!traverseIndirections(tp, t))
1636 return false;
1637 continue;
1640 /* Goes down one level of indirection, then calls traverseIndirection() on
1641 * the result.
1642 * Returns:
1643 * true if t is isolated from tp
1645 static bool traverse(Type tp, Type t)
1647 tp = tp.baseElemOf();
1648 switch (tp.ty)
1650 case Tarray:
1651 case Tpointer:
1652 return traverseIndirections(tp.nextOf(), t);
1654 case Taarray:
1655 case Tclass:
1656 return traverseIndirections(tp, t);
1658 case Tstruct:
1659 /* Drill down and check the struct's fields
1661 auto sym = tp.toDsymbol(null).isStructDeclaration();
1662 foreach (v; sym.fields)
1664 Type tprmi = v.type.addMod(tp.mod);
1665 //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1666 if (!traverse(tprmi, t))
1667 return false;
1669 return true;
1671 default:
1672 return true;
1676 if (!traverse(tp, t))
1677 return false;
1679 // The 'this' reference is a parameter, too
1680 if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
1682 Type tthis = ad.getType().addMod(tf.mod);
1683 //printf("\ttthis = %s\n", tthis.toChars());
1684 if (!traverseIndirections(tthis, t))
1685 return false;
1688 return true;
1691 /****************************************
1692 * Determine if function needs a static frame pointer.
1693 * Returns:
1694 * `true` if function is really nested within other function.
1695 * Contracts:
1696 * If isNested() returns true, isThis() should return false,
1697 * unless the function needs a dual-context pointer.
1699 bool isNested() const
1701 auto f = toAliasFunc();
1702 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1703 return ((f.storage_class & STC.static_) == 0) &&
1704 (f.linkage == LINK.d) &&
1705 (f.toParent2().isFuncDeclaration() !is null ||
1706 f.toParent2() !is f.toParentLocal());
1709 /****************************************
1710 * Determine if function is a non-static member function
1711 * that has an implicit 'this' expression.
1712 * Returns:
1713 * The aggregate it is a member of, or null.
1714 * Contracts:
1715 * Both isThis() and isNested() should return true if function needs a dual-context pointer,
1716 * otherwise if isThis() returns true, isNested() should return false.
1718 override inout(AggregateDeclaration) isThis() inout
1720 //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1721 auto ad = (storage_class & STC.static_) ? .objc.isThis(this) : isMemberLocal();
1722 //printf("-FuncDeclaration::isThis() %p\n", ad);
1723 return ad;
1726 override final bool needThis()
1728 //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1729 return toAliasFunc().isThis() !is null;
1732 // Determine if a function is pedantically virtual
1733 final bool isVirtualMethod()
1735 if (toAliasFunc() != this)
1736 return toAliasFunc().isVirtualMethod();
1738 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1739 if (!isVirtual())
1740 return false;
1741 // If it's a final method, and does not override anything, then it is not virtual
1742 if (isFinalFunc() && foverrides.dim == 0)
1744 return false;
1746 return true;
1749 // Determine if function goes into virtual function pointer table
1750 bool isVirtual() const
1752 if (toAliasFunc() != this)
1753 return toAliasFunc().isVirtual();
1755 auto p = toParent();
1757 if (!isMember || !p.isClassDeclaration)
1758 return false;
1760 if (p.isClassDeclaration.classKind == ClassKind.objc)
1761 return .objc.isVirtual(this);
1763 version (none)
1765 printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1766 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), visibility == Visibility.Kind.private_, isCtorDeclaration(), linkage != LINK.d);
1767 printf("result is %d\n", isMember() && !(isStatic() || visibility == Visibility.Kind.private_ || visibility == Visibility.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()));
1769 return !(isStatic() || visibility.kind == Visibility.Kind.private_ || visibility.kind == Visibility.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc());
1772 final bool isFinalFunc() const
1774 if (toAliasFunc() != this)
1775 return toAliasFunc().isFinalFunc();
1777 version (none)
1779 auto cd = toParent().isClassDeclaration();
1780 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal());
1781 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_));
1782 printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_)));
1783 if (cd)
1784 printf("\tmember of %s\n", cd.toChars());
1786 if (!isMember())
1787 return false;
1788 if (Declaration.isFinal())
1789 return true;
1790 auto cd = toParent().isClassDeclaration();
1791 return (cd !is null) && (cd.storage_class & STC.final_);
1794 bool addPreInvariant()
1796 auto ad = isThis();
1797 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1798 return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked);
1801 bool addPostInvariant()
1803 auto ad = isThis();
1804 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1805 return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked);
1808 override const(char)* kind() const
1810 return generated ? "generated function" : "function";
1813 /********************************************
1814 * Returns:
1815 * true if there are no overloads of this function
1817 final bool isUnique() const
1819 bool result = false;
1820 overloadApply(cast() this, (Dsymbol s)
1822 auto f = s.isFuncDeclaration();
1823 if (!f)
1824 return 0;
1825 if (result)
1827 result = false;
1828 return 1; // ambiguous, done
1830 else
1832 result = true;
1833 return 0;
1836 return result;
1839 /*********************************************
1840 * In the current function, we are calling 'this' function.
1841 * 1. Check to see if the current function can call 'this' function, issue error if not.
1842 * 2. If the current function is not the parent of 'this' function, then add
1843 * the current function to the list of siblings of 'this' function.
1844 * 3. If the current function is a literal, and it's accessing an uplevel scope,
1845 * then mark it as a delegate.
1846 * Returns true if error occurs.
1848 extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
1850 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
1852 if (auto fld = this.isFuncLiteralDeclaration())
1854 if (fld.tok == TOK.reserved)
1856 fld.tok = TOK.function_;
1857 fld.vthis = null;
1861 if (!parent || parent == sc.parent)
1862 return false;
1863 if (ident == Id.require || ident == Id.ensure)
1864 return false;
1865 if (!isThis() && !isNested())
1866 return false;
1868 // The current function
1869 FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
1870 if (!fdthis)
1871 return false; // out of function scope
1873 Dsymbol p = toParentLocal();
1874 Dsymbol p2 = toParent2();
1876 // Function literals from fdthis to p must be delegates
1877 ensureStaticLinkTo(fdthis, p);
1878 if (p != p2)
1879 ensureStaticLinkTo(fdthis, p2);
1881 if (isNested())
1883 // The function that this function is in
1884 bool checkEnclosing(FuncDeclaration fdv)
1886 if (!fdv)
1887 return false;
1888 if (fdv == fdthis)
1889 return false;
1891 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
1892 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
1893 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
1895 // Add this function to the list of those which called us
1896 if (fdthis != this)
1898 bool found = false;
1899 for (size_t i = 0; i < siblingCallers.dim; ++i)
1901 if (siblingCallers[i] == fdthis)
1902 found = true;
1904 if (!found)
1906 //printf("\tadding sibling %s\n", fdthis.toPrettyChars());
1907 if (!sc.intypeof && !(sc.flags & SCOPE.compile))
1908 siblingCallers.push(fdthis);
1912 const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this);
1913 if (lv == LevelError)
1914 return true; // error
1915 if (lv == -1)
1916 return false; // downlevel call
1917 if (lv == 0)
1918 return false; // same level call
1920 return false; // Uplevel call
1923 if (checkEnclosing(p.isFuncDeclaration()))
1924 return true;
1925 if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
1926 return true;
1928 return false;
1931 /*******************************
1932 * Look at all the variables in this function that are referenced
1933 * by nested functions, and determine if a closure needs to be
1934 * created for them.
1936 final bool needsClosure()
1938 /* Need a closure for all the closureVars[] if any of the
1939 * closureVars[] are accessed by a
1940 * function that escapes the scope of this function.
1941 * We take the conservative approach and decide that a function needs
1942 * a closure if it:
1943 * 1) is a virtual function
1944 * 2) has its address taken
1945 * 3) has a parent that escapes
1946 * 4) calls another nested function that needs a closure
1948 * Note that since a non-virtual function can be called by
1949 * a virtual one, if that non-virtual function accesses a closure
1950 * var, the closure still has to be taken. Hence, we check for isThis()
1951 * instead of isVirtual(). (thanks to David Friedman)
1953 * When the function returns a local struct or class, `requiresClosure`
1954 * is already set to `true` upon entering this function when the
1955 * struct/class refers to a local variable and a closure is needed.
1958 //printf("FuncDeclaration::needsClosure() %s\n", toChars());
1960 if (requiresClosure)
1961 goto Lyes;
1963 for (size_t i = 0; i < closureVars.dim; i++)
1965 VarDeclaration v = closureVars[i];
1966 //printf("\tv = %s\n", v.toChars());
1968 for (size_t j = 0; j < v.nestedrefs.dim; j++)
1970 FuncDeclaration f = v.nestedrefs[j];
1971 assert(f != this);
1973 /* __require and __ensure will always get called directly,
1974 * so they never make outer functions closure.
1976 if (f.ident == Id.require || f.ident == Id.ensure)
1977 continue;
1979 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
1981 /* Look to see if f escapes. We consider all parents of f within
1982 * this, and also all siblings which call f; if any of them escape,
1983 * so does f.
1984 * Mark all affected functions as requiring closures.
1986 for (Dsymbol s = f; s && s != this; s = s.toParentP(this))
1988 FuncDeclaration fx = s.isFuncDeclaration();
1989 if (!fx)
1990 continue;
1991 if (fx.isThis() || fx.tookAddressOf)
1993 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
1995 /* Mark as needing closure any functions between this and f
1997 markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this);
1999 requiresClosure = true;
2002 /* We also need to check if any sibling functions that
2003 * called us, have escaped. This is recursive: we need
2004 * to check the callers of our siblings.
2006 if (checkEscapingSiblings(fx, this))
2007 requiresClosure = true;
2009 /* https://issues.dlang.org/show_bug.cgi?id=12406
2010 * Iterate all closureVars to mark all descendant
2011 * nested functions that access to the closing context of this function.
2016 if (requiresClosure)
2017 goto Lyes;
2019 return false;
2021 Lyes:
2022 //printf("\tneeds closure\n");
2023 return true;
2026 /***********************************************
2027 * Check that the function contains any closure.
2028 * If it's @nogc, report suitable errors.
2029 * This is mostly consistent with FuncDeclaration::needsClosure().
2031 * Returns:
2032 * true if any errors occur.
2034 extern (D) final bool checkClosure()
2036 if (!needsClosure())
2037 return false;
2039 if (setGC())
2041 error("is `@nogc` yet allocates closures with the GC");
2042 if (global.gag) // need not report supplemental errors
2043 return true;
2045 else
2047 printGCUsage(loc, "using closure causes GC allocation");
2048 return false;
2051 FuncDeclarations a;
2052 foreach (v; closureVars)
2054 foreach (f; v.nestedrefs)
2056 assert(f !is this);
2058 LcheckAncestorsOfANestedRef:
2059 for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
2061 auto fx = s.isFuncDeclaration();
2062 if (!fx)
2063 continue;
2064 if (fx.isThis() ||
2065 fx.tookAddressOf ||
2066 checkEscapingSiblings(fx, this))
2068 foreach (f2; a)
2070 if (f2 == f)
2071 break LcheckAncestorsOfANestedRef;
2073 a.push(f);
2074 .errorSupplemental(f.loc, "%s closes over variable %s at %s",
2075 f.toPrettyChars(), v.toChars(), v.loc.toChars());
2076 break LcheckAncestorsOfANestedRef;
2082 return true;
2085 /***********************************************
2086 * Determine if function's variables are referenced by a function
2087 * nested within it.
2089 final bool hasNestedFrameRefs()
2091 if (closureVars.dim)
2092 return true;
2094 /* If a virtual function has contracts, assume its variables are referenced
2095 * by those contracts, even if they aren't. Because they might be referenced
2096 * by the overridden or overriding function's contracts.
2097 * This can happen because frequire and fensure are implemented as nested functions,
2098 * and they can be called directly by an overriding function and the overriding function's
2099 * context had better match, or
2100 * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
2102 if (fdrequire || fdensure)
2103 return true;
2105 if (foverrides.dim && isVirtualMethod())
2107 for (size_t i = 0; i < foverrides.dim; i++)
2109 FuncDeclaration fdv = foverrides[i];
2110 if (fdv.hasNestedFrameRefs())
2111 return true;
2114 return false;
2117 /****************************************************
2118 * Check whether result variable can be built.
2119 * Returns:
2120 * `true` if the function has a return type that
2121 * is different from `void`.
2123 extern (D) private bool canBuildResultVar()
2125 auto f = cast(TypeFunction)type;
2126 return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
2129 /****************************************************
2130 * Declare result variable lazily.
2132 extern (D) final void buildResultVar(Scope* sc, Type tret)
2134 if (!vresult)
2136 Loc loc = fensure ? fensure.loc : this.loc;
2138 /* If inferRetType is true, tret may not be a correct return type yet.
2139 * So, in here it may be a temporary type for vresult, and after
2140 * fbody.dsymbolSemantic() running, vresult.type might be modified.
2142 vresult = new VarDeclaration(loc, tret, Id.result, null);
2143 vresult.storage_class |= STC.nodtor | STC.temp;
2144 if (!isVirtual())
2145 vresult.storage_class |= STC.const_;
2146 vresult.storage_class |= STC.result;
2148 // set before the semantic() for checkNestedReference()
2149 vresult.parent = this;
2152 if (sc && vresult.semanticRun == PASS.init)
2154 TypeFunction tf = type.toTypeFunction();
2155 if (tf.isref)
2156 vresult.storage_class |= STC.ref_;
2157 vresult.type = tret;
2159 vresult.dsymbolSemantic(sc);
2161 if (!sc.insert(vresult))
2162 error("out result %s is already defined", vresult.toChars());
2163 assert(vresult.parent == this);
2167 /****************************************************
2168 * Merge into this function the 'in' contracts of all it overrides.
2169 * 'in's are OR'd together, i.e. only one of them needs to pass.
2171 extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
2173 /* If a base function and its override both have an IN contract, then
2174 * only one of them needs to succeed. This is done by generating:
2176 * void derived.in() {
2177 * try {
2178 * base.in();
2180 * catch () {
2181 * ... body of derived.in() ...
2185 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2186 * If base.in() throws, then derived.in()'s body is executed.
2189 foreach (fdv; foverrides)
2191 /* The semantic pass on the contracts of the overridden functions must
2192 * be completed before code generation occurs.
2193 * https://issues.dlang.org/show_bug.cgi?id=3602
2195 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2197 assert(fdv._scope);
2198 Scope* sc = fdv._scope.push();
2199 sc.stc &= ~STC.override_;
2200 fdv.semantic3(sc);
2201 sc.pop();
2204 sf = fdv.mergeFrequire(sf, params);
2205 if (!sf || !fdv.fdrequire)
2206 return null;
2207 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2208 /* Make the call:
2209 * try { __require(params); }
2210 * catch (Throwable) { frequire; }
2212 params = Expression.arraySyntaxCopy(params);
2213 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2214 Statement s2 = new ExpStatement(loc, e);
2216 auto c = new Catch(loc, getThrowable(), null, sf);
2217 c.internalCatch = true;
2218 auto catches = new Catches();
2219 catches.push(c);
2220 sf = new TryCatchStatement(loc, s2, catches);
2222 return sf;
2225 /****************************************************
2226 * Merge into this function the 'in' contracts of all it overrides.
2228 extern (D) final Statement mergeFrequireInclusivePreview(Statement sf, Expressions* params)
2230 /* If a base function and its override both have an IN contract, then
2231 * the override in contract must widen the guarantee of the base contract.
2232 * This is checked by generating:
2234 * void derived.in() {
2235 * try {
2236 * ... body of derived.in() ...
2238 * catch () {
2239 * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
2240 * base.in();
2241 * assert(false, "Logic error: " ~ thr.msg);
2245 foreach (fdv; foverrides)
2247 /* The semantic pass on the contracts of the overridden functions must
2248 * be completed before code generation occurs.
2249 * https://issues.dlang.org/show_bug.cgi?id=3602
2251 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2253 assert(fdv._scope);
2254 Scope* sc = fdv._scope.push();
2255 sc.stc &= ~STC.override_;
2256 fdv.semantic3(sc);
2257 sc.pop();
2260 sf = fdv.mergeFrequireInclusivePreview(sf, params);
2261 if (sf && fdv.fdrequire)
2263 const loc = this.fdrequire.loc;
2265 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2266 /* Make the call:
2267 * try { frequire; }
2268 * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
2270 Identifier id = Identifier.generateId("thr");
2271 params = Expression.arraySyntaxCopy(params);
2272 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2273 Statement s2 = new ExpStatement(loc, e);
2274 // assert(false, ...)
2275 // TODO make this a runtime helper to allow:
2276 // - chaining the original expression
2277 // - nogc concatenation
2278 Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
2279 Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
2281 Statement s3 = new CompoundStatement(loc, s2, fail);
2283 auto c = new Catch(loc, getThrowable(), id, s3);
2284 c.internalCatch = true;
2285 auto catches = new Catches();
2286 catches.push(c);
2287 sf = new TryCatchStatement(loc, sf, catches);
2289 else
2290 return null;
2292 return sf;
2295 /****************************************************
2296 * Determine whether an 'out' contract is declared inside
2297 * the given function or any of its overrides.
2298 * Params:
2299 * fd = the function to search
2300 * Returns:
2301 * true found an 'out' contract
2303 static bool needsFensure(FuncDeclaration fd)
2305 if (fd.fensures)
2306 return true;
2308 foreach (fdv; fd.foverrides)
2310 if (needsFensure(fdv))
2311 return true;
2313 return false;
2316 /****************************************************
2317 * Rewrite contracts as statements.
2319 final void buildEnsureRequire()
2322 if (frequires)
2324 /* in { statements1... }
2325 * in { statements2... }
2326 * ...
2327 * becomes:
2328 * in { { statements1... } { statements2... } ... }
2330 assert(frequires.dim);
2331 auto loc = (*frequires)[0].loc;
2332 auto s = new Statements;
2333 foreach (r; *frequires)
2335 s.push(new ScopeStatement(r.loc, r, r.loc));
2337 frequire = new CompoundStatement(loc, s);
2340 if (fensures)
2342 /* out(id1) { statements1... }
2343 * out(id2) { statements2... }
2344 * ...
2345 * becomes:
2346 * out(__result) { { ref id1 = __result; { statements1... } }
2347 * { ref id2 = __result; { statements2... } } ... }
2349 assert(fensures.dim);
2350 auto loc = (*fensures)[0].ensure.loc;
2351 auto s = new Statements;
2352 foreach (r; *fensures)
2354 if (r.id && canBuildResultVar())
2356 auto rloc = r.ensure.loc;
2357 auto resultId = new IdentifierExp(rloc, Id.result);
2358 auto init = new ExpInitializer(rloc, resultId);
2359 auto stc = STC.ref_ | STC.temp | STC.result;
2360 auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
2361 auto sdecl = new ExpStatement(rloc, decl);
2362 s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
2364 else
2366 s.push(r.ensure);
2369 fensure = new CompoundStatement(loc, s);
2372 if (!isVirtual())
2373 return;
2375 /* Rewrite contracts as nested functions, then call them. Doing it as nested
2376 * functions means that overriding functions can call them.
2378 TypeFunction f = cast(TypeFunction) type;
2380 /* Make a copy of the parameters and make them all ref */
2381 static Parameters* toRefCopy(ParameterList parameterList)
2383 auto result = new Parameters();
2385 foreach (n, p; parameterList)
2387 p = p.syntaxCopy();
2388 if (!(p.storageClass & STC.lazy_))
2389 p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
2390 p.defaultArg = null; // won't be the same with ref
2391 result.push(p);
2394 return result;
2397 if (frequire)
2399 /* in { ... }
2400 * becomes:
2401 * void __require(ref params) { ... }
2402 * __require(params);
2404 Loc loc = frequire.loc;
2405 fdrequireParams = new Expressions();
2406 if (parameters)
2408 foreach (vd; *parameters)
2409 fdrequireParams.push(new VarExp(loc, vd));
2411 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2412 auto fparams = toRefCopy(fo.parameterList);
2413 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2414 tf.isnothrow = f.isnothrow;
2415 tf.isnogc = f.isnogc;
2416 tf.purity = f.purity;
2417 tf.trust = f.trust;
2418 auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
2419 fd.fbody = frequire;
2420 Statement s1 = new ExpStatement(loc, fd);
2421 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
2422 Statement s2 = new ExpStatement(loc, e);
2423 frequire = new CompoundStatement(loc, s1, s2);
2424 fdrequire = fd;
2427 /* We need to set fdensureParams here and not in the block below to
2428 * have the parameters available when calling a base class ensure(),
2429 * even if this function doesn't have an out contract.
2431 fdensureParams = new Expressions();
2432 if (canBuildResultVar())
2433 fdensureParams.push(new IdentifierExp(loc, Id.result));
2434 if (parameters)
2436 foreach (vd; *parameters)
2437 fdensureParams.push(new VarExp(loc, vd));
2440 if (fensure)
2442 /* out (result) { ... }
2443 * becomes:
2444 * void __ensure(ref tret result, ref params) { ... }
2445 * __ensure(result, params);
2447 Loc loc = fensure.loc;
2448 auto fparams = new Parameters();
2449 if (canBuildResultVar())
2451 Parameter p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
2452 fparams.push(p);
2454 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2455 fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
2456 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2457 tf.isnothrow = f.isnothrow;
2458 tf.isnogc = f.isnogc;
2459 tf.purity = f.purity;
2460 tf.trust = f.trust;
2461 auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
2462 fd.fbody = fensure;
2463 Statement s1 = new ExpStatement(loc, fd);
2464 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
2465 Statement s2 = new ExpStatement(loc, e);
2466 fensure = new CompoundStatement(loc, s1, s2);
2467 fdensure = fd;
2471 /****************************************************
2472 * Merge into this function the 'out' contracts of all it overrides.
2473 * 'out's are AND'd together, i.e. all of them need to pass.
2475 extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
2477 /* Same comments as for mergeFrequire(), except that we take care
2478 * of generating a consistent reference to the 'result' local by
2479 * explicitly passing 'result' to the nested function as a reference
2480 * argument.
2481 * This won't work for the 'this' parameter as it would require changing
2482 * the semantic code for the nested function so that it looks on the parameter
2483 * list for the 'this' pointer, something that would need an unknown amount
2484 * of tweaking of various parts of the compiler that I'd rather leave alone.
2486 foreach (fdv; foverrides)
2488 /* The semantic pass on the contracts of the overridden functions must
2489 * be completed before code generation occurs.
2490 * https://issues.dlang.org/show_bug.cgi?id=3602 and
2491 * https://issues.dlang.org/show_bug.cgi?id=5230
2493 if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
2495 assert(fdv._scope);
2496 Scope* sc = fdv._scope.push();
2497 sc.stc &= ~STC.override_;
2498 fdv.semantic3(sc);
2499 sc.pop();
2502 sf = fdv.mergeFensure(sf, oid, params);
2503 if (fdv.fdensure)
2505 //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2506 // Make the call: __ensure(result, params)
2507 params = Expression.arraySyntaxCopy(params);
2508 if (canBuildResultVar())
2510 Type t1 = fdv.type.nextOf().toBasetype();
2511 Type t2 = this.type.nextOf().toBasetype();
2512 if (t1.isBaseOf(t2, null))
2514 /* Making temporary reference variable is necessary
2515 * in covariant return.
2516 * https://issues.dlang.org/show_bug.cgi?id=5204
2517 * https://issues.dlang.org/show_bug.cgi?id=10479
2519 Expression* eresult = &(*params)[0];
2520 auto ei = new ExpInitializer(Loc.initial, *eresult);
2521 auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
2522 v.storage_class |= STC.temp;
2523 auto de = new DeclarationExp(Loc.initial, v);
2524 auto ve = new VarExp(Loc.initial, v);
2525 *eresult = new CommaExp(Loc.initial, de, ve);
2528 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
2529 Statement s2 = new ExpStatement(loc, e);
2531 if (sf)
2533 sf = new CompoundStatement(sf.loc, s2, sf);
2535 else
2536 sf = s2;
2539 return sf;
2542 /*********************************************
2543 * Returns: the function's parameter list, and whether
2544 * it is variadic or not.
2546 final ParameterList getParameterList()
2548 if (type)
2550 TypeFunction fdtype = type.isTypeFunction();
2551 if (fdtype) // Could also be TypeError
2552 return fdtype.parameterList;
2555 return ParameterList(null, VarArg.none);
2558 /**********************************
2559 * Generate a FuncDeclaration for a runtime library function.
2561 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
2563 return genCfunc(fparams, treturn, Identifier.idPool(name, cast(uint)strlen(name)), stc);
2566 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
2568 FuncDeclaration fd;
2569 TypeFunction tf;
2570 Dsymbol s;
2571 __gshared DsymbolTable st = null;
2573 //printf("genCfunc(name = '%s')\n", id.toChars());
2574 //printf("treturn\n\t"); treturn.print();
2576 // See if already in table
2577 if (!st)
2578 st = new DsymbolTable();
2579 s = st.lookup(id);
2580 if (s)
2582 fd = s.isFuncDeclaration();
2583 assert(fd);
2584 assert(fd.type.nextOf().equals(treturn));
2586 else
2588 tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc);
2589 fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf);
2590 fd.visibility = Visibility(Visibility.Kind.public_);
2591 fd.linkage = LINK.c;
2593 st.insert(fd);
2595 return fd;
2598 /******************
2599 * Check parameters and return type of D main() function.
2600 * Issue error messages.
2602 extern (D) final void checkDmain()
2604 TypeFunction tf = type.toTypeFunction();
2605 const nparams = tf.parameterList.length;
2606 bool argerr;
2607 if (nparams == 1)
2609 auto fparam0 = tf.parameterList[0];
2610 auto t = fparam0.type.toBasetype();
2611 if (t.ty != Tarray ||
2612 t.nextOf().ty != Tarray ||
2613 t.nextOf().nextOf().ty != Tchar ||
2614 fparam0.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
2616 argerr = true;
2620 if (!tf.nextOf())
2621 // auto main(), check after semantic
2622 assert(this.inferRetType);
2623 else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid && tf.nextOf().ty != Tnoreturn)
2624 error("must return `int`, `void` or `noreturn`, not `%s`", tf.nextOf().toChars());
2625 else if (tf.parameterList.varargs || nparams >= 2 || argerr)
2626 error("parameters must be `main()` or `main(string[] args)`");
2629 /***********************************************
2630 * Check all return statements for a function to verify that returning
2631 * using NRVO is possible.
2633 * Returns:
2634 * `false` if the result cannot be returned by hidden reference.
2636 final bool checkNRVO()
2638 if (!nrvo_can || returns is null)
2639 return false;
2641 auto tf = type.toTypeFunction();
2642 if (tf.isref)
2643 return false;
2645 foreach (rs; *returns)
2647 if (auto ve = rs.exp.isVarExp())
2649 auto v = ve.var.isVarDeclaration();
2650 if (!v || v.isOut() || v.isRef())
2651 return false;
2652 else if (nrvo_var is null)
2654 // Variables in the data segment (e.g. globals, TLS or not),
2655 // parameters and closure variables cannot be NRVOed.
2656 if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
2657 return false;
2658 // The variable type needs to be equivalent to the return type.
2659 if (!v.type.equivalent(tf.next))
2660 return false;
2661 //printf("Setting nrvo to %s\n", v.toChars());
2662 nrvo_var = v;
2664 else if (nrvo_var != v)
2665 return false;
2667 else //if (!exp.isLvalue()) // keep NRVO-ability
2668 return false;
2670 return true;
2673 override final inout(FuncDeclaration) isFuncDeclaration() inout
2675 return this;
2678 inout(FuncDeclaration) toAliasFunc() inout
2680 return this;
2683 override void accept(Visitor v)
2685 v.visit(this);
2689 /********************************************************
2690 * Generate Expression to call the invariant.
2691 * Input:
2692 * ad aggregate with the invariant
2693 * vthis variable with 'this'
2694 * Returns:
2695 * void expression that calls the invariant
2697 Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
2699 Expression e = null;
2700 // Call invariant directly only if it exists
2701 FuncDeclaration inv = ad.inv;
2702 ClassDeclaration cd = ad.isClassDeclaration();
2704 while (!inv && cd)
2706 cd = cd.baseClass;
2707 if (!cd)
2708 break;
2709 inv = cd.inv;
2711 if (inv)
2713 version (all)
2715 // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
2716 // For the correct mangling,
2717 // run attribute inference on inv if needed.
2718 inv.functionSemantic();
2721 //e = new DsymbolExp(Loc.initial, inv);
2722 //e = new CallExp(Loc.initial, e);
2723 //e = e.semantic(sc2);
2725 /* https://issues.dlang.org/show_bug.cgi?id=13113
2726 * Currently virtual invariant calls completely
2727 * bypass attribute enforcement.
2728 * Change the behavior of pre-invariant call by following it.
2730 e = new ThisExp(Loc.initial);
2731 e.type = ad.type.addMod(vthis.type.mod);
2732 e = new DotVarExp(Loc.initial, e, inv, false);
2733 e.type = inv.type;
2734 e = new CallExp(Loc.initial, e);
2735 e.type = Type.tvoid;
2737 return e;
2740 /***************************************************
2741 * Visit each overloaded function/template in turn, and call dg(s) on it.
2742 * Exit when no more, or dg(s) returns nonzero.
2744 * Params:
2745 * fstart = symbol to start from
2746 * dg = the delegate to be called on the overload
2747 * sc = context used to check if symbol is accessible (and therefore visible),
2748 * can be null
2750 * Returns:
2751 * ==0 continue
2752 * !=0 done (and the return value from the last dg() call)
2754 extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
2756 Dsymbol next;
2757 for (auto d = fstart; d; d = next)
2759 import dmd.access : checkSymbolAccess;
2760 if (auto od = d.isOverDeclaration())
2762 /* The scope is needed here to check whether a function in
2763 an overload set was added by means of a private alias (or a
2764 selective import). If the scope where the alias is created
2765 is imported somewhere, the overload set is visible, but the private
2766 alias is not.
2768 if (sc)
2770 if (checkSymbolAccess(sc, od))
2772 if (int r = overloadApply(od.aliassym, dg, sc))
2773 return r;
2776 else if (int r = overloadApply(od.aliassym, dg, sc))
2777 return r;
2778 next = od.overnext;
2780 else if (auto fa = d.isFuncAliasDeclaration())
2782 if (fa.hasOverloads)
2784 if (int r = overloadApply(fa.funcalias, dg, sc))
2785 return r;
2787 else if (auto fd = fa.toAliasFunc())
2789 if (int r = dg(fd))
2790 return r;
2792 else
2794 d.error("is aliased to a function");
2795 break;
2797 next = fa.overnext;
2799 else if (auto ad = d.isAliasDeclaration())
2801 if (sc)
2803 if (checkSymbolAccess(sc, ad))
2804 next = ad.toAlias();
2806 else
2807 next = ad.toAlias();
2808 if (next == ad)
2809 break;
2810 if (next == fstart)
2811 break;
2813 else if (auto td = d.isTemplateDeclaration())
2815 if (int r = dg(td))
2816 return r;
2817 next = td.overnext;
2819 else if (auto fd = d.isFuncDeclaration())
2821 if (int r = dg(fd))
2822 return r;
2823 next = fd.overnext;
2825 else if (auto os = d.isOverloadSet())
2827 foreach (ds; os.a)
2828 if (int r = dg(ds))
2829 return r;
2831 else
2833 d.error("is aliased to a function");
2834 break;
2835 // BUG: should print error message?
2838 return 0;
2842 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
2843 mismatching modifiers to `buf`.
2845 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
2846 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
2848 Params:
2849 buf = output buffer to write to
2850 lhsMod = modifier on the left-hand side
2851 lhsMod = modifier on the right-hand side
2853 Returns:
2855 A tuple with `isMutable` and `isNotShared` set
2856 if the `lhsMod` is missing those modifiers (compared to rhs).
2858 auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod)
2860 static struct Mismatches
2862 bool isNotShared;
2863 bool isMutable;
2866 Mismatches mismatches;
2868 bool bothMutable = ((lhsMod & rhsMod) == 0);
2869 bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0;
2870 bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_);
2872 if (lhsMod & MODFlags.shared_)
2873 buf.writestring("`shared` ");
2874 else if (sharedMismatch && !(lhsMod & MODFlags.immutable_))
2876 buf.writestring("non-shared ");
2877 mismatches.isNotShared = true;
2880 if (bothMutable && sharedMismatchOnly)
2883 else if (lhsMod & MODFlags.immutable_)
2884 buf.writestring("`immutable` ");
2885 else if (lhsMod & MODFlags.const_)
2886 buf.writestring("`const` ");
2887 else if (lhsMod & MODFlags.wild)
2888 buf.writestring("`inout` ");
2889 else
2891 buf.writestring("mutable ");
2892 mismatches.isMutable = true;
2895 return mismatches;
2899 unittest
2901 OutBuffer buf;
2902 auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0);
2903 assert(buf[] == "`shared` ");
2904 assert(!mismatches.isNotShared);
2906 buf.setsize(0);
2907 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_);
2908 assert(buf[] == "non-shared ");
2909 assert(mismatches.isNotShared);
2911 buf.setsize(0);
2912 mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0);
2913 assert(buf[] == "`const` ");
2914 assert(!mismatches.isMutable);
2916 buf.setsize(0);
2917 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_);
2918 assert(buf[] == "mutable ");
2919 assert(mismatches.isMutable);
2922 private const(char)* prependSpace(const(char)* str)
2924 if (!str || !*str) return "";
2926 return (" " ~ str.toDString() ~ "\0").ptr;
2929 /// Flag used by $(LREF resolveFuncCall).
2930 enum FuncResolveFlag : ubyte
2932 standard = 0, /// issue error messages, solve the call.
2933 quiet = 1, /// do not issue error message on no match, just return `null`.
2934 overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous
2935 /// matches and need explicit this.
2938 /*******************************************
2939 * Given a symbol that could be either a FuncDeclaration or
2940 * a function template, resolve it to a function symbol.
2941 * Params:
2942 * loc = instantiation location
2943 * sc = instantiation scope
2944 * s = instantiation symbol
2945 * tiargs = initial list of template arguments
2946 * tthis = if !NULL, the `this` argument type
2947 * fargs = arguments to function
2948 * flags = see $(LREF FuncResolveFlag).
2949 * Returns:
2950 * if match is found, then function symbol, else null
2952 FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
2953 Objects* tiargs, Type tthis, Expressions* fargs, FuncResolveFlag flags)
2955 if (!s)
2956 return null; // no match
2958 version (none)
2960 printf("resolveFuncCall('%s')\n", s.toChars());
2961 if (tthis)
2962 printf("\tthis: %s\n", tthis.toChars());
2963 if (fargs)
2965 for (size_t i = 0; i < fargs.dim; i++)
2967 Expression arg = (*fargs)[i];
2968 assert(arg.type);
2969 printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
2974 if (tiargs && arrayObjectIsError(tiargs) ||
2975 fargs && arrayObjectIsError(cast(Objects*)fargs))
2977 return null;
2980 MatchAccumulator m;
2981 functionResolve(m, s, loc, sc, tiargs, tthis, fargs, null);
2982 auto orig_s = s;
2984 if (m.last > MATCH.nomatch && m.lastf)
2986 if (m.count == 1) // exactly one match
2988 if (!(flags & FuncResolveFlag.quiet))
2989 m.lastf.functionSemantic();
2990 return m.lastf;
2992 if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
2994 return m.lastf;
2998 /* Failed to find a best match.
2999 * Do nothing or print error.
3001 if (m.last == MATCH.nomatch)
3003 // error was caused on matched function, not on the matching itself,
3004 // so return the function to produce a better diagnostic
3005 if (m.count == 1)
3006 return m.lastf;
3009 // We are done at this point, as the rest of this function generate
3010 // a diagnostic on invalid match
3011 if (flags & FuncResolveFlag.quiet)
3012 return null;
3014 auto fd = s.isFuncDeclaration();
3015 auto od = s.isOverDeclaration();
3016 auto td = s.isTemplateDeclaration();
3017 if (td && td.funcroot)
3018 s = fd = td.funcroot;
3020 OutBuffer tiargsBuf;
3021 arrayObjectsToBuffer(&tiargsBuf, tiargs);
3023 OutBuffer fargsBuf;
3024 fargsBuf.writeByte('(');
3025 argExpTypesToCBuffer(&fargsBuf, fargs);
3026 fargsBuf.writeByte(')');
3027 if (tthis)
3028 tthis.modToBuffer(&fargsBuf);
3030 // The call is ambiguous
3031 if (m.lastf && m.nextf)
3033 TypeFunction tf1 = m.lastf.type.toTypeFunction();
3034 TypeFunction tf2 = m.nextf.type.toTypeFunction();
3035 const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
3036 const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
3038 const(char)* mod1 = prependSpace(MODtoChars(tf1.mod));
3039 const(char)* mod2 = prependSpace(MODtoChars(tf2.mod));
3041 .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
3042 s.parent.toPrettyChars(), s.ident.toChars(),
3043 fargsBuf.peekChars(),
3044 m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1,
3045 m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2);
3046 return null;
3049 // no match, generate an error messages
3050 if (!fd)
3052 // all of overloads are templates
3053 if (td)
3055 .error(loc, "%s `%s.%s` cannot deduce function from argument types `!(%s)%s`",
3056 td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
3057 tiargsBuf.peekChars(), fargsBuf.peekChars());
3059 printCandidates(loc, td, sc.isDeprecated());
3060 return null;
3062 /* This case used to happen when several ctors are mixed in an agregate.
3063 A (bad) error message is already generated in overloadApply().
3064 see https://issues.dlang.org/show_bug.cgi?id=19729
3065 and https://issues.dlang.org/show_bug.cgi?id=17259
3067 if (!od)
3068 return null;
3071 if (od)
3073 .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
3074 od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
3075 return null;
3078 // remove when deprecation period of class allocators and deallocators is over
3079 if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
3080 return null;
3082 bool hasOverloads = fd.overnext !is null;
3083 auto tf = fd.type.isTypeFunction();
3084 // if type is an error, the original type should be there for better diagnostics
3085 if (!tf)
3086 tf = fd.originalType.toTypeFunction();
3088 if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch
3090 OutBuffer thisBuf, funcBuf;
3091 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
3092 auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
3093 if (hasOverloads)
3095 .error(loc, "none of the overloads of `%s` are callable using a %sobject",
3096 fd.ident.toChars(), thisBuf.peekChars());
3097 printCandidates(loc, fd, sc.isDeprecated());
3098 return null;
3101 const(char)* failMessage;
3102 functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
3103 if (failMessage)
3105 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3106 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3107 tf.modToChars(), fargsBuf.peekChars());
3108 errorSupplemental(loc, failMessage);
3109 return null;
3112 .error(loc, "%smethod `%s` is not callable using a %sobject",
3113 funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
3115 if (mismatches.isNotShared)
3116 .errorSupplemental(fd.loc, "Consider adding `shared` here");
3117 else if (mismatches.isMutable)
3118 .errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
3119 return null;
3122 //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
3123 if (hasOverloads)
3125 .error(loc, "none of the overloads of `%s` are callable using argument types `%s`",
3126 fd.toChars(), fargsBuf.peekChars());
3127 printCandidates(loc, fd, sc.isDeprecated());
3128 return null;
3131 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3132 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3133 tf.modToChars(), fargsBuf.peekChars());
3134 // re-resolve to check for supplemental message
3135 const(char)* failMessage;
3136 functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
3137 if (failMessage)
3138 errorSupplemental(loc, failMessage);
3139 return null;
3142 /*******************************************
3143 * Prints template and function overload candidates as supplemental errors.
3144 * Params:
3145 * loc = instantiation location
3146 * declaration = the declaration to print overload candidates for
3147 * showDeprecated = If `false`, `deprecated` function won't be shown
3149 private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
3150 if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
3152 // max num of overloads to print (-v overrides this).
3153 enum int DisplayLimit = 5;
3154 int displayed;
3155 const(char)* constraintsTip;
3157 // determine if the first candidate was printed
3158 bool printed = false;
3160 overloadApply(declaration, (Dsymbol s)
3162 Dsymbol nextOverload;
3164 if (auto fd = s.isFuncDeclaration())
3166 // Don't print overloads which have errors.
3167 // Not that if the whole overload set has errors, we'll never reach
3168 // this point so there's no risk of printing no candidate
3169 if (fd.errors || fd.type.ty == Terror)
3170 return 0;
3171 // Don't print disabled functions, or `deprecated` outside of deprecated scope
3172 if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
3173 return 0;
3175 const single_candidate = fd.overnext is null;
3176 auto tf = cast(TypeFunction) fd.type;
3177 .errorSupplemental(fd.loc,
3178 printed ? " `%s%s`" :
3179 single_candidate ? "Candidate is: `%s%s`" : "Candidates are: `%s%s`",
3180 fd.toPrettyChars(),
3181 parametersTypeToChars(tf.parameterList));
3182 printed = true;
3183 nextOverload = fd.overnext;
3185 else if (auto td = s.isTemplateDeclaration())
3187 import dmd.staticcond;
3189 const tmsg = td.toCharsNoConstraints();
3190 const cmsg = td.getConstraintEvalError(constraintsTip);
3192 const single_candidate = td.overnext is null;
3194 // add blank space if there are multiple candidates
3195 // the length of the blank space is `strlen("Candidates are: ")`
3197 if (cmsg)
3199 .errorSupplemental(td.loc,
3200 printed ? " `%s`\n%s" :
3201 single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
3202 tmsg, cmsg);
3203 printed = true;
3205 else
3207 .errorSupplemental(td.loc,
3208 printed ? " `%s`" :
3209 single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
3210 tmsg);
3211 printed = true;
3213 nextOverload = td.overnext;
3216 if (global.params.verbose || ++displayed < DisplayLimit)
3217 return 0;
3219 // Too many overloads to sensibly display.
3220 // Just show count of remaining overloads.
3221 int num = 0;
3222 overloadApply(nextOverload, (s) { ++num; return 0; });
3224 if (num > 0)
3225 .errorSupplemental(loc, "... (%d more, -v to show) ...", num);
3226 return 1; // stop iterating
3229 // Nothing was displayed, all overloads are either disabled or deprecated
3230 if (!displayed)
3231 .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
3232 // should be only in verbose mode
3233 if (constraintsTip)
3234 .tip(constraintsTip);
3237 /**************************************
3238 * Returns an indirect type one step from t.
3240 Type getIndirection(Type t)
3242 t = t.baseElemOf();
3243 if (t.ty == Tarray || t.ty == Tpointer)
3244 return t.nextOf().toBasetype();
3245 if (t.ty == Taarray || t.ty == Tclass)
3246 return t;
3247 if (t.ty == Tstruct)
3248 return t.hasPointers() ? t : null; // TODO
3250 // should consider TypeDelegate?
3251 return null;
3254 /**************************************
3255 * Performs type-based alias analysis between a newly created value and a pre-
3256 * existing memory reference:
3258 * Assuming that a reference A to a value of type `ta` was available to the code
3259 * that created a reference B to a value of type `tb`, it returns whether B
3260 * might alias memory reachable from A based on the types involved (either
3261 * directly or via any number of indirections in either A or B).
3263 * This relation is not symmetric in the two arguments. For example, a
3264 * a `const(int)` reference can point to a pre-existing `int`, but not the other
3265 * way round.
3267 * Examples:
3269 * ta, tb, result
3270 * `const(int)`, `int`, `false`
3271 * `int`, `const(int)`, `true`
3272 * `int`, `immutable(int)`, `false`
3273 * const(immutable(int)*), immutable(int)*, false // BUG: returns true
3275 * Params:
3276 * ta = value type being referred to
3277 * tb = referred to value type that could be constructed from ta
3279 * Returns:
3280 * true if reference to `tb` is isolated from reference to `ta`
3282 private bool traverseIndirections(Type ta, Type tb)
3284 //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
3286 static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
3288 //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
3289 ta = ta.baseElemOf();
3290 tb = tb.baseElemOf();
3292 // First, check if the pointed-to types are convertible to each other such
3293 // that they might alias directly.
3294 static bool mayAliasDirect(Type source, Type target)
3296 return
3297 // if source is the same as target or can be const-converted to target
3298 source.constConv(target) != MATCH.nomatch ||
3299 // if target is void and source can be const-converted to target
3300 (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
3303 if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
3305 //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3306 return false;
3308 if (ta.nextOf() && ta.nextOf() == tb.nextOf())
3310 //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3311 return true;
3314 if (tb.ty == Tclass || tb.ty == Tstruct)
3316 /* Traverse the type of each field of the aggregate
3318 bool* found = table.getLvalue(tb.deco);
3319 if (*found == true)
3320 return true; // We have already seen this symbol, break the cycle
3321 else
3322 *found = true;
3324 AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
3325 foreach (v; sym.fields)
3327 Type tprmi = v.type.addMod(tb.mod);
3328 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
3329 if (!traverse(ta, tprmi, table, reversePass))
3330 return false;
3333 else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
3335 Type tind = tb.nextOf();
3336 if (!traverse(ta, tind, table, reversePass))
3337 return false;
3339 else if (tb.hasPointers())
3341 // BUG: consider the context pointer of delegate types
3342 return false;
3345 // Still no match, so try breaking up ta if we have not done so yet.
3346 if (!reversePass)
3348 scope newTable = AssocArray!(const(char)*, bool)();
3349 return traverse(tb, ta, newTable, true);
3352 return true;
3355 // To handle arbitrary levels of indirections in both parameters, we
3356 // recursively descend into aggregate members/levels of indirection in both
3357 // `ta` and `tb` while avoiding cycles. Start with the original types.
3358 scope table = AssocArray!(const(char)*, bool)();
3359 const result = traverse(ta, tb, table, false);
3360 //printf(" returns %d\n", result);
3361 return result;
3364 /* For all functions between outerFunc and f, mark them as needing
3365 * a closure.
3367 private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc)
3369 for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc))
3371 FuncDeclaration fy = sx.isFuncDeclaration();
3372 if (fy && fy.closureVars.dim)
3374 /* fy needs a closure if it has closureVars[],
3375 * because the frame pointer in the closure will be accessed.
3377 fy.requiresClosure = true;
3382 /********
3383 * Given a nested function f inside a function outerFunc, check
3384 * if any sibling callers of f have escaped. If so, mark
3385 * all the enclosing functions as needing closures.
3386 * This is recursive: we need to check the callers of our siblings.
3387 * Note that nested functions can only call lexically earlier nested
3388 * functions, so loops are impossible.
3389 * Params:
3390 * f = inner function (nested within outerFunc)
3391 * outerFunc = outer function
3392 * p = for internal recursion use
3393 * Returns:
3394 * true if any closures were needed
3396 private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
3398 static struct PrevSibling
3400 PrevSibling* p;
3401 FuncDeclaration f;
3404 PrevSibling ps;
3405 ps.p = cast(PrevSibling*)p;
3406 ps.f = f;
3408 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
3409 bool bAnyClosures = false;
3410 for (size_t i = 0; i < f.siblingCallers.dim; ++i)
3412 FuncDeclaration g = f.siblingCallers[i];
3413 if (g.isThis() || g.tookAddressOf)
3415 markAsNeedingClosure(g, outerFunc);
3416 bAnyClosures = true;
3419 for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc))
3421 // A parent of the sibling had its address taken.
3422 // Assume escaping of parent affects its children, so needs propagating.
3423 // see https://issues.dlang.org/show_bug.cgi?id=19679
3424 FuncDeclaration parentFunc = parent.isFuncDeclaration;
3425 if (parentFunc && parentFunc.tookAddressOf)
3427 markAsNeedingClosure(parentFunc, outerFunc);
3428 bAnyClosures = true;
3432 PrevSibling* prev = cast(PrevSibling*)p;
3433 while (1)
3435 if (!prev)
3437 bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
3438 break;
3440 if (prev.f == g)
3441 break;
3442 prev = prev.p;
3445 //printf("\t%d\n", bAnyClosures);
3446 return bAnyClosures;
3449 /***********************************************************
3450 * Used as a way to import a set of functions from another scope into this one.
3452 extern (C++) final class FuncAliasDeclaration : FuncDeclaration
3454 FuncDeclaration funcalias;
3455 bool hasOverloads;
3457 extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true)
3459 super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type);
3460 assert(funcalias != this);
3461 this.funcalias = funcalias;
3463 this.hasOverloads = hasOverloads;
3464 if (hasOverloads)
3466 if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration())
3467 this.hasOverloads = fad.hasOverloads;
3469 else
3471 // for internal use
3472 assert(!funcalias.isFuncAliasDeclaration());
3473 this.hasOverloads = false;
3475 userAttribDecl = funcalias.userAttribDecl;
3478 override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
3480 return this;
3483 override const(char)* kind() const
3485 return "function alias";
3488 override inout(FuncDeclaration) toAliasFunc() inout
3490 return funcalias.toAliasFunc();
3493 override void accept(Visitor v)
3495 v.visit(this);
3499 /***********************************************************
3501 extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
3503 TOK tok; // TOK.function_ or TOK.delegate_
3504 Type treq; // target of return type inference
3506 // backend
3507 bool deferToObj;
3509 extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null)
3511 super(loc, endloc, null, STC.undefined_, type);
3512 this.ident = id ? id : Id.empty;
3513 this.tok = tok;
3514 this.fes = fes;
3515 // Always infer scope for function literals
3516 // See https://issues.dlang.org/show_bug.cgi?id=20362
3517 this.flags |= FUNCFLAG.inferScope;
3518 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
3521 override FuncLiteralDeclaration syntaxCopy(Dsymbol s)
3523 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
3524 assert(!s);
3525 auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident);
3526 f.treq = treq; // don't need to copy
3527 FuncDeclaration.syntaxCopy(f);
3528 return f;
3531 override bool isNested() const
3533 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
3534 return (tok != TOK.function_) && !isThis();
3537 override inout(AggregateDeclaration) isThis() inout
3539 return tok == TOK.delegate_ ? super.isThis() : null;
3542 override bool isVirtual() const
3544 return false;
3547 override bool addPreInvariant()
3549 return false;
3552 override bool addPostInvariant()
3554 return false;
3557 /*******************************
3558 * Modify all expression type of return statements to tret.
3560 * On function literals, return type may be modified based on the context type
3561 * after its semantic3 is done, in FuncExp::implicitCastTo.
3563 * A function() dg = (){ return new B(); } // OK if is(B : A) == true
3565 * If B to A conversion is convariant that requires offseet adjusting,
3566 * all return statements should be adjusted to return expressions typed A.
3568 void modifyReturns(Scope* sc, Type tret)
3570 import dmd.statement_rewrite_walker;
3572 extern (C++) final class RetWalker : StatementRewriteWalker
3574 alias visit = typeof(super).visit;
3575 public:
3576 Scope* sc;
3577 Type tret;
3578 FuncLiteralDeclaration fld;
3580 override void visit(ReturnStatement s)
3582 Expression exp = s.exp;
3583 if (exp && !exp.type.equals(tret))
3585 s.exp = exp.castTo(sc, tret);
3590 if (semanticRun < PASS.semantic3done)
3591 return;
3593 if (fes)
3594 return;
3596 scope RetWalker w = new RetWalker();
3597 w.sc = sc;
3598 w.tret = tret;
3599 w.fld = this;
3600 fbody.accept(w);
3602 // Also update the inferred function type to match the new return type.
3603 // This is required so the code generator does not try to cast the
3604 // modified returns back to the original type.
3605 if (inferRetType && type.nextOf() != tret)
3606 type.toTypeFunction().next = tret;
3609 override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
3611 return this;
3614 override const(char)* kind() const
3616 // GCC requires the (char*) casts
3617 return (tok != TOK.function_) ? "delegate" : "function";
3620 override const(char)* toPrettyChars(bool QualifyTypes = false)
3622 if (parent)
3624 TemplateInstance ti = parent.isTemplateInstance();
3625 if (ti)
3626 return ti.tempdecl.toPrettyChars(QualifyTypes);
3628 return Dsymbol.toPrettyChars(QualifyTypes);
3631 override void accept(Visitor v)
3633 v.visit(this);
3637 /***********************************************************
3639 extern (C++) final class CtorDeclaration : FuncDeclaration
3641 bool isCpCtor;
3642 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
3644 super(loc, endloc, Id.ctor, stc, type);
3645 this.isCpCtor = isCpCtor;
3646 //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars());
3649 override CtorDeclaration syntaxCopy(Dsymbol s)
3651 assert(!s);
3652 auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy());
3653 FuncDeclaration.syntaxCopy(f);
3654 return f;
3657 override const(char)* kind() const
3659 return isCpCtor ? "copy constructor" : "constructor";
3662 override const(char)* toChars() const
3664 return "this";
3667 override bool isVirtual() const
3669 return false;
3672 override bool addPreInvariant()
3674 return false;
3677 override bool addPostInvariant()
3679 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3682 override inout(CtorDeclaration) isCtorDeclaration() inout
3684 return this;
3687 override void accept(Visitor v)
3689 v.visit(this);
3693 /***********************************************************
3695 extern (C++) final class PostBlitDeclaration : FuncDeclaration
3697 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
3699 super(loc, endloc, id, stc, null);
3702 override PostBlitDeclaration syntaxCopy(Dsymbol s)
3704 assert(!s);
3705 auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
3706 FuncDeclaration.syntaxCopy(dd);
3707 return dd;
3710 override bool isVirtual() const
3712 return false;
3715 override bool addPreInvariant()
3717 return false;
3720 override bool addPostInvariant()
3722 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3725 override bool overloadInsert(Dsymbol s)
3727 return false; // cannot overload postblits
3730 override inout(PostBlitDeclaration) isPostBlitDeclaration() inout
3732 return this;
3735 override void accept(Visitor v)
3737 v.visit(this);
3741 /***********************************************************
3743 extern (C++) final class DtorDeclaration : FuncDeclaration
3745 extern (D) this(const ref Loc loc, const ref Loc endloc)
3747 super(loc, endloc, Id.dtor, STC.undefined_, null);
3750 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
3752 super(loc, endloc, id, stc, null);
3755 override DtorDeclaration syntaxCopy(Dsymbol s)
3757 assert(!s);
3758 auto dd = new DtorDeclaration(loc, endloc, storage_class, ident);
3759 FuncDeclaration.syntaxCopy(dd);
3760 return dd;
3763 override const(char)* kind() const
3765 return "destructor";
3768 override const(char)* toChars() const
3770 return "~this";
3773 override bool isVirtual() const
3775 // D dtor's don't get put into the vtbl[]
3776 // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
3777 return vtblIndex != -1;
3780 override bool addPreInvariant()
3782 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3785 override bool addPostInvariant()
3787 return false;
3790 override bool overloadInsert(Dsymbol s)
3792 return false; // cannot overload destructors
3795 override inout(DtorDeclaration) isDtorDeclaration() inout
3797 return this;
3800 override void accept(Visitor v)
3802 v.visit(this);
3806 /***********************************************************
3808 extern (C++) class StaticCtorDeclaration : FuncDeclaration
3810 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3812 super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null);
3815 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
3817 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
3820 override StaticCtorDeclaration syntaxCopy(Dsymbol s)
3822 assert(!s);
3823 auto scd = new StaticCtorDeclaration(loc, endloc, storage_class);
3824 FuncDeclaration.syntaxCopy(scd);
3825 return scd;
3828 override final inout(AggregateDeclaration) isThis() inout @nogc nothrow pure @safe
3830 return null;
3833 override final bool isVirtual() const @nogc nothrow pure @safe
3835 return false;
3838 override final bool addPreInvariant() @nogc nothrow pure @safe
3840 return false;
3843 override final bool addPostInvariant() @nogc nothrow pure @safe
3845 return false;
3848 override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
3850 return true;
3853 override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
3855 return this;
3858 override void accept(Visitor v)
3860 v.visit(this);
3864 /***********************************************************
3866 extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
3868 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3870 super(loc, endloc, "_sharedStaticCtor", stc);
3873 override SharedStaticCtorDeclaration syntaxCopy(Dsymbol s)
3875 assert(!s);
3876 auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
3877 FuncDeclaration.syntaxCopy(scd);
3878 return scd;
3881 override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
3883 return this;
3886 override void accept(Visitor v)
3888 v.visit(this);
3892 /***********************************************************
3894 extern (C++) class StaticDtorDeclaration : FuncDeclaration
3896 VarDeclaration vgate; // 'gate' variable
3898 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3900 super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null);
3903 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
3905 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
3908 override StaticDtorDeclaration syntaxCopy(Dsymbol s)
3910 assert(!s);
3911 auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
3912 FuncDeclaration.syntaxCopy(sdd);
3913 return sdd;
3916 override final inout(AggregateDeclaration) isThis() inout
3918 return null;
3921 override final bool isVirtual() const
3923 return false;
3926 override final bool hasStaticCtorOrDtor()
3928 return true;
3931 override final bool addPreInvariant()
3933 return false;
3936 override final bool addPostInvariant()
3938 return false;
3941 override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
3943 return this;
3946 override void accept(Visitor v)
3948 v.visit(this);
3952 /***********************************************************
3954 extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
3956 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3958 super(loc, endloc, "_sharedStaticDtor", stc);
3961 override SharedStaticDtorDeclaration syntaxCopy(Dsymbol s)
3963 assert(!s);
3964 auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
3965 FuncDeclaration.syntaxCopy(sdd);
3966 return sdd;
3969 override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
3971 return this;
3974 override void accept(Visitor v)
3976 v.visit(this);
3980 /***********************************************************
3982 extern (C++) final class InvariantDeclaration : FuncDeclaration
3984 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
3986 super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
3987 this.fbody = fbody;
3990 override InvariantDeclaration syntaxCopy(Dsymbol s)
3992 assert(!s);
3993 auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null);
3994 FuncDeclaration.syntaxCopy(id);
3995 return id;
3998 override bool isVirtual() const
4000 return false;
4003 override bool addPreInvariant()
4005 return false;
4008 override bool addPostInvariant()
4010 return false;
4013 override inout(InvariantDeclaration) isInvariantDeclaration() inout
4015 return this;
4018 override void accept(Visitor v)
4020 v.visit(this);
4025 /***********************************************************
4027 extern (C++) final class UnitTestDeclaration : FuncDeclaration
4029 char* codedoc; // for documented unittest
4031 // toObjFile() these nested functions after this one
4032 FuncDeclarations deferredNested;
4034 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
4036 super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null);
4037 this.codedoc = codedoc;
4040 override UnitTestDeclaration syntaxCopy(Dsymbol s)
4042 assert(!s);
4043 auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
4044 FuncDeclaration.syntaxCopy(utd);
4045 return utd;
4048 override inout(AggregateDeclaration) isThis() inout
4050 return null;
4053 override bool isVirtual() const
4055 return false;
4058 override bool addPreInvariant()
4060 return false;
4063 override bool addPostInvariant()
4065 return false;
4068 override inout(UnitTestDeclaration) isUnitTestDeclaration() inout
4070 return this;
4073 override void accept(Visitor v)
4075 v.visit(this);
4079 /***********************************************************
4081 extern (C++) final class NewDeclaration : FuncDeclaration
4083 extern (D) this(const ref Loc loc, StorageClass stc)
4085 super(loc, Loc.initial, Id.classNew, STC.static_ | stc, null);
4088 override NewDeclaration syntaxCopy(Dsymbol s)
4090 assert(!s);
4091 auto f = new NewDeclaration(loc, storage_class);
4092 FuncDeclaration.syntaxCopy(f);
4093 return f;
4096 override const(char)* kind() const
4098 return "allocator";
4101 override bool isVirtual() const
4103 return false;
4106 override bool addPreInvariant()
4108 return false;
4111 override bool addPostInvariant()
4113 return false;
4116 override inout(NewDeclaration) isNewDeclaration() inout
4118 return this;
4121 override void accept(Visitor v)
4123 v.visit(this);