2 * Defines a function declaration.
5 * - function/delegate literals
7 * - (static/shared) constructors/destructors/post-blits
11 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
12 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
13 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
14 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d)
15 * Documentation: https://dlang.org/phobos/dmd_func.html
16 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d
21 import core.stdc.stdio;
22 import core.stdc.string;
24 import dmd.arraytypes;
29 import dmd.declaration;
30 import dmd.delegatize;
31 import dmd.dinterpret;
36 import dmd.dsymbolsem;
40 import dmd.expression;
44 import dmd.identifier;
50 import dmd.common.outbuffer;
51 import dmd.root.rootobject;
52 import dmd.root.string;
53 import dmd.root.stringtable;
56 import dmd.statement_rewrite_walker;
58 import dmd.statementsem;
65 uninitialized, /// not computed yet
72 unknown = 255, /// not known if this is a builtin
73 unimp = 0, /// this is not a builtin
74 gcc, /// this is a GCC builtin
75 llvm, /// this is an LLVM builtin
111 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
113 extern (C++) final class NrvoWalker : StatementRewriteWalker
115 alias visit = typeof(super).visit;
120 override void visit(ReturnStatement s)
122 // See if all returns are instead to be replaced with a goto returnLabel;
128 * vresult = exp; goto Lresult;
130 auto gs = new GotoStatement(s.loc, Id.returnLabel);
131 gs.label = fd.returnLabel;
135 s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
141 override void visit(TryFinallyStatement s)
143 DtorExpStatement des;
144 if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
145 fd.nrvo_var == des.var)
147 if (!(global.params.useExceptions && ClassDeclaration.throwable))
149 /* Don't need to call destructor at all, since it is nrvo
151 replaceCurrent(s._body);
152 s._body.accept(this);
156 /* Normally local variable dtors are called regardless exceptions.
157 * But for nrvo_var, its dtor should be called only when exception is thrown.
160 * try { s.body; } finally { nrvo_var.edtor; }
161 * // equivalent with:
162 * // s.body; scope(exit) nrvo_var.edtor;
164 * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
165 * // equivalent with:
166 * // s.body; scope(failure) nrvo_var.edtor;
168 Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
169 Identifier id = Identifier.generateId("__o");
171 Statement handler = new PeelStatement(sexception);
172 if (sexception.blockExit(fd, false) & BE.fallthru)
174 auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
175 ts.internalThrow = true;
176 handler = new CompoundStatement(Loc.initial, handler, ts);
179 auto catches = new Catches();
180 auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
181 ctch.internalCatch = true;
182 ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
185 Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
191 StatementRewriteWalker.visit(s);
195 private struct FUNCFLAG
197 bool purityInprocess; /// working on determining purity
198 bool safetyInprocess; /// working on determining safety
199 bool nothrowInprocess; /// working on determining nothrow
200 bool nogcInprocess; /// working on determining @nogc
201 bool returnInprocess; /// working on inferring 'return' for parameters
202 bool inlineScanned; /// function has been scanned for inline possibilities
203 bool inferScope; /// infer 'scope' for parameters
204 bool hasCatches; /// function has try-catch statements
205 bool skipCodegen; /// do not generate code for this function.
206 bool printf; /// is a printf-like function
207 bool scanf; /// is a scanf-like function
208 bool noreturn; /// the function does not return
209 bool isNRVO = true; /// Support for named return value optimization
210 bool isNaked; /// The function is 'naked' (see inline ASM)
211 bool isGenerated; /// The function is compiler generated (e.g. `opCmp`)
212 bool isIntroducing; /// If this function introduces the overload set
213 bool hasSemantic3Errors; /// If errors in semantic3 this function's frame ptr
214 bool hasNoEH; /// No exception unwinding is needed
215 bool inferRetType; /// Return type is to be inferred
216 bool hasDualContext; /// has a dual-context 'this' parameter
217 bool hasAlwaysInlines; /// Contains references to functions that must be inlined
218 bool isCrtCtor; /// Has attribute pragma(crt_constructor)
219 bool isCrtDtor; /// Has attribute pragma(crt_destructor)
220 bool hasEscapingSiblings;/// Has sibling functions that escape
221 bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed
224 /***********************************************************
225 * Tuple of result identifier (possibly null) and statement.
226 * This is used to store out contracts: out(id){ ensure }
228 extern (C++) struct Ensure
235 return Ensure(id, ensure.syntaxCopy());
238 /*****************************************
239 * Do syntax copy of an array of Ensure's.
241 static Ensures* arraySyntaxCopy(Ensures* a)
249 (*b)[i] = e.syntaxCopy();
257 /***********************************************************
259 extern (C++) class FuncDeclaration : Declaration
261 Statements* frequires; /// in contracts
262 Ensures* fensures; /// out contracts
263 Statement frequire; /// lowered in contract
264 Statement fensure; /// lowered out contract
265 Statement fbody; /// function body
267 FuncDeclarations foverrides; /// functions this function overrides
268 FuncDeclaration fdrequire; /// function that does the in contract
269 FuncDeclaration fdensure; /// function that does the out contract
271 Expressions* fdrequireParams; /// argument list for __require
272 Expressions* fdensureParams; /// argument list for __ensure
274 const(char)* mangleString; /// mangled symbol created from mangleExact()
276 VarDeclaration vresult; /// result variable for out contracts
277 LabelDsymbol returnLabel; /// where the return goes
279 bool[size_t] isTypeIsolatedCache; /// cache for the potentially very expensive isTypeIsolated check
281 // used to prevent symbols in different
282 // scopes from having the same name
283 DsymbolTable localsymtab;
284 VarDeclaration vthis; /// 'this' parameter (member and nested)
285 VarDeclaration v_arguments; /// '_arguments' parameter
287 VarDeclaration v_argptr; /// '_argptr' variable
288 VarDeclarations* parameters; /// Array of VarDeclaration's for parameters
289 DsymbolTable labtab; /// statement label symbol table
290 Dsymbol overnext; /// next in overload list
291 FuncDeclaration overnext0; /// next in overload list (only used during IFTI)
292 Loc endloc; /// location of closing curly bracket
293 int vtblIndex = -1; /// for member functions, index into vtbl[]
295 ILS inlineStatusStmt = ILS.uninitialized;
296 ILS inlineStatusExp = ILS.uninitialized;
297 PINLINE inlining = PINLINE.default_;
299 int inlineNest; /// !=0 if nested inline
301 ForeachStatement fes; /// if foreach body, this is the foreach
302 BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[]
303 /** if !=NULL, then this is the type
304 of the 'introducing' function
305 this one is overriding
309 StorageClass storage_class2; /// storage class for template onemember's
311 // Things that should really go into Scope
313 /// 1 if there's a return exp; statement
314 /// 2 if there's a throw statement
315 /// 4 if there's an assert(0)
316 /// 8 if there's inline asm
317 /// 16 if there are multiple return statements
320 VarDeclaration nrvo_var; /// variable to replace with shidden
321 Symbol* shidden; /// hidden pointer passed to function
323 ReturnStatements* returns;
325 GotoStatements* gotos; /// Gotos with forward references
329 VarDeclarations* alignSectionVars; /// local variables with alignment needs larger than stackAlign
330 Symbol* salignSection; /// pointer to aligned section, if any
333 /// set if this is a known, builtin function we can evaluate at compile time
334 BUILTIN builtin = BUILTIN.unknown;
336 /// set if someone took the address of this function
339 bool requiresClosure; // this function needs a closure
341 /** local variables in this function which are referenced by nested functions
342 * (They'll get put into the "closure" for this function.)
344 VarDeclarations closureVars;
346 /** Outer variables which are referenced by this nested function
347 * (the inverse of closureVars)
349 VarDeclarations outerVars;
351 /// Sibling nested functions which called this one
352 FuncDeclarations siblingCallers;
354 FuncDeclarations *inlinedNestedCallees;
356 /// In case of failed `@safe` inference, store the error that made the function `@system` for
357 /// better diagnostics
358 AttributeViolation* safetyViolation;
360 /// See the `FUNCFLAG` struct
361 import dmd.common.bitfields;
362 mixin(generateBitFields!(FUNCFLAG, uint));
365 * Data for a function declaration that is needed for the Objective-C
368 ObjcFuncDeclaration objc;
370 extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false)
373 //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type);
374 //printf("storage_class = x%x\n", storage_class);
375 this.storage_class = storage_class;
379 // Normalize storage_class, because function-type related attributes
380 // are already set in the 'type' in parsing phase.
381 this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
383 this.endloc = endloc;
385 this.noreturn = true;
387 /* The type given for "infer the return type" is a TypeFunction with
388 * NULL for the return type.
390 if (type && type.nextOf() is null)
391 this.inferRetType = true;
394 static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
396 return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn);
399 override FuncDeclaration syntaxCopy(Dsymbol s)
401 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
402 FuncDeclaration f = s ? cast(FuncDeclaration)s
403 : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), this.noreturn != 0);
404 f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
405 f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
406 f.fbody = fbody ? fbody.syntaxCopy() : null;
410 /****************************************************
411 * Resolve forward reference of function signature -
412 * parameter types, return type, and attributes.
414 * false if any errors exist in the signature.
416 final bool functionSemantic()
418 //printf("functionSemantic() %p %s\n", this, toChars());
422 this.cppnamespace = _scope.namespace;
424 if (!originalType) // semantic not yet run
426 TemplateInstance spec = isSpeculative();
427 uint olderrs = global.errors;
428 uint oldgag = global.gag;
429 if (global.gag && !spec)
431 dsymbolSemantic(this, _scope);
433 if (spec && global.errors != olderrs)
434 spec.errors = (global.errors - olderrs != 0);
435 if (olderrs != global.errors) // if errors compiling this function
439 // if inferring return type, sematic3 needs to be run
440 // - When the function body contains any errors, we cannot assume
441 // the inferred return type is valid.
442 // So, the body errors should become the function signature error.
443 if (inferRetType && type && !type.nextOf())
444 return functionSemantic3();
447 if (isInstantiated() && !isVirtualMethod() &&
448 ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident))
450 AggregateDeclaration ad = isMemberLocal();
451 if (ad && ad.sizeok != Sizeok.done)
453 /* Currently dmd cannot resolve forward references per methods,
454 * then setting SIZOKfwd is too conservative and would break existing code.
455 * So, just stop method attributes inference until ad.dsymbolSemantic() done.
457 //ad.sizeok = Sizeok.fwd;
460 return functionSemantic3() || !errors;
463 if (storage_class & STC.inference)
464 return functionSemantic3() || !errors;
469 /****************************************************
470 * Resolve forward reference of function body.
471 * Returns false if any errors exist in the body.
473 final bool functionSemantic3()
475 if (semanticRun < PASS.semantic3 && _scope)
477 /* Forward reference - we need to run semantic3 on this function.
478 * If errors are gagged, and it's not part of a template instance,
479 * we need to temporarily ungag errors.
481 TemplateInstance spec = isSpeculative();
482 uint olderrs = global.errors;
483 uint oldgag = global.gag;
484 if (global.gag && !spec)
486 semantic3(this, _scope);
489 // If it is a speculatively-instantiated template, and errors occur,
490 // we need to mark the template as having errors.
491 if (spec && global.errors != olderrs)
492 spec.errors = (global.errors - olderrs != 0);
493 if (olderrs != global.errors) // if errors compiling this function
497 return !errors && !this.hasSemantic3Errors();
500 /****************************************************
501 * Check that this function type is properly resolved.
502 * If not, report "forward reference error" and return true.
504 extern (D) final bool checkForwardRef(const ref Loc loc)
506 if (!functionSemantic())
509 /* No deco means the functionSemantic() call could not resolve
510 * forward referenes in the type of this function.
514 bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3);
515 .error(loc, "forward reference to %s`%s`",
516 (inSemantic3 ? "inferred return type of function " : "").ptr,
523 // called from semantic3
525 * Creates and returns the hidden parameters for this function declaration.
527 * Hidden parameters include the `this` parameter of a class, struct or
528 * nested function and the selector parameter for Objective-C methods.
530 extern (D) final void declareThis(Scope* sc)
532 const bool dualCtx = (toParent2() != toParentLocal());
534 this.hasDualContext = true;
536 if (!dualCtx && !ad && !isNested())
539 objc.selectorParameter = null;
543 Type addModStc(Type t)
545 return t.addMod(type.mod).addStorageClass(storage_class);
548 if (dualCtx || isNested())
550 /* The 'this' for a nested function is the link to the
551 * enclosing function's stack frame.
552 * Note that nested functions and member functions are disjoint.
554 Type tthis = addModStc(dualCtx ?
555 Type.tvoidptr.sarrayOf(2).pointerTo() :
556 Type.tvoid.pointerTo());
557 vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null);
558 vthis.storage_class |= STC.parameter | STC.nodtor;
562 Type thandle = addModStc(ad.handleType());
563 vthis = new ThisDeclaration(loc, thandle);
564 vthis.storage_class |= STC.parameter;
565 if (thandle.ty == Tstruct)
567 vthis.storage_class |= STC.ref_;
571 if (auto tf = type.isTypeFunction())
574 vthis.storage_class |= STC.return_;
576 vthis.storage_class |= STC.scope_;
577 if (tf.isreturnscope)
578 vthis.storage_class |= STC.returnScope;
581 vthis.dsymbolSemantic(sc);
582 if (!sc.insert(vthis))
586 objc.selectorParameter = .objc.createSelectorParameter(this, sc);
589 override final bool equals(const RootObject o) const
594 if (auto s = isDsymbol(o))
597 auto fd2 = s.isFuncDeclaration();
601 auto fa1 = fd1.isFuncAliasDeclaration();
602 auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
604 auto fa2 = fd2.isFuncAliasDeclaration();
605 auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
609 return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
612 bool b1 = fa1 !is null;
613 if (b1 && faf1.isUnique() && !fa1.hasOverloads)
616 bool b2 = fa2 !is null;
617 if (b2 && faf2.isUnique() && !fa2.hasOverloads)
623 return faf1.toParent().equals(faf2.toParent()) &&
624 faf1.ident.equals(faf2.ident) &&
625 faf1.type.equals(faf2.type);
630 /****************************************************
631 * Determine if 'this' overrides fd.
632 * Return !=0 if it does.
634 final int overrides(FuncDeclaration fd)
637 if (fd.ident == ident)
639 const cov = type.covariant(fd.type);
640 if (cov != Covariant.distinct)
642 ClassDeclaration cd1 = toParent().isClassDeclaration();
643 ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
644 if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
651 /*************************************************
652 * Find index of function in vtbl[0..length] that
653 * this function overrides.
654 * Prefer an exact match to a covariant one.
656 * vtbl = vtable to use
657 * dim = maximal vtable dimension
660 * -2 can't determine because of forward references
662 final int findVtblIndex(Dsymbols* vtbl, int dim)
664 //printf("findVtblIndex() %s\n", toChars());
665 FuncDeclaration mismatch = null;
666 StorageClass mismatchstc = 0;
670 for (int vi = 0; vi < dim; vi++)
672 FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration();
673 if (fdv && fdv.ident == ident)
675 if (type.equals(fdv.type)) // if exact match
677 if (fdv.parent.isClassDeclaration())
682 continue; // keep looking
684 return vi; // no need to look further
689 error("cannot determine overridden function");
697 StorageClass stc = 0;
698 const cov = type.covariant(fdv.type, &stc);
699 //printf("\tbaseclass cov = %d\n", cov);
702 case Covariant.distinct:
703 // types are distinct
707 bestvi = vi; // covariant, but not identical
709 // keep looking for an exact match
714 mismatch = fdv; // overrides, but is not covariant
716 // keep looking for an exact match
718 case Covariant.fwdref:
719 return -2; // forward references
723 if (_linkage == LINK.cpp && bestvi != -1)
725 StorageClass stc = 0;
726 FuncDeclaration fdv = (*vtbl)[bestvi].isFuncDeclaration();
727 assert(fdv && fdv.ident == ident);
728 if (type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no)
730 /* https://issues.dlang.org/show_bug.cgi?id=22351
731 * Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not.
732 * For now, continue to allow D covariant rules to apply when `override` has been used,
733 * but issue a deprecation warning that this behaviour will change in the future.
734 * Otherwise, follow the C++ covariant rules, which will create a new vtable entry.
738 /* @@@DEPRECATED_2.110@@@
739 * After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch,
740 * but also the `cppCovariant` parameter from Type.covariant, and update the function
741 * so that both `LINK.cpp` covariant conditions within are always checked.
743 .deprecation(loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated",
744 fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(),
745 toPrettyChars(), type.toTypeFunction().parameterList.parametersTypeToChars(), type.modToChars());
747 const char* where = type.isNaked() ? "parameters" : "type";
748 deprecationSupplemental(loc, "Either remove `override`, or adjust the `const` qualifiers of the "
749 ~ "overriding function %s", where);
753 // Treat as if Covariant.no
761 if (bestvi == -1 && mismatch)
764 //mismatch.type.print();
765 //printf("%s %s\n", type.deco, mismatch.type.deco);
766 //printf("stc = %llx\n", mismatchstc);
769 // Fix it by modifying the type to add the storage classes
770 type = type.addStorageClass(mismatchstc);
777 /*********************************
778 * If function a function in a base class,
779 * return that base class.
781 * base class if overriding, null if not
783 final BaseClass* overrideInterface()
785 for (ClassDeclaration cd = toParent2().isClassDeclaration(); cd; cd = cd.baseClass)
787 foreach (b; cd.interfaces)
789 auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length);
797 /****************************************************
798 * Overload this FuncDeclaration with the new one f.
799 * Return true if successful; i.e. no conflict.
801 override bool overloadInsert(Dsymbol s)
803 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
805 AliasDeclaration ad = s.isAliasDeclaration();
809 return overnext.overloadInsert(ad);
810 if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof)
812 //printf("\tad = '%s'\n", ad.type.toChars());
816 //printf("\ttrue: no conflict\n");
819 TemplateDeclaration td = s.isTemplateDeclaration();
825 return overnext.overloadInsert(td);
829 FuncDeclaration fd = s.isFuncDeclaration();
835 /* Disable this check because:
837 * semantic() isn't run yet on foo(), so the const hasn't been
842 printf("type = %s\n", type.toChars());
843 printf("fd.type = %s\n", fd.type.toChars());
845 // fd.type can be NULL for overloaded constructors
846 if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
848 //printf("\tfalse: conflict %s\n", kind());
855 td = overnext.isTemplateDeclaration();
857 fd.overloadInsert(td);
859 return overnext.overloadInsert(fd);
862 //printf("\ttrue: no conflict\n");
866 /********************************************
867 * Find function in overload list that exactly matches t.
869 extern (D) final FuncDeclaration overloadExactMatch(Type t)
872 overloadApply(this, (Dsymbol s)
874 auto f = s.isFuncDeclaration();
877 if (f.storage_class & STC.disable)
879 if (t.equals(f.type))
885 /* Allow covariant matches, as long as the return type
886 * is just a const conversion.
887 * This allows things like pure functions to match with an impure function type.
889 if (t.ty == Tfunction)
891 auto tf = cast(TypeFunction)f.type;
892 if (tf.covariant(t) == Covariant.yes &&
893 tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
904 /********************************************
905 * Find function in overload list that matches to the 'this' modifier.
906 * There's four result types.
908 * 1. If the 'tthis' matches only one candidate, it's an "exact match".
909 * Returns the function and 'hasOverloads' is set to false.
910 * eg. If 'tthis" is mutable and there's only one mutable method.
911 * 2. If there's two or more match candidates, but a candidate function will be
913 * Returns the better match function but 'hasOverloads' is set to true.
914 * eg. If 'tthis' is mutable, and there's both mutable and const methods,
915 * the mutable method will be a better match.
916 * 3. If there's two or more match candidates, but there's no better match,
917 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
918 * eg. If 'tthis' is mutable, and there's two or more mutable methods.
919 * 4. If there's no candidates, it's "no match" and returns null with error report.
920 * e.g. If 'tthis' is const but there's no const methods.
922 extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
924 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
926 overloadApply(this, (Dsymbol s)
928 auto f = s.isFuncDeclaration();
929 if (!f || f == m.lastf) // skip duplicates
932 auto tf = f.type.toTypeFunction();
933 //printf("tf = %s\n", tf.toChars());
936 if (tthis) // non-static functions are preferred than static ones
939 match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
941 match = MATCH.constant; // keep static function in overload candidates
943 else // static functions are preferred than non-static ones
946 match = MATCH.convert;
950 if (match == MATCH.nomatch)
953 if (match > m.last) goto LcurrIsBetter;
954 if (match < m.last) goto LlastIsBetter;
956 // See if one of the matches overrides the other.
957 if (m.lastf.overrides(f)) goto LlastIsBetter;
958 if (f.overrides(m.lastf)) goto LcurrIsBetter;
960 //printf("\tambiguous\n");
966 //printf("\tlastbetter\n");
967 m.count++; // count up
971 //printf("\tisbetter\n");
972 if (m.last <= MATCH.convert)
974 // clear last secondary matching
980 m.count++; // count up
984 if (m.count == 1) // exact match
986 hasOverloads = false;
988 else if (m.count > 1) // better or ambiguous match
995 auto tf = this.type.toTypeFunction();
997 assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
999 OutBuffer thisBuf, funcBuf;
1000 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
1001 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
1002 .error(loc, "%smethod %s is not callable using a %sobject",
1003 funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
1009 /********************************************
1010 * find function template root in overload list
1012 extern (D) final TemplateDeclaration findTemplateDeclRoot()
1014 FuncDeclaration f = this;
1015 while (f && f.overnext)
1017 //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
1018 TemplateDeclaration td = f.overnext.isTemplateDeclaration();
1021 f = f.overnext.isFuncDeclaration();
1026 /********************************************
1027 * Returns true if function was declared
1028 * directly or indirectly in a unittest block
1030 final bool inUnittest()
1035 if (f.isUnitTestDeclaration())
1043 /*************************************
1044 * Determine partial specialization order of 'this' vs g.
1045 * This is very similar to TemplateDeclaration::leastAsSpecialized().
1047 * match 'this' is at least as specialized as g
1048 * 0 g is more specialized than 'this'
1050 final MATCH leastAsSpecialized(FuncDeclaration g, Identifiers* names)
1052 enum LOG_LEASTAS = 0;
1053 static if (LOG_LEASTAS)
1055 import core.stdc.stdio : printf;
1056 printf("%s.leastAsSpecialized(%s, %s)\n", toChars(), g.toChars(), names ? names.toChars() : "null");
1057 printf("%s, %s\n", type.toChars(), g.type.toChars());
1060 /* This works by calling g() with f()'s parameters, and
1061 * if that is possible, then f() is at least as specialized
1065 TypeFunction tf = type.toTypeFunction();
1066 TypeFunction tg = g.type.toTypeFunction();
1068 /* If both functions have a 'this' pointer, and the mods are not
1069 * the same and g's is not const, then this is less specialized.
1071 if (needThis() && g.needThis() && tf.mod != tg.mod)
1073 if (isCtorDeclaration())
1075 if (!MODimplicitConv(tg.mod, tf.mod))
1076 return MATCH.nomatch;
1080 if (!MODimplicitConv(tf.mod, tg.mod))
1081 return MATCH.nomatch;
1085 /* Create a dummy array of arguments out of the parameters to f()
1088 foreach (u, p; tf.parameterList)
1091 if (p.isReference())
1093 e = new IdentifierExp(Loc.initial, p.ident);
1097 e = p.type.defaultInitLiteral(Loc.initial);
1101 MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
1102 if (m > MATCH.nomatch)
1104 /* A variadic parameter list is less specialized than a
1107 if (tf.parameterList.varargs && !tg.parameterList.varargs)
1108 goto L1; // less specialized
1110 static if (LOG_LEASTAS)
1112 printf(" matches %d, so is least as specialized\n", m);
1117 static if (LOG_LEASTAS)
1119 printf(" doesn't match, so is not as specialized\n");
1121 return MATCH.nomatch;
1124 /********************************
1125 * Searches for a label with the given identifier. This function will insert a new
1126 * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
1129 * ident = identifier of the requested label
1130 * loc = location used when creating a new `LabelDsymbol`
1132 * Returns: the `LabelDsymbol` for `ident`
1134 final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial)
1138 labtab = new DsymbolTable(); // guess we need one
1140 s = labtab.lookup(ident);
1143 s = new LabelDsymbol(ident, loc);
1146 return cast(LabelDsymbol)s;
1149 /*****************************************
1150 * Determine lexical level difference from `this` to nested function `fd`.
1152 * fd = target of call
1153 * intypeof = !=0 if inside typeof
1156 * >0 decrease nesting by number
1157 * -1 increase nesting by 1 (`fd` is nested within `this`)
1158 * LevelError error, `this` cannot call `fd`
1160 final int getLevel(FuncDeclaration fd, int intypeof)
1162 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
1163 Dsymbol fdparent = fd.toParent2();
1164 if (fdparent == this)
1169 while (fd != s && fdparent != s.toParent2())
1171 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
1172 if (auto thisfd = s.isFuncDeclaration())
1174 if (!thisfd.isNested() && !thisfd.vthis && !intypeof)
1179 if (auto thiscd = s.isAggregateDeclaration())
1181 /* AggregateDeclaration::isNested returns true only when
1182 * it has a hidden pointer.
1183 * But, calling the function belongs unrelated lexical scope
1184 * is still allowed inside typeof.
1186 * struct Map(alias fun) {
1187 * typeof({ return fun(); }) RetType;
1188 * // No member function makes Map struct 'not nested'.
1191 if (!thiscd.isNested() && !intypeof)
1198 s = s.toParentP(fd);
1205 /***********************************
1206 * Determine lexical level difference from `this` to nested function `fd`.
1207 * Issue error if `this` cannot call `fd`.
1210 * loc = location for error messages
1212 * fd = target of call
1213 * decl = The `Declaration` that triggered this check.
1214 * Used to provide a better error message only.
1217 * >0 decrease nesting by number
1218 * -1 increase nesting by 1 (`fd` is nested within 'this')
1221 final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd,
1224 int level = getLevel(fd, sc.intypeof);
1225 if (level != LevelError)
1228 // Don't give error if in template constraint
1229 if (!(sc.flags & SCOPE.constraint))
1231 const(char)* xstatic = isStatic() ? "`static` " : "";
1232 // better diagnostics for static functions
1233 .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
1234 xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(),
1235 fd.toPrettyChars());
1236 .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
1242 enum LevelError = -2;
1244 override const(char)* toPrettyChars(bool QualifyTypes = false)
1249 return Dsymbol.toPrettyChars(QualifyTypes);
1252 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
1253 final const(char)* toFullSignature()
1256 functionToBufferWithIdent(type.toTypeFunction(), &buf, toChars(), isStatic);
1257 return buf.extractChars();
1260 final bool isMain() const
1262 return ident == Id.main && resolvedLinkage() != LINK.c && !isMember() && !isNested();
1265 final bool isCMain() const
1267 return ident == Id.main && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1270 final bool isWinMain() const
1272 //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1275 bool x = ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1276 printf("%s\n", x ? "yes" : "no");
1281 return ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1285 final bool isDllMain() const
1287 return ident == Id.DllMain && resolvedLinkage() != LINK.c && !isMember();
1290 final bool isRtInit() const
1292 return ident == Id.rt_init && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1295 override final bool isExport() const
1297 return visibility.kind == Visibility.Kind.export_;
1300 override final bool isImportedSymbol() const
1302 //printf("isImportedSymbol()\n");
1303 //printf("protection = %d\n", visibility);
1304 return (visibility.kind == Visibility.Kind.export_) && !fbody;
1307 override final bool isCodeseg() const pure nothrow @nogc @safe
1309 return true; // functions are always in the code segment
1312 override final bool isOverloadable() const
1314 return true; // functions can be overloaded
1317 /***********************************
1318 * Override so it can work even if semantic() hasn't yet
1321 override final bool isAbstract()
1323 if (storage_class & STC.abstract_)
1325 if (semanticRun >= PASS.semanticdone)
1330 if (_scope.stc & STC.abstract_)
1332 parent = _scope.parent;
1333 Dsymbol parent = toParent();
1334 if (parent.isInterfaceDeclaration())
1340 /**********************************
1341 * Decide if attributes for this function can be inferred from examining
1342 * the function body.
1346 final bool canInferAttributes(Scope* sc)
1351 if (isVirtualMethod() &&
1353 * https://issues.dlang.org/show_bug.cgi?id=21719
1355 * If we have an auto virtual function we can infer
1358 !(inferRetType && !isCtorDeclaration()))
1359 return false; // since they may be overridden
1362 /********** this is for backwards compatibility for the moment ********/
1363 (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
1366 if (isFuncLiteralDeclaration() || // externs are not possible with literals
1367 (storage_class & STC.inference) || // do attribute inference
1368 (inferRetType && !isCtorDeclaration()))
1371 if (isInstantiated())
1373 auto ti = parent.isTemplateInstance();
1374 if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
1381 /*****************************************
1382 * Initialize for inferring the attributes of this function.
1384 final void initInferAttributes()
1386 //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1387 TypeFunction tf = type.toTypeFunction();
1388 if (tf.purity == PURE.impure) // purity not specified
1389 purityInprocess = true;
1391 if (tf.trust == TRUST.default_)
1392 safetyInprocess = true;
1395 nothrowInprocess = true;
1398 nogcInprocess = true;
1400 if (!isVirtual() || this.isIntroducing())
1401 returnInprocess = true;
1403 // Initialize for inferring STC.scope_
1409 //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1410 TypeFunction tf = type.toTypeFunction();
1411 if (purityInprocess)
1413 if (tf.purity == PURE.fwdref)
1415 PURE purity = tf.purity;
1416 if (purity > PURE.weak && isNested())
1418 if (purity > PURE.weak && needThis())
1420 // The attribute of the 'this' reference affects purity strength
1421 if (type.mod & MODFlags.immutable_)
1424 else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
1425 purity = PURE.const_;
1430 // ^ This rely on the current situation that every FuncDeclaration has a
1431 // unique TypeFunction.
1435 final PURE isPureBypassingInference()
1437 if (purityInprocess)
1443 /**************************************
1444 * The function is doing something impure,
1445 * so mark it as impure.
1446 * If there's a purity error, return true.
1448 extern (D) final bool setImpure()
1450 if (purityInprocess)
1452 purityInprocess = false;
1454 fes.func.setImpure();
1461 extern (D) final uint flags()
1466 extern (D) final uint flags(uint f)
1474 if (safetyInprocess)
1476 return type.toTypeFunction().trust == TRUST.safe;
1479 final bool isSafeBypassingInference()
1481 return !(safetyInprocess) && isSafe();
1484 final bool isTrusted()
1486 if (safetyInprocess)
1488 return type.toTypeFunction().trust == TRUST.trusted;
1491 /**************************************
1492 * The function is doing something unsafe, so mark it as unsafe.
1495 * gag = surpress error message (used in escape.d)
1496 * loc = location of error
1497 * fmt = printf-style format string
1498 * arg0 = (optional) argument for first %s format specifier
1499 * arg1 = (optional) argument for second %s format specifier
1500 * arg2 = (optional) argument for third %s format specifier
1501 * Returns: whether there's a safe error
1503 extern (D) final bool setUnsafe(
1504 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
1505 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
1507 if (safetyInprocess)
1509 safetyInprocess = false;
1510 type.toTypeFunction().trust = TRUST.system;
1512 safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);
1515 fes.func.setUnsafe();
1520 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
1527 /**************************************
1528 * The function is calling `@system` function `f`, so mark it as unsafe.
1531 * f = function being called (needed for diagnostic of inferred functions)
1532 * Returns: whether there's a safe error
1534 extern (D) final bool setUnsafeCall(FuncDeclaration f)
1536 return setUnsafe(false, f.loc, null, f, null);
1541 //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1544 return type.toTypeFunction().isnogc;
1547 final bool isNogcBypassingInference()
1549 return !nogcInprocess && isNogc();
1552 /**************************************
1553 * The function is doing something that may allocate with the GC,
1554 * so mark it as not nogc (not no-how).
1556 * true if function is marked as @nogc, meaning a user error occurred
1558 extern (D) final bool setGC()
1560 //printf("setGC() %s\n", toChars());
1561 if (nogcInprocess && semanticRun < PASS.semantic3 && _scope)
1563 this.semantic2(_scope);
1564 this.semantic3(_scope);
1569 nogcInprocess = false;
1570 type.toTypeFunction().isnogc = false;
1579 extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
1581 if (!global.params.vgc)
1584 Module m = getModule();
1585 if (m && m.isRoot() && !inUnittest())
1587 message(loc, "vgc: %s", warn);
1591 /********************************************
1592 * See if pointers from function parameters, mutable globals, or uplevel functions
1593 * could leak into return value.
1595 * true if the function return value is isolated from
1596 * any inputs to the function
1598 extern (D) final bool isReturnIsolated()
1600 //printf("isReturnIsolated(this: %s)\n", this.toChars);
1601 TypeFunction tf = type.toTypeFunction();
1604 Type treti = tf.next;
1606 return isTypeIsolatedIndirect(treti); // check influence from parameters
1608 return isTypeIsolated(treti);
1611 /********************
1612 * See if pointers from function parameters, mutable globals, or uplevel functions
1613 * could leak into type `t`.
1615 * t = type to check if it is isolated
1617 * true if `t` is isolated from
1618 * any inputs to the function
1620 extern (D) final bool isTypeIsolated(Type t)
1622 StringTable!Type parentTypes;
1623 const uniqueTypeID = t.getUniqueID();
1626 const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
1627 if (cacheResultPtr !is null)
1628 return *cacheResultPtr;
1630 parentTypes._init();
1631 const isIsolated = isTypeIsolated(t, parentTypes);
1632 isTypeIsolatedCache[uniqueTypeID] = isIsolated;
1637 parentTypes._init();
1638 return isTypeIsolated(t, parentTypes);
1643 extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
1645 //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
1652 return isTypeIsolatedIndirect(t.nextOf()); // go down one level
1656 return isTypeIsolatedIndirect(t);
1659 /* Drill down and check the struct's fields
1661 auto sym = t.toDsymbol(null).isStructDeclaration();
1662 const tName = t.toChars.toDString;
1663 const entry = parentTypes.insert(tName, t);
1666 //we've already seen this type in a parent, not isolated
1669 foreach (v; sym.fields)
1671 Type tmi = v.type.addMod(t.mod);
1672 //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
1673 // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
1674 if (!isTypeIsolated(tmi, parentTypes))
1684 /********************************************
1686 * t = type of object to test one level of indirection down
1688 * true if an object typed `t` has no indirections
1689 * which could have come from the function's parameters, mutable
1690 * globals, or uplevel functions.
1692 private bool isTypeIsolatedIndirect(Type t)
1694 //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1697 /* Since `t` is one level down from an indirection, it could pick
1698 * up a reference to a mutable global or an outer function, so
1701 if (!isPureBypassingInference() || isNested())
1704 TypeFunction tf = type.toTypeFunction();
1706 //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1708 foreach (i, fparam; tf.parameterList)
1710 Type tp = fparam.type;
1714 if (fparam.isLazy() || fparam.isReference())
1716 if (!traverseIndirections(tp, t))
1721 /* Goes down one level of indirection, then calls traverseIndirection() on
1724 * true if t is isolated from tp
1726 static bool traverse(Type tp, Type t)
1728 tp = tp.baseElemOf();
1733 return traverseIndirections(tp.nextOf(), t);
1737 return traverseIndirections(tp, t);
1740 /* Drill down and check the struct's fields
1742 auto sym = tp.toDsymbol(null).isStructDeclaration();
1743 foreach (v; sym.fields)
1745 Type tprmi = v.type.addMod(tp.mod);
1746 //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1747 if (!traverse(tprmi, t))
1757 if (!traverse(tp, t))
1760 // The 'this' reference is a parameter, too
1761 if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
1763 Type tthis = ad.getType().addMod(tf.mod);
1764 //printf("\ttthis = %s\n", tthis.toChars());
1765 if (!traverseIndirections(tthis, t))
1772 /****************************************
1773 * Determine if function needs a static frame pointer.
1775 * `true` if function is really nested within other function.
1777 * If isNested() returns true, isThis() should return false,
1778 * unless the function needs a dual-context pointer.
1780 bool isNested() const
1782 auto f = toAliasFunc();
1783 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1784 return ((f.storage_class & STC.static_) == 0) &&
1785 (f._linkage == LINK.d) &&
1786 (f.toParent2().isFuncDeclaration() !is null ||
1787 f.toParent2() !is f.toParentLocal());
1790 /****************************************
1791 * Determine if function is a non-static member function
1792 * that has an implicit 'this' expression.
1794 * The aggregate it is a member of, or null.
1796 * Both isThis() and isNested() should return true if function needs a dual-context pointer,
1797 * otherwise if isThis() returns true, isNested() should return false.
1799 override inout(AggregateDeclaration) isThis() inout
1801 //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1802 auto ad = (storage_class & STC.static_) ? .objc.isThis(this) : isMemberLocal();
1803 //printf("-FuncDeclaration::isThis() %p\n", ad);
1807 override final bool needThis()
1809 //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1810 return toAliasFunc().isThis() !is null;
1813 // Determine if a function is pedantically virtual
1814 final bool isVirtualMethod()
1816 if (toAliasFunc() != this)
1817 return toAliasFunc().isVirtualMethod();
1819 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1822 // If it's a final method, and does not override anything, then it is not virtual
1823 if (isFinalFunc() && foverrides.length == 0)
1830 // Determine if function goes into virtual function pointer table
1831 bool isVirtual() const
1833 if (toAliasFunc() != this)
1834 return toAliasFunc().isVirtual();
1836 auto p = toParent();
1838 if (!isMember || !p.isClassDeclaration)
1841 if (p.isClassDeclaration.classKind == ClassKind.objc)
1842 return .objc.isVirtual(this);
1846 printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1847 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), visibility == Visibility.Kind.private_, isCtorDeclaration(), linkage != LINK.d);
1848 printf("result is %d\n", isMember() && !(isStatic() || visibility == Visibility.Kind.private_ || visibility == Visibility.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()));
1850 return !(isStatic() || visibility.kind == Visibility.Kind.private_ || visibility.kind == Visibility.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc());
1853 final bool isFinalFunc() const
1855 if (toAliasFunc() != this)
1856 return toAliasFunc().isFinalFunc();
1860 auto cd = toParent().isClassDeclaration();
1861 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal());
1862 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_));
1863 printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_)));
1865 printf("\tmember of %s\n", cd.toChars());
1869 if (Declaration.isFinal())
1871 auto cd = toParent().isClassDeclaration();
1872 return (cd !is null) && (cd.storage_class & STC.final_);
1875 bool addPreInvariant()
1878 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1879 return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
1882 bool addPostInvariant()
1885 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1886 return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
1889 override const(char)* kind() const
1891 return this.isGenerated() ? "generated function" : "function";
1894 /********************************************
1896 * true if there are no overloads of this function
1898 final bool isUnique() const
1900 bool result = false;
1901 overloadApply(cast() this, (Dsymbol s)
1903 auto f = s.isFuncDeclaration();
1909 return 1; // ambiguous, done
1920 /*********************************************
1921 * In the current function, we are calling 'this' function.
1922 * 1. Check to see if the current function can call 'this' function, issue error if not.
1923 * 2. If the current function is not the parent of 'this' function, then add
1924 * the current function to the list of siblings of 'this' function.
1925 * 3. If the current function is a literal, and it's accessing an uplevel scope,
1926 * then mark it as a delegate.
1927 * Returns true if error occurs.
1929 extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
1931 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
1933 if (auto fld = this.isFuncLiteralDeclaration())
1935 if (fld.tok == TOK.reserved)
1937 fld.tok = TOK.function_;
1942 if (!parent || parent == sc.parent)
1944 if (ident == Id.require || ident == Id.ensure)
1946 if (!isThis() && !isNested())
1949 // The current function
1950 FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
1952 return false; // out of function scope
1954 Dsymbol p = toParentLocal();
1955 Dsymbol p2 = toParent2();
1957 // Function literals from fdthis to p must be delegates
1958 ensureStaticLinkTo(fdthis, p);
1960 ensureStaticLinkTo(fdthis, p2);
1964 // The function that this function is in
1965 bool checkEnclosing(FuncDeclaration fdv)
1972 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
1973 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
1974 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
1976 // Add this function to the list of those which called us
1980 for (size_t i = 0; i < siblingCallers.length; ++i)
1982 if (siblingCallers[i] == fdthis)
1987 //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
1988 if (!sc.intypeof && !(sc.flags & SCOPE.compile))
1990 siblingCallers.push(fdthis);
1991 computedEscapingSiblings = false;
1996 const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this);
1997 if (lv == LevelError)
1998 return true; // error
2000 return false; // downlevel call
2002 return false; // same level call
2004 return false; // Uplevel call
2007 if (checkEnclosing(p.isFuncDeclaration()))
2009 if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
2015 /*******************************
2016 * Look at all the variables in this function that are referenced
2017 * by nested functions, and determine if a closure needs to be
2020 final bool needsClosure()
2022 /* Need a closure for all the closureVars[] if any of the
2023 * closureVars[] are accessed by a
2024 * function that escapes the scope of this function.
2025 * We take the conservative approach and decide that a function needs
2027 * 1) is a virtual function
2028 * 2) has its address taken
2029 * 3) has a parent that escapes
2030 * 4) calls another nested function that needs a closure
2032 * Note that since a non-virtual function can be called by
2033 * a virtual one, if that non-virtual function accesses a closure
2034 * var, the closure still has to be taken. Hence, we check for isThis()
2035 * instead of isVirtual(). (thanks to David Friedman)
2037 * When the function returns a local struct or class, `requiresClosure`
2038 * is already set to `true` upon entering this function when the
2039 * struct/class refers to a local variable and a closure is needed.
2041 //printf("FuncDeclaration::needsClosure() %s\n", toPrettyChars());
2043 if (requiresClosure)
2046 for (size_t i = 0; i < closureVars.length; i++)
2048 VarDeclaration v = closureVars[i];
2049 //printf("\tv = %s\n", v.toChars());
2051 for (size_t j = 0; j < v.nestedrefs.length; j++)
2053 FuncDeclaration f = v.nestedrefs[j];
2056 /* __require and __ensure will always get called directly,
2057 * so they never make outer functions closure.
2059 if (f.ident == Id.require || f.ident == Id.ensure)
2062 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
2064 /* Look to see if f escapes. We consider all parents of f within
2065 * this, and also all siblings which call f; if any of them escape,
2067 * Mark all affected functions as requiring closures.
2069 for (Dsymbol s = f; s && s != this; s = s.toParentP(this))
2071 FuncDeclaration fx = s.isFuncDeclaration();
2074 if (fx.isThis() || fx.tookAddressOf)
2076 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
2078 /* Mark as needing closure any functions between this and f
2080 markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this);
2082 requiresClosure = true;
2085 /* We also need to check if any sibling functions that
2086 * called us, have escaped. This is recursive: we need
2087 * to check the callers of our siblings.
2089 if (checkEscapingSiblings(fx, this))
2090 requiresClosure = true;
2092 /* https://issues.dlang.org/show_bug.cgi?id=12406
2093 * Iterate all closureVars to mark all descendant
2094 * nested functions that access to the closing context of this function.
2099 if (requiresClosure)
2108 /***********************************************
2109 * Check that the function contains any closure.
2110 * If it's @nogc, report suitable errors.
2111 * This is mostly consistent with FuncDeclaration::needsClosure().
2114 * true if any errors occur.
2116 extern (C++) final bool checkClosure()
2118 //printf("checkClosure() %s\n", toPrettyChars());
2119 if (!needsClosure())
2124 error("is `@nogc` yet allocates closure for `%s()` with the GC", toChars());
2125 if (global.gag) // need not report supplemental errors
2128 else if (global.params.betterC)
2130 error("is `-betterC` yet allocates closure for `%s()` with the GC", toChars());
2131 if (global.gag) // need not report supplemental errors
2136 printGCUsage(loc, "using closure causes GC allocation");
2141 foreach (v; closureVars)
2143 foreach (f; v.nestedrefs)
2147 LcheckAncestorsOfANestedRef:
2148 for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
2150 auto fx = s.isFuncDeclaration();
2155 checkEscapingSiblings(fx, this))
2160 break LcheckAncestorsOfANestedRef;
2163 .errorSupplemental(f.loc, "`%s` closes over variable `%s` at %s",
2164 f.toPrettyChars(), v.toChars(), v.loc.toChars());
2165 break LcheckAncestorsOfANestedRef;
2174 /***********************************************
2175 * Determine if function's variables are referenced by a function
2178 final bool hasNestedFrameRefs()
2180 if (closureVars.length)
2183 /* If a virtual function has contracts, assume its variables are referenced
2184 * by those contracts, even if they aren't. Because they might be referenced
2185 * by the overridden or overriding function's contracts.
2186 * This can happen because frequire and fensure are implemented as nested functions,
2187 * and they can be called directly by an overriding function and the overriding function's
2188 * context had better match, or
2189 * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
2191 if (fdrequire || fdensure)
2194 if (foverrides.length && isVirtualMethod())
2196 for (size_t i = 0; i < foverrides.length; i++)
2198 FuncDeclaration fdv = foverrides[i];
2199 if (fdv.hasNestedFrameRefs())
2206 /****************************************************
2207 * Check whether result variable can be built.
2209 * `true` if the function has a return type that
2210 * is different from `void`.
2212 extern (D) private bool canBuildResultVar()
2214 auto f = cast(TypeFunction)type;
2215 return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
2218 /****************************************************
2219 * Declare result variable lazily.
2221 extern (D) final void buildResultVar(Scope* sc, Type tret)
2225 Loc loc = fensure ? fensure.loc : this.loc;
2227 /* If inferRetType is true, tret may not be a correct return type yet.
2228 * So, in here it may be a temporary type for vresult, and after
2229 * fbody.dsymbolSemantic() running, vresult.type might be modified.
2231 vresult = new VarDeclaration(loc, tret, Id.result, null);
2232 vresult.storage_class |= STC.nodtor | STC.temp;
2234 vresult.storage_class |= STC.const_;
2235 vresult.storage_class |= STC.result;
2237 // set before the semantic() for checkNestedReference()
2238 vresult.parent = this;
2241 if (sc && vresult.semanticRun == PASS.initial)
2243 TypeFunction tf = type.toTypeFunction();
2245 vresult.storage_class |= STC.ref_;
2246 vresult.type = tret;
2248 vresult.dsymbolSemantic(sc);
2250 if (!sc.insert(vresult))
2251 error("out result %s is already defined", vresult.toChars());
2252 assert(vresult.parent == this);
2256 /****************************************************
2257 * Merge into this function the 'in' contracts of all it overrides.
2258 * 'in's are OR'd together, i.e. only one of them needs to pass.
2260 extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
2262 /* If a base function and its override both have an IN contract, then
2263 * only one of them needs to succeed. This is done by generating:
2265 * void derived.in() {
2270 * ... body of derived.in() ...
2274 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2275 * If base.in() throws, then derived.in()'s body is executed.
2278 foreach (fdv; foverrides)
2280 /* The semantic pass on the contracts of the overridden functions must
2281 * be completed before code generation occurs.
2282 * https://issues.dlang.org/show_bug.cgi?id=3602
2284 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2287 Scope* sc = fdv._scope.push();
2288 sc.stc &= ~STC.override_;
2293 sf = fdv.mergeFrequire(sf, params);
2294 if (!sf || !fdv.fdrequire)
2296 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2298 * try { __require(params); }
2299 * catch (Throwable) { frequire; }
2301 params = Expression.arraySyntaxCopy(params);
2302 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2303 Statement s2 = new ExpStatement(loc, e);
2305 auto c = new Catch(loc, getThrowable(), null, sf);
2306 c.internalCatch = true;
2307 auto catches = new Catches();
2309 sf = new TryCatchStatement(loc, s2, catches);
2314 /****************************************************
2315 * Merge into this function the 'in' contracts of all it overrides.
2317 extern (D) final Statement mergeFrequireInclusivePreview(Statement sf, Expressions* params)
2319 /* If a base function and its override both have an IN contract, then
2320 * the override in contract must widen the guarantee of the base contract.
2321 * This is checked by generating:
2323 * void derived.in() {
2325 * ... body of derived.in() ...
2328 * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
2330 * assert(false, "Logic error: " ~ thr.msg);
2335 foreach (fdv; foverrides)
2337 /* The semantic pass on the contracts of the overridden functions must
2338 * be completed before code generation occurs.
2339 * https://issues.dlang.org/show_bug.cgi?id=3602
2341 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2344 Scope* sc = fdv._scope.push();
2345 sc.stc &= ~STC.override_;
2350 sf = fdv.mergeFrequireInclusivePreview(sf, params);
2351 if (sf && fdv.fdrequire)
2353 const loc = this.fdrequire.loc;
2355 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2358 * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
2360 Identifier id = Identifier.generateId("thr");
2361 params = Expression.arraySyntaxCopy(params);
2362 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2363 Statement s2 = new ExpStatement(loc, e);
2364 // assert(false, ...)
2365 // TODO make this a runtime helper to allow:
2366 // - chaining the original expression
2367 // - nogc concatenation
2368 Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
2369 Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
2371 Statement s3 = new CompoundStatement(loc, s2, fail);
2373 auto c = new Catch(loc, getThrowable(), id, s3);
2374 c.internalCatch = true;
2375 auto catches = new Catches();
2377 sf = new TryCatchStatement(loc, sf, catches);
2385 /****************************************************
2386 * Determine whether an 'out' contract is declared inside
2387 * the given function or any of its overrides.
2389 * fd = the function to search
2391 * true found an 'out' contract
2393 static bool needsFensure(FuncDeclaration fd)
2398 foreach (fdv; fd.foverrides)
2400 if (needsFensure(fdv))
2406 /****************************************************
2407 * Rewrite contracts as statements.
2409 final void buildEnsureRequire()
2414 /* in { statements1... }
2415 * in { statements2... }
2418 * in { { statements1... } { statements2... } ... }
2420 assert(frequires.length);
2421 auto loc = (*frequires)[0].loc;
2422 auto s = new Statements;
2423 foreach (r; *frequires)
2425 s.push(new ScopeStatement(r.loc, r, r.loc));
2427 frequire = new CompoundStatement(loc, s);
2432 /* out(id1) { statements1... }
2433 * out(id2) { statements2... }
2436 * out(__result) { { ref id1 = __result; { statements1... } }
2437 * { ref id2 = __result; { statements2... } } ... }
2439 assert(fensures.length);
2440 auto loc = (*fensures)[0].ensure.loc;
2441 auto s = new Statements;
2442 foreach (r; *fensures)
2444 if (r.id && canBuildResultVar())
2446 auto rloc = r.ensure.loc;
2447 auto resultId = new IdentifierExp(rloc, Id.result);
2448 auto init = new ExpInitializer(rloc, resultId);
2449 auto stc = STC.ref_ | STC.temp | STC.result;
2450 auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
2451 auto sdecl = new ExpStatement(rloc, decl);
2452 s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
2459 fensure = new CompoundStatement(loc, s);
2465 /* Rewrite contracts as nested functions, then call them. Doing it as nested
2466 * functions means that overriding functions can call them.
2468 TypeFunction f = cast(TypeFunction) type;
2470 /* Make a copy of the parameters and make them all ref */
2471 static Parameters* toRefCopy(ParameterList parameterList)
2473 auto result = new Parameters();
2475 foreach (n, p; parameterList)
2479 p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
2480 p.defaultArg = null; // won't be the same with ref
2491 * void __require(ref params) { ... }
2492 * __require(params);
2494 Loc loc = frequire.loc;
2495 fdrequireParams = new Expressions();
2498 foreach (vd; *parameters)
2499 fdrequireParams.push(new VarExp(loc, vd));
2501 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2502 auto fparams = toRefCopy(fo.parameterList);
2503 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2504 tf.isnothrow = f.isnothrow;
2505 tf.isnogc = f.isnogc;
2506 tf.purity = f.purity;
2508 auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
2509 fd.fbody = frequire;
2510 Statement s1 = new ExpStatement(loc, fd);
2511 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
2512 Statement s2 = new ExpStatement(loc, e);
2513 frequire = new CompoundStatement(loc, s1, s2);
2517 /* We need to set fdensureParams here and not in the block below to
2518 * have the parameters available when calling a base class ensure(),
2519 * even if this function doesn't have an out contract.
2521 fdensureParams = new Expressions();
2522 if (canBuildResultVar())
2523 fdensureParams.push(new IdentifierExp(loc, Id.result));
2526 foreach (vd; *parameters)
2527 fdensureParams.push(new VarExp(loc, vd));
2532 /* out (result) { ... }
2534 * void __ensure(ref tret result, ref params) { ... }
2535 * __ensure(result, params);
2537 Loc loc = fensure.loc;
2538 auto fparams = new Parameters();
2539 if (canBuildResultVar())
2541 Parameter p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
2544 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2545 fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
2546 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2547 tf.isnothrow = f.isnothrow;
2548 tf.isnogc = f.isnogc;
2549 tf.purity = f.purity;
2551 auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
2553 Statement s1 = new ExpStatement(loc, fd);
2554 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
2555 Statement s2 = new ExpStatement(loc, e);
2556 fensure = new CompoundStatement(loc, s1, s2);
2561 /****************************************************
2562 * Merge into this function the 'out' contracts of all it overrides.
2563 * 'out's are AND'd together, i.e. all of them need to pass.
2565 extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
2567 /* Same comments as for mergeFrequire(), except that we take care
2568 * of generating a consistent reference to the 'result' local by
2569 * explicitly passing 'result' to the nested function as a reference
2571 * This won't work for the 'this' parameter as it would require changing
2572 * the semantic code for the nested function so that it looks on the parameter
2573 * list for the 'this' pointer, something that would need an unknown amount
2574 * of tweaking of various parts of the compiler that I'd rather leave alone.
2576 foreach (fdv; foverrides)
2578 /* The semantic pass on the contracts of the overridden functions must
2579 * be completed before code generation occurs.
2580 * https://issues.dlang.org/show_bug.cgi?id=3602 and
2581 * https://issues.dlang.org/show_bug.cgi?id=5230
2583 if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
2586 Scope* sc = fdv._scope.push();
2587 sc.stc &= ~STC.override_;
2592 sf = fdv.mergeFensure(sf, oid, params);
2595 //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2596 // Make the call: __ensure(result, params)
2597 params = Expression.arraySyntaxCopy(params);
2598 if (canBuildResultVar())
2600 Type t1 = fdv.type.nextOf().toBasetype();
2601 Type t2 = this.type.nextOf().toBasetype();
2602 if (t1.isBaseOf(t2, null))
2604 /* Making temporary reference variable is necessary
2605 * in covariant return.
2606 * https://issues.dlang.org/show_bug.cgi?id=5204
2607 * https://issues.dlang.org/show_bug.cgi?id=10479
2609 Expression* eresult = &(*params)[0];
2610 auto ei = new ExpInitializer(Loc.initial, *eresult);
2611 auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
2612 v.storage_class |= STC.temp;
2613 auto de = new DeclarationExp(Loc.initial, v);
2614 auto ve = new VarExp(Loc.initial, v);
2615 *eresult = new CommaExp(Loc.initial, de, ve);
2618 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
2619 Statement s2 = new ExpStatement(loc, e);
2623 sf = new CompoundStatement(sf.loc, s2, sf);
2632 /*********************************************
2633 * Returns: the function's parameter list, and whether
2634 * it is variadic or not.
2636 final ParameterList getParameterList()
2640 TypeFunction fdtype = type.isTypeFunction();
2641 if (fdtype) // Could also be TypeError
2642 return fdtype.parameterList;
2645 return ParameterList(null, VarArg.none);
2648 /**********************************
2649 * Generate a FuncDeclaration for a runtime library function.
2651 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
2653 return genCfunc(fparams, treturn, Identifier.idPool(name, cast(uint)strlen(name)), stc);
2656 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
2661 __gshared DsymbolTable st = null;
2663 //printf("genCfunc(name = '%s')\n", id.toChars());
2664 //printf("treturn\n\t"); treturn.print();
2666 // See if already in table
2668 st = new DsymbolTable();
2672 fd = s.isFuncDeclaration();
2674 assert(fd.type.nextOf().equals(treturn));
2678 tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc);
2679 fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf);
2680 fd.visibility = Visibility(Visibility.Kind.public_);
2681 fd._linkage = LINK.c;
2689 + Checks the parameter and return types iff this is a `main` function.
2691 + The following signatures are allowed for a `D main`:
2692 + - Either no or a single parameter of type `string[]`
2693 + - Return type is either `void`, `int` or `noreturn`
2695 + The following signatures are standard C:
2697 + - `int main(int, char**)`
2699 + This function accepts the following non-standard extensions:
2700 + - `char** envp` as a third parameter
2701 + - `void` / `noreturn` as return type
2703 + This function will issue errors for unexpected arguments / return types.
2705 extern (D) final void checkMain()
2707 if (ident != Id.main || isMember() || isNested())
2708 return; // Not a main function
2710 TypeFunction tf = type.toTypeFunction();
2712 Type retType = tf.nextOf();
2715 // auto main(), check after semantic
2716 assert(this.inferRetType);
2720 /// Checks whether `t` is equivalent to `char**`
2721 /// Ignores qualifiers and treats enums according to their base type
2722 static bool isCharPtrPtr(Type t)
2724 auto tp = t.toBasetype().isTypePointer();
2728 tp = tp.next.toBasetype().isTypePointer();
2732 return tp.next.toBasetype().ty == Tchar;
2735 // Neither of these qualifiers is allowed because they affect the ABI
2736 enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
2738 const nparams = tf.parameterList.length;
2741 const linkage = resolvedLinkage();
2742 if (linkage == LINK.d)
2746 auto fparam0 = tf.parameterList[0];
2747 auto t = fparam0.type.toBasetype();
2748 if (t.ty != Tarray ||
2749 t.nextOf().ty != Tarray ||
2750 t.nextOf().nextOf().ty != Tchar ||
2751 fparam0.storageClass & invalidSTC)
2757 if (tf.parameterList.varargs || nparams >= 2 || argerr)
2758 error("parameter list must be empty or accept one parameter of type `string[]`");
2761 else if (linkage == LINK.c)
2763 if (nparams == 2 || nparams == 3)
2765 // Argument count must be int
2766 auto argCount = tf.parameterList[0];
2767 argerr |= !!(argCount.storageClass & invalidSTC);
2768 argerr |= argCount.type.toBasetype().ty != Tint32;
2770 // Argument pointer must be char**
2771 auto argPtr = tf.parameterList[1];
2772 argerr |= !!(argPtr.storageClass & invalidSTC);
2773 argerr |= !isCharPtrPtr(argPtr.type);
2775 // `char** environ` is a common extension, see J.5.1 of the C standard
2778 auto envPtr = tf.parameterList[2];
2779 argerr |= !!(envPtr.storageClass & invalidSTC);
2780 argerr |= !isCharPtrPtr(envPtr.type);
2784 argerr = nparams != 0;
2786 // Disallow variadic main() - except for K&R declarations in C files.
2787 // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
2788 if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
2793 error("parameters must match one of the following signatures");
2794 loc.errorSupplemental("`main()`");
2795 loc.errorSupplemental("`main(int argc, char** argv)`");
2796 loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
2800 return; // Neither C nor D main, ignore (should probably be an error)
2802 // Allow enums with appropriate base types (same ABI)
2803 retType = retType.toBasetype();
2805 if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
2806 error("must return `int`, `void` or `noreturn`, not `%s`", tf.nextOf().toChars());
2809 /***********************************************
2810 * Check all return statements for a function to verify that returning
2811 * using NRVO is possible.
2814 * `false` if the result cannot be returned by hidden reference.
2816 final bool checkNRVO()
2818 if (!isNRVO() || returns is null)
2821 auto tf = type.toTypeFunction();
2825 foreach (rs; *returns)
2827 if (auto ve = rs.exp.isVarExp())
2829 auto v = ve.var.isVarDeclaration();
2830 if (!v || v.isReference())
2832 else if (nrvo_var is null)
2834 // Variables in the data segment (e.g. globals, TLS or not),
2835 // parameters and closure variables cannot be NRVOed.
2836 if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
2838 if (v.nestedrefs.length && needsClosure())
2840 // don't know if the return storage is aligned
2843 if (alignSectionVars && (*alignSectionVars).contains(v))
2846 // The variable type needs to be equivalent to the return type.
2847 if (!v.type.equivalent(tf.next))
2849 //printf("Setting nrvo to %s\n", v.toChars());
2852 else if (nrvo_var != v)
2855 else //if (!exp.isLvalue()) // keep NRVO-ability
2861 override final inout(FuncDeclaration) isFuncDeclaration() inout
2866 inout(FuncDeclaration) toAliasFunc() inout
2871 override void accept(Visitor v)
2877 /********************************************************
2878 * Generate Expression to call the invariant.
2880 * ad aggregate with the invariant
2881 * vthis variable with 'this'
2883 * void expression that calls the invariant
2885 Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
2887 Expression e = null;
2888 // Call invariant directly only if it exists
2889 FuncDeclaration inv = ad.inv;
2890 ClassDeclaration cd = ad.isClassDeclaration();
2903 // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
2904 // For the correct mangling,
2905 // run attribute inference on inv if needed.
2906 inv.functionSemantic();
2909 //e = new DsymbolExp(Loc.initial, inv);
2910 //e = new CallExp(Loc.initial, e);
2911 //e = e.semantic(sc2);
2913 /* https://issues.dlang.org/show_bug.cgi?id=13113
2914 * Currently virtual invariant calls completely
2915 * bypass attribute enforcement.
2916 * Change the behavior of pre-invariant call by following it.
2918 e = new ThisExp(Loc.initial);
2919 e.type = ad.type.addMod(vthis.type.mod);
2920 e = new DotVarExp(Loc.initial, e, inv, false);
2922 e = new CallExp(Loc.initial, e);
2923 e.type = Type.tvoid;
2928 /***************************************************
2929 * Visit each overloaded function/template in turn, and call dg(s) on it.
2930 * Exit when no more, or dg(s) returns nonzero.
2933 * fstart = symbol to start from
2934 * dg = the delegate to be called on the overload
2935 * sc = context used to check if symbol is accessible (and therefore visible),
2940 * !=0 done (and the return value from the last dg() call)
2942 extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
2946 int overloadApplyRecurse(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc)
2948 // Detect cyclic calls.
2949 if (visited.contains(fstart))
2951 visited.push(fstart);
2954 for (auto d = fstart; d; d = next)
2956 import dmd.access : checkSymbolAccess;
2957 if (auto od = d.isOverDeclaration())
2959 /* The scope is needed here to check whether a function in
2960 an overload set was added by means of a private alias (or a
2961 selective import). If the scope where the alias is created
2962 is imported somewhere, the overload set is visible, but the private
2967 if (checkSymbolAccess(sc, od))
2969 if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
2973 else if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
2977 else if (auto fa = d.isFuncAliasDeclaration())
2979 if (fa.hasOverloads)
2981 if (int r = overloadApplyRecurse(fa.funcalias, dg, sc))
2984 else if (auto fd = fa.toAliasFunc())
2991 d.error("is aliased to a function");
2996 else if (auto ad = d.isAliasDeclaration())
3000 if (checkSymbolAccess(sc, ad))
3001 next = ad.toAlias();
3004 next = ad.toAlias();
3010 else if (auto td = d.isTemplateDeclaration())
3016 else if (auto fd = d.isFuncDeclaration())
3022 else if (auto os = d.isOverloadSet())
3030 d.error("is aliased to a function");
3032 // BUG: should print error message?
3037 return overloadApplyRecurse(fstart, dg, sc);
3041 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
3042 mismatching modifiers to `buf`.
3044 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
3045 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
3048 buf = output buffer to write to
3049 lhsMod = modifier on the left-hand side
3050 lhsMod = modifier on the right-hand side
3054 A tuple with `isMutable` and `isNotShared` set
3055 if the `lhsMod` is missing those modifiers (compared to rhs).
3057 auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod)
3059 static struct Mismatches
3065 Mismatches mismatches;
3067 bool bothMutable = ((lhsMod & rhsMod) == 0);
3068 bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0;
3069 bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_);
3071 if (lhsMod & MODFlags.shared_)
3072 buf.writestring("`shared` ");
3073 else if (sharedMismatch && !(lhsMod & MODFlags.immutable_))
3075 buf.writestring("non-shared ");
3076 mismatches.isNotShared = true;
3079 if (bothMutable && sharedMismatchOnly)
3082 else if (lhsMod & MODFlags.immutable_)
3083 buf.writestring("`immutable` ");
3084 else if (lhsMod & MODFlags.const_)
3085 buf.writestring("`const` ");
3086 else if (lhsMod & MODFlags.wild)
3087 buf.writestring("`inout` ");
3090 buf.writestring("mutable ");
3091 mismatches.isMutable = true;
3101 auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0);
3102 assert(buf[] == "`shared` ");
3103 assert(!mismatches.isNotShared);
3106 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_);
3107 assert(buf[] == "non-shared ");
3108 assert(mismatches.isNotShared);
3111 mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0);
3112 assert(buf[] == "`const` ");
3113 assert(!mismatches.isMutable);
3116 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_);
3117 assert(buf[] == "mutable ");
3118 assert(mismatches.isMutable);
3121 private const(char)* prependSpace(const(char)* str)
3123 if (!str || !*str) return "";
3125 return (" " ~ str.toDString() ~ "\0").ptr;
3128 /// Flag used by $(LREF resolveFuncCall).
3129 enum FuncResolveFlag : ubyte
3131 standard = 0, /// issue error messages, solve the call.
3132 quiet = 1, /// do not issue error message on no match, just return `null`.
3133 overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous
3134 /// matches and need explicit this.
3137 /*******************************************
3138 * Given a symbol that could be either a FuncDeclaration or
3139 * a function template, resolve it to a function symbol.
3141 * loc = instantiation location
3142 * sc = instantiation scope
3143 * s = instantiation symbol
3144 * tiargs = initial list of template arguments
3145 * tthis = if !NULL, the `this` argument type
3146 * argumentList = arguments to function
3147 * flags = see $(LREF FuncResolveFlag).
3149 * if match is found, then function symbol, else null
3151 FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
3152 Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
3154 auto fargs = argumentList.arguments;
3156 return null; // no match
3160 printf("resolveFuncCall('%s')\n", s.toChars());
3162 printf("\tthis: %s\n", tthis.toChars());
3165 for (size_t i = 0; i < fargs.length; i++)
3167 Expression arg = (*fargs)[i];
3169 printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
3172 printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
3175 if (tiargs && arrayObjectIsError(tiargs))
3178 foreach (arg; *fargs)
3183 functionResolve(m, s, loc, sc, tiargs, tthis, argumentList);
3186 if (m.last > MATCH.nomatch && m.lastf)
3188 if (m.count == 1) // exactly one match
3190 if (!(flags & FuncResolveFlag.quiet))
3191 m.lastf.functionSemantic();
3194 if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
3200 /* Failed to find a best match.
3201 * Do nothing or print error.
3203 if (m.last == MATCH.nomatch)
3205 // error was caused on matched function, not on the matching itself,
3206 // so return the function to produce a better diagnostic
3211 // We are done at this point, as the rest of this function generate
3212 // a diagnostic on invalid match
3213 if (flags & FuncResolveFlag.quiet)
3216 auto fd = s.isFuncDeclaration();
3217 auto od = s.isOverDeclaration();
3218 auto td = s.isTemplateDeclaration();
3219 if (td && td.funcroot)
3220 s = fd = td.funcroot;
3222 OutBuffer tiargsBuf;
3223 arrayObjectsToBuffer(&tiargsBuf, tiargs);
3226 fargsBuf.writeByte('(');
3227 argExpTypesToCBuffer(&fargsBuf, fargs);
3228 fargsBuf.writeByte(')');
3230 tthis.modToBuffer(&fargsBuf);
3232 // The call is ambiguous
3233 if (m.lastf && m.nextf)
3235 TypeFunction tf1 = m.lastf.type.toTypeFunction();
3236 TypeFunction tf2 = m.nextf.type.toTypeFunction();
3237 const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
3238 const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
3240 const(char)* mod1 = prependSpace(MODtoChars(tf1.mod));
3241 const(char)* mod2 = prependSpace(MODtoChars(tf2.mod));
3243 .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
3244 s.parent.toPrettyChars(), s.ident.toChars(),
3245 fargsBuf.peekChars(),
3246 m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1,
3247 m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2);
3251 // no match, generate an error messages
3254 // all of overloads are templates
3257 .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`",
3258 td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
3259 tiargsBuf.peekChars(), fargsBuf.peekChars());
3261 if (!global.gag || global.params.showGaggedErrors)
3262 printCandidates(loc, td, sc.isDeprecated());
3265 /* This case used to happen when several ctors are mixed in an agregate.
3266 A (bad) error message is already generated in overloadApply().
3267 see https://issues.dlang.org/show_bug.cgi?id=19729
3268 and https://issues.dlang.org/show_bug.cgi?id=17259
3276 .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
3277 od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
3281 // remove when deprecation period of class allocators and deallocators is over
3282 if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
3285 bool hasOverloads = fd.overnext !is null;
3286 auto tf = fd.type.isTypeFunction();
3287 // if type is an error, the original type should be there for better diagnostics
3289 tf = fd.originalType.toTypeFunction();
3291 if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch
3293 OutBuffer thisBuf, funcBuf;
3294 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
3295 auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
3298 .error(loc, "none of the overloads of `%s` are callable using a %sobject",
3299 fd.ident.toChars(), thisBuf.peekChars());
3300 if (!global.gag || global.params.showGaggedErrors)
3301 printCandidates(loc, fd, sc.isDeprecated());
3305 const(char)* failMessage;
3306 functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
3309 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3310 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3311 tf.modToChars(), fargsBuf.peekChars());
3312 errorSupplemental(loc, failMessage);
3316 .error(loc, "%smethod `%s` is not callable using a %sobject",
3317 funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
3319 if (mismatches.isNotShared)
3320 .errorSupplemental(fd.loc, "Consider adding `shared` here");
3321 else if (mismatches.isMutable)
3322 .errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
3326 //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
3329 .error(loc, "none of the overloads of `%s` are callable using argument types `%s`",
3330 fd.toChars(), fargsBuf.peekChars());
3331 if (!global.gag || global.params.showGaggedErrors)
3332 printCandidates(loc, fd, sc.isDeprecated());
3336 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3337 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3338 tf.modToChars(), fargsBuf.peekChars());
3340 // re-resolve to check for supplemental message
3341 if (!global.gag || global.params.showGaggedErrors)
3345 if (auto classType = tthis.isTypeClass())
3347 if (auto baseClass = classType.sym.baseClass)
3349 if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
3351 MatchAccumulator mErr;
3352 functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
3353 if (mErr.last > MATCH.nomatch && mErr.lastf)
3355 errorSupplemental(loc, "%s `%s` hides base class function `%s`",
3356 fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
3357 errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
3358 fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
3365 const(char)* failMessage;
3366 functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
3368 errorSupplemental(loc, failMessage);
3373 /*******************************************
3374 * Prints template and function overload candidates as supplemental errors.
3376 * loc = instantiation location
3377 * declaration = the declaration to print overload candidates for
3378 * showDeprecated = If `false`, `deprecated` function won't be shown
3380 private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
3381 if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
3383 // max num of overloads to print (-v or -verror-supplements overrides this).
3384 const int DisplayLimit = !global.params.verbose ?
3385 (global.params.errorSupplementLimit ? global.params.errorSupplementLimit : int.max)
3387 const(char)* constraintsTip;
3388 // determine if the first candidate was printed
3391 bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false)
3393 if (auto fd = s.isFuncDeclaration())
3395 // Don't print overloads which have errors.
3396 // Not that if the whole overload set has errors, we'll never reach
3397 // this point so there's no risk of printing no candidate
3398 if (fd.errors || fd.type.ty == Terror)
3400 // Don't print disabled functions, or `deprecated` outside of deprecated scope
3401 if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
3405 auto tf = cast(TypeFunction) fd.type;
3406 .errorSupplemental(fd.loc,
3407 printed ? " `%s%s`" :
3408 single_candidate ? "Candidate is: `%s%s`" : "Candidates are: `%s%s`",
3410 parametersTypeToChars(tf.parameterList));
3412 else if (auto td = s.isTemplateDeclaration())
3414 import dmd.staticcond;
3418 const tmsg = td.toCharsNoConstraints();
3419 const cmsg = td.getConstraintEvalError(constraintsTip);
3421 // add blank space if there are multiple candidates
3422 // the length of the blank space is `strlen("Candidates are: ")`
3426 .errorSupplemental(td.loc,
3427 printed ? " `%s`\n%s" :
3428 single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
3433 .errorSupplemental(td.loc,
3435 single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
3441 // determine if there's > 1 candidate
3443 overloadApply(declaration, (s) {
3444 if (matchSymbol(s, false))
3449 overloadApply(declaration, (s) {
3450 if (global.params.verbose || printed < DisplayLimit)
3452 if (matchSymbol(s, true, count == 1))
3457 // Too many overloads to sensibly display.
3458 // Just show count of remaining overloads.
3459 if (matchSymbol(s, false))
3465 .errorSupplemental(loc, "... (%d more, -v to show) ...", skipped);
3467 // Nothing was displayed, all overloads are either disabled or deprecated
3469 .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
3470 // should be only in verbose mode
3472 .tip(constraintsTip);
3475 /**************************************
3476 * Returns an indirect type one step from t.
3478 Type getIndirection(Type t)
3481 if (t.ty == Tarray || t.ty == Tpointer)
3482 return t.nextOf().toBasetype();
3483 if (t.ty == Taarray || t.ty == Tclass)
3485 if (t.ty == Tstruct)
3486 return t.hasPointers() ? t : null; // TODO
3488 // should consider TypeDelegate?
3492 /**************************************
3493 * Performs type-based alias analysis between a newly created value and a pre-
3494 * existing memory reference:
3496 * Assuming that a reference A to a value of type `ta` was available to the code
3497 * that created a reference B to a value of type `tb`, it returns whether B
3498 * might alias memory reachable from A based on the types involved (either
3499 * directly or via any number of indirections in either A or B).
3501 * This relation is not symmetric in the two arguments. For example, a
3502 * a `const(int)` reference can point to a pre-existing `int`, but not the other
3508 * `const(int)`, `int`, `false`
3509 * `int`, `const(int)`, `true`
3510 * `int`, `immutable(int)`, `false`
3511 * const(immutable(int)*), immutable(int)*, false // BUG: returns true
3514 * ta = value type being referred to
3515 * tb = referred to value type that could be constructed from ta
3518 * true if reference to `tb` is isolated from reference to `ta`
3520 private bool traverseIndirections(Type ta, Type tb)
3522 //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
3524 static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
3526 //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
3527 ta = ta.baseElemOf();
3528 tb = tb.baseElemOf();
3530 // First, check if the pointed-to types are convertible to each other such
3531 // that they might alias directly.
3532 static bool mayAliasDirect(Type source, Type target)
3535 // if source is the same as target or can be const-converted to target
3536 source.constConv(target) != MATCH.nomatch ||
3537 // if target is void and source can be const-converted to target
3538 (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
3541 if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
3543 //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3546 if (ta.nextOf() && ta.nextOf() == tb.nextOf())
3548 //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3552 if (tb.ty == Tclass || tb.ty == Tstruct)
3554 /* Traverse the type of each field of the aggregate
3556 bool* found = table.getLvalue(tb.deco);
3558 return true; // We have already seen this symbol, break the cycle
3562 AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
3563 foreach (v; sym.fields)
3565 Type tprmi = v.type.addMod(tb.mod);
3566 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
3567 if (!traverse(ta, tprmi, table, reversePass))
3571 else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
3573 Type tind = tb.nextOf();
3574 if (!traverse(ta, tind, table, reversePass))
3577 else if (tb.hasPointers())
3579 // BUG: consider the context pointer of delegate types
3583 // Still no match, so try breaking up ta if we have not done so yet.
3586 scope newTable = AssocArray!(const(char)*, bool)();
3587 return traverse(tb, ta, newTable, true);
3593 // To handle arbitrary levels of indirections in both parameters, we
3594 // recursively descend into aggregate members/levels of indirection in both
3595 // `ta` and `tb` while avoiding cycles. Start with the original types.
3596 scope table = AssocArray!(const(char)*, bool)();
3597 const result = traverse(ta, tb, table, false);
3598 //printf(" returns %d\n", result);
3602 /* For all functions between outerFunc and f, mark them as needing
3605 private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc)
3607 for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc))
3609 FuncDeclaration fy = sx.isFuncDeclaration();
3610 if (fy && fy.closureVars.length)
3612 /* fy needs a closure if it has closureVars[],
3613 * because the frame pointer in the closure will be accessed.
3615 fy.requiresClosure = true;
3621 * Given a nested function f inside a function outerFunc, check
3622 * if any sibling callers of f have escaped. If so, mark
3623 * all the enclosing functions as needing closures.
3624 * This is recursive: we need to check the callers of our siblings.
3625 * Note that nested functions can only call lexically earlier nested
3626 * functions, so loops are impossible.
3628 * f = inner function (nested within outerFunc)
3629 * outerFunc = outer function
3630 * p = for internal recursion use
3632 * true if any closures were needed
3634 private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
3636 static struct PrevSibling
3642 if (f.computedEscapingSiblings)
3643 return f.hasEscapingSiblings;
3646 ps.p = cast(PrevSibling*)p;
3649 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
3650 bool bAnyClosures = false;
3651 for (size_t i = 0; i < f.siblingCallers.length; ++i)
3653 FuncDeclaration g = f.siblingCallers[i];
3654 if (g.isThis() || g.tookAddressOf)
3656 markAsNeedingClosure(g, outerFunc);
3657 bAnyClosures = true;
3660 for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc))
3662 // A parent of the sibling had its address taken.
3663 // Assume escaping of parent affects its children, so needs propagating.
3664 // see https://issues.dlang.org/show_bug.cgi?id=19679
3665 FuncDeclaration parentFunc = parent.isFuncDeclaration;
3666 if (parentFunc && parentFunc.tookAddressOf)
3668 markAsNeedingClosure(parentFunc, outerFunc);
3669 bAnyClosures = true;
3673 PrevSibling* prev = cast(PrevSibling*)p;
3678 bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
3686 f.hasEscapingSiblings = bAnyClosures;
3687 f.computedEscapingSiblings = true;
3688 //printf("\t%d\n", bAnyClosures);
3689 return bAnyClosures;
3692 /***********************************************************
3693 * Used as a way to import a set of functions from another scope into this one.
3695 extern (C++) final class FuncAliasDeclaration : FuncDeclaration
3697 FuncDeclaration funcalias;
3700 extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true)
3702 super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type);
3703 assert(funcalias != this);
3704 this.funcalias = funcalias;
3706 this.hasOverloads = hasOverloads;
3709 if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration())
3710 this.hasOverloads = fad.hasOverloads;
3715 assert(!funcalias.isFuncAliasDeclaration());
3716 this.hasOverloads = false;
3718 userAttribDecl = funcalias.userAttribDecl;
3721 override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
3726 override const(char)* kind() const
3728 return "function alias";
3731 override inout(FuncDeclaration) toAliasFunc() inout
3733 return funcalias.toAliasFunc();
3736 override void accept(Visitor v)
3742 /***********************************************************
3744 extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
3746 TOK tok; // TOK.function_ or TOK.delegate_
3747 Type treq; // target of return type inference
3752 extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null, StorageClass storage_class = STC.undefined_)
3754 super(loc, endloc, null, storage_class, type);
3755 this.ident = id ? id : Id.empty;
3758 // Always infer scope for function literals
3759 // See https://issues.dlang.org/show_bug.cgi?id=20362
3760 this.inferScope = true;
3761 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
3764 override FuncLiteralDeclaration syntaxCopy(Dsymbol s)
3766 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
3768 auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident, storage_class & STC.auto_);
3769 f.treq = treq; // don't need to copy
3770 FuncDeclaration.syntaxCopy(f);
3774 override bool isNested() const
3776 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
3777 return (tok != TOK.function_) && !isThis();
3780 override inout(AggregateDeclaration) isThis() inout
3782 return tok == TOK.delegate_ ? super.isThis() : null;
3785 override bool isVirtual() const
3790 override bool addPreInvariant()
3795 override bool addPostInvariant()
3800 /*******************************
3801 * Modify all expression type of return statements to tret.
3803 * On function literals, return type may be modified based on the context type
3804 * after its semantic3 is done, in FuncExp::implicitCastTo.
3806 * A function() dg = (){ return new B(); } // OK if is(B : A) == true
3808 * If B to A conversion is convariant that requires offseet adjusting,
3809 * all return statements should be adjusted to return expressions typed A.
3811 void modifyReturns(Scope* sc, Type tret)
3813 import dmd.statement_rewrite_walker;
3815 extern (C++) final class RetWalker : StatementRewriteWalker
3817 alias visit = typeof(super).visit;
3821 FuncLiteralDeclaration fld;
3823 override void visit(ReturnStatement s)
3825 Expression exp = s.exp;
3826 if (exp && !exp.type.equals(tret))
3827 s.exp = exp.implicitCastTo(sc, tret);
3831 if (semanticRun < PASS.semantic3done)
3837 scope RetWalker w = new RetWalker();
3843 // Also update the inferred function type to match the new return type.
3844 // This is required so the code generator does not try to cast the
3845 // modified returns back to the original type.
3846 if (inferRetType && type.nextOf() != tret)
3847 type.toTypeFunction().next = tret;
3850 override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
3855 override const(char)* kind() const
3857 // GCC requires the (char*) casts
3858 return (tok != TOK.function_) ? "delegate" : "function";
3861 override const(char)* toPrettyChars(bool QualifyTypes = false)
3865 TemplateInstance ti = parent.isTemplateInstance();
3867 return ti.tempdecl.toPrettyChars(QualifyTypes);
3869 return Dsymbol.toPrettyChars(QualifyTypes);
3872 override void accept(Visitor v)
3878 /***********************************************************
3880 extern (C++) final class CtorDeclaration : FuncDeclaration
3883 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
3885 super(loc, endloc, Id.ctor, stc, type);
3886 this.isCpCtor = isCpCtor;
3887 //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
3890 override CtorDeclaration syntaxCopy(Dsymbol s)
3893 auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy());
3894 FuncDeclaration.syntaxCopy(f);
3898 override const(char)* kind() const
3900 return isCpCtor ? "copy constructor" : "constructor";
3903 override const(char)* toChars() const
3908 override bool isVirtual() const
3913 override bool addPreInvariant()
3918 override bool addPostInvariant()
3920 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3923 override inout(CtorDeclaration) isCtorDeclaration() inout
3928 override void accept(Visitor v)
3934 /***********************************************************
3936 extern (C++) final class PostBlitDeclaration : FuncDeclaration
3938 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
3940 super(loc, endloc, id, stc, null);
3943 override PostBlitDeclaration syntaxCopy(Dsymbol s)
3946 auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
3947 FuncDeclaration.syntaxCopy(dd);
3951 override bool isVirtual() const
3956 override bool addPreInvariant()
3961 override bool addPostInvariant()
3963 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3966 override bool overloadInsert(Dsymbol s)
3968 return false; // cannot overload postblits
3971 override inout(PostBlitDeclaration) isPostBlitDeclaration() inout
3976 override void accept(Visitor v)
3982 /***********************************************************
3984 extern (C++) final class DtorDeclaration : FuncDeclaration
3986 extern (D) this(const ref Loc loc, const ref Loc endloc)
3988 super(loc, endloc, Id.dtor, STC.undefined_, null);
3991 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
3993 super(loc, endloc, id, stc, null);
3996 override DtorDeclaration syntaxCopy(Dsymbol s)
3999 auto dd = new DtorDeclaration(loc, endloc, storage_class, ident);
4000 FuncDeclaration.syntaxCopy(dd);
4004 override const(char)* kind() const
4006 return "destructor";
4009 override const(char)* toChars() const
4014 override bool isVirtual() const
4016 // D dtor's don't get put into the vtbl[]
4017 // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
4018 return vtblIndex != -1;
4021 override bool addPreInvariant()
4023 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
4026 override bool addPostInvariant()
4031 override bool overloadInsert(Dsymbol s)
4033 return false; // cannot overload destructors
4036 override inout(DtorDeclaration) isDtorDeclaration() inout
4041 override void accept(Visitor v)
4047 /***********************************************************
4049 extern (C++) class StaticCtorDeclaration : FuncDeclaration
4051 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4053 super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null);
4056 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
4058 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
4061 override StaticCtorDeclaration syntaxCopy(Dsymbol s)
4064 auto scd = new StaticCtorDeclaration(loc, endloc, storage_class);
4065 FuncDeclaration.syntaxCopy(scd);
4069 override final inout(AggregateDeclaration) isThis() inout @nogc nothrow pure @safe
4074 override final bool isVirtual() const @nogc nothrow pure @safe
4079 override final bool addPreInvariant() @nogc nothrow pure @safe
4084 override final bool addPostInvariant() @nogc nothrow pure @safe
4089 override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
4094 override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
4099 override void accept(Visitor v)
4105 /***********************************************************
4107 extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
4109 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4111 super(loc, endloc, "_sharedStaticCtor", stc);
4114 override SharedStaticCtorDeclaration syntaxCopy(Dsymbol s)
4117 auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
4118 FuncDeclaration.syntaxCopy(scd);
4122 override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
4127 override void accept(Visitor v)
4133 /***********************************************************
4135 extern (C++) class StaticDtorDeclaration : FuncDeclaration
4137 VarDeclaration vgate; // 'gate' variable
4139 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4141 super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null);
4144 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
4146 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
4149 override StaticDtorDeclaration syntaxCopy(Dsymbol s)
4152 auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
4153 FuncDeclaration.syntaxCopy(sdd);
4157 override final inout(AggregateDeclaration) isThis() inout
4162 override final bool isVirtual() const
4167 override final bool hasStaticCtorOrDtor()
4172 override final bool addPreInvariant()
4177 override final bool addPostInvariant()
4182 override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
4187 override void accept(Visitor v)
4193 /***********************************************************
4195 extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
4197 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4199 super(loc, endloc, "_sharedStaticDtor", stc);
4202 override SharedStaticDtorDeclaration syntaxCopy(Dsymbol s)
4205 auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
4206 FuncDeclaration.syntaxCopy(sdd);
4210 override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
4215 override void accept(Visitor v)
4221 /***********************************************************
4223 extern (C++) final class InvariantDeclaration : FuncDeclaration
4225 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
4227 // Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list.
4228 super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
4232 override InvariantDeclaration syntaxCopy(Dsymbol s)
4235 auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null);
4236 FuncDeclaration.syntaxCopy(id);
4240 override bool isVirtual() const
4245 override bool addPreInvariant()
4250 override bool addPostInvariant()
4255 override inout(InvariantDeclaration) isInvariantDeclaration() inout
4260 override void accept(Visitor v)
4265 extern (D) void fixupInvariantIdent(size_t offset)
4268 idBuf.writestring("__invariant");
4269 idBuf.print(offset);
4271 ident = Identifier.idPool(idBuf[]);
4276 /***********************************************************
4278 extern (C++) final class UnitTestDeclaration : FuncDeclaration
4280 char* codedoc; // for documented unittest
4282 // toObjFile() these nested functions after this one
4283 FuncDeclarations deferredNested;
4285 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
4287 super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null);
4288 this.codedoc = codedoc;
4291 override UnitTestDeclaration syntaxCopy(Dsymbol s)
4294 auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
4295 FuncDeclaration.syntaxCopy(utd);
4299 override inout(AggregateDeclaration) isThis() inout
4304 override bool isVirtual() const
4309 override bool addPreInvariant()
4314 override bool addPostInvariant()
4319 override inout(UnitTestDeclaration) isUnitTestDeclaration() inout
4324 override void accept(Visitor v)
4330 /***********************************************************
4332 extern (C++) final class NewDeclaration : FuncDeclaration
4334 extern (D) this(const ref Loc loc, StorageClass stc)
4336 super(loc, Loc.initial, Id.classNew, STC.static_ | stc, null);
4339 override NewDeclaration syntaxCopy(Dsymbol s)
4342 auto f = new NewDeclaration(loc, storage_class);
4343 FuncDeclaration.syntaxCopy(f);
4347 override const(char)* kind() const
4352 override bool isVirtual() const
4357 override bool addPreInvariant()
4362 override bool addPostInvariant()
4367 override inout(NewDeclaration) isNewDeclaration() inout
4372 override void accept(Visitor v)
4378 /**************************************
4379 * When a traits(compiles) is used on a function literal call
4380 * we need to take into account if the body of the function
4381 * violates any attributes, however, we must not affect the
4382 * attribute inference on the outer function. The attributes
4383 * of the function literal still need to be inferred, therefore
4384 * we need a way to check for the scope that the traits compiles
4388 * sc = scope to be checked for
4390 * Returns: `true` if the provided scope is the root
4391 * of the traits compiles list of scopes.
4393 bool isRootTraitsCompilesScope(Scope* sc)
4395 return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
4398 /**************************************
4399 * A statement / expression in this scope is not `@safe`,
4400 * so mark the enclosing function as `@system`
4403 * sc = scope that the unsafe statement / expression is in
4404 * gag = surpress error message (used in escape.d)
4405 * loc = location of error
4406 * fmt = printf-style format string
4407 * arg0 = (optional) argument for first %s format specifier
4408 * arg1 = (optional) argument for second %s format specifier
4409 * arg2 = (optional) argument for third %s format specifier
4410 * Returns: whether there's a safe error
4412 bool setUnsafe(Scope* sc,
4413 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
4414 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
4417 return false; // typeof(cast(int*)0) is safe
4419 if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
4426 if (sc.varDecl.storage_class & STC.safe)
4428 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4431 else if (!(sc.varDecl.storage_class & STC.system))
4433 sc.varDecl.storage_class |= STC.system;
4440 if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
4442 if (sc.func.isSafeBypassingInference())
4444 // Message wil be gagged, but still call error() to update global.errors and for
4446 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4452 return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
4455 /***************************************
4456 * Like `setUnsafe`, but for safety errors still behind preview switches
4458 * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
4459 * the behavior changes based on the setting:
4461 * - In case of `-revert=fs`, it does nothing.
4462 * - In case of `-preview=fs`, it's the same as `setUnsafe`
4463 * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
4466 * sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
4467 * fs = feature state from the preview flag
4468 * gag = surpress error message
4469 * loc = location of error
4470 * msg = printf-style format string
4471 * arg0 = (optional) argument for first %s format specifier
4472 * arg1 = (optional) argument for second %s format specifier
4473 * arg2 = (optional) argument for third %s format specifier
4474 * Returns: whether an actual safe error (not deprecation) occured
4476 bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
4477 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
4479 if (fs == FeatureState.disabled)
4483 else if (fs == FeatureState.enabled)
4485 return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
4491 if (sc.func.isSafeBypassingInference())
4494 previewErrorFunc(sc.isDeprecated(), fs)(
4495 loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : ""
4498 else if (!sc.func.safetyViolation)
4500 import dmd.func : AttributeViolation;
4501 sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
4507 /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
4510 /// - a regular safety error, stored in (fmtStr, arg0, arg1)
4511 /// - a call to a function without the attribute, which is a special case, because in that case,
4512 /// that function might recursively also have a `AttributeViolation`. This way, in case
4513 /// of a big call stack, the error can go down all the way to the root cause.
4514 /// The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`.
4515 struct AttributeViolation
4517 /// location of error
4519 /// printf-style format string
4520 const(char)* fmtStr = null;
4521 /// Arguments for up to two `%s` format specifiers in format string
4522 RootObject arg0 = null;
4524 RootObject arg1 = null;
4526 RootObject arg2 = null;
4529 /// Print the reason why `fd` was inferred `@system` as a supplemental error
4531 /// fd = function to check
4532 /// maxDepth = up to how many functions deep to report errors
4533 /// deprecation = print deprecations instead of errors
4534 void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth, bool deprecation)
4536 auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
4537 if (auto s = fd.safetyViolation)
4541 errorFunc(s.loc, deprecation ?
4542 "which would be `@system` because of:" :
4543 "which was inferred `@system` because of:");
4544 errorFunc(s.loc, s.fmtStr,
4545 s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
4547 else if (s.arg0.dyncast() == DYNCAST.dsymbol)
4549 if (FuncDeclaration fd2 = (cast(Dsymbol) s.arg0).isFuncDeclaration())
4553 errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
4554 errorSupplementalInferredSafety(fd2, maxDepth - 1, deprecation);