d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9
[official-gcc.git] / gcc / d / dmd / func.d
blobadfecc83a1789925eeb2d3951d1fa10ed9bcfb32
1 /**
2 * Defines a function declaration.
4 * Includes:
5 * - function/delegate literals
6 * - function aliases
7 * - (static/shared) constructors/destructors/post-blits
8 * - `invariant`
9 * - `unittest`
11 * Copyright: Copyright (C) 1999-2024 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
19 module dmd.func;
21 import core.stdc.stdio;
22 import core.stdc.string;
23 import dmd.aggregate;
24 import dmd.arraytypes;
25 import dmd.astenums;
26 import dmd.blockexit;
27 import dmd.gluelayer;
28 import dmd.dcast;
29 import dmd.dclass;
30 import dmd.declaration;
31 import dmd.delegatize;
32 import dmd.dinterpret;
33 import dmd.dmodule;
34 import dmd.dscope;
35 import dmd.dstruct;
36 import dmd.dsymbol;
37 import dmd.dsymbolsem;
38 import dmd.dtemplate;
39 import dmd.errors;
40 import dmd.escape;
41 import dmd.expression;
42 import dmd.funcsem;
43 import dmd.globals;
44 import dmd.hdrgen;
45 import dmd.id;
46 import dmd.identifier;
47 import dmd.init;
48 import dmd.location;
49 import dmd.mtype;
50 import dmd.objc;
51 import dmd.root.aav;
52 import dmd.common.outbuffer;
53 import dmd.rootobject;
54 import dmd.root.string;
55 import dmd.root.stringtable;
56 import dmd.semantic2;
57 import dmd.semantic3;
58 import dmd.statement_rewrite_walker;
59 import dmd.statement;
60 import dmd.statementsem;
61 import dmd.tokens;
62 import dmd.visitor;
64 version (IN_GCC) {}
65 else version (IN_LLVM) {}
66 else version = MARS;
68 /// Inline Status
69 enum ILS : ubyte
71 uninitialized, /// not computed yet
72 no, /// cannot inline
73 yes, /// can inline
76 enum BUILTIN : ubyte
78 unknown = 255, /// not known if this is a builtin
79 unimp = 0, /// this is not a builtin
80 gcc, /// this is a GCC builtin
81 llvm, /// this is an LLVM builtin
82 sin,
83 cos,
84 tan,
85 sqrt,
86 fabs,
87 ldexp,
88 log,
89 log2,
90 log10,
91 exp,
92 expm1,
93 exp2,
94 round,
95 floor,
96 ceil,
97 trunc,
98 copysign,
99 pow,
100 fmin,
101 fmax,
102 fma,
103 isnan,
104 isinfinity,
105 isfinite,
106 bsf,
107 bsr,
108 bswap,
109 popcnt,
110 yl2x,
111 yl2xp1,
112 toPrecFloat,
113 toPrecDouble,
114 toPrecReal
117 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
119 extern (C++) final class NrvoWalker : StatementRewriteWalker
121 alias visit = typeof(super).visit;
122 public:
123 FuncDeclaration fd;
124 Scope* sc;
126 override void visit(ReturnStatement s)
128 // See if all returns are instead to be replaced with a goto returnLabel;
129 if (fd.returnLabel)
131 /* Rewrite:
132 * return exp;
133 * as:
134 * vresult = exp; goto Lresult;
136 auto gs = new GotoStatement(s.loc, Id.returnLabel);
137 gs.label = fd.returnLabel;
139 Statement s1 = gs;
140 if (s.exp)
141 s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
143 replaceCurrent(s1);
147 override void visit(TryFinallyStatement s)
149 DtorExpStatement des;
150 if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
151 fd.nrvo_var == des.var)
153 if (!(global.params.useExceptions && ClassDeclaration.throwable))
155 /* Don't need to call destructor at all, since it is nrvo
157 replaceCurrent(s._body);
158 s._body.accept(this);
159 return;
162 /* Normally local variable dtors are called regardless exceptions.
163 * But for nrvo_var, its dtor should be called only when exception is thrown.
165 * Rewrite:
166 * try { s.body; } finally { nrvo_var.edtor; }
167 * // equivalent with:
168 * // s.body; scope(exit) nrvo_var.edtor;
169 * as:
170 * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
171 * // equivalent with:
172 * // s.body; scope(failure) nrvo_var.edtor;
174 Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
175 Identifier id = Identifier.generateId("__o");
177 Statement handler = new PeelStatement(sexception);
178 if (sexception.blockExit(fd, null) & BE.fallthru)
180 auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
181 ts.internalThrow = true;
182 handler = new CompoundStatement(Loc.initial, handler, ts);
185 auto catches = new Catches();
186 auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
187 ctch.internalCatch = true;
188 ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
189 catches.push(ctch);
191 Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
192 fd.hasNoEH = false;
193 replaceCurrent(s2);
194 s2.accept(this);
196 else
197 StatementRewriteWalker.visit(s);
201 private struct FUNCFLAG
203 bool purityInprocess; /// working on determining purity
204 bool safetyInprocess; /// working on determining safety
205 bool nothrowInprocess; /// working on determining nothrow
206 bool nogcInprocess; /// working on determining @nogc
207 bool returnInprocess; /// working on inferring 'return' for parameters
208 bool inlineScanned; /// function has been scanned for inline possibilities
209 bool inferScope; /// infer 'scope' for parameters
210 bool hasCatches; /// function has try-catch statements
211 bool skipCodegen; /// do not generate code for this function.
212 bool printf; /// is a printf-like function
214 bool scanf; /// is a scanf-like function
215 bool noreturn; /// the function does not return
216 bool isNRVO = true; /// Support for named return value optimization
217 bool isNaked; /// The function is 'naked' (see inline ASM)
218 bool isGenerated; /// The function is compiler generated (e.g. `opCmp`)
219 bool isIntroducing; /// If this function introduces the overload set
220 bool hasSemantic3Errors; /// If errors in semantic3 this function's frame ptr
221 bool hasNoEH; /// No exception unwinding is needed
222 bool inferRetType; /// Return type is to be inferred
223 bool hasDualContext; /// has a dual-context 'this' parameter
225 bool hasAlwaysInlines; /// Contains references to functions that must be inlined
226 bool isCrtCtor; /// Has attribute pragma(crt_constructor)
227 bool isCrtDtor; /// Has attribute pragma(crt_destructor)
228 bool hasEscapingSiblings;/// Has sibling functions that escape
229 bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed
230 bool dllImport; /// __declspec(dllimport)
231 bool dllExport; /// __declspec(dllexport)
234 /***********************************************************
235 * Tuple of result identifier (possibly null) and statement.
236 * This is used to store out contracts: out(id){ ensure }
238 extern (C++) struct Ensure
240 Identifier id;
241 Statement ensure;
243 Ensure syntaxCopy()
245 return Ensure(id, ensure.syntaxCopy());
248 /*****************************************
249 * Do syntax copy of an array of Ensure's.
251 static Ensures* arraySyntaxCopy(Ensures* a)
253 Ensures* b = null;
254 if (a)
256 b = a.copy();
257 foreach (i, e; *a)
259 (*b)[i] = e.syntaxCopy();
262 return b;
267 /***********************************************************
268 * Most functions don't have contracts, so save memory by grouping
269 * this information into a separate struct
271 private struct ContractInfo
273 Statements* frequires; /// in contracts
274 Ensures* fensures; /// out contracts
275 Statement frequire; /// lowered in contract
276 Statement fensure; /// lowered out contract
277 FuncDeclaration fdrequire; /// function that does the in contract
278 FuncDeclaration fdensure; /// function that does the out contract
279 Expressions* fdrequireParams; /// argument list for __require
280 Expressions* fdensureParams; /// argument list for __ensure
283 /***********************************************************
285 extern (C++) class FuncDeclaration : Declaration
287 Statement fbody; /// function body
289 FuncDeclarations foverrides; /// functions this function overrides
291 private ContractInfo* contracts; /// contract information
293 const(char)* mangleString; /// mangled symbol created from mangleExact()
295 VarDeclaration vresult; /// result variable for out contracts
296 LabelDsymbol returnLabel; /// where the return goes
298 bool[size_t] isTypeIsolatedCache; /// cache for the potentially very expensive isTypeIsolated check
300 // used to prevent symbols in different
301 // scopes from having the same name
302 DsymbolTable localsymtab;
303 VarDeclaration vthis; /// 'this' parameter (member and nested)
304 VarDeclaration v_arguments; /// '_arguments' parameter
306 VarDeclaration v_argptr; /// '_argptr' variable
307 VarDeclarations* parameters; /// Array of VarDeclaration's for parameters
308 DsymbolTable labtab; /// statement label symbol table
309 Dsymbol overnext; /// next in overload list
310 FuncDeclaration overnext0; /// next in overload list (only used during IFTI)
311 Loc endloc; /// location of closing curly bracket
312 int vtblIndex = -1; /// for member functions, index into vtbl[]
314 ILS inlineStatusStmt = ILS.uninitialized;
315 ILS inlineStatusExp = ILS.uninitialized;
316 PINLINE inlining = PINLINE.default_;
318 int inlineNest; /// !=0 if nested inline
320 ForeachStatement fes; /// if foreach body, this is the foreach
321 BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[]
322 /** if !=NULL, then this is the type
323 of the 'introducing' function
324 this one is overriding
326 Type tintro;
328 StorageClass storage_class2; /// storage class for template onemember's
330 // Things that should really go into Scope
332 /// 1 if there's a return exp; statement
333 /// 2 if there's a throw statement
334 /// 4 if there's an assert(0)
335 /// 8 if there's inline asm
336 /// 16 if there are multiple return statements
337 int hasReturnExp;
339 VarDeclaration nrvo_var; /// variable to replace with shidden
340 Symbol* shidden; /// hidden pointer passed to function
342 ReturnStatements* returns;
344 GotoStatements* gotos; /// Gotos with forward references
346 version (MARS)
348 VarDeclarations* alignSectionVars; /// local variables with alignment needs larger than stackAlign
349 Symbol* salignSection; /// pointer to aligned section, if any
352 /// set if this is a known, builtin function we can evaluate at compile time
353 BUILTIN builtin = BUILTIN.unknown;
355 /// set if someone took the address of this function
356 int tookAddressOf;
358 bool requiresClosure; // this function needs a closure
360 /** local variables in this function which are referenced by nested functions
361 * (They'll get put into the "closure" for this function.)
363 VarDeclarations closureVars;
365 /** Outer variables which are referenced by this nested function
366 * (the inverse of closureVars)
368 VarDeclarations outerVars;
370 /// Sibling nested functions which called this one
371 FuncDeclarations siblingCallers;
373 FuncDeclarations *inlinedNestedCallees;
375 /// In case of failed `@safe` inference, store the error that made the function `@system` for
376 /// better diagnostics
377 AttributeViolation* safetyViolation;
378 AttributeViolation* nogcViolation;
379 AttributeViolation* pureViolation;
380 AttributeViolation* nothrowViolation;
382 /// See the `FUNCFLAG` struct
383 import dmd.common.bitfields;
384 mixin(generateBitFields!(FUNCFLAG, uint));
387 * Data for a function declaration that is needed for the Objective-C
388 * integration.
390 ObjcFuncDeclaration objc;
392 extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false)
394 super(loc, ident);
395 //.printf("FuncDeclaration(id = '%s', type = %s)\n", ident.toChars(), type.toChars());
396 //.printf("storage_class = x%llx\n", storage_class);
397 this.storage_class = storage_class;
398 this.type = type;
399 if (type)
401 // Normalize storage_class, because function-type related attributes
402 // are already set in the 'type' in parsing phase.
403 this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
405 this.endloc = endloc;
406 if (noreturn)
407 this.noreturn = true;
409 /* The type given for "infer the return type" is a TypeFunction with
410 * NULL for the return type.
412 if (type && type.nextOf() is null)
413 this.inferRetType = true;
416 static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
418 return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn);
421 final nothrow pure @safe
423 private ref ContractInfo getContracts()
425 if (!contracts)
426 contracts = new ContractInfo();
427 return *contracts;
430 // getters
431 inout(Statements*) frequires() inout { return contracts ? contracts.frequires : null; }
432 inout(Ensures*) fensures() inout { return contracts ? contracts.fensures : null; }
433 inout(Statement) frequire() inout { return contracts ? contracts.frequire: null; }
434 inout(Statement) fensure() inout { return contracts ? contracts.fensure : null; }
435 inout(FuncDeclaration) fdrequire() inout { return contracts ? contracts.fdrequire : null; }
436 inout(FuncDeclaration) fdensure() inout { return contracts ? contracts.fdensure: null; }
437 inout(Expressions*) fdrequireParams() inout { return contracts ? contracts.fdrequireParams: null; }
438 inout(Expressions*) fdensureParams() inout { return contracts ? contracts.fdensureParams: null; }
440 extern (D) private static string generateContractSetter(string field, string type)
442 return type ~ " " ~ field ~ "(" ~ type ~ " param)" ~
444 if (!param && !contracts) return null;
445 return getContracts()." ~ field ~ " = param;
449 mixin(generateContractSetter("frequires", "Statements*"));
450 mixin(generateContractSetter("fensures", "Ensures*"));
451 mixin(generateContractSetter("frequire", "Statement"));
452 mixin(generateContractSetter("fensure", "Statement"));
453 mixin(generateContractSetter("fdrequire", "FuncDeclaration"));
454 mixin(generateContractSetter("fdensure", "FuncDeclaration"));
455 mixin(generateContractSetter("fdrequireParams", "Expressions*"));
456 mixin(generateContractSetter("fdensureParams", "Expressions*"));
459 override FuncDeclaration syntaxCopy(Dsymbol s)
461 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
462 FuncDeclaration f = s ? cast(FuncDeclaration)s
463 : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), this.noreturn != 0);
464 f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
465 f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
466 f.fbody = fbody ? fbody.syntaxCopy() : null;
467 return f;
470 /****************************************************
471 * Check that this function type is properly resolved.
472 * If not, report "forward reference error" and return true.
474 extern (D) final bool checkForwardRef(const ref Loc loc)
476 if (!functionSemantic(this))
477 return true;
479 /* No deco means the functionSemantic() call could not resolve
480 * forward referenes in the type of this function.
482 if (!type.deco)
484 bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3);
485 .error(loc, "forward reference to %s`%s`",
486 (inSemantic3 ? "inferred return type of function " : "").ptr,
487 toChars());
488 return true;
490 return false;
493 override final bool equals(const RootObject o) const
495 if (this == o)
496 return true;
498 if (auto s = isDsymbol(o))
500 auto fd1 = this;
501 auto fd2 = s.isFuncDeclaration();
502 if (!fd2)
503 return false;
505 auto fa1 = fd1.isFuncAliasDeclaration();
506 auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
508 auto fa2 = fd2.isFuncAliasDeclaration();
509 auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
511 if (fa1 && fa2)
513 return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
516 bool b1 = fa1 !is null;
517 if (b1 && faf1.isUnique() && !fa1.hasOverloads)
518 b1 = false;
520 bool b2 = fa2 !is null;
521 if (b2 && faf2.isUnique() && !fa2.hasOverloads)
522 b2 = false;
524 if (b1 != b2)
525 return false;
527 return faf1.toParent().equals(faf2.toParent()) &&
528 faf1.ident.equals(faf2.ident) &&
529 faf1.type.equals(faf2.type);
531 return false;
534 /****************************************************
535 * Determine if 'this' overrides fd.
536 * Return !=0 if it does.
538 extern (D) final int overrides(FuncDeclaration fd)
540 int result = 0;
541 if (fd.ident == ident)
543 import dmd.typesem : covariant;
544 const cov = type.covariant(fd.type);
545 if (cov != Covariant.distinct)
547 ClassDeclaration cd1 = toParent().isClassDeclaration();
548 ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
549 if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
550 result = 1;
553 return result;
556 /*************************************************
557 * Find index of function in vtbl[0..length] that
558 * this function overrides.
559 * Prefer an exact match to a covariant one.
560 * Params:
561 * vtbl = vtable to use
562 * dim = maximal vtable dimension
563 * Returns:
564 * -1 didn't find one
565 * -2 can't determine because of forward references
567 final int findVtblIndex(Dsymbols* vtbl, int dim)
569 //printf("findVtblIndex() %s\n", toChars());
570 import dmd.typesem : covariant;
572 FuncDeclaration mismatch = null;
573 StorageClass mismatchstc = 0;
574 int mismatchvi = -1;
575 int exactvi = -1;
576 int bestvi = -1;
577 for (int vi = 0; vi < dim; vi++)
579 FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration();
580 if (fdv && fdv.ident == ident)
582 if (type.equals(fdv.type)) // if exact match
584 if (fdv.parent.isClassDeclaration())
586 if (fdv.isFuture())
588 bestvi = vi;
589 continue; // keep looking
591 return vi; // no need to look further
594 if (exactvi >= 0)
596 .error(loc, "%s `%s` cannot determine overridden function", kind, toPrettyChars);
597 return exactvi;
599 exactvi = vi;
600 bestvi = vi;
601 continue;
604 StorageClass stc = 0;
605 const cov = type.covariant(fdv.type, &stc);
606 //printf("\tbaseclass cov = %d\n", cov);
607 final switch (cov)
609 case Covariant.distinct:
610 // types are distinct
611 break;
613 case Covariant.yes:
614 bestvi = vi; // covariant, but not identical
615 break;
616 // keep looking for an exact match
618 case Covariant.no:
619 mismatchvi = vi;
620 mismatchstc = stc;
621 mismatch = fdv; // overrides, but is not covariant
622 break;
623 // keep looking for an exact match
625 case Covariant.fwdref:
626 return -2; // forward references
630 if (_linkage == LINK.cpp && bestvi != -1)
632 StorageClass stc = 0;
633 FuncDeclaration fdv = (*vtbl)[bestvi].isFuncDeclaration();
634 assert(fdv && fdv.ident == ident);
635 if (type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no)
637 /* https://issues.dlang.org/show_bug.cgi?id=22351
638 * Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not.
639 * For now, continue to allow D covariant rules to apply when `override` has been used,
640 * but issue a deprecation warning that this behaviour will change in the future.
641 * Otherwise, follow the C++ covariant rules, which will create a new vtable entry.
643 if (isOverride())
645 /* @@@DEPRECATED_2.110@@@
646 * After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch,
647 * but also the `cppCovariant` parameter from Type.covariant, and update the function
648 * so that both `LINK.cpp` covariant conditions within are always checked.
650 .deprecation(loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated",
651 fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(),
652 toPrettyChars(), type.toTypeFunction().parameterList.parametersTypeToChars(), type.modToChars());
654 const char* where = type.isNaked() ? "parameters" : "type";
655 deprecationSupplemental(loc, "Either remove `override`, or adjust the `const` qualifiers of the "
656 ~ "overriding function %s", where);
658 else
660 // Treat as if Covariant.no
661 mismatchvi = bestvi;
662 mismatchstc = stc;
663 mismatch = fdv;
664 bestvi = -1;
668 if (bestvi == -1 && mismatch)
670 //type.print();
671 //mismatch.type.print();
672 //printf("%s %s\n", type.deco, mismatch.type.deco);
673 //printf("stc = %llx\n", mismatchstc);
674 if (mismatchstc)
676 // Fix it by modifying the type to add the storage classes
677 type = type.addStorageClass(mismatchstc);
678 bestvi = mismatchvi;
681 return bestvi;
684 /*********************************
685 * If function a function in a base class,
686 * return that base class.
687 * Returns:
688 * base class if overriding, null if not
690 extern (D) final BaseClass* overrideInterface()
692 for (ClassDeclaration cd = toParent2().isClassDeclaration(); cd; cd = cd.baseClass)
694 foreach (b; cd.interfaces)
696 auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length);
697 if (v >= 0)
698 return b;
701 return null;
704 /****************************************************
705 * Overload this FuncDeclaration with the new one f.
706 * Return true if successful; i.e. no conflict.
708 override bool overloadInsert(Dsymbol s)
710 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
711 assert(s != this);
712 AliasDeclaration ad = s.isAliasDeclaration();
713 if (ad)
715 if (overnext)
716 return overnext.overloadInsert(ad);
717 if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof)
719 //printf("\tad = '%s'\n", ad.type.toChars());
720 return false;
722 overnext = ad;
723 //printf("\ttrue: no conflict\n");
724 return true;
726 TemplateDeclaration td = s.isTemplateDeclaration();
727 if (td)
729 if (!td.funcroot)
730 td.funcroot = this;
731 if (overnext)
732 return overnext.overloadInsert(td);
733 overnext = td;
734 return true;
736 FuncDeclaration fd = s.isFuncDeclaration();
737 if (!fd)
738 return false;
740 version (none)
742 /* Disable this check because:
743 * const void foo();
744 * semantic() isn't run yet on foo(), so the const hasn't been
745 * applied yet.
747 if (type)
749 printf("type = %s\n", type.toChars());
750 printf("fd.type = %s\n", fd.type.toChars());
752 // fd.type can be NULL for overloaded constructors
753 if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
755 //printf("\tfalse: conflict %s\n", kind());
756 return false;
760 if (overnext)
762 td = overnext.isTemplateDeclaration();
763 if (td)
764 fd.overloadInsert(td);
765 else
766 return overnext.overloadInsert(fd);
768 overnext = fd;
769 //printf("\ttrue: no conflict\n");
770 return true;
773 /********************************************
774 * Find function in overload list that exactly matches t.
776 extern (D) final FuncDeclaration overloadExactMatch(Type t)
778 FuncDeclaration fd;
779 overloadApply(this, (Dsymbol s)
781 auto f = s.isFuncDeclaration();
782 if (!f)
783 return 0;
784 if (f.storage_class & STC.disable)
785 return 0;
786 if (t.equals(f.type))
788 fd = f;
789 return 1;
792 /* Allow covariant matches, as long as the return type
793 * is just a const conversion.
794 * This allows things like pure functions to match with an impure function type.
796 if (t.ty == Tfunction)
798 import dmd.typesem : covariant;
799 auto tf = cast(TypeFunction)f.type;
800 if (tf.covariant(t) == Covariant.yes &&
801 tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
803 fd = f;
804 return 1;
807 return 0;
809 return fd;
812 /********************************************
813 * Find function in overload list that matches to the 'this' modifier.
814 * There's four result types.
816 * 1. If the 'tthis' matches only one candidate, it's an "exact match".
817 * Returns the function and 'hasOverloads' is set to false.
818 * eg. If 'tthis" is mutable and there's only one mutable method.
819 * 2. If there's two or more match candidates, but a candidate function will be
820 * a "better match".
821 * Returns the better match function but 'hasOverloads' is set to true.
822 * eg. If 'tthis' is mutable, and there's both mutable and const methods,
823 * the mutable method will be a better match.
824 * 3. If there's two or more match candidates, but there's no better match,
825 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
826 * eg. If 'tthis' is mutable, and there's two or more mutable methods.
827 * 4. If there's no candidates, it's "no match" and returns null with error report.
828 * e.g. If 'tthis' is const but there's no const methods.
830 extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
832 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
833 MatchAccumulator m;
834 overloadApply(this, (Dsymbol s)
836 auto f = s.isFuncDeclaration();
837 if (!f || f == m.lastf) // skip duplicates
838 return 0;
840 auto tf = f.type.toTypeFunction();
841 //printf("tf = %s\n", tf.toChars());
843 MATCH match;
844 if (tthis) // non-static functions are preferred than static ones
846 if (f.needThis())
847 match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
848 else
849 match = MATCH.constant; // keep static function in overload candidates
851 else // static functions are preferred than non-static ones
853 if (f.needThis())
854 match = MATCH.convert;
855 else
856 match = MATCH.exact;
858 if (match == MATCH.nomatch)
859 return 0;
861 if (match > m.last) goto LcurrIsBetter;
862 if (match < m.last) goto LlastIsBetter;
864 // See if one of the matches overrides the other.
865 if (m.lastf.overrides(f)) goto LlastIsBetter;
866 if (f.overrides(m.lastf)) goto LcurrIsBetter;
868 //printf("\tambiguous\n");
869 m.nextf = f;
870 m.count++;
871 return 0;
873 LlastIsBetter:
874 //printf("\tlastbetter\n");
875 m.count++; // count up
876 return 0;
878 LcurrIsBetter:
879 //printf("\tisbetter\n");
880 if (m.last <= MATCH.convert)
882 // clear last secondary matching
883 m.nextf = null;
884 m.count = 0;
886 m.last = match;
887 m.lastf = f;
888 m.count++; // count up
889 return 0;
892 if (m.count == 1) // exact match
894 hasOverloads = false;
896 else if (m.count > 1) // better or ambiguous match
898 hasOverloads = true;
900 else // no match
902 hasOverloads = true;
903 auto tf = this.type.toTypeFunction();
904 assert(tthis);
905 assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
907 OutBuffer thisBuf, funcBuf;
908 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
909 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
910 .error(loc, "%smethod %s is not callable using a %sobject", kind, toPrettyChars,
911 funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
914 return m.lastf;
917 /********************************************
918 * find function template root in overload list
920 extern (D) final TemplateDeclaration findTemplateDeclRoot()
922 FuncDeclaration f = this;
923 while (f && f.overnext)
925 //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
926 TemplateDeclaration td = f.overnext.isTemplateDeclaration();
927 if (td)
928 return td;
929 f = f.overnext.isFuncDeclaration();
931 return null;
934 /********************************************
935 * Returns true if function was declared
936 * directly or indirectly in a unittest block
938 final bool inUnittest()
940 Dsymbol f = this;
943 if (f.isUnitTestDeclaration())
944 return true;
945 f = f.toParent();
947 while (f);
948 return false;
951 /*************************************
952 * Determine partial specialization order of functions `f` vs `g`.
953 * This is very similar to TemplateDeclaration::leastAsSpecialized().
954 * Params:
955 * f = first function
956 * g = second function
957 * names = names of parameters
958 * Returns:
959 * match 'this' is at least as specialized as g
960 * 0 g is more specialized than 'this'
962 static MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names)
964 enum LOG_LEASTAS = 0;
965 static if (LOG_LEASTAS)
967 import core.stdc.stdio : printf;
968 printf("leastAsSpecialized(%s, %s, %s)\n", f.toChars(), g.toChars(), names ? names.toChars() : "null");
969 printf("%s, %s\n", f.type.toChars(), g.type.toChars());
972 /* This works by calling g() with f()'s parameters, and
973 * if that is possible, then f() is at least as specialized
974 * as g() is.
977 TypeFunction tf = f.type.toTypeFunction();
978 TypeFunction tg = g.type.toTypeFunction();
980 /* If both functions have a 'this' pointer, and the mods are not
981 * the same and g's is not const, then this is less specialized.
983 if (f.needThis() && g.needThis() && tf.mod != tg.mod)
985 if (f.isCtorDeclaration())
987 if (!MODimplicitConv(tg.mod, tf.mod))
988 return MATCH.nomatch;
990 else
992 if (!MODimplicitConv(tf.mod, tg.mod))
993 return MATCH.nomatch;
997 /* Create a dummy array of arguments out of the parameters to f()
999 Expressions args;
1000 foreach (u, p; tf.parameterList)
1002 Expression e;
1003 if (p.isReference())
1005 e = new IdentifierExp(Loc.initial, p.ident);
1006 e.type = p.type;
1008 else
1009 e = p.type.defaultInitLiteral(Loc.initial);
1010 args.push(e);
1013 import dmd.typesem : callMatch;
1014 MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
1015 if (m > MATCH.nomatch)
1017 /* A variadic parameter list is less specialized than a
1018 * non-variadic one.
1020 if (tf.parameterList.varargs && !tg.parameterList.varargs)
1021 goto L1; // less specialized
1023 static if (LOG_LEASTAS)
1025 printf(" matches %d, so is least as specialized\n", m);
1027 return m;
1030 static if (LOG_LEASTAS)
1032 printf(" doesn't match, so is not as specialized\n");
1034 return MATCH.nomatch;
1037 /********************************
1038 * Searches for a label with the given identifier. This function will insert a new
1039 * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
1041 * Params:
1042 * ident = identifier of the requested label
1043 * loc = location used when creating a new `LabelDsymbol`
1045 * Returns: the `LabelDsymbol` for `ident`
1047 final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc)
1049 Dsymbol s;
1050 if (!labtab)
1051 labtab = new DsymbolTable(); // guess we need one
1053 s = labtab.lookup(ident);
1054 if (!s)
1056 s = new LabelDsymbol(ident, loc);
1057 labtab.insert(s);
1059 return cast(LabelDsymbol)s;
1062 /*****************************************
1063 * Determine lexical level difference from `this` to nested function `fd`.
1064 * Params:
1065 * fd = target of call
1066 * intypeof = !=0 if inside typeof
1067 * Returns:
1068 * 0 same level
1069 * >0 decrease nesting by number
1070 * -1 increase nesting by 1 (`fd` is nested within `this`)
1071 * LevelError error, `this` cannot call `fd`
1073 extern (D) final int getLevel(FuncDeclaration fd, int intypeof)
1075 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
1076 Dsymbol fdparent = fd.toParent2();
1077 if (fdparent == this)
1078 return -1;
1080 Dsymbol s = this;
1081 int level = 0;
1082 while (fd != s && fdparent != s.toParent2())
1084 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
1085 if (auto thisfd = s.isFuncDeclaration())
1087 if (!thisfd.isNested() && !thisfd.vthis && !intypeof)
1088 return LevelError;
1090 else
1092 if (auto thiscd = s.isAggregateDeclaration())
1094 /* AggregateDeclaration::isNested returns true only when
1095 * it has a hidden pointer.
1096 * But, calling the function belongs unrelated lexical scope
1097 * is still allowed inside typeof.
1099 * struct Map(alias fun) {
1100 * typeof({ return fun(); }) RetType;
1101 * // No member function makes Map struct 'not nested'.
1104 if (!thiscd.isNested() && !intypeof)
1105 return LevelError;
1107 else
1108 return LevelError;
1111 s = s.toParentP(fd);
1112 assert(s);
1113 level++;
1115 return level;
1118 /***********************************
1119 * Determine lexical level difference from `this` to nested function `fd`.
1120 * Issue error if `this` cannot call `fd`.
1122 * Params:
1123 * loc = location for error messages
1124 * sc = context
1125 * fd = target of call
1126 * decl = The `Declaration` that triggered this check.
1127 * Used to provide a better error message only.
1128 * Returns:
1129 * 0 same level
1130 * >0 decrease nesting by number
1131 * -1 increase nesting by 1 (`fd` is nested within 'this')
1132 * LevelError error
1134 extern (D) final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd,
1135 Declaration decl)
1137 int level = getLevel(fd, sc.intypeof);
1138 if (level != LevelError)
1139 return level;
1141 // Don't give error if in template constraint
1142 if (!(sc.flags & SCOPE.constraint))
1144 const(char)* xstatic = isStatic() ? "`static` " : "";
1145 // better diagnostics for static functions
1146 .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
1147 xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(),
1148 fd.toPrettyChars());
1149 .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
1150 return LevelError;
1152 return 1;
1155 enum LevelError = -2;
1157 override const(char)* toPrettyChars(bool QualifyTypes = false)
1159 if (isMain())
1160 return "D main";
1161 else
1162 return Dsymbol.toPrettyChars(QualifyTypes);
1165 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
1166 final const(char)* toFullSignature()
1168 OutBuffer buf;
1169 functionToBufferWithIdent(type.toTypeFunction(), buf, toChars(), isStatic);
1170 return buf.extractChars();
1173 final bool isMain() const
1175 return ident == Id.main && resolvedLinkage() != LINK.c && !isMember() && !isNested();
1178 final bool isCMain() const
1180 return ident == Id.main && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1183 final bool isWinMain() const
1185 //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1186 version (none)
1188 bool x = ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1189 printf("%s\n", x ? "yes" : "no");
1190 return x;
1192 else
1194 return ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1198 final bool isDllMain() const
1200 return ident == Id.DllMain && resolvedLinkage() != LINK.c && !isMember();
1203 final bool isRtInit() const
1205 return ident == Id.rt_init && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1208 override final bool isExport() const
1210 return visibility.kind == Visibility.Kind.export_ || dllExport;
1213 override final bool isImportedSymbol() const
1215 //printf("isImportedSymbol()\n");
1216 //printf("protection = %d\n", visibility);
1217 return (visibility.kind == Visibility.Kind.export_ || dllImport) && !fbody;
1220 override final bool isCodeseg() const pure nothrow @nogc @safe
1222 return true; // functions are always in the code segment
1225 override final bool isOverloadable() const
1227 return true; // functions can be overloaded
1230 /***********************************
1231 * Override so it can work even if semantic() hasn't yet
1232 * been run.
1234 override final bool isAbstract()
1236 if (storage_class & STC.abstract_)
1237 return true;
1238 if (semanticRun >= PASS.semanticdone)
1239 return false;
1241 if (_scope)
1243 if (_scope.stc & STC.abstract_)
1244 return true;
1245 parent = _scope.parent;
1246 Dsymbol parent = toParent();
1247 if (parent.isInterfaceDeclaration())
1248 return true;
1250 return false;
1253 /**********************************
1254 * Decide if attributes for this function can be inferred from examining
1255 * the function body.
1256 * Returns:
1257 * true if can
1259 final bool canInferAttributes(Scope* sc)
1261 if (!fbody)
1262 return false;
1264 if (isVirtualMethod() &&
1266 * https://issues.dlang.org/show_bug.cgi?id=21719
1268 * If we have an auto virtual function we can infer
1269 * the attributes.
1271 !(inferRetType && !isCtorDeclaration()))
1272 return false; // since they may be overridden
1274 if (sc.func &&
1275 /********** this is for backwards compatibility for the moment ********/
1276 (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
1277 return true;
1279 if (isFuncLiteralDeclaration() || // externs are not possible with literals
1280 (storage_class & STC.inference) || // do attribute inference
1281 (inferRetType && !isCtorDeclaration()))
1282 return true;
1284 if (isInstantiated())
1286 auto ti = parent.isTemplateInstance();
1287 if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
1288 return true;
1291 return false;
1294 /*****************************************
1295 * Initialize for inferring the attributes of this function.
1297 final void initInferAttributes()
1299 //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1300 TypeFunction tf = type.toTypeFunction();
1301 if (tf.purity == PURE.impure) // purity not specified
1302 purityInprocess = true;
1304 if (tf.trust == TRUST.default_)
1305 safetyInprocess = true;
1307 if (!tf.isnothrow)
1308 nothrowInprocess = true;
1310 if (!tf.isnogc)
1311 nogcInprocess = true;
1313 if (!isVirtual() || this.isIntroducing())
1314 returnInprocess = true;
1316 // Initialize for inferring STC.scope_
1317 inferScope = true;
1320 final PURE isPure()
1322 //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1324 import dmd.typesem : purityLevel;
1326 TypeFunction tf = type.toTypeFunction();
1327 if (purityInprocess)
1328 setImpure();
1329 if (tf.purity == PURE.fwdref)
1330 tf.purityLevel();
1331 PURE purity = tf.purity;
1332 if (purity > PURE.weak && isNested())
1333 purity = PURE.weak;
1334 if (purity > PURE.weak && needThis())
1336 // The attribute of the 'this' reference affects purity strength
1337 if (type.mod & MODFlags.immutable_)
1340 else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
1341 purity = PURE.const_;
1342 else
1343 purity = PURE.weak;
1345 tf.purity = purity;
1346 // ^ This rely on the current situation that every FuncDeclaration has a
1347 // unique TypeFunction.
1348 return purity;
1351 extern (D) final PURE isPureBypassingInference()
1353 if (purityInprocess)
1354 return PURE.fwdref;
1355 else
1356 return isPure();
1359 /**************************************
1360 * The function is doing something impure, so mark it as impure.
1362 * Params:
1363 * loc = location of impure action
1364 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1365 * arg0 = (optional) argument to format string
1367 * Returns: `true` if there's a purity error
1369 extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
1371 if (purityInprocess)
1373 purityInprocess = false;
1374 if (fmt)
1375 pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action
1376 else if (arg0)
1377 pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
1379 if (fes)
1380 fes.func.setImpure(loc, fmt, arg0);
1382 else if (isPure())
1383 return true;
1384 return false;
1387 extern (D) final uint flags()
1389 return bitFields;
1392 extern (D) final uint flags(uint f)
1394 bitFields = f;
1395 return bitFields;
1398 final bool isSafe()
1400 if (safetyInprocess)
1401 setUnsafe();
1402 return type.toTypeFunction().trust == TRUST.safe;
1405 extern (D) final bool isSafeBypassingInference()
1407 return !(safetyInprocess) && isSafe();
1410 final bool isTrusted()
1412 if (safetyInprocess)
1413 setUnsafe();
1414 return type.toTypeFunction().trust == TRUST.trusted;
1417 /**************************************
1418 * The function is doing something unsafe, so mark it as unsafe.
1420 * Params:
1421 * gag = surpress error message (used in escape.d)
1422 * loc = location of error
1423 * fmt = printf-style format string
1424 * arg0 = (optional) argument for first %s format specifier
1425 * arg1 = (optional) argument for second %s format specifier
1426 * arg2 = (optional) argument for third %s format specifier
1427 * Returns: whether there's a safe error
1429 extern (D) final bool setUnsafe(
1430 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
1431 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
1433 if (safetyInprocess)
1435 safetyInprocess = false;
1436 type.toTypeFunction().trust = TRUST.system;
1437 if (fmt || arg0)
1438 safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);
1440 if (fes)
1441 fes.func.setUnsafe();
1443 else if (isSafe())
1445 if (!gag && fmt)
1446 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
1448 return true;
1450 return false;
1453 /**************************************
1454 * The function is calling `@system` function `f`, so mark it as unsafe.
1456 * Params:
1457 * f = function being called (needed for diagnostic of inferred functions)
1458 * Returns: whether there's a safe error
1460 extern (D) final bool setUnsafeCall(FuncDeclaration f)
1462 return setUnsafe(false, f.loc, null, f, null);
1465 final bool isNogc()
1467 //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1468 if (nogcInprocess)
1469 setGC(loc, null);
1470 return type.toTypeFunction().isnogc;
1473 extern (D) final bool isNogcBypassingInference()
1475 return !nogcInprocess && isNogc();
1478 /**************************************
1479 * The function is doing something that may allocate with the GC,
1480 * so mark it as not nogc (not no-how).
1482 * Params:
1483 * loc = location of impure action
1484 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1485 * arg0 = (optional) argument to format string
1487 * Returns:
1488 * true if function is marked as @nogc, meaning a user error occurred
1490 extern (D) final bool setGC(Loc loc, const(char)* fmt, RootObject arg0 = null)
1492 //printf("setGC() %s\n", toChars());
1493 if (nogcInprocess && semanticRun < PASS.semantic3 && _scope)
1495 this.semantic2(_scope);
1496 this.semantic3(_scope);
1499 if (nogcInprocess)
1501 nogcInprocess = false;
1502 if (fmt)
1503 nogcViolation = new AttributeViolation(loc, fmt, this, arg0); // action that requires GC
1504 else if (arg0)
1505 nogcViolation = new AttributeViolation(loc, fmt, arg0); // call to non-@nogc function
1507 type.toTypeFunction().isnogc = false;
1508 if (fes)
1509 fes.func.setGC(Loc.init, null, null);
1511 else if (isNogc())
1512 return true;
1513 return false;
1516 /**************************************
1517 * The function calls non-`@nogc` function f, mark it as not nogc.
1518 * Params:
1519 * f = function being called
1520 * Returns:
1521 * true if function is marked as @nogc, meaning a user error occurred
1523 extern (D) final bool setGCCall(FuncDeclaration f)
1525 return setGC(loc, null, f);
1528 /**************************************
1529 * The function is doing something that may throw an exception, register that in case nothrow is being inferred
1531 * Params:
1532 * loc = location of action
1533 * fmt = format string for error message
1534 * arg0 = (optional) argument to format string
1536 extern (D) final void setThrow(Loc loc, const(char)* fmt, RootObject arg0 = null)
1538 if (nothrowInprocess && !nothrowViolation)
1540 nothrowViolation = new AttributeViolation(loc, fmt, arg0); // action that requires GC
1544 /**************************************
1545 * The function calls non-`nothrow` function f, register that in case nothrow is being inferred
1546 * Params:
1547 * loc = location of call
1548 * f = function being called
1550 extern (D) final void setThrowCall(Loc loc, FuncDeclaration f)
1552 return setThrow(loc, null, f);
1555 extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
1557 if (!global.params.v.gc)
1558 return;
1560 Module m = getModule();
1561 if (m && m.isRoot() && !inUnittest())
1563 message(loc, "vgc: %s", warn);
1567 /********************************************
1568 * See if pointers from function parameters, mutable globals, or uplevel functions
1569 * could leak into return value.
1570 * Returns:
1571 * true if the function return value is isolated from
1572 * any inputs to the function
1574 extern (D) final bool isReturnIsolated()
1576 //printf("isReturnIsolated(this: %s)\n", this.toChars);
1577 TypeFunction tf = type.toTypeFunction();
1578 assert(tf.next);
1580 Type treti = tf.next;
1581 if (tf.isref)
1582 return isTypeIsolatedIndirect(treti); // check influence from parameters
1584 return isTypeIsolated(treti);
1587 /********************
1588 * See if pointers from function parameters, mutable globals, or uplevel functions
1589 * could leak into type `t`.
1590 * Params:
1591 * t = type to check if it is isolated
1592 * Returns:
1593 * true if `t` is isolated from
1594 * any inputs to the function
1596 extern (D) final bool isTypeIsolated(Type t)
1598 StringTable!Type parentTypes;
1599 const uniqueTypeID = t.getUniqueID();
1600 if (uniqueTypeID)
1602 const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
1603 if (cacheResultPtr !is null)
1604 return *cacheResultPtr;
1606 parentTypes._init();
1607 const isIsolated = isTypeIsolated(t, parentTypes);
1608 isTypeIsolatedCache[uniqueTypeID] = isIsolated;
1609 return isIsolated;
1611 else
1613 parentTypes._init();
1614 return isTypeIsolated(t, parentTypes);
1618 ///ditto
1619 extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
1621 //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
1623 t = t.baseElemOf();
1624 switch (t.ty)
1626 case Tarray:
1627 case Tpointer:
1628 return isTypeIsolatedIndirect(t.nextOf()); // go down one level
1630 case Taarray:
1631 case Tclass:
1632 return isTypeIsolatedIndirect(t);
1634 case Tstruct:
1635 /* Drill down and check the struct's fields
1637 import dmd.typesem : toDsymbol;
1638 auto sym = t.toDsymbol(null).isStructDeclaration();
1639 const tName = t.toChars.toDString;
1640 const entry = parentTypes.insert(tName, t);
1641 if (entry == null)
1643 //we've already seen this type in a parent, not isolated
1644 return false;
1646 foreach (v; sym.fields)
1648 Type tmi = v.type.addMod(t.mod);
1649 //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
1650 // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
1651 if (!isTypeIsolated(tmi, parentTypes))
1652 return false;
1654 return true;
1656 default:
1657 return true;
1661 /********************************************
1662 * Params:
1663 * t = type of object to test one level of indirection down
1664 * Returns:
1665 * true if an object typed `t` has no indirections
1666 * which could have come from the function's parameters, mutable
1667 * globals, or uplevel functions.
1669 private bool isTypeIsolatedIndirect(Type t)
1671 //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1672 assert(t);
1674 /* Since `t` is one level down from an indirection, it could pick
1675 * up a reference to a mutable global or an outer function, so
1676 * return false.
1678 if (!isPureBypassingInference() || isNested())
1679 return false;
1681 TypeFunction tf = type.toTypeFunction();
1683 //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1685 foreach (i, fparam; tf.parameterList)
1687 Type tp = fparam.type;
1688 if (!tp)
1689 continue;
1691 if (fparam.isLazy() || fparam.isReference())
1693 if (!traverseIndirections(tp, t))
1694 return false;
1695 continue;
1698 /* Goes down one level of indirection, then calls traverseIndirection() on
1699 * the result.
1700 * Returns:
1701 * true if t is isolated from tp
1703 static bool traverse(Type tp, Type t)
1705 tp = tp.baseElemOf();
1706 switch (tp.ty)
1708 case Tarray:
1709 case Tpointer:
1710 return traverseIndirections(tp.nextOf(), t);
1712 case Taarray:
1713 case Tclass:
1714 return traverseIndirections(tp, t);
1716 case Tstruct:
1717 /* Drill down and check the struct's fields
1719 import dmd.typesem : toDsymbol;
1720 auto sym = tp.toDsymbol(null).isStructDeclaration();
1721 foreach (v; sym.fields)
1723 Type tprmi = v.type.addMod(tp.mod);
1724 //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1725 if (!traverse(tprmi, t))
1726 return false;
1728 return true;
1730 default:
1731 return true;
1735 if (!traverse(tp, t))
1736 return false;
1738 // The 'this' reference is a parameter, too
1739 if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
1741 Type tthis = ad.getType().addMod(tf.mod);
1742 //printf("\ttthis = %s\n", tthis.toChars());
1743 if (!traverseIndirections(tthis, t))
1744 return false;
1747 return true;
1750 /****************************************
1751 * Determine if function needs a static frame pointer.
1752 * Returns:
1753 * `true` if function is really nested within other function.
1754 * Contracts:
1755 * If isNested() returns true, isThis() should return false,
1756 * unless the function needs a dual-context pointer.
1758 bool isNested() const
1760 auto f = toAliasFunc();
1761 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1762 return ((f.storage_class & STC.static_) == 0) &&
1763 (f._linkage == LINK.d) &&
1764 (f.toParent2().isFuncDeclaration() !is null ||
1765 f.toParent2() !is f.toParentLocal());
1768 /****************************************
1769 * Determine if function is a non-static member function
1770 * that has an implicit 'this' expression.
1771 * Returns:
1772 * The aggregate it is a member of, or null.
1773 * Contracts:
1774 * Both isThis() and isNested() should return true if function needs a dual-context pointer,
1775 * otherwise if isThis() returns true, isNested() should return false.
1777 override inout(AggregateDeclaration) isThis() inout
1779 //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1780 auto ad = (storage_class & STC.static_) ? .objc.isThis(this) : isMemberLocal();
1781 //printf("-FuncDeclaration::isThis() %p\n", ad);
1782 return ad;
1785 override final bool needThis()
1787 //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1788 return toAliasFunc().isThis() !is null;
1791 // Determine if a function is pedantically virtual
1792 final bool isVirtualMethod()
1794 if (toAliasFunc() != this)
1795 return toAliasFunc().isVirtualMethod();
1797 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1798 if (!isVirtual())
1799 return false;
1800 // If it's a final method, and does not override anything, then it is not virtual
1801 if (isFinalFunc() && foverrides.length == 0)
1803 return false;
1805 return true;
1808 // Determine if function goes into virtual function pointer table
1809 bool isVirtual() const
1811 if (toAliasFunc() != this)
1812 return toAliasFunc().isVirtual();
1814 auto p = toParent();
1816 if (!isMember || !p.isClassDeclaration)
1817 return false;
1819 if (p.isClassDeclaration.classKind == ClassKind.objc)
1820 return .objc.isVirtual(this);
1822 version (none)
1824 printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1825 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), visibility == Visibility.Kind.private_, isCtorDeclaration(), linkage != LINK.d);
1826 printf("result is %d\n", isMember() && !(isStatic() || visibility == Visibility.Kind.private_ || visibility == Visibility.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()));
1828 return !(isStatic() || visibility.kind == Visibility.Kind.private_ || visibility.kind == Visibility.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc());
1831 final bool isFinalFunc() const
1833 if (toAliasFunc() != this)
1834 return toAliasFunc().isFinalFunc();
1836 version (none)
1838 auto cd = toParent().isClassDeclaration();
1839 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal());
1840 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_));
1841 printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_)));
1842 if (cd)
1843 printf("\tmember of %s\n", cd.toChars());
1845 if (!isMember())
1846 return false;
1847 if (Declaration.isFinal())
1848 return true;
1849 auto cd = toParent().isClassDeclaration();
1850 return (cd !is null) && (cd.storage_class & STC.final_);
1853 bool addPreInvariant()
1855 auto ad = isThis();
1856 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1857 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());
1860 bool addPostInvariant()
1862 auto ad = isThis();
1863 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1864 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());
1867 override const(char)* kind() const
1869 return this.isGenerated() ? "generated function" : "function";
1872 /********************************************
1873 * Returns:
1874 * true if there are no overloads of this function
1876 final bool isUnique() const
1878 bool result = false;
1879 overloadApply(cast() this, (Dsymbol s)
1881 auto f = s.isFuncDeclaration();
1882 auto td = s.isTemplateDeclaration();
1883 if (!f && !td)
1884 return 0;
1885 if (result)
1887 result = false;
1888 return 1; // ambiguous, done
1890 else
1892 result = true;
1893 return 0;
1896 return result;
1899 /*********************************************
1900 * In the current function, we are calling 'this' function.
1901 * 1. Check to see if the current function can call 'this' function, issue error if not.
1902 * 2. If the current function is not the parent of 'this' function, then add
1903 * the current function to the list of siblings of 'this' function.
1904 * 3. If the current function is a literal, and it's accessing an uplevel scope,
1905 * then mark it as a delegate.
1906 * Returns true if error occurs.
1908 extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
1910 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
1912 if (auto fld = this.isFuncLiteralDeclaration())
1914 if (fld.tok == TOK.reserved)
1916 fld.tok = TOK.function_;
1917 fld.vthis = null;
1921 if (!parent || parent == sc.parent)
1922 return false;
1923 if (ident == Id.require || ident == Id.ensure)
1924 return false;
1925 if (!isThis() && !isNested())
1926 return false;
1928 // The current function
1929 FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
1930 if (!fdthis)
1931 return false; // out of function scope
1933 Dsymbol p = toParentLocal();
1934 Dsymbol p2 = toParent2();
1936 // Function literals from fdthis to p must be delegates
1937 ensureStaticLinkTo(fdthis, p);
1938 if (p != p2)
1939 ensureStaticLinkTo(fdthis, p2);
1941 if (isNested())
1943 // The function that this function is in
1944 bool checkEnclosing(FuncDeclaration fdv)
1946 if (!fdv)
1947 return false;
1948 if (fdv == fdthis)
1949 return false;
1951 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
1952 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
1953 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
1955 // Add this function to the list of those which called us
1956 if (fdthis != this)
1958 bool found = false;
1959 for (size_t i = 0; i < siblingCallers.length; ++i)
1961 if (siblingCallers[i] == fdthis)
1962 found = true;
1964 if (!found)
1966 //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
1967 if (!sc.intypeof && !(sc.flags & SCOPE.compile))
1969 siblingCallers.push(fdthis);
1970 computedEscapingSiblings = false;
1975 const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this);
1976 if (lv == LevelError)
1977 return true; // error
1978 if (lv == -1)
1979 return false; // downlevel call
1980 if (lv == 0)
1981 return false; // same level call
1983 return false; // Uplevel call
1986 if (checkEnclosing(p.isFuncDeclaration()))
1987 return true;
1988 if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
1989 return true;
1991 return false;
1994 /*******************************
1995 * Look at all the variables in this function that are referenced
1996 * by nested functions, and determine if a closure needs to be
1997 * created for them.
1999 final bool needsClosure()
2001 /* Need a closure for all the closureVars[] if any of the
2002 * closureVars[] are accessed by a
2003 * function that escapes the scope of this function.
2004 * We take the conservative approach and decide that a function needs
2005 * a closure if it:
2006 * 1) is a virtual function
2007 * 2) has its address taken
2008 * 3) has a parent that escapes
2009 * 4) calls another nested function that needs a closure
2011 * Note that since a non-virtual function can be called by
2012 * a virtual one, if that non-virtual function accesses a closure
2013 * var, the closure still has to be taken. Hence, we check for isThis()
2014 * instead of isVirtual(). (thanks to David Friedman)
2016 * When the function returns a local struct or class, `requiresClosure`
2017 * is already set to `true` upon entering this function when the
2018 * struct/class refers to a local variable and a closure is needed.
2020 //printf("FuncDeclaration::needsClosure() %s\n", toPrettyChars());
2022 if (requiresClosure)
2023 goto Lyes;
2025 for (size_t i = 0; i < closureVars.length; i++)
2027 VarDeclaration v = closureVars[i];
2028 //printf("\tv = %s\n", v.toChars());
2030 for (size_t j = 0; j < v.nestedrefs.length; j++)
2032 FuncDeclaration f = v.nestedrefs[j];
2033 assert(f != this);
2035 /* __require and __ensure will always get called directly,
2036 * so they never make outer functions closure.
2038 if (f.ident == Id.require || f.ident == Id.ensure)
2039 continue;
2041 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
2043 /* Look to see if f escapes. We consider all parents of f within
2044 * this, and also all siblings which call f; if any of them escape,
2045 * so does f.
2046 * Mark all affected functions as requiring closures.
2048 for (Dsymbol s = f; s && s != this; s = s.toParentP(this))
2050 FuncDeclaration fx = s.isFuncDeclaration();
2051 if (!fx)
2052 continue;
2053 if (fx.isThis() || fx.tookAddressOf)
2055 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
2057 /* Mark as needing closure any functions between this and f
2059 markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this);
2061 requiresClosure = true;
2064 /* We also need to check if any sibling functions that
2065 * called us, have escaped. This is recursive: we need
2066 * to check the callers of our siblings.
2068 if (checkEscapingSiblings(fx, this))
2069 requiresClosure = true;
2071 /* https://issues.dlang.org/show_bug.cgi?id=12406
2072 * Iterate all closureVars to mark all descendant
2073 * nested functions that access to the closing context of this function.
2078 if (requiresClosure)
2079 goto Lyes;
2081 return false;
2083 Lyes:
2084 return true;
2087 /***********************************************
2088 * Check that the function contains any closure.
2089 * If it's @nogc, report suitable errors.
2090 * This is mostly consistent with FuncDeclaration::needsClosure().
2092 * Returns:
2093 * true if any errors occur.
2095 extern (C++) final bool checkClosure()
2097 //printf("checkClosure() %s\n", toPrettyChars());
2098 if (!needsClosure())
2099 return false;
2101 if (setGC(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", this))
2103 .error(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", kind, toPrettyChars, toChars());
2104 if (global.gag) // need not report supplemental errors
2105 return true;
2107 else if (!global.params.useGC)
2109 .error(loc, "%s `%s` is `-betterC` yet allocates closure for `%s()` with the GC", kind, toPrettyChars, toChars());
2110 if (global.gag) // need not report supplemental errors
2111 return true;
2113 else
2115 printGCUsage(loc, "using closure causes GC allocation");
2116 return false;
2119 FuncDeclarations a;
2120 foreach (v; closureVars)
2122 foreach (f; v.nestedrefs)
2124 assert(f !is this);
2126 LcheckAncestorsOfANestedRef:
2127 for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
2129 auto fx = s.isFuncDeclaration();
2130 if (!fx)
2131 continue;
2132 if (fx.isThis() ||
2133 fx.tookAddressOf ||
2134 checkEscapingSiblings(fx, this))
2136 foreach (f2; a)
2138 if (f2 == f)
2139 break LcheckAncestorsOfANestedRef;
2141 a.push(f);
2142 .errorSupplemental(f.loc, "%s `%s` closes over variable `%s`",
2143 f.kind, f.toPrettyChars(), v.toChars());
2144 if (v.ident != Id.This)
2145 .errorSupplemental(v.loc, "`%s` declared here", v.toChars());
2147 break LcheckAncestorsOfANestedRef;
2153 return true;
2156 /***********************************************
2157 * Determine if function's variables are referenced by a function
2158 * nested within it.
2160 final bool hasNestedFrameRefs()
2162 if (closureVars.length)
2163 return true;
2165 /* If a virtual function has contracts, assume its variables are referenced
2166 * by those contracts, even if they aren't. Because they might be referenced
2167 * by the overridden or overriding function's contracts.
2168 * This can happen because frequire and fensure are implemented as nested functions,
2169 * and they can be called directly by an overriding function and the overriding function's
2170 * context had better match, or
2171 * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
2173 if (fdrequire || fdensure)
2174 return true;
2176 if (foverrides.length && isVirtualMethod())
2178 for (size_t i = 0; i < foverrides.length; i++)
2180 FuncDeclaration fdv = foverrides[i];
2181 if (fdv.hasNestedFrameRefs())
2182 return true;
2185 return false;
2188 /****************************************************
2189 * Check whether result variable can be built.
2190 * Returns:
2191 * `true` if the function has a return type that
2192 * is different from `void`.
2194 extern (D) private bool canBuildResultVar()
2196 auto f = cast(TypeFunction)type;
2197 return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
2200 /****************************************************
2201 * Declare result variable lazily.
2203 extern (D) final void buildResultVar(Scope* sc, Type tret)
2205 if (!vresult)
2207 Loc loc = fensure ? fensure.loc : this.loc;
2209 /* If inferRetType is true, tret may not be a correct return type yet.
2210 * So, in here it may be a temporary type for vresult, and after
2211 * fbody.dsymbolSemantic() running, vresult.type might be modified.
2213 vresult = new VarDeclaration(loc, tret, Id.result, null);
2214 vresult.storage_class |= STC.nodtor | STC.temp;
2215 if (!isVirtual())
2216 vresult.storage_class |= STC.const_;
2217 vresult.storage_class |= STC.result;
2219 // set before the semantic() for checkNestedReference()
2220 vresult.parent = this;
2223 if (sc && vresult.semanticRun == PASS.initial)
2225 TypeFunction tf = type.toTypeFunction();
2226 if (tf.isref)
2227 vresult.storage_class |= STC.ref_;
2228 vresult.type = tret;
2230 vresult.dsymbolSemantic(sc);
2232 if (!sc.insert(vresult))
2233 .error(loc, "%s `%s` out result %s is already defined", kind, toPrettyChars, vresult.toChars());
2234 assert(vresult.parent == this);
2238 /****************************************************
2239 * Merge into this function the 'in' contracts of all it overrides.
2240 * 'in's are OR'd together, i.e. only one of them needs to pass.
2242 extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
2244 /* If a base function and its override both have an IN contract, then
2245 * only one of them needs to succeed. This is done by generating:
2247 * void derived.in() {
2248 * try {
2249 * base.in();
2251 * catch () {
2252 * ... body of derived.in() ...
2256 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2257 * If base.in() throws, then derived.in()'s body is executed.
2260 foreach (fdv; foverrides)
2262 /* The semantic pass on the contracts of the overridden functions must
2263 * be completed before code generation occurs.
2264 * https://issues.dlang.org/show_bug.cgi?id=3602
2266 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2268 assert(fdv._scope);
2269 Scope* sc = fdv._scope.push();
2270 sc.stc &= ~STC.override_;
2271 fdv.semantic3(sc);
2272 sc.pop();
2275 sf = fdv.mergeFrequire(sf, params);
2276 if (!sf || !fdv.fdrequire)
2277 return null;
2278 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2279 /* Make the call:
2280 * try { __require(params); }
2281 * catch (Throwable) { frequire; }
2283 params = Expression.arraySyntaxCopy(params);
2284 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2285 Statement s2 = new ExpStatement(loc, e);
2287 auto c = new Catch(loc, getThrowable(), null, sf);
2288 c.internalCatch = true;
2289 auto catches = new Catches();
2290 catches.push(c);
2291 sf = new TryCatchStatement(loc, s2, catches);
2293 return sf;
2296 /****************************************************
2297 * Merge into this function the 'in' contracts of all it overrides.
2299 extern (D) final Statement mergeFrequireInclusivePreview(Statement sf, Expressions* params)
2301 /* If a base function and its override both have an IN contract, then
2302 * the override in contract must widen the guarantee of the base contract.
2303 * This is checked by generating:
2305 * void derived.in() {
2306 * try {
2307 * ... body of derived.in() ...
2309 * catch () {
2310 * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
2311 * base.in();
2312 * assert(false, "Logic error: " ~ thr.msg);
2317 foreach (fdv; foverrides)
2319 /* The semantic pass on the contracts of the overridden functions must
2320 * be completed before code generation occurs.
2321 * https://issues.dlang.org/show_bug.cgi?id=3602
2323 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2325 assert(fdv._scope);
2326 Scope* sc = fdv._scope.push();
2327 sc.stc &= ~STC.override_;
2328 fdv.semantic3(sc);
2329 sc.pop();
2332 sf = fdv.mergeFrequireInclusivePreview(sf, params);
2333 if (sf && fdv.fdrequire)
2335 const loc = this.fdrequire.loc;
2337 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2338 /* Make the call:
2339 * try { frequire; }
2340 * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
2342 Identifier id = Identifier.generateId("thr");
2343 params = Expression.arraySyntaxCopy(params);
2344 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2345 Statement s2 = new ExpStatement(loc, e);
2346 // assert(false, ...)
2347 // TODO make this a runtime helper to allow:
2348 // - chaining the original expression
2349 // - nogc concatenation
2350 Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
2351 Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
2353 Statement s3 = new CompoundStatement(loc, s2, fail);
2355 auto c = new Catch(loc, getThrowable(), id, s3);
2356 c.internalCatch = true;
2357 auto catches = new Catches();
2358 catches.push(c);
2359 sf = new TryCatchStatement(loc, sf, catches);
2361 else
2362 return null;
2364 return sf;
2367 /****************************************************
2368 * Determine whether an 'out' contract is declared inside
2369 * the given function or any of its overrides.
2370 * Params:
2371 * fd = the function to search
2372 * Returns:
2373 * true found an 'out' contract
2375 static bool needsFensure(FuncDeclaration fd) @safe
2377 if (fd.fensures)
2378 return true;
2380 foreach (fdv; fd.foverrides)
2382 if (needsFensure(fdv))
2383 return true;
2385 return false;
2388 /****************************************************
2389 * Rewrite contracts as statements.
2391 final void buildEnsureRequire()
2394 if (frequires)
2396 /* in { statements1... }
2397 * in { statements2... }
2398 * ...
2399 * becomes:
2400 * in { { statements1... } { statements2... } ... }
2402 assert(frequires.length);
2403 auto loc = (*frequires)[0].loc;
2404 auto s = new Statements;
2405 foreach (r; *frequires)
2407 s.push(new ScopeStatement(r.loc, r, r.loc));
2409 frequire = new CompoundStatement(loc, s);
2412 if (fensures)
2414 /* out(id1) { statements1... }
2415 * out(id2) { statements2... }
2416 * ...
2417 * becomes:
2418 * out(__result) { { ref id1 = __result; { statements1... } }
2419 * { ref id2 = __result; { statements2... } } ... }
2421 assert(fensures.length);
2422 auto loc = (*fensures)[0].ensure.loc;
2423 auto s = new Statements;
2424 foreach (r; *fensures)
2426 if (r.id && canBuildResultVar())
2428 auto rloc = r.ensure.loc;
2429 auto resultId = new IdentifierExp(rloc, Id.result);
2430 auto init = new ExpInitializer(rloc, resultId);
2431 auto stc = STC.ref_ | STC.temp | STC.result;
2432 auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
2433 auto sdecl = new ExpStatement(rloc, decl);
2434 s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
2436 else
2438 s.push(r.ensure);
2441 fensure = new CompoundStatement(loc, s);
2444 if (!isVirtual())
2445 return;
2447 /* Rewrite contracts as nested functions, then call them. Doing it as nested
2448 * functions means that overriding functions can call them.
2450 TypeFunction f = cast(TypeFunction) type;
2452 /* Make a copy of the parameters and make them all ref */
2453 static Parameters* toRefCopy(ParameterList parameterList)
2455 auto result = new Parameters();
2457 foreach (n, p; parameterList)
2459 p = p.syntaxCopy();
2460 if (!p.isLazy())
2461 p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
2462 p.defaultArg = null; // won't be the same with ref
2463 result.push(p);
2466 return result;
2469 if (frequire)
2471 /* in { ... }
2472 * becomes:
2473 * void __require(ref params) { ... }
2474 * __require(params);
2476 Loc loc = frequire.loc;
2477 fdrequireParams = new Expressions();
2478 if (parameters)
2480 foreach (vd; *parameters)
2481 fdrequireParams.push(new VarExp(loc, vd));
2483 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2484 auto fparams = toRefCopy(fo.parameterList);
2485 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2486 tf.isnothrow = f.isnothrow;
2487 tf.isnogc = f.isnogc;
2488 tf.purity = f.purity;
2489 tf.trust = f.trust;
2490 auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
2491 fd.fbody = frequire;
2492 Statement s1 = new ExpStatement(loc, fd);
2493 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
2494 Statement s2 = new ExpStatement(loc, e);
2495 frequire = new CompoundStatement(loc, s1, s2);
2496 fdrequire = fd;
2499 /* We need to set fdensureParams here and not in the block below to
2500 * have the parameters available when calling a base class ensure(),
2501 * even if this function doesn't have an out contract.
2503 fdensureParams = new Expressions();
2504 if (canBuildResultVar())
2505 fdensureParams.push(new IdentifierExp(loc, Id.result));
2506 if (parameters)
2508 foreach (vd; *parameters)
2509 fdensureParams.push(new VarExp(loc, vd));
2512 if (fensure)
2514 /* out (result) { ... }
2515 * becomes:
2516 * void __ensure(ref tret result, ref params) { ... }
2517 * __ensure(result, params);
2519 Loc loc = fensure.loc;
2520 auto fparams = new Parameters();
2521 if (canBuildResultVar())
2523 Parameter p = new Parameter(loc, STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
2524 fparams.push(p);
2526 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2527 fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
2528 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2529 tf.isnothrow = f.isnothrow;
2530 tf.isnogc = f.isnogc;
2531 tf.purity = f.purity;
2532 tf.trust = f.trust;
2533 auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
2534 fd.fbody = fensure;
2535 Statement s1 = new ExpStatement(loc, fd);
2536 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
2537 Statement s2 = new ExpStatement(loc, e);
2538 fensure = new CompoundStatement(loc, s1, s2);
2539 fdensure = fd;
2543 /****************************************************
2544 * Merge into this function the 'out' contracts of all it overrides.
2545 * 'out's are AND'd together, i.e. all of them need to pass.
2547 extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
2549 /* Same comments as for mergeFrequire(), except that we take care
2550 * of generating a consistent reference to the 'result' local by
2551 * explicitly passing 'result' to the nested function as a reference
2552 * argument.
2553 * This won't work for the 'this' parameter as it would require changing
2554 * the semantic code for the nested function so that it looks on the parameter
2555 * list for the 'this' pointer, something that would need an unknown amount
2556 * of tweaking of various parts of the compiler that I'd rather leave alone.
2558 foreach (fdv; foverrides)
2560 /* The semantic pass on the contracts of the overridden functions must
2561 * be completed before code generation occurs.
2562 * https://issues.dlang.org/show_bug.cgi?id=3602 and
2563 * https://issues.dlang.org/show_bug.cgi?id=5230
2565 if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
2567 assert(fdv._scope);
2568 Scope* sc = fdv._scope.push();
2569 sc.stc &= ~STC.override_;
2570 fdv.semantic3(sc);
2571 sc.pop();
2574 sf = fdv.mergeFensure(sf, oid, params);
2575 if (fdv.fdensure)
2577 //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2578 // Make the call: __ensure(result, params)
2579 params = Expression.arraySyntaxCopy(params);
2580 if (canBuildResultVar())
2582 Type t1 = fdv.type.nextOf().toBasetype();
2583 Type t2 = this.type.nextOf().toBasetype();
2584 import dmd.typesem : isBaseOf;
2585 if (t1.isBaseOf(t2, null))
2587 /* Making temporary reference variable is necessary
2588 * in covariant return.
2589 * https://issues.dlang.org/show_bug.cgi?id=5204
2590 * https://issues.dlang.org/show_bug.cgi?id=10479
2592 Expression* eresult = &(*params)[0];
2593 auto ei = new ExpInitializer(Loc.initial, *eresult);
2594 auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
2595 v.storage_class |= STC.temp;
2596 auto de = new DeclarationExp(Loc.initial, v);
2597 auto ve = new VarExp(Loc.initial, v);
2598 *eresult = new CommaExp(Loc.initial, de, ve);
2601 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
2602 Statement s2 = new ExpStatement(loc, e);
2604 if (sf)
2606 sf = new CompoundStatement(sf.loc, s2, sf);
2608 else
2609 sf = s2;
2612 return sf;
2615 /*********************************************
2616 * Returns: the function's parameter list, and whether
2617 * it is variadic or not.
2619 final ParameterList getParameterList()
2621 if (type)
2623 TypeFunction fdtype = type.isTypeFunction();
2624 if (fdtype) // Could also be TypeError
2625 return fdtype.parameterList;
2628 return ParameterList(null, VarArg.none);
2631 /**********************************
2632 * Generate a FuncDeclaration for a runtime library function.
2634 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
2636 return genCfunc(fparams, treturn, Identifier.idPool(name[0 .. strlen(name)]), stc);
2639 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
2641 FuncDeclaration fd;
2642 TypeFunction tf;
2643 Dsymbol s;
2644 __gshared DsymbolTable st = null;
2646 //printf("genCfunc(name = '%s')\n", id.toChars());
2647 //printf("treturn\n\t"); treturn.print();
2649 // See if already in table
2650 if (!st)
2651 st = new DsymbolTable();
2652 s = st.lookup(id);
2653 if (s)
2655 fd = s.isFuncDeclaration();
2656 assert(fd);
2657 assert(fd.type.nextOf().equals(treturn));
2659 else
2661 tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc);
2662 fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf);
2663 fd.visibility = Visibility(Visibility.Kind.public_);
2664 fd._linkage = LINK.c;
2666 st.insert(fd);
2668 return fd;
2672 + Checks the parameter and return types iff this is a `main` function.
2674 + The following signatures are allowed for a `D main`:
2675 + - Either no or a single parameter of type `string[]`
2676 + - Return type is either `void`, `int` or `noreturn`
2678 + The following signatures are standard C:
2679 + - `int main()`
2680 + - `int main(int, char**)`
2682 + This function accepts the following non-standard extensions:
2683 + - `char** envp` as a third parameter
2684 + - `void` / `noreturn` as return type
2686 + This function will issue errors for unexpected arguments / return types.
2688 extern (D) final void checkMain()
2690 if (ident != Id.main || isMember() || isNested())
2691 return; // Not a main function
2693 TypeFunction tf = type.toTypeFunction();
2695 Type retType = tf.nextOf();
2696 if (!retType)
2698 // auto main(), check after semantic
2699 assert(this.inferRetType);
2700 return;
2703 /// Checks whether `t` is equivalent to `char**`
2704 /// Ignores qualifiers and treats enums according to their base type
2705 static bool isCharPtrPtr(Type t)
2707 auto tp = t.toBasetype().isTypePointer();
2708 if (!tp)
2709 return false;
2711 tp = tp.next.toBasetype().isTypePointer();
2712 if (!tp)
2713 return false;
2715 return tp.next.toBasetype().ty == Tchar;
2718 // Neither of these qualifiers is allowed because they affect the ABI
2719 enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
2721 const nparams = tf.parameterList.length;
2722 bool argerr;
2724 const linkage = resolvedLinkage();
2725 if (linkage == LINK.d)
2727 if (nparams == 1)
2729 auto fparam0 = tf.parameterList[0];
2730 auto t = fparam0.type.toBasetype();
2731 if (t.ty != Tarray ||
2732 t.nextOf().ty != Tarray ||
2733 t.nextOf().nextOf().ty != Tchar ||
2734 fparam0.storageClass & invalidSTC)
2736 argerr = true;
2740 if (tf.parameterList.varargs || nparams >= 2 || argerr)
2741 .error(loc, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", kind, toPrettyChars);
2744 else if (linkage == LINK.c)
2746 if (nparams == 2 || nparams == 3)
2748 // Argument count must be int
2749 auto argCount = tf.parameterList[0];
2750 argerr |= !!(argCount.storageClass & invalidSTC);
2751 argerr |= argCount.type.toBasetype().ty != Tint32;
2753 // Argument pointer must be char**
2754 auto argPtr = tf.parameterList[1];
2755 argerr |= !!(argPtr.storageClass & invalidSTC);
2756 argerr |= !isCharPtrPtr(argPtr.type);
2758 // `char** environ` is a common extension, see J.5.1 of the C standard
2759 if (nparams == 3)
2761 auto envPtr = tf.parameterList[2];
2762 argerr |= !!(envPtr.storageClass & invalidSTC);
2763 argerr |= !isCharPtrPtr(envPtr.type);
2766 else
2767 argerr = nparams != 0;
2769 // Disallow variadic main() - except for K&R declarations in C files.
2770 // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
2771 if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
2772 argerr |= true;
2774 if (argerr)
2776 .error(loc, "%s `%s` parameters must match one of the following signatures", kind, toPrettyChars);
2777 loc.errorSupplemental("`main()`");
2778 loc.errorSupplemental("`main(int argc, char** argv)`");
2779 loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
2782 else
2783 return; // Neither C nor D main, ignore (should probably be an error)
2785 // Allow enums with appropriate base types (same ABI)
2786 retType = retType.toBasetype();
2788 if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
2789 .error(loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", kind, toPrettyChars, tf.nextOf().toChars());
2792 /***********************************************
2793 * Check all return statements for a function to verify that returning
2794 * using NRVO is possible.
2796 * Returns:
2797 * `false` if the result cannot be returned by hidden reference.
2799 extern (D) final bool checkNRVO()
2801 if (!isNRVO() || returns is null)
2802 return false;
2804 auto tf = type.toTypeFunction();
2805 if (tf.isref)
2806 return false;
2808 foreach (rs; *returns)
2810 if (auto ve = rs.exp.isVarExp())
2812 auto v = ve.var.isVarDeclaration();
2813 if (!v || v.isReference())
2814 return false;
2815 else if (nrvo_var is null)
2817 // Variables in the data segment (e.g. globals, TLS or not),
2818 // parameters and closure variables cannot be NRVOed.
2819 if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
2820 return false;
2821 if (v.nestedrefs.length && needsClosure())
2822 return false;
2823 // don't know if the return storage is aligned
2824 version (MARS)
2826 if (alignSectionVars && (*alignSectionVars).contains(v))
2827 return false;
2829 // The variable type needs to be equivalent to the return type.
2830 if (!v.type.equivalent(tf.next))
2831 return false;
2832 //printf("Setting nrvo to %s\n", v.toChars());
2833 nrvo_var = v;
2835 else if (nrvo_var != v)
2836 return false;
2838 else //if (!exp.isLvalue()) // keep NRVO-ability
2839 return false;
2841 return true;
2844 override final inout(FuncDeclaration) isFuncDeclaration() inout
2846 return this;
2849 inout(FuncDeclaration) toAliasFunc() inout
2851 return this;
2854 override void accept(Visitor v)
2856 v.visit(this);
2860 /********************************************************
2861 * Generate Expression to call the invariant.
2862 * Input:
2863 * ad aggregate with the invariant
2864 * vthis variable with 'this'
2865 * Returns:
2866 * void expression that calls the invariant
2868 Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
2870 Expression e = null;
2871 // Call invariant directly only if it exists
2872 FuncDeclaration inv = ad.inv;
2873 ClassDeclaration cd = ad.isClassDeclaration();
2875 while (!inv && cd)
2877 cd = cd.baseClass;
2878 if (!cd)
2879 break;
2880 inv = cd.inv;
2882 if (inv)
2884 version (all)
2886 // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
2887 // For the correct mangling,
2888 // run attribute inference on inv if needed.
2889 functionSemantic(inv);
2892 //e = new DsymbolExp(Loc.initial, inv);
2893 //e = new CallExp(Loc.initial, e);
2894 //e = e.semantic(sc2);
2896 /* https://issues.dlang.org/show_bug.cgi?id=13113
2897 * Currently virtual invariant calls completely
2898 * bypass attribute enforcement.
2899 * Change the behavior of pre-invariant call by following it.
2901 e = new ThisExp(Loc.initial);
2902 e.type = ad.type.addMod(vthis.type.mod);
2903 e = new DotVarExp(Loc.initial, e, inv, false);
2904 e.type = inv.type;
2905 e = new CallExp(Loc.initial, e);
2906 e.type = Type.tvoid;
2908 return e;
2911 /***************************************************
2912 * Visit each overloaded function/template in turn, and call dg(s) on it.
2913 * Exit when no more, or dg(s) returns nonzero.
2915 * Params:
2916 * fstart = symbol to start from
2917 * dg = the delegate to be called on the overload
2918 * sc = context used to check if symbol is accessible (and therefore visible),
2919 * can be null
2921 * Returns:
2922 * ==0 continue
2923 * !=0 done (and the return value from the last dg() call)
2925 extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
2927 Dsymbols visited;
2929 int overloadApplyRecurse(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc)
2931 // Detect cyclic calls.
2932 if (visited.contains(fstart))
2933 return 0;
2934 visited.push(fstart);
2936 Dsymbol next;
2937 for (auto d = fstart; d; d = next)
2939 import dmd.access : checkSymbolAccess;
2940 if (auto od = d.isOverDeclaration())
2942 /* The scope is needed here to check whether a function in
2943 an overload set was added by means of a private alias (or a
2944 selective import). If the scope where the alias is created
2945 is imported somewhere, the overload set is visible, but the private
2946 alias is not.
2948 if (sc)
2950 if (checkSymbolAccess(sc, od))
2952 if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
2953 return r;
2956 else if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
2957 return r;
2958 next = od.overnext;
2960 else if (auto fa = d.isFuncAliasDeclaration())
2962 if (fa.hasOverloads)
2964 if (int r = overloadApplyRecurse(fa.funcalias, dg, sc))
2965 return r;
2967 else if (auto fd = fa.toAliasFunc())
2969 if (int r = dg(fd))
2970 return r;
2972 else
2974 .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
2975 break;
2977 next = fa.overnext;
2979 else if (auto ad = d.isAliasDeclaration())
2981 if (sc)
2983 if (checkSymbolAccess(sc, ad))
2984 next = ad.toAlias();
2986 else
2987 next = ad.toAlias();
2988 if (next == ad)
2989 break;
2990 if (next == fstart)
2991 break;
2993 else if (auto td = d.isTemplateDeclaration())
2995 if (int r = dg(td))
2996 return r;
2997 next = td.overnext;
2999 else if (auto fd = d.isFuncDeclaration())
3001 if (int r = dg(fd))
3002 return r;
3003 next = fd.overnext;
3005 else if (auto os = d.isOverloadSet())
3007 foreach (ds; os.a)
3008 if (int r = dg(ds))
3009 return r;
3011 else
3013 .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
3014 break;
3015 // BUG: should print error message?
3018 return 0;
3020 return overloadApplyRecurse(fstart, dg, sc);
3024 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
3025 mismatching modifiers to `buf`.
3027 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
3028 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
3030 Params:
3031 buf = output buffer to write to
3032 lhsMod = modifier on the left-hand side
3033 lhsMod = modifier on the right-hand side
3035 Returns:
3037 A tuple with `isMutable` and `isNotShared` set
3038 if the `lhsMod` is missing those modifiers (compared to rhs).
3040 auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod)
3042 static struct Mismatches
3044 bool isNotShared;
3045 bool isMutable;
3048 Mismatches mismatches;
3050 bool bothMutable = ((lhsMod & rhsMod) == 0);
3051 bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0;
3052 bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_);
3054 if (lhsMod & MODFlags.shared_)
3055 buf.writestring("`shared` ");
3056 else if (sharedMismatch && !(lhsMod & MODFlags.immutable_))
3058 buf.writestring("non-shared ");
3059 mismatches.isNotShared = true;
3062 if (bothMutable && sharedMismatchOnly)
3065 else if (lhsMod & MODFlags.immutable_)
3066 buf.writestring("`immutable` ");
3067 else if (lhsMod & MODFlags.const_)
3068 buf.writestring("`const` ");
3069 else if (lhsMod & MODFlags.wild)
3070 buf.writestring("`inout` ");
3071 else
3073 buf.writestring("mutable ");
3074 mismatches.isMutable = true;
3077 return mismatches;
3081 unittest
3083 OutBuffer buf;
3084 auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0);
3085 assert(buf[] == "`shared` ");
3086 assert(!mismatches.isNotShared);
3088 buf.setsize(0);
3089 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_);
3090 assert(buf[] == "non-shared ");
3091 assert(mismatches.isNotShared);
3093 buf.setsize(0);
3094 mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0);
3095 assert(buf[] == "`const` ");
3096 assert(!mismatches.isMutable);
3098 buf.setsize(0);
3099 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_);
3100 assert(buf[] == "mutable ");
3101 assert(mismatches.isMutable);
3104 /// Flag used by $(LREF resolveFuncCall).
3105 enum FuncResolveFlag : ubyte
3107 standard = 0, /// issue error messages, solve the call.
3108 quiet = 1, /// do not issue error message on no match, just return `null`.
3109 overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous
3110 /// matches and need explicit this.
3111 ufcs = 4, /// trying to resolve UFCS call
3114 /*******************************************
3115 * Given a symbol that could be either a FuncDeclaration or
3116 * a function template, resolve it to a function symbol.
3117 * Params:
3118 * loc = instantiation location
3119 * sc = instantiation scope
3120 * s = instantiation symbol
3121 * tiargs = initial list of template arguments
3122 * tthis = if !NULL, the `this` argument type
3123 * argumentList = arguments to function
3124 * flags = see $(LREF FuncResolveFlag).
3125 * Returns:
3126 * if match is found, then function symbol, else null
3128 FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
3129 Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
3131 auto fargs = argumentList.arguments;
3132 if (!s)
3133 return null; // no match
3135 version (none)
3137 printf("resolveFuncCall('%s')\n", s.toChars());
3138 if (tthis)
3139 printf("\tthis: %s\n", tthis.toChars());
3140 if (fargs)
3142 for (size_t i = 0; i < fargs.length; i++)
3144 Expression arg = (*fargs)[i];
3145 assert(arg.type);
3146 printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
3149 printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
3152 if (tiargs && arrayObjectIsError(*tiargs))
3153 return null;
3154 if (fargs !is null)
3155 foreach (arg; *fargs)
3156 if (isError(arg))
3157 return null;
3159 MatchAccumulator m;
3160 functionResolve(m, s, loc, sc, tiargs, tthis, argumentList);
3161 auto orig_s = s;
3163 if (m.last > MATCH.nomatch && m.lastf)
3165 if (m.count == 1) // exactly one match
3167 if (!(flags & FuncResolveFlag.quiet))
3168 functionSemantic(m.lastf);
3169 return m.lastf;
3171 if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
3173 return m.lastf;
3177 /* Failed to find a best match.
3178 * Do nothing or print error.
3180 if (m.last == MATCH.nomatch)
3182 // error was caused on matched function, not on the matching itself,
3183 // so return the function to produce a better diagnostic
3184 if (m.count == 1)
3185 return m.lastf;
3188 // We are done at this point, as the rest of this function generate
3189 // a diagnostic on invalid match
3190 if (flags & FuncResolveFlag.quiet)
3191 return null;
3193 auto fd = s.isFuncDeclaration();
3194 auto od = s.isOverDeclaration();
3195 auto td = s.isTemplateDeclaration();
3196 if (td && td.funcroot)
3197 s = fd = td.funcroot;
3199 OutBuffer tiargsBuf;
3200 arrayObjectsToBuffer(tiargsBuf, tiargs);
3202 OutBuffer fargsBuf;
3203 fargsBuf.writeByte('(');
3204 argExpTypesToCBuffer(fargsBuf, fargs);
3205 fargsBuf.writeByte(')');
3206 if (tthis)
3207 tthis.modToBuffer(fargsBuf);
3209 // The call is ambiguous
3210 if (m.lastf && m.nextf)
3212 TypeFunction tf1 = m.lastf.type.toTypeFunction();
3213 TypeFunction tf2 = m.nextf.type.toTypeFunction();
3214 const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
3215 const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
3217 .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
3218 s.parent.toPrettyChars(), s.ident.toChars(),
3219 fargsBuf.peekChars(),
3220 m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(),
3221 m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars());
3222 return null;
3225 // no match, generate an error messages
3226 if (flags & FuncResolveFlag.ufcs)
3228 auto arg = (*fargs)[0];
3229 .error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars());
3230 .errorSupplemental(loc, "the following error occured while looking for a UFCS match");
3233 if (!fd)
3235 // all of overloads are templates
3236 if (td)
3238 if (!od && !td.overnext)
3240 .error(loc, "%s `%s` is not callable using argument types `!(%s)%s`",
3241 td.kind(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
3243 else
3245 .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`",
3246 td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
3247 tiargsBuf.peekChars(), fargsBuf.peekChars());
3251 if (!global.gag || global.params.v.showGaggedErrors)
3252 printCandidates(loc, td, sc.isDeprecated());
3253 return null;
3255 /* This case used to happen when several ctors are mixed in an agregate.
3256 A (bad) error message is already generated in overloadApply().
3257 see https://issues.dlang.org/show_bug.cgi?id=19729
3258 and https://issues.dlang.org/show_bug.cgi?id=17259
3260 if (!od)
3261 return null;
3264 if (od)
3266 .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
3267 od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
3268 return null;
3271 // remove when deprecation period of class allocators and deallocators is over
3272 if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
3273 return null;
3275 bool hasOverloads = fd.overnext !is null;
3276 auto tf = fd.type.isTypeFunction();
3277 // if type is an error, the original type should be there for better diagnostics
3278 if (!tf)
3279 tf = fd.originalType.toTypeFunction();
3281 // modifier mismatch
3282 if (tthis && (fd.isCtorDeclaration() ?
3283 !MODimplicitConv(tf.mod, tthis.mod) :
3284 !MODimplicitConv(tthis.mod, tf.mod)))
3286 OutBuffer thisBuf, funcBuf;
3287 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
3288 auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
3289 if (hasOverloads)
3291 OutBuffer buf;
3292 buf.argExpTypesToCBuffer(fargs);
3293 if (fd.isCtorDeclaration())
3294 .error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`",
3295 fd.toChars(), thisBuf.peekChars(), buf.peekChars());
3296 else
3297 .error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`",
3298 fd.toChars(), thisBuf.peekChars(), buf.peekChars());
3300 if (!global.gag || global.params.v.showGaggedErrors)
3301 printCandidates(loc, fd, sc.isDeprecated());
3302 return null;
3305 bool calledHelper;
3306 void errorHelper(const(char)* failMessage) scope
3308 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3309 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3310 tf.modToChars(), fargsBuf.peekChars());
3311 errorSupplemental(loc, failMessage);
3312 calledHelper = true;
3315 functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper);
3316 if (calledHelper)
3317 return null;
3319 if (fd.isCtorDeclaration())
3320 .error(loc, "%s%s `%s` cannot construct a %sobject",
3321 funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars());
3322 else
3323 .error(loc, "%smethod `%s` is not callable using a %sobject",
3324 funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
3326 if (mismatches.isNotShared)
3327 .errorSupplemental(fd.loc, "Consider adding `shared` here");
3328 else if (mismatches.isMutable)
3329 .errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
3330 return null;
3333 //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
3334 if (hasOverloads)
3336 .error(loc, "none of the overloads of `%s` are callable using argument types `%s`",
3337 fd.toChars(), fargsBuf.peekChars());
3338 if (!global.gag || global.params.v.showGaggedErrors)
3339 printCandidates(loc, fd, sc.isDeprecated());
3340 return null;
3343 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3344 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3345 tf.modToChars(), fargsBuf.peekChars());
3347 // re-resolve to check for supplemental message
3348 if (!global.gag || global.params.v.showGaggedErrors)
3350 if (tthis)
3352 if (auto classType = tthis.isTypeClass())
3354 if (auto baseClass = classType.sym.baseClass)
3356 if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
3358 MatchAccumulator mErr;
3359 functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
3360 if (mErr.last > MATCH.nomatch && mErr.lastf)
3362 errorSupplemental(loc, "%s `%s` hides base class function `%s`",
3363 fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
3364 errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
3365 fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
3366 return null;
3373 void errorHelper2(const(char)* failMessage) scope
3375 errorSupplemental(loc, failMessage);
3378 functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2);
3380 return null;
3383 /*******************************************
3384 * Prints template and function overload candidates as supplemental errors.
3385 * Params:
3386 * loc = instantiation location
3387 * declaration = the declaration to print overload candidates for
3388 * showDeprecated = If `false`, `deprecated` function won't be shown
3390 private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
3391 if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
3393 // max num of overloads to print (-v or -verror-supplements overrides this).
3394 const uint DisplayLimit = global.params.v.errorSupplementCount();
3395 const(char)* constraintsTip;
3396 // determine if the first candidate was printed
3397 int printed;
3399 bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false)
3401 if (auto fd = s.isFuncDeclaration())
3403 // Don't print overloads which have errors.
3404 // Not that if the whole overload set has errors, we'll never reach
3405 // this point so there's no risk of printing no candidate
3406 if (fd.errors || fd.type.ty == Terror)
3407 return false;
3408 // Don't print disabled functions, or `deprecated` outside of deprecated scope
3409 if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
3410 return false;
3411 if (!print)
3412 return true;
3413 auto tf = cast(TypeFunction) fd.type;
3414 OutBuffer buf;
3415 buf.writestring(fd.toPrettyChars());
3416 buf.writestring(parametersTypeToChars(tf.parameterList));
3417 if (tf.mod)
3419 buf.writeByte(' ');
3420 buf.MODtoBuffer(tf.mod);
3422 .errorSupplemental(fd.loc,
3423 printed ? " `%s`" :
3424 single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars());
3426 else if (auto td = s.isTemplateDeclaration())
3428 import dmd.staticcond;
3430 if (!print)
3431 return true;
3432 OutBuffer buf;
3433 HdrGenState hgs;
3434 hgs.skipConstraints = true;
3435 toCharsMaybeConstraints(td, buf, hgs);
3436 const tmsg = buf.peekChars();
3437 const cmsg = td.getConstraintEvalError(constraintsTip);
3439 // add blank space if there are multiple candidates
3440 // the length of the blank space is `strlen("Candidates are: ")`
3442 if (cmsg)
3444 .errorSupplemental(td.loc,
3445 printed ? " `%s`\n%s" :
3446 single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
3447 tmsg, cmsg);
3449 else
3451 .errorSupplemental(td.loc,
3452 printed ? " `%s`" :
3453 single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
3454 tmsg);
3457 return true;
3459 // determine if there's > 1 candidate
3460 int count = 0;
3461 overloadApply(declaration, (s) {
3462 if (matchSymbol(s, false))
3463 count++;
3464 return count > 1;
3466 int skipped = 0;
3467 overloadApply(declaration, (s) {
3468 if (global.params.v.verbose || printed < DisplayLimit)
3470 if (matchSymbol(s, true, count == 1))
3471 printed++;
3473 else
3475 // Too many overloads to sensibly display.
3476 // Just show count of remaining overloads.
3477 if (matchSymbol(s, false))
3478 skipped++;
3480 return 0;
3482 if (skipped > 0)
3483 .errorSupplemental(loc, "... (%d more, -v to show) ...", skipped);
3485 // Nothing was displayed, all overloads are either disabled or deprecated
3486 if (!printed)
3487 .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
3488 // should be only in verbose mode
3489 if (constraintsTip)
3490 .tip(constraintsTip);
3493 /**************************************
3494 * Returns an indirect type one step from t.
3496 Type getIndirection(Type t)
3498 import dmd.typesem : hasPointers;
3499 t = t.baseElemOf();
3500 if (t.ty == Tarray || t.ty == Tpointer)
3501 return t.nextOf().toBasetype();
3502 if (t.ty == Taarray || t.ty == Tclass)
3503 return t;
3504 if (t.ty == Tstruct)
3505 return t.hasPointers() ? t : null; // TODO
3507 // should consider TypeDelegate?
3508 return null;
3511 /**************************************
3512 * Performs type-based alias analysis between a newly created value and a pre-
3513 * existing memory reference:
3515 * Assuming that a reference A to a value of type `ta` was available to the code
3516 * that created a reference B to a value of type `tb`, it returns whether B
3517 * might alias memory reachable from A based on the types involved (either
3518 * directly or via any number of indirections in either A or B).
3520 * This relation is not symmetric in the two arguments. For example, a
3521 * a `const(int)` reference can point to a pre-existing `int`, but not the other
3522 * way round.
3524 * Examples:
3526 * ta, tb, result
3527 * `const(int)`, `int`, `false`
3528 * `int`, `const(int)`, `true`
3529 * `int`, `immutable(int)`, `false`
3530 * const(immutable(int)*), immutable(int)*, false // BUG: returns true
3532 * Params:
3533 * ta = value type being referred to
3534 * tb = referred to value type that could be constructed from ta
3536 * Returns:
3537 * true if reference to `tb` is isolated from reference to `ta`
3539 private bool traverseIndirections(Type ta, Type tb)
3541 //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
3543 static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
3545 import dmd.typesem : hasPointers;
3546 //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
3547 ta = ta.baseElemOf();
3548 tb = tb.baseElemOf();
3550 // First, check if the pointed-to types are convertible to each other such
3551 // that they might alias directly.
3552 static bool mayAliasDirect(Type source, Type target)
3554 return
3555 // if source is the same as target or can be const-converted to target
3556 source.constConv(target) != MATCH.nomatch ||
3557 // if target is void and source can be const-converted to target
3558 (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
3561 if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
3563 //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3564 return false;
3566 if (ta.nextOf() && ta.nextOf() == tb.nextOf())
3568 //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3569 return true;
3572 if (tb.ty == Tclass || tb.ty == Tstruct)
3574 /* Traverse the type of each field of the aggregate
3576 bool* found = table.getLvalue(tb.deco);
3577 if (*found == true)
3578 return true; // We have already seen this symbol, break the cycle
3579 else
3580 *found = true;
3582 import dmd.typesem : toDsymbol;
3583 AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
3584 foreach (v; sym.fields)
3586 Type tprmi = v.type.addMod(tb.mod);
3587 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
3588 if (!traverse(ta, tprmi, table, reversePass))
3589 return false;
3592 else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
3594 Type tind = tb.nextOf();
3595 if (!traverse(ta, tind, table, reversePass))
3596 return false;
3598 else if (tb.hasPointers())
3600 // BUG: consider the context pointer of delegate types
3601 return false;
3604 // Still no match, so try breaking up ta if we have not done so yet.
3605 if (!reversePass)
3607 scope newTable = AssocArray!(const(char)*, bool)();
3608 return traverse(tb, ta, newTable, true);
3611 return true;
3614 // To handle arbitrary levels of indirections in both parameters, we
3615 // recursively descend into aggregate members/levels of indirection in both
3616 // `ta` and `tb` while avoiding cycles. Start with the original types.
3617 scope table = AssocArray!(const(char)*, bool)();
3618 const result = traverse(ta, tb, table, false);
3619 //printf(" returns %d\n", result);
3620 return result;
3623 /* For all functions between outerFunc and f, mark them as needing
3624 * a closure.
3626 private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc)
3628 for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc))
3630 FuncDeclaration fy = sx.isFuncDeclaration();
3631 if (fy && fy.closureVars.length)
3633 /* fy needs a closure if it has closureVars[],
3634 * because the frame pointer in the closure will be accessed.
3636 fy.requiresClosure = true;
3641 /********
3642 * Given a nested function f inside a function outerFunc, check
3643 * if any sibling callers of f have escaped. If so, mark
3644 * all the enclosing functions as needing closures.
3645 * This is recursive: we need to check the callers of our siblings.
3646 * Note that nested functions can only call lexically earlier nested
3647 * functions, so loops are impossible.
3648 * Params:
3649 * f = inner function (nested within outerFunc)
3650 * outerFunc = outer function
3651 * p = for internal recursion use
3652 * Returns:
3653 * true if any closures were needed
3655 private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
3657 static struct PrevSibling
3659 PrevSibling* p;
3660 FuncDeclaration f;
3663 if (f.computedEscapingSiblings)
3664 return f.hasEscapingSiblings;
3666 PrevSibling ps;
3667 ps.p = cast(PrevSibling*)p;
3668 ps.f = f;
3670 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
3671 bool bAnyClosures = false;
3672 for (size_t i = 0; i < f.siblingCallers.length; ++i)
3674 FuncDeclaration g = f.siblingCallers[i];
3675 if (g.isThis() || g.tookAddressOf)
3677 markAsNeedingClosure(g, outerFunc);
3678 bAnyClosures = true;
3681 for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc))
3683 // A parent of the sibling had its address taken.
3684 // Assume escaping of parent affects its children, so needs propagating.
3685 // see https://issues.dlang.org/show_bug.cgi?id=19679
3686 FuncDeclaration parentFunc = parent.isFuncDeclaration;
3687 if (parentFunc && parentFunc.tookAddressOf)
3689 markAsNeedingClosure(parentFunc, outerFunc);
3690 bAnyClosures = true;
3694 PrevSibling* prev = cast(PrevSibling*)p;
3695 while (1)
3697 if (!prev)
3699 bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
3700 break;
3702 if (prev.f == g)
3703 break;
3704 prev = prev.p;
3707 f.hasEscapingSiblings = bAnyClosures;
3708 f.computedEscapingSiblings = true;
3709 //printf("\t%d\n", bAnyClosures);
3710 return bAnyClosures;
3713 /***********************************************************
3714 * Used as a way to import a set of functions from another scope into this one.
3716 extern (C++) final class FuncAliasDeclaration : FuncDeclaration
3718 FuncDeclaration funcalias;
3719 bool hasOverloads;
3721 extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true)
3723 super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type);
3724 assert(funcalias != this);
3725 this.funcalias = funcalias;
3727 this.hasOverloads = hasOverloads;
3728 if (hasOverloads)
3730 if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration())
3731 this.hasOverloads = fad.hasOverloads;
3733 else
3735 // for internal use
3736 assert(!funcalias.isFuncAliasDeclaration());
3737 this.hasOverloads = false;
3739 userAttribDecl = funcalias.userAttribDecl;
3742 override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
3744 return this;
3747 override const(char)* kind() const
3749 return "function alias";
3752 override inout(FuncDeclaration) toAliasFunc() inout
3754 return funcalias.toAliasFunc();
3757 override void accept(Visitor v)
3759 v.visit(this);
3763 /***********************************************************
3765 extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
3767 TOK tok; // TOK.function_ or TOK.delegate_
3768 Type treq; // target of return type inference
3770 // backend
3771 bool deferToObj;
3773 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_)
3775 super(loc, endloc, null, storage_class, type);
3776 this.ident = id ? id : Id.empty;
3777 this.tok = tok;
3778 this.fes = fes;
3779 // Always infer scope for function literals
3780 // See https://issues.dlang.org/show_bug.cgi?id=20362
3781 this.inferScope = true;
3782 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
3785 override FuncLiteralDeclaration syntaxCopy(Dsymbol s)
3787 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
3788 assert(!s);
3789 auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident, storage_class & STC.auto_);
3790 f.treq = treq; // don't need to copy
3791 FuncDeclaration.syntaxCopy(f);
3792 return f;
3795 override bool isNested() const
3797 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
3798 return (tok != TOK.function_) && !isThis();
3801 override inout(AggregateDeclaration) isThis() inout
3803 return tok == TOK.delegate_ ? super.isThis() : null;
3806 override bool isVirtual() const
3808 return false;
3811 override bool addPreInvariant()
3813 return false;
3816 override bool addPostInvariant()
3818 return false;
3821 /*******************************
3822 * Modify all expression type of return statements to tret.
3824 * On function literals, return type may be modified based on the context type
3825 * after its semantic3 is done, in FuncExp::implicitCastTo.
3827 * A function() dg = (){ return new B(); } // OK if is(B : A) == true
3829 * If B to A conversion is convariant that requires offseet adjusting,
3830 * all return statements should be adjusted to return expressions typed A.
3832 extern (D) void modifyReturns(Scope* sc, Type tret)
3834 import dmd.statement_rewrite_walker;
3836 extern (C++) final class RetWalker : StatementRewriteWalker
3838 alias visit = typeof(super).visit;
3839 public:
3840 Scope* sc;
3841 Type tret;
3842 FuncLiteralDeclaration fld;
3844 override void visit(ReturnStatement s)
3846 Expression exp = s.exp;
3847 if (exp && !exp.type.equals(tret))
3848 s.exp = exp.implicitCastTo(sc, tret);
3852 if (semanticRun < PASS.semantic3done)
3853 return;
3855 if (fes)
3856 return;
3858 scope RetWalker w = new RetWalker();
3859 w.sc = sc;
3860 w.tret = tret;
3861 w.fld = this;
3862 fbody.accept(w);
3864 // Also update the inferred function type to match the new return type.
3865 // This is required so the code generator does not try to cast the
3866 // modified returns back to the original type.
3867 if (inferRetType && type.nextOf() != tret)
3868 type.toTypeFunction().next = tret;
3871 override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
3873 return this;
3876 override const(char)* kind() const
3878 // GCC requires the (char*) casts
3879 return (tok != TOK.function_) ? "delegate" : "function";
3882 override const(char)* toPrettyChars(bool QualifyTypes = false)
3884 if (parent)
3886 TemplateInstance ti = parent.isTemplateInstance();
3887 if (ti)
3888 return ti.tempdecl.toPrettyChars(QualifyTypes);
3890 return Dsymbol.toPrettyChars(QualifyTypes);
3893 override void accept(Visitor v)
3895 v.visit(this);
3899 /***********************************************************
3901 extern (C++) final class CtorDeclaration : FuncDeclaration
3903 bool isCpCtor;
3904 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
3906 super(loc, endloc, Id.ctor, stc, type);
3907 this.isCpCtor = isCpCtor;
3908 //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
3911 override CtorDeclaration syntaxCopy(Dsymbol s)
3913 assert(!s);
3914 auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy());
3915 FuncDeclaration.syntaxCopy(f);
3916 return f;
3919 override const(char)* kind() const
3921 return isCpCtor ? "copy constructor" : "constructor";
3924 override const(char)* toChars() const
3926 return "this";
3929 override bool isVirtual() const
3931 return false;
3934 override bool addPreInvariant()
3936 return false;
3939 override bool addPostInvariant()
3941 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3944 override inout(CtorDeclaration) isCtorDeclaration() inout
3946 return this;
3949 override void accept(Visitor v)
3951 v.visit(this);
3955 /***********************************************************
3957 extern (C++) final class PostBlitDeclaration : FuncDeclaration
3959 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
3961 super(loc, endloc, id, stc, null);
3964 override PostBlitDeclaration syntaxCopy(Dsymbol s)
3966 assert(!s);
3967 auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
3968 FuncDeclaration.syntaxCopy(dd);
3969 return dd;
3972 override bool isVirtual() const
3974 return false;
3977 override bool addPreInvariant()
3979 return false;
3982 override bool addPostInvariant()
3984 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3987 override bool overloadInsert(Dsymbol s)
3989 return false; // cannot overload postblits
3992 override inout(PostBlitDeclaration) isPostBlitDeclaration() inout
3994 return this;
3997 override void accept(Visitor v)
3999 v.visit(this);
4003 /***********************************************************
4005 extern (C++) final class DtorDeclaration : FuncDeclaration
4007 extern (D) this(const ref Loc loc, const ref Loc endloc)
4009 super(loc, endloc, Id.dtor, STC.undefined_, null);
4012 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
4014 super(loc, endloc, id, stc, null);
4017 override DtorDeclaration syntaxCopy(Dsymbol s)
4019 assert(!s);
4020 auto dd = new DtorDeclaration(loc, endloc, storage_class, ident);
4021 FuncDeclaration.syntaxCopy(dd);
4022 return dd;
4025 override const(char)* kind() const
4027 return "destructor";
4030 override const(char)* toChars() const
4032 return "~this";
4035 override bool isVirtual() const
4037 // D dtor's don't get put into the vtbl[]
4038 // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
4039 return vtblIndex != -1;
4042 override bool addPreInvariant()
4044 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
4047 override bool addPostInvariant()
4049 return false;
4052 override bool overloadInsert(Dsymbol s)
4054 return false; // cannot overload destructors
4057 override inout(DtorDeclaration) isDtorDeclaration() inout
4059 return this;
4062 override void accept(Visitor v)
4064 v.visit(this);
4068 /***********************************************************
4070 extern (C++) class StaticCtorDeclaration : FuncDeclaration
4072 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4074 super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null);
4077 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
4079 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
4082 override StaticCtorDeclaration syntaxCopy(Dsymbol s)
4084 assert(!s);
4085 auto scd = new StaticCtorDeclaration(loc, endloc, storage_class);
4086 FuncDeclaration.syntaxCopy(scd);
4087 return scd;
4090 override final inout(AggregateDeclaration) isThis() inout @nogc nothrow pure @safe
4092 return null;
4095 override final bool isVirtual() const @nogc nothrow pure @safe
4097 return false;
4100 override final bool addPreInvariant() @nogc nothrow pure @safe
4102 return false;
4105 override final bool addPostInvariant() @nogc nothrow pure @safe
4107 return false;
4110 override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
4112 return true;
4115 override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
4117 return this;
4120 override void accept(Visitor v)
4122 v.visit(this);
4126 /***********************************************************
4128 extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
4130 /// Exclude this constructor from cyclic dependency check
4131 bool standalone;
4133 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4135 super(loc, endloc, "_sharedStaticCtor", stc);
4138 override SharedStaticCtorDeclaration syntaxCopy(Dsymbol s)
4140 assert(!s);
4141 auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
4142 FuncDeclaration.syntaxCopy(scd);
4143 return scd;
4146 override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
4148 return this;
4151 override void accept(Visitor v)
4153 v.visit(this);
4157 /***********************************************************
4159 extern (C++) class StaticDtorDeclaration : FuncDeclaration
4161 VarDeclaration vgate; // 'gate' variable
4163 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4165 super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null);
4168 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
4170 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
4173 override StaticDtorDeclaration syntaxCopy(Dsymbol s)
4175 assert(!s);
4176 auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
4177 FuncDeclaration.syntaxCopy(sdd);
4178 return sdd;
4181 override final inout(AggregateDeclaration) isThis() inout
4183 return null;
4186 override final bool isVirtual() const
4188 return false;
4191 override final bool hasStaticCtorOrDtor()
4193 return true;
4196 override final bool addPreInvariant()
4198 return false;
4201 override final bool addPostInvariant()
4203 return false;
4206 override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
4208 return this;
4211 override void accept(Visitor v)
4213 v.visit(this);
4217 /***********************************************************
4219 extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
4221 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4223 super(loc, endloc, "_sharedStaticDtor", stc);
4226 override SharedStaticDtorDeclaration syntaxCopy(Dsymbol s)
4228 assert(!s);
4229 auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
4230 FuncDeclaration.syntaxCopy(sdd);
4231 return sdd;
4234 override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
4236 return this;
4239 override void accept(Visitor v)
4241 v.visit(this);
4245 /***********************************************************
4247 extern (C++) final class InvariantDeclaration : FuncDeclaration
4249 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
4251 // Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list.
4252 super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
4253 this.fbody = fbody;
4256 override InvariantDeclaration syntaxCopy(Dsymbol s)
4258 assert(!s);
4259 auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null);
4260 FuncDeclaration.syntaxCopy(id);
4261 return id;
4264 override bool isVirtual() const
4266 return false;
4269 override bool addPreInvariant()
4271 return false;
4274 override bool addPostInvariant()
4276 return false;
4279 override inout(InvariantDeclaration) isInvariantDeclaration() inout
4281 return this;
4284 override void accept(Visitor v)
4286 v.visit(this);
4289 extern (D) void fixupInvariantIdent(size_t offset)
4291 OutBuffer idBuf;
4292 idBuf.writestring("__invariant");
4293 idBuf.print(offset);
4295 ident = Identifier.idPool(idBuf[]);
4300 /***********************************************************
4302 extern (C++) final class UnitTestDeclaration : FuncDeclaration
4304 char* codedoc; // for documented unittest
4306 // toObjFile() these nested functions after this one
4307 FuncDeclarations deferredNested;
4309 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
4311 super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null);
4312 this.codedoc = codedoc;
4315 override UnitTestDeclaration syntaxCopy(Dsymbol s)
4317 assert(!s);
4318 auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
4319 FuncDeclaration.syntaxCopy(utd);
4320 return utd;
4323 override inout(AggregateDeclaration) isThis() inout
4325 return null;
4328 override bool isVirtual() const
4330 return false;
4333 override bool addPreInvariant()
4335 return false;
4338 override bool addPostInvariant()
4340 return false;
4343 override inout(UnitTestDeclaration) isUnitTestDeclaration() inout
4345 return this;
4348 override void accept(Visitor v)
4350 v.visit(this);
4354 /***********************************************************
4356 extern (C++) final class NewDeclaration : FuncDeclaration
4358 extern (D) this(const ref Loc loc, StorageClass stc)
4360 super(loc, Loc.initial, Id.classNew, STC.static_ | stc, null);
4363 override NewDeclaration syntaxCopy(Dsymbol s)
4365 assert(!s);
4366 auto f = new NewDeclaration(loc, storage_class);
4367 FuncDeclaration.syntaxCopy(f);
4368 return f;
4371 override const(char)* kind() const
4373 return "allocator";
4376 override bool isVirtual() const
4378 return false;
4381 override bool addPreInvariant()
4383 return false;
4386 override bool addPostInvariant()
4388 return false;
4391 override inout(NewDeclaration) isNewDeclaration() inout
4393 return this;
4396 override void accept(Visitor v)
4398 v.visit(this);
4402 /**************************************
4403 * When a traits(compiles) is used on a function literal call
4404 * we need to take into account if the body of the function
4405 * violates any attributes, however, we must not affect the
4406 * attribute inference on the outer function. The attributes
4407 * of the function literal still need to be inferred, therefore
4408 * we need a way to check for the scope that the traits compiles
4409 * introduces.
4411 * Params:
4412 * sc = scope to be checked for
4414 * Returns: `true` if the provided scope is the root
4415 * of the traits compiles list of scopes.
4417 bool isRootTraitsCompilesScope(Scope* sc)
4419 return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
4422 /**************************************
4423 * A statement / expression in this scope is not `@safe`,
4424 * so mark the enclosing function as `@system`
4426 * Params:
4427 * sc = scope that the unsafe statement / expression is in
4428 * gag = surpress error message (used in escape.d)
4429 * loc = location of error
4430 * fmt = printf-style format string
4431 * arg0 = (optional) argument for first %s format specifier
4432 * arg1 = (optional) argument for second %s format specifier
4433 * arg2 = (optional) argument for third %s format specifier
4434 * Returns: whether there's a safe error
4436 bool setUnsafe(Scope* sc,
4437 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
4438 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
4440 if (sc.intypeof)
4441 return false; // typeof(cast(int*)0) is safe
4443 if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
4444 return false;
4446 if (!sc.func)
4448 if (sc.varDecl)
4450 if (sc.varDecl.storage_class & STC.safe)
4452 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4453 return true;
4455 else if (!(sc.varDecl.storage_class & STC.trusted))
4457 sc.varDecl.storage_class |= STC.system;
4458 sc.varDecl.systemInferred = true;
4461 return false;
4465 if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
4467 if (sc.func.isSafeBypassingInference())
4469 // Message wil be gagged, but still call error() to update global.errors and for
4470 // -verrors=spec
4471 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4472 return true;
4474 return false;
4477 return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
4480 /***************************************
4481 * Like `setUnsafe`, but for safety errors still behind preview switches
4483 * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
4484 * the behavior changes based on the setting:
4486 * - In case of `-revert=fs`, it does nothing.
4487 * - In case of `-preview=fs`, it's the same as `setUnsafe`
4488 * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
4490 * Params:
4491 * sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
4492 * fs = feature state from the preview flag
4493 * gag = surpress error message
4494 * loc = location of error
4495 * msg = printf-style format string
4496 * arg0 = (optional) argument for first %s format specifier
4497 * arg1 = (optional) argument for second %s format specifier
4498 * arg2 = (optional) argument for third %s format specifier
4499 * Returns: whether an actual safe error (not deprecation) occured
4501 bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
4502 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
4504 //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
4505 with (FeatureState) final switch (fs)
4507 case disabled:
4508 return false;
4510 case enabled:
4511 return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
4513 case default_:
4514 if (!sc.func)
4515 return false;
4516 if (sc.func.isSafeBypassingInference())
4518 if (!gag)
4520 warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4523 else if (!sc.func.safetyViolation)
4525 import dmd.func : AttributeViolation;
4526 sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
4528 return false;
4532 /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
4534 /// Has two modes:
4535 /// - a regular safety error, stored in (fmtStr, arg0, arg1)
4536 /// - a call to a function without the attribute, which is a special case, because in that case,
4537 /// that function might recursively also have a `AttributeViolation`. This way, in case
4538 /// of a big call stack, the error can go down all the way to the root cause.
4539 /// The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`.
4540 struct AttributeViolation
4542 /// location of error
4543 Loc loc = Loc.init;
4544 /// printf-style format string
4545 const(char)* fmtStr = null;
4546 /// Arguments for up to two `%s` format specifiers in format string
4547 RootObject arg0 = null;
4548 /// ditto
4549 RootObject arg1 = null;
4550 /// ditto
4551 RootObject arg2 = null;
4554 /// Print the reason why `fd` was inferred `@system` as a supplemental error
4555 /// Params:
4556 /// fd = function to check
4557 /// maxDepth = up to how many functions deep to report errors
4558 /// deprecation = print deprecations instead of errors
4559 /// stc = storage class of attribute to check
4560 void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc)
4562 auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
4564 AttributeViolation* s;
4565 const(char)* attr;
4566 if (stc & STC.safe)
4568 s = fd.safetyViolation;
4569 attr = "@safe";
4571 else if (stc & STC.pure_)
4573 s = fd.pureViolation;
4574 attr = "pure";
4576 else if (stc & STC.nothrow_)
4578 s = fd.nothrowViolation;
4579 attr = "nothrow";
4581 else if (stc & STC.nogc)
4583 s = fd.nogcViolation;
4584 attr = "@nogc";
4587 if (s)
4589 if (s.fmtStr)
4591 errorFunc(s.loc, deprecation ?
4592 "which wouldn't be `%s` because of:" :
4593 "which wasn't inferred `%s` because of:", attr);
4594 if (stc == STC.nogc || stc == STC.pure_)
4596 auto f = (cast(Dsymbol) s.arg0).isFuncDeclaration();
4597 errorFunc(s.loc, s.fmtStr, f.kind(), f.toPrettyChars(), s.arg1 ? s.arg1.toChars() : "");
4599 else
4601 errorFunc(s.loc, s.fmtStr,
4602 s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
4605 else if (auto sa = s.arg0.isDsymbol())
4607 if (FuncDeclaration fd2 = sa.isFuncDeclaration())
4609 if (maxDepth > 0)
4611 errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
4612 errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc);