d: Merge upstream dmd, druntime 26f049fb26, phobos 330d6a4fd.
[official-gcc.git] / gcc / d / dmd / func.d
blob60457351af6a72a53c5ecd2f5a788483a90a1682
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-2023 by The D Language Foundation, All Rights Reserved
12 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
13 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
14 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d)
15 * Documentation: https://dlang.org/phobos/dmd_func.html
16 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d
19 module dmd.func;
21 import core.stdc.stdio;
22 import core.stdc.string;
23 import dmd.aggregate;
24 import dmd.arraytypes;
25 import dmd.astenums;
26 import dmd.blockexit;
27 import dmd.gluelayer;
28 import dmd.dclass;
29 import dmd.declaration;
30 import dmd.delegatize;
31 import dmd.dinterpret;
32 import dmd.dmodule;
33 import dmd.dscope;
34 import dmd.dstruct;
35 import dmd.dsymbol;
36 import dmd.dsymbolsem;
37 import dmd.dtemplate;
38 import dmd.errors;
39 import dmd.escape;
40 import dmd.expression;
41 import dmd.globals;
42 import dmd.hdrgen;
43 import dmd.id;
44 import dmd.identifier;
45 import dmd.init;
46 import dmd.location;
47 import dmd.mtype;
48 import dmd.objc;
49 import dmd.root.aav;
50 import dmd.common.outbuffer;
51 import dmd.root.rootobject;
52 import dmd.root.string;
53 import dmd.root.stringtable;
54 import dmd.semantic2;
55 import dmd.semantic3;
56 import dmd.statement_rewrite_walker;
57 import dmd.statement;
58 import dmd.statementsem;
59 import dmd.tokens;
60 import dmd.visitor;
62 version (IN_GCC) {}
63 else version (IN_LLVM) {}
64 else version = MARS;
66 /// Inline Status
67 enum ILS : ubyte
69 uninitialized, /// not computed yet
70 no, /// cannot inline
71 yes, /// can inline
74 enum BUILTIN : ubyte
76 unknown = 255, /// not known if this is a builtin
77 unimp = 0, /// this is not a builtin
78 gcc, /// this is a GCC builtin
79 llvm, /// this is an LLVM builtin
80 sin,
81 cos,
82 tan,
83 sqrt,
84 fabs,
85 ldexp,
86 log,
87 log2,
88 log10,
89 exp,
90 expm1,
91 exp2,
92 round,
93 floor,
94 ceil,
95 trunc,
96 copysign,
97 pow,
98 fmin,
99 fmax,
100 fma,
101 isnan,
102 isinfinity,
103 isfinite,
104 bsf,
105 bsr,
106 bswap,
107 popcnt,
108 yl2x,
109 yl2xp1,
110 toPrecFloat,
111 toPrecDouble,
112 toPrecReal
115 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
117 extern (C++) final class NrvoWalker : StatementRewriteWalker
119 alias visit = typeof(super).visit;
120 public:
121 FuncDeclaration fd;
122 Scope* sc;
124 override void visit(ReturnStatement s)
126 // See if all returns are instead to be replaced with a goto returnLabel;
127 if (fd.returnLabel)
129 /* Rewrite:
130 * return exp;
131 * as:
132 * vresult = exp; goto Lresult;
134 auto gs = new GotoStatement(s.loc, Id.returnLabel);
135 gs.label = fd.returnLabel;
137 Statement s1 = gs;
138 if (s.exp)
139 s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
141 replaceCurrent(s1);
145 override void visit(TryFinallyStatement s)
147 DtorExpStatement des;
148 if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
149 fd.nrvo_var == des.var)
151 if (!(global.params.useExceptions && ClassDeclaration.throwable))
153 /* Don't need to call destructor at all, since it is nrvo
155 replaceCurrent(s._body);
156 s._body.accept(this);
157 return;
160 /* Normally local variable dtors are called regardless exceptions.
161 * But for nrvo_var, its dtor should be called only when exception is thrown.
163 * Rewrite:
164 * try { s.body; } finally { nrvo_var.edtor; }
165 * // equivalent with:
166 * // s.body; scope(exit) nrvo_var.edtor;
167 * as:
168 * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
169 * // equivalent with:
170 * // s.body; scope(failure) nrvo_var.edtor;
172 Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
173 Identifier id = Identifier.generateId("__o");
175 Statement handler = new PeelStatement(sexception);
176 if (sexception.blockExit(fd, false) & BE.fallthru)
178 auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
179 ts.internalThrow = true;
180 handler = new CompoundStatement(Loc.initial, handler, ts);
183 auto catches = new Catches();
184 auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
185 ctch.internalCatch = true;
186 ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
187 catches.push(ctch);
189 Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
190 fd.hasNoEH = false;
191 replaceCurrent(s2);
192 s2.accept(this);
194 else
195 StatementRewriteWalker.visit(s);
199 private struct FUNCFLAG
201 bool purityInprocess; /// working on determining purity
202 bool safetyInprocess; /// working on determining safety
203 bool nothrowInprocess; /// working on determining nothrow
204 bool nogcInprocess; /// working on determining @nogc
205 bool returnInprocess; /// working on inferring 'return' for parameters
206 bool inlineScanned; /// function has been scanned for inline possibilities
207 bool inferScope; /// infer 'scope' for parameters
208 bool hasCatches; /// function has try-catch statements
209 bool skipCodegen; /// do not generate code for this function.
210 bool printf; /// is a printf-like function
212 bool scanf; /// is a scanf-like function
213 bool noreturn; /// the function does not return
214 bool isNRVO = true; /// Support for named return value optimization
215 bool isNaked; /// The function is 'naked' (see inline ASM)
216 bool isGenerated; /// The function is compiler generated (e.g. `opCmp`)
217 bool isIntroducing; /// If this function introduces the overload set
218 bool hasSemantic3Errors; /// If errors in semantic3 this function's frame ptr
219 bool hasNoEH; /// No exception unwinding is needed
220 bool inferRetType; /// Return type is to be inferred
221 bool hasDualContext; /// has a dual-context 'this' parameter
223 bool hasAlwaysInlines; /// Contains references to functions that must be inlined
224 bool isCrtCtor; /// Has attribute pragma(crt_constructor)
225 bool isCrtDtor; /// Has attribute pragma(crt_destructor)
226 bool hasEscapingSiblings;/// Has sibling functions that escape
227 bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed
228 bool dllImport; /// __declspec(dllimport)
229 bool dllExport; /// __declspec(dllexport)
232 /***********************************************************
233 * Tuple of result identifier (possibly null) and statement.
234 * This is used to store out contracts: out(id){ ensure }
236 extern (C++) struct Ensure
238 Identifier id;
239 Statement ensure;
241 Ensure syntaxCopy()
243 return Ensure(id, ensure.syntaxCopy());
246 /*****************************************
247 * Do syntax copy of an array of Ensure's.
249 static Ensures* arraySyntaxCopy(Ensures* a)
251 Ensures* b = null;
252 if (a)
254 b = a.copy();
255 foreach (i, e; *a)
257 (*b)[i] = e.syntaxCopy();
260 return b;
265 /***********************************************************
266 * Most functions don't have contracts, so save memory by grouping
267 * this information into a separate struct
269 private struct ContractInfo
271 Statements* frequires; /// in contracts
272 Ensures* fensures; /// out contracts
273 Statement frequire; /// lowered in contract
274 Statement fensure; /// lowered out contract
275 FuncDeclaration fdrequire; /// function that does the in contract
276 FuncDeclaration fdensure; /// function that does the out contract
277 Expressions* fdrequireParams; /// argument list for __require
278 Expressions* fdensureParams; /// argument list for __ensure
281 /***********************************************************
283 extern (C++) class FuncDeclaration : Declaration
285 Statement fbody; /// function body
287 FuncDeclarations foverrides; /// functions this function overrides
289 private ContractInfo* contracts; /// contract information
291 const(char)* mangleString; /// mangled symbol created from mangleExact()
293 VarDeclaration vresult; /// result variable for out contracts
294 LabelDsymbol returnLabel; /// where the return goes
296 bool[size_t] isTypeIsolatedCache; /// cache for the potentially very expensive isTypeIsolated check
298 // used to prevent symbols in different
299 // scopes from having the same name
300 DsymbolTable localsymtab;
301 VarDeclaration vthis; /// 'this' parameter (member and nested)
302 VarDeclaration v_arguments; /// '_arguments' parameter
304 VarDeclaration v_argptr; /// '_argptr' variable
305 VarDeclarations* parameters; /// Array of VarDeclaration's for parameters
306 DsymbolTable labtab; /// statement label symbol table
307 Dsymbol overnext; /// next in overload list
308 FuncDeclaration overnext0; /// next in overload list (only used during IFTI)
309 Loc endloc; /// location of closing curly bracket
310 int vtblIndex = -1; /// for member functions, index into vtbl[]
312 ILS inlineStatusStmt = ILS.uninitialized;
313 ILS inlineStatusExp = ILS.uninitialized;
314 PINLINE inlining = PINLINE.default_;
316 int inlineNest; /// !=0 if nested inline
318 ForeachStatement fes; /// if foreach body, this is the foreach
319 BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[]
320 /** if !=NULL, then this is the type
321 of the 'introducing' function
322 this one is overriding
324 Type tintro;
326 StorageClass storage_class2; /// storage class for template onemember's
328 // Things that should really go into Scope
330 /// 1 if there's a return exp; statement
331 /// 2 if there's a throw statement
332 /// 4 if there's an assert(0)
333 /// 8 if there's inline asm
334 /// 16 if there are multiple return statements
335 int hasReturnExp;
337 VarDeclaration nrvo_var; /// variable to replace with shidden
338 Symbol* shidden; /// hidden pointer passed to function
340 ReturnStatements* returns;
342 GotoStatements* gotos; /// Gotos with forward references
344 version (MARS)
346 VarDeclarations* alignSectionVars; /// local variables with alignment needs larger than stackAlign
347 Symbol* salignSection; /// pointer to aligned section, if any
350 /// set if this is a known, builtin function we can evaluate at compile time
351 BUILTIN builtin = BUILTIN.unknown;
353 /// set if someone took the address of this function
354 int tookAddressOf;
356 bool requiresClosure; // this function needs a closure
358 /** local variables in this function which are referenced by nested functions
359 * (They'll get put into the "closure" for this function.)
361 VarDeclarations closureVars;
363 /** Outer variables which are referenced by this nested function
364 * (the inverse of closureVars)
366 VarDeclarations outerVars;
368 /// Sibling nested functions which called this one
369 FuncDeclarations siblingCallers;
371 FuncDeclarations *inlinedNestedCallees;
373 /// In case of failed `@safe` inference, store the error that made the function `@system` for
374 /// better diagnostics
375 AttributeViolation* safetyViolation;
376 AttributeViolation* nogcViolation;
377 AttributeViolation* pureViolation;
378 AttributeViolation* nothrowViolation;
380 /// See the `FUNCFLAG` struct
381 import dmd.common.bitfields;
382 mixin(generateBitFields!(FUNCFLAG, uint));
385 * Data for a function declaration that is needed for the Objective-C
386 * integration.
388 ObjcFuncDeclaration objc;
390 extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false)
392 super(loc, ident);
393 //.printf("FuncDeclaration(id = '%s', type = %s)\n", ident.toChars(), type.toChars());
394 //.printf("storage_class = x%llx\n", storage_class);
395 this.storage_class = storage_class;
396 this.type = type;
397 if (type)
399 // Normalize storage_class, because function-type related attributes
400 // are already set in the 'type' in parsing phase.
401 this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
403 this.endloc = endloc;
404 if (noreturn)
405 this.noreturn = true;
407 /* The type given for "infer the return type" is a TypeFunction with
408 * NULL for the return type.
410 if (type && type.nextOf() is null)
411 this.inferRetType = true;
414 static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
416 return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn);
419 final nothrow pure @safe
421 private ref ContractInfo getContracts()
423 if (!contracts)
424 contracts = new ContractInfo();
425 return *contracts;
428 // getters
429 inout(Statements*) frequires() inout { return contracts ? contracts.frequires : null; }
430 inout(Ensures*) fensures() inout { return contracts ? contracts.fensures : null; }
431 inout(Statement) frequire() inout { return contracts ? contracts.frequire: null; }
432 inout(Statement) fensure() inout { return contracts ? contracts.fensure : null; }
433 inout(FuncDeclaration) fdrequire() inout { return contracts ? contracts.fdrequire : null; }
434 inout(FuncDeclaration) fdensure() inout { return contracts ? contracts.fdensure: null; }
435 inout(Expressions*) fdrequireParams() inout { return contracts ? contracts.fdrequireParams: null; }
436 inout(Expressions*) fdensureParams() inout { return contracts ? contracts.fdensureParams: null; }
438 extern (D) private static string generateContractSetter(string field, string type)
440 return type ~ " " ~ field ~ "(" ~ type ~ " param)" ~
442 if (!param && !contracts) return null;
443 return getContracts()." ~ field ~ " = param;
447 mixin(generateContractSetter("frequires", "Statements*"));
448 mixin(generateContractSetter("fensures", "Ensures*"));
449 mixin(generateContractSetter("frequire", "Statement"));
450 mixin(generateContractSetter("fensure", "Statement"));
451 mixin(generateContractSetter("fdrequire", "FuncDeclaration"));
452 mixin(generateContractSetter("fdensure", "FuncDeclaration"));
453 mixin(generateContractSetter("fdrequireParams", "Expressions*"));
454 mixin(generateContractSetter("fdensureParams", "Expressions*"));
457 override FuncDeclaration syntaxCopy(Dsymbol s)
459 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
460 FuncDeclaration f = s ? cast(FuncDeclaration)s
461 : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), this.noreturn != 0);
462 f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
463 f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
464 f.fbody = fbody ? fbody.syntaxCopy() : null;
465 return f;
468 /****************************************************
469 * Resolve forward reference of function signature -
470 * parameter types, return type, and attributes.
471 * Returns:
472 * false if any errors exist in the signature.
474 final bool functionSemantic()
476 //printf("functionSemantic() %p %s\n", this, toChars());
477 if (!_scope)
478 return !errors;
480 this.cppnamespace = _scope.namespace;
482 if (!originalType) // semantic not yet run
484 TemplateInstance spec = isSpeculative();
485 uint olderrs = global.errors;
486 uint oldgag = global.gag;
487 if (global.gag && !spec)
488 global.gag = 0;
489 dsymbolSemantic(this, _scope);
490 global.gag = oldgag;
491 if (spec && global.errors != olderrs)
492 spec.errors = (global.errors - olderrs != 0);
493 if (olderrs != global.errors) // if errors compiling this function
494 return false;
497 // if inferring return type, sematic3 needs to be run
498 // - When the function body contains any errors, we cannot assume
499 // the inferred return type is valid.
500 // So, the body errors should become the function signature error.
501 if (inferRetType && type && !type.nextOf())
502 return functionSemantic3();
504 TemplateInstance ti;
505 if (isInstantiated() && !isVirtualMethod() &&
506 ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident))
508 AggregateDeclaration ad = isMemberLocal();
509 if (ad && ad.sizeok != Sizeok.done)
511 /* Currently dmd cannot resolve forward references per methods,
512 * then setting SIZOKfwd is too conservative and would break existing code.
513 * So, just stop method attributes inference until ad.dsymbolSemantic() done.
515 //ad.sizeok = Sizeok.fwd;
517 else
518 return functionSemantic3() || !errors;
521 if (storage_class & STC.inference)
522 return functionSemantic3() || !errors;
524 return !errors;
527 /****************************************************
528 * Resolve forward reference of function body.
529 * Returns false if any errors exist in the body.
531 final bool functionSemantic3()
533 if (semanticRun < PASS.semantic3 && _scope)
535 /* Forward reference - we need to run semantic3 on this function.
536 * If errors are gagged, and it's not part of a template instance,
537 * we need to temporarily ungag errors.
539 TemplateInstance spec = isSpeculative();
540 uint olderrs = global.errors;
541 uint oldgag = global.gag;
542 if (global.gag && !spec)
543 global.gag = 0;
544 semantic3(this, _scope);
545 global.gag = oldgag;
547 // If it is a speculatively-instantiated template, and errors occur,
548 // we need to mark the template as having errors.
549 if (spec && global.errors != olderrs)
550 spec.errors = (global.errors - olderrs != 0);
551 if (olderrs != global.errors) // if errors compiling this function
552 return false;
555 return !errors && !this.hasSemantic3Errors();
558 /****************************************************
559 * Check that this function type is properly resolved.
560 * If not, report "forward reference error" and return true.
562 extern (D) final bool checkForwardRef(const ref Loc loc)
564 if (!functionSemantic())
565 return true;
567 /* No deco means the functionSemantic() call could not resolve
568 * forward referenes in the type of this function.
570 if (!type.deco)
572 bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3);
573 .error(loc, "forward reference to %s`%s`",
574 (inSemantic3 ? "inferred return type of function " : "").ptr,
575 toChars());
576 return true;
578 return false;
581 // called from semantic3
583 * Creates and returns the hidden parameters for this function declaration.
585 * Hidden parameters include the `this` parameter of a class, struct or
586 * nested function and the selector parameter for Objective-C methods.
588 extern (D) final void declareThis(Scope* sc)
590 const bool dualCtx = (toParent2() != toParentLocal());
591 if (dualCtx)
592 this.hasDualContext = true;
593 auto ad = isThis();
594 if (!dualCtx && !ad && !isNested())
596 vthis = null;
597 objc.selectorParameter = null;
598 return;
601 Type addModStc(Type t)
603 return t.addMod(type.mod).addStorageClass(storage_class);
606 if (dualCtx || isNested())
608 /* The 'this' for a nested function is the link to the
609 * enclosing function's stack frame.
610 * Note that nested functions and member functions are disjoint.
612 Type tthis = addModStc(dualCtx ?
613 Type.tvoidptr.sarrayOf(2).pointerTo() :
614 Type.tvoid.pointerTo());
615 vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null);
616 vthis.storage_class |= STC.parameter | STC.nodtor;
618 else if (ad)
620 Type thandle = addModStc(ad.handleType());
621 vthis = new ThisDeclaration(loc, thandle);
622 vthis.storage_class |= STC.parameter;
623 if (thandle.ty == Tstruct)
625 vthis.storage_class |= STC.ref_;
629 if (auto tf = type.isTypeFunction())
631 if (tf.isreturn)
632 vthis.storage_class |= STC.return_;
633 if (tf.isScopeQual)
634 vthis.storage_class |= STC.scope_;
635 if (tf.isreturnscope)
636 vthis.storage_class |= STC.returnScope;
639 vthis.dsymbolSemantic(sc);
640 if (!sc.insert(vthis))
641 assert(0);
642 vthis.parent = this;
643 if (ad)
644 objc.selectorParameter = .objc.createSelectorParameter(this, sc);
647 override final bool equals(const RootObject o) const
649 if (this == o)
650 return true;
652 if (auto s = isDsymbol(o))
654 auto fd1 = this;
655 auto fd2 = s.isFuncDeclaration();
656 if (!fd2)
657 return false;
659 auto fa1 = fd1.isFuncAliasDeclaration();
660 auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
662 auto fa2 = fd2.isFuncAliasDeclaration();
663 auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
665 if (fa1 && fa2)
667 return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
670 bool b1 = fa1 !is null;
671 if (b1 && faf1.isUnique() && !fa1.hasOverloads)
672 b1 = false;
674 bool b2 = fa2 !is null;
675 if (b2 && faf2.isUnique() && !fa2.hasOverloads)
676 b2 = false;
678 if (b1 != b2)
679 return false;
681 return faf1.toParent().equals(faf2.toParent()) &&
682 faf1.ident.equals(faf2.ident) &&
683 faf1.type.equals(faf2.type);
685 return false;
688 /****************************************************
689 * Determine if 'this' overrides fd.
690 * Return !=0 if it does.
692 final int overrides(FuncDeclaration fd)
694 int result = 0;
695 if (fd.ident == ident)
697 const cov = type.covariant(fd.type);
698 if (cov != Covariant.distinct)
700 ClassDeclaration cd1 = toParent().isClassDeclaration();
701 ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
702 if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
703 result = 1;
706 return result;
709 /*************************************************
710 * Find index of function in vtbl[0..length] that
711 * this function overrides.
712 * Prefer an exact match to a covariant one.
713 * Params:
714 * vtbl = vtable to use
715 * dim = maximal vtable dimension
716 * Returns:
717 * -1 didn't find one
718 * -2 can't determine because of forward references
720 final int findVtblIndex(Dsymbols* vtbl, int dim)
722 //printf("findVtblIndex() %s\n", toChars());
723 FuncDeclaration mismatch = null;
724 StorageClass mismatchstc = 0;
725 int mismatchvi = -1;
726 int exactvi = -1;
727 int bestvi = -1;
728 for (int vi = 0; vi < dim; vi++)
730 FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration();
731 if (fdv && fdv.ident == ident)
733 if (type.equals(fdv.type)) // if exact match
735 if (fdv.parent.isClassDeclaration())
737 if (fdv.isFuture())
739 bestvi = vi;
740 continue; // keep looking
742 return vi; // no need to look further
745 if (exactvi >= 0)
747 error("cannot determine overridden function");
748 return exactvi;
750 exactvi = vi;
751 bestvi = vi;
752 continue;
755 StorageClass stc = 0;
756 const cov = type.covariant(fdv.type, &stc);
757 //printf("\tbaseclass cov = %d\n", cov);
758 final switch (cov)
760 case Covariant.distinct:
761 // types are distinct
762 break;
764 case Covariant.yes:
765 bestvi = vi; // covariant, but not identical
766 break;
767 // keep looking for an exact match
769 case Covariant.no:
770 mismatchvi = vi;
771 mismatchstc = stc;
772 mismatch = fdv; // overrides, but is not covariant
773 break;
774 // keep looking for an exact match
776 case Covariant.fwdref:
777 return -2; // forward references
781 if (_linkage == LINK.cpp && bestvi != -1)
783 StorageClass stc = 0;
784 FuncDeclaration fdv = (*vtbl)[bestvi].isFuncDeclaration();
785 assert(fdv && fdv.ident == ident);
786 if (type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no)
788 /* https://issues.dlang.org/show_bug.cgi?id=22351
789 * Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not.
790 * For now, continue to allow D covariant rules to apply when `override` has been used,
791 * but issue a deprecation warning that this behaviour will change in the future.
792 * Otherwise, follow the C++ covariant rules, which will create a new vtable entry.
794 if (isOverride())
796 /* @@@DEPRECATED_2.110@@@
797 * After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch,
798 * but also the `cppCovariant` parameter from Type.covariant, and update the function
799 * so that both `LINK.cpp` covariant conditions within are always checked.
801 .deprecation(loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated",
802 fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(),
803 toPrettyChars(), type.toTypeFunction().parameterList.parametersTypeToChars(), type.modToChars());
805 const char* where = type.isNaked() ? "parameters" : "type";
806 deprecationSupplemental(loc, "Either remove `override`, or adjust the `const` qualifiers of the "
807 ~ "overriding function %s", where);
809 else
811 // Treat as if Covariant.no
812 mismatchvi = bestvi;
813 mismatchstc = stc;
814 mismatch = fdv;
815 bestvi = -1;
819 if (bestvi == -1 && mismatch)
821 //type.print();
822 //mismatch.type.print();
823 //printf("%s %s\n", type.deco, mismatch.type.deco);
824 //printf("stc = %llx\n", mismatchstc);
825 if (mismatchstc)
827 // Fix it by modifying the type to add the storage classes
828 type = type.addStorageClass(mismatchstc);
829 bestvi = mismatchvi;
832 return bestvi;
835 /*********************************
836 * If function a function in a base class,
837 * return that base class.
838 * Returns:
839 * base class if overriding, null if not
841 final BaseClass* overrideInterface()
843 for (ClassDeclaration cd = toParent2().isClassDeclaration(); cd; cd = cd.baseClass)
845 foreach (b; cd.interfaces)
847 auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length);
848 if (v >= 0)
849 return b;
852 return null;
855 /****************************************************
856 * Overload this FuncDeclaration with the new one f.
857 * Return true if successful; i.e. no conflict.
859 override bool overloadInsert(Dsymbol s)
861 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
862 assert(s != this);
863 AliasDeclaration ad = s.isAliasDeclaration();
864 if (ad)
866 if (overnext)
867 return overnext.overloadInsert(ad);
868 if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof)
870 //printf("\tad = '%s'\n", ad.type.toChars());
871 return false;
873 overnext = ad;
874 //printf("\ttrue: no conflict\n");
875 return true;
877 TemplateDeclaration td = s.isTemplateDeclaration();
878 if (td)
880 if (!td.funcroot)
881 td.funcroot = this;
882 if (overnext)
883 return overnext.overloadInsert(td);
884 overnext = td;
885 return true;
887 FuncDeclaration fd = s.isFuncDeclaration();
888 if (!fd)
889 return false;
891 version (none)
893 /* Disable this check because:
894 * const void foo();
895 * semantic() isn't run yet on foo(), so the const hasn't been
896 * applied yet.
898 if (type)
900 printf("type = %s\n", type.toChars());
901 printf("fd.type = %s\n", fd.type.toChars());
903 // fd.type can be NULL for overloaded constructors
904 if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
906 //printf("\tfalse: conflict %s\n", kind());
907 return false;
911 if (overnext)
913 td = overnext.isTemplateDeclaration();
914 if (td)
915 fd.overloadInsert(td);
916 else
917 return overnext.overloadInsert(fd);
919 overnext = fd;
920 //printf("\ttrue: no conflict\n");
921 return true;
924 /********************************************
925 * Find function in overload list that exactly matches t.
927 extern (D) final FuncDeclaration overloadExactMatch(Type t)
929 FuncDeclaration fd;
930 overloadApply(this, (Dsymbol s)
932 auto f = s.isFuncDeclaration();
933 if (!f)
934 return 0;
935 if (f.storage_class & STC.disable)
936 return 0;
937 if (t.equals(f.type))
939 fd = f;
940 return 1;
943 /* Allow covariant matches, as long as the return type
944 * is just a const conversion.
945 * This allows things like pure functions to match with an impure function type.
947 if (t.ty == Tfunction)
949 auto tf = cast(TypeFunction)f.type;
950 if (tf.covariant(t) == Covariant.yes &&
951 tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
953 fd = f;
954 return 1;
957 return 0;
959 return fd;
962 /********************************************
963 * Find function in overload list that matches to the 'this' modifier.
964 * There's four result types.
966 * 1. If the 'tthis' matches only one candidate, it's an "exact match".
967 * Returns the function and 'hasOverloads' is set to false.
968 * eg. If 'tthis" is mutable and there's only one mutable method.
969 * 2. If there's two or more match candidates, but a candidate function will be
970 * a "better match".
971 * Returns the better match function but 'hasOverloads' is set to true.
972 * eg. If 'tthis' is mutable, and there's both mutable and const methods,
973 * the mutable method will be a better match.
974 * 3. If there's two or more match candidates, but there's no better match,
975 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
976 * eg. If 'tthis' is mutable, and there's two or more mutable methods.
977 * 4. If there's no candidates, it's "no match" and returns null with error report.
978 * e.g. If 'tthis' is const but there's no const methods.
980 extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
982 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
983 MatchAccumulator m;
984 overloadApply(this, (Dsymbol s)
986 auto f = s.isFuncDeclaration();
987 if (!f || f == m.lastf) // skip duplicates
988 return 0;
990 auto tf = f.type.toTypeFunction();
991 //printf("tf = %s\n", tf.toChars());
993 MATCH match;
994 if (tthis) // non-static functions are preferred than static ones
996 if (f.needThis())
997 match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
998 else
999 match = MATCH.constant; // keep static function in overload candidates
1001 else // static functions are preferred than non-static ones
1003 if (f.needThis())
1004 match = MATCH.convert;
1005 else
1006 match = MATCH.exact;
1008 if (match == MATCH.nomatch)
1009 return 0;
1011 if (match > m.last) goto LcurrIsBetter;
1012 if (match < m.last) goto LlastIsBetter;
1014 // See if one of the matches overrides the other.
1015 if (m.lastf.overrides(f)) goto LlastIsBetter;
1016 if (f.overrides(m.lastf)) goto LcurrIsBetter;
1018 //printf("\tambiguous\n");
1019 m.nextf = f;
1020 m.count++;
1021 return 0;
1023 LlastIsBetter:
1024 //printf("\tlastbetter\n");
1025 m.count++; // count up
1026 return 0;
1028 LcurrIsBetter:
1029 //printf("\tisbetter\n");
1030 if (m.last <= MATCH.convert)
1032 // clear last secondary matching
1033 m.nextf = null;
1034 m.count = 0;
1036 m.last = match;
1037 m.lastf = f;
1038 m.count++; // count up
1039 return 0;
1042 if (m.count == 1) // exact match
1044 hasOverloads = false;
1046 else if (m.count > 1) // better or ambiguous match
1048 hasOverloads = true;
1050 else // no match
1052 hasOverloads = true;
1053 auto tf = this.type.toTypeFunction();
1054 assert(tthis);
1055 assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
1057 OutBuffer thisBuf, funcBuf;
1058 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
1059 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
1060 .error(loc, "%smethod %s is not callable using a %sobject",
1061 funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
1064 return m.lastf;
1067 /********************************************
1068 * find function template root in overload list
1070 extern (D) final TemplateDeclaration findTemplateDeclRoot()
1072 FuncDeclaration f = this;
1073 while (f && f.overnext)
1075 //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
1076 TemplateDeclaration td = f.overnext.isTemplateDeclaration();
1077 if (td)
1078 return td;
1079 f = f.overnext.isFuncDeclaration();
1081 return null;
1084 /********************************************
1085 * Returns true if function was declared
1086 * directly or indirectly in a unittest block
1088 final bool inUnittest()
1090 Dsymbol f = this;
1093 if (f.isUnitTestDeclaration())
1094 return true;
1095 f = f.toParent();
1097 while (f);
1098 return false;
1101 /*************************************
1102 * Determine partial specialization order of 'this' vs g.
1103 * This is very similar to TemplateDeclaration::leastAsSpecialized().
1104 * Returns:
1105 * match 'this' is at least as specialized as g
1106 * 0 g is more specialized than 'this'
1108 final MATCH leastAsSpecialized(FuncDeclaration g, Identifiers* names)
1110 enum LOG_LEASTAS = 0;
1111 static if (LOG_LEASTAS)
1113 import core.stdc.stdio : printf;
1114 printf("%s.leastAsSpecialized(%s, %s)\n", toChars(), g.toChars(), names ? names.toChars() : "null");
1115 printf("%s, %s\n", type.toChars(), g.type.toChars());
1118 /* This works by calling g() with f()'s parameters, and
1119 * if that is possible, then f() is at least as specialized
1120 * as g() is.
1123 TypeFunction tf = type.toTypeFunction();
1124 TypeFunction tg = g.type.toTypeFunction();
1126 /* If both functions have a 'this' pointer, and the mods are not
1127 * the same and g's is not const, then this is less specialized.
1129 if (needThis() && g.needThis() && tf.mod != tg.mod)
1131 if (isCtorDeclaration())
1133 if (!MODimplicitConv(tg.mod, tf.mod))
1134 return MATCH.nomatch;
1136 else
1138 if (!MODimplicitConv(tf.mod, tg.mod))
1139 return MATCH.nomatch;
1143 /* Create a dummy array of arguments out of the parameters to f()
1145 Expressions args;
1146 foreach (u, p; tf.parameterList)
1148 Expression e;
1149 if (p.isReference())
1151 e = new IdentifierExp(Loc.initial, p.ident);
1152 e.type = p.type;
1154 else
1155 e = p.type.defaultInitLiteral(Loc.initial);
1156 args.push(e);
1159 MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
1160 if (m > MATCH.nomatch)
1162 /* A variadic parameter list is less specialized than a
1163 * non-variadic one.
1165 if (tf.parameterList.varargs && !tg.parameterList.varargs)
1166 goto L1; // less specialized
1168 static if (LOG_LEASTAS)
1170 printf(" matches %d, so is least as specialized\n", m);
1172 return m;
1175 static if (LOG_LEASTAS)
1177 printf(" doesn't match, so is not as specialized\n");
1179 return MATCH.nomatch;
1182 /********************************
1183 * Searches for a label with the given identifier. This function will insert a new
1184 * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
1186 * Params:
1187 * ident = identifier of the requested label
1188 * loc = location used when creating a new `LabelDsymbol`
1190 * Returns: the `LabelDsymbol` for `ident`
1192 final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial)
1194 Dsymbol s;
1195 if (!labtab)
1196 labtab = new DsymbolTable(); // guess we need one
1198 s = labtab.lookup(ident);
1199 if (!s)
1201 s = new LabelDsymbol(ident, loc);
1202 labtab.insert(s);
1204 return cast(LabelDsymbol)s;
1207 /*****************************************
1208 * Determine lexical level difference from `this` to nested function `fd`.
1209 * Params:
1210 * fd = target of call
1211 * intypeof = !=0 if inside typeof
1212 * Returns:
1213 * 0 same level
1214 * >0 decrease nesting by number
1215 * -1 increase nesting by 1 (`fd` is nested within `this`)
1216 * LevelError error, `this` cannot call `fd`
1218 final int getLevel(FuncDeclaration fd, int intypeof)
1220 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
1221 Dsymbol fdparent = fd.toParent2();
1222 if (fdparent == this)
1223 return -1;
1225 Dsymbol s = this;
1226 int level = 0;
1227 while (fd != s && fdparent != s.toParent2())
1229 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
1230 if (auto thisfd = s.isFuncDeclaration())
1232 if (!thisfd.isNested() && !thisfd.vthis && !intypeof)
1233 return LevelError;
1235 else
1237 if (auto thiscd = s.isAggregateDeclaration())
1239 /* AggregateDeclaration::isNested returns true only when
1240 * it has a hidden pointer.
1241 * But, calling the function belongs unrelated lexical scope
1242 * is still allowed inside typeof.
1244 * struct Map(alias fun) {
1245 * typeof({ return fun(); }) RetType;
1246 * // No member function makes Map struct 'not nested'.
1249 if (!thiscd.isNested() && !intypeof)
1250 return LevelError;
1252 else
1253 return LevelError;
1256 s = s.toParentP(fd);
1257 assert(s);
1258 level++;
1260 return level;
1263 /***********************************
1264 * Determine lexical level difference from `this` to nested function `fd`.
1265 * Issue error if `this` cannot call `fd`.
1267 * Params:
1268 * loc = location for error messages
1269 * sc = context
1270 * fd = target of call
1271 * decl = The `Declaration` that triggered this check.
1272 * Used to provide a better error message only.
1273 * Returns:
1274 * 0 same level
1275 * >0 decrease nesting by number
1276 * -1 increase nesting by 1 (`fd` is nested within 'this')
1277 * LevelError error
1279 final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd,
1280 Declaration decl)
1282 int level = getLevel(fd, sc.intypeof);
1283 if (level != LevelError)
1284 return level;
1286 // Don't give error if in template constraint
1287 if (!(sc.flags & SCOPE.constraint))
1289 const(char)* xstatic = isStatic() ? "`static` " : "";
1290 // better diagnostics for static functions
1291 .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
1292 xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(),
1293 fd.toPrettyChars());
1294 .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
1295 return LevelError;
1297 return 1;
1300 enum LevelError = -2;
1302 override const(char)* toPrettyChars(bool QualifyTypes = false)
1304 if (isMain())
1305 return "D main";
1306 else
1307 return Dsymbol.toPrettyChars(QualifyTypes);
1310 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
1311 final const(char)* toFullSignature()
1313 OutBuffer buf;
1314 functionToBufferWithIdent(type.toTypeFunction(), &buf, toChars(), isStatic);
1315 return buf.extractChars();
1318 final bool isMain() const
1320 return ident == Id.main && resolvedLinkage() != LINK.c && !isMember() && !isNested();
1323 final bool isCMain() const
1325 return ident == Id.main && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1328 final bool isWinMain() const
1330 //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1331 version (none)
1333 bool x = ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1334 printf("%s\n", x ? "yes" : "no");
1335 return x;
1337 else
1339 return ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1343 final bool isDllMain() const
1345 return ident == Id.DllMain && resolvedLinkage() != LINK.c && !isMember();
1348 final bool isRtInit() const
1350 return ident == Id.rt_init && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1353 override final bool isExport() const
1355 return visibility.kind == Visibility.Kind.export_ || dllExport;
1358 override final bool isImportedSymbol() const
1360 //printf("isImportedSymbol()\n");
1361 //printf("protection = %d\n", visibility);
1362 return (visibility.kind == Visibility.Kind.export_ || dllImport) && !fbody;
1365 override final bool isCodeseg() const pure nothrow @nogc @safe
1367 return true; // functions are always in the code segment
1370 override final bool isOverloadable() const
1372 return true; // functions can be overloaded
1375 /***********************************
1376 * Override so it can work even if semantic() hasn't yet
1377 * been run.
1379 override final bool isAbstract()
1381 if (storage_class & STC.abstract_)
1382 return true;
1383 if (semanticRun >= PASS.semanticdone)
1384 return false;
1386 if (_scope)
1388 if (_scope.stc & STC.abstract_)
1389 return true;
1390 parent = _scope.parent;
1391 Dsymbol parent = toParent();
1392 if (parent.isInterfaceDeclaration())
1393 return true;
1395 return false;
1398 /**********************************
1399 * Decide if attributes for this function can be inferred from examining
1400 * the function body.
1401 * Returns:
1402 * true if can
1404 final bool canInferAttributes(Scope* sc)
1406 if (!fbody)
1407 return false;
1409 if (isVirtualMethod() &&
1411 * https://issues.dlang.org/show_bug.cgi?id=21719
1413 * If we have an auto virtual function we can infer
1414 * the attributes.
1416 !(inferRetType && !isCtorDeclaration()))
1417 return false; // since they may be overridden
1419 if (sc.func &&
1420 /********** this is for backwards compatibility for the moment ********/
1421 (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
1422 return true;
1424 if (isFuncLiteralDeclaration() || // externs are not possible with literals
1425 (storage_class & STC.inference) || // do attribute inference
1426 (inferRetType && !isCtorDeclaration()))
1427 return true;
1429 if (isInstantiated())
1431 auto ti = parent.isTemplateInstance();
1432 if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
1433 return true;
1436 return false;
1439 /*****************************************
1440 * Initialize for inferring the attributes of this function.
1442 final void initInferAttributes()
1444 //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1445 TypeFunction tf = type.toTypeFunction();
1446 if (tf.purity == PURE.impure) // purity not specified
1447 purityInprocess = true;
1449 if (tf.trust == TRUST.default_)
1450 safetyInprocess = true;
1452 if (!tf.isnothrow)
1453 nothrowInprocess = true;
1455 if (!tf.isnogc)
1456 nogcInprocess = true;
1458 if (!isVirtual() || this.isIntroducing())
1459 returnInprocess = true;
1461 // Initialize for inferring STC.scope_
1462 inferScope = true;
1465 final PURE isPure()
1467 //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1468 TypeFunction tf = type.toTypeFunction();
1469 if (purityInprocess)
1470 setImpure();
1471 if (tf.purity == PURE.fwdref)
1472 tf.purityLevel();
1473 PURE purity = tf.purity;
1474 if (purity > PURE.weak && isNested())
1475 purity = PURE.weak;
1476 if (purity > PURE.weak && needThis())
1478 // The attribute of the 'this' reference affects purity strength
1479 if (type.mod & MODFlags.immutable_)
1482 else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
1483 purity = PURE.const_;
1484 else
1485 purity = PURE.weak;
1487 tf.purity = purity;
1488 // ^ This rely on the current situation that every FuncDeclaration has a
1489 // unique TypeFunction.
1490 return purity;
1493 final PURE isPureBypassingInference()
1495 if (purityInprocess)
1496 return PURE.fwdref;
1497 else
1498 return isPure();
1501 /**************************************
1502 * The function is doing something impure, so mark it as impure.
1504 * Params:
1505 * loc = location of impure action
1506 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1507 * arg0 = (optional) argument to format string
1509 * Returns: `true` if there's a purity error
1511 extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
1513 if (purityInprocess)
1515 purityInprocess = false;
1516 if (fmt)
1517 pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action
1518 else if (arg0)
1519 pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
1521 if (fes)
1522 fes.func.setImpure(loc, fmt, arg0);
1524 else if (isPure())
1525 return true;
1526 return false;
1529 extern (D) final uint flags()
1531 return bitFields;
1534 extern (D) final uint flags(uint f)
1536 bitFields = f;
1537 return bitFields;
1540 final bool isSafe()
1542 if (safetyInprocess)
1543 setUnsafe();
1544 return type.toTypeFunction().trust == TRUST.safe;
1547 final bool isSafeBypassingInference()
1549 return !(safetyInprocess) && isSafe();
1552 final bool isTrusted()
1554 if (safetyInprocess)
1555 setUnsafe();
1556 return type.toTypeFunction().trust == TRUST.trusted;
1559 /**************************************
1560 * The function is doing something unsafe, so mark it as unsafe.
1562 * Params:
1563 * gag = surpress error message (used in escape.d)
1564 * loc = location of error
1565 * fmt = printf-style format string
1566 * arg0 = (optional) argument for first %s format specifier
1567 * arg1 = (optional) argument for second %s format specifier
1568 * arg2 = (optional) argument for third %s format specifier
1569 * Returns: whether there's a safe error
1571 extern (D) final bool setUnsafe(
1572 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
1573 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
1575 if (safetyInprocess)
1577 safetyInprocess = false;
1578 type.toTypeFunction().trust = TRUST.system;
1579 if (fmt || arg0)
1580 safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);
1582 if (fes)
1583 fes.func.setUnsafe();
1585 else if (isSafe())
1587 if (!gag && fmt)
1588 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
1590 return true;
1592 return false;
1595 /**************************************
1596 * The function is calling `@system` function `f`, so mark it as unsafe.
1598 * Params:
1599 * f = function being called (needed for diagnostic of inferred functions)
1600 * Returns: whether there's a safe error
1602 extern (D) final bool setUnsafeCall(FuncDeclaration f)
1604 return setUnsafe(false, f.loc, null, f, null);
1607 final bool isNogc()
1609 //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1610 if (nogcInprocess)
1611 setGC(loc, null);
1612 return type.toTypeFunction().isnogc;
1615 final bool isNogcBypassingInference()
1617 return !nogcInprocess && isNogc();
1620 /**************************************
1621 * The function is doing something that may allocate with the GC,
1622 * so mark it as not nogc (not no-how).
1624 * Params:
1625 * loc = location of impure action
1626 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1627 * arg0 = (optional) argument to format string
1629 * Returns:
1630 * true if function is marked as @nogc, meaning a user error occurred
1632 extern (D) final bool setGC(Loc loc, const(char)* fmt, RootObject arg0 = null)
1634 //printf("setGC() %s\n", toChars());
1635 if (nogcInprocess && semanticRun < PASS.semantic3 && _scope)
1637 this.semantic2(_scope);
1638 this.semantic3(_scope);
1641 if (nogcInprocess)
1643 nogcInprocess = false;
1644 if (fmt)
1645 nogcViolation = new AttributeViolation(loc, fmt, this, arg0); // action that requires GC
1646 else if (arg0)
1647 nogcViolation = new AttributeViolation(loc, fmt, arg0); // call to non-@nogc function
1649 type.toTypeFunction().isnogc = false;
1650 if (fes)
1651 fes.func.setGC(Loc.init, null, null);
1653 else if (isNogc())
1654 return true;
1655 return false;
1658 /**************************************
1659 * The function calls non-`@nogc` function f, mark it as not nogc.
1660 * Params:
1661 * f = function being called
1662 * Returns:
1663 * true if function is marked as @nogc, meaning a user error occurred
1665 extern (D) final bool setGCCall(FuncDeclaration f)
1667 return setGC(loc, null, f);
1670 /**************************************
1671 * The function is doing something that may throw an exception, register that in case nothrow is being inferred
1673 * Params:
1674 * loc = location of action
1675 * fmt = format string for error message
1676 * arg0 = (optional) argument to format string
1678 extern (D) final void setThrow(Loc loc, const(char)* fmt, RootObject arg0 = null)
1680 if (nothrowInprocess && !nothrowViolation)
1682 nothrowViolation = new AttributeViolation(loc, fmt, arg0); // action that requires GC
1686 /**************************************
1687 * The function calls non-`nothrow` function f, register that in case nothrow is being inferred
1688 * Params:
1689 * loc = location of call
1690 * f = function being called
1692 extern (D) final void setThrowCall(Loc loc, FuncDeclaration f)
1694 return setThrow(loc, null, f);
1697 extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
1699 if (!global.params.vgc)
1700 return;
1702 Module m = getModule();
1703 if (m && m.isRoot() && !inUnittest())
1705 message(loc, "vgc: %s", warn);
1709 /********************************************
1710 * See if pointers from function parameters, mutable globals, or uplevel functions
1711 * could leak into return value.
1712 * Returns:
1713 * true if the function return value is isolated from
1714 * any inputs to the function
1716 extern (D) final bool isReturnIsolated()
1718 //printf("isReturnIsolated(this: %s)\n", this.toChars);
1719 TypeFunction tf = type.toTypeFunction();
1720 assert(tf.next);
1722 Type treti = tf.next;
1723 if (tf.isref)
1724 return isTypeIsolatedIndirect(treti); // check influence from parameters
1726 return isTypeIsolated(treti);
1729 /********************
1730 * See if pointers from function parameters, mutable globals, or uplevel functions
1731 * could leak into type `t`.
1732 * Params:
1733 * t = type to check if it is isolated
1734 * Returns:
1735 * true if `t` is isolated from
1736 * any inputs to the function
1738 extern (D) final bool isTypeIsolated(Type t)
1740 StringTable!Type parentTypes;
1741 const uniqueTypeID = t.getUniqueID();
1742 if (uniqueTypeID)
1744 const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
1745 if (cacheResultPtr !is null)
1746 return *cacheResultPtr;
1748 parentTypes._init();
1749 const isIsolated = isTypeIsolated(t, parentTypes);
1750 isTypeIsolatedCache[uniqueTypeID] = isIsolated;
1751 return isIsolated;
1753 else
1755 parentTypes._init();
1756 return isTypeIsolated(t, parentTypes);
1760 ///ditto
1761 extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
1763 //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
1765 t = t.baseElemOf();
1766 switch (t.ty)
1768 case Tarray:
1769 case Tpointer:
1770 return isTypeIsolatedIndirect(t.nextOf()); // go down one level
1772 case Taarray:
1773 case Tclass:
1774 return isTypeIsolatedIndirect(t);
1776 case Tstruct:
1777 /* Drill down and check the struct's fields
1779 auto sym = t.toDsymbol(null).isStructDeclaration();
1780 const tName = t.toChars.toDString;
1781 const entry = parentTypes.insert(tName, t);
1782 if (entry == null)
1784 //we've already seen this type in a parent, not isolated
1785 return false;
1787 foreach (v; sym.fields)
1789 Type tmi = v.type.addMod(t.mod);
1790 //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
1791 // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
1792 if (!isTypeIsolated(tmi, parentTypes))
1793 return false;
1795 return true;
1797 default:
1798 return true;
1802 /********************************************
1803 * Params:
1804 * t = type of object to test one level of indirection down
1805 * Returns:
1806 * true if an object typed `t` has no indirections
1807 * which could have come from the function's parameters, mutable
1808 * globals, or uplevel functions.
1810 private bool isTypeIsolatedIndirect(Type t)
1812 //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1813 assert(t);
1815 /* Since `t` is one level down from an indirection, it could pick
1816 * up a reference to a mutable global or an outer function, so
1817 * return false.
1819 if (!isPureBypassingInference() || isNested())
1820 return false;
1822 TypeFunction tf = type.toTypeFunction();
1824 //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1826 foreach (i, fparam; tf.parameterList)
1828 Type tp = fparam.type;
1829 if (!tp)
1830 continue;
1832 if (fparam.isLazy() || fparam.isReference())
1834 if (!traverseIndirections(tp, t))
1835 return false;
1836 continue;
1839 /* Goes down one level of indirection, then calls traverseIndirection() on
1840 * the result.
1841 * Returns:
1842 * true if t is isolated from tp
1844 static bool traverse(Type tp, Type t)
1846 tp = tp.baseElemOf();
1847 switch (tp.ty)
1849 case Tarray:
1850 case Tpointer:
1851 return traverseIndirections(tp.nextOf(), t);
1853 case Taarray:
1854 case Tclass:
1855 return traverseIndirections(tp, t);
1857 case Tstruct:
1858 /* Drill down and check the struct's fields
1860 auto sym = tp.toDsymbol(null).isStructDeclaration();
1861 foreach (v; sym.fields)
1863 Type tprmi = v.type.addMod(tp.mod);
1864 //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1865 if (!traverse(tprmi, t))
1866 return false;
1868 return true;
1870 default:
1871 return true;
1875 if (!traverse(tp, t))
1876 return false;
1878 // The 'this' reference is a parameter, too
1879 if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
1881 Type tthis = ad.getType().addMod(tf.mod);
1882 //printf("\ttthis = %s\n", tthis.toChars());
1883 if (!traverseIndirections(tthis, t))
1884 return false;
1887 return true;
1890 /****************************************
1891 * Determine if function needs a static frame pointer.
1892 * Returns:
1893 * `true` if function is really nested within other function.
1894 * Contracts:
1895 * If isNested() returns true, isThis() should return false,
1896 * unless the function needs a dual-context pointer.
1898 bool isNested() const
1900 auto f = toAliasFunc();
1901 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1902 return ((f.storage_class & STC.static_) == 0) &&
1903 (f._linkage == LINK.d) &&
1904 (f.toParent2().isFuncDeclaration() !is null ||
1905 f.toParent2() !is f.toParentLocal());
1908 /****************************************
1909 * Determine if function is a non-static member function
1910 * that has an implicit 'this' expression.
1911 * Returns:
1912 * The aggregate it is a member of, or null.
1913 * Contracts:
1914 * Both isThis() and isNested() should return true if function needs a dual-context pointer,
1915 * otherwise if isThis() returns true, isNested() should return false.
1917 override inout(AggregateDeclaration) isThis() inout
1919 //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1920 auto ad = (storage_class & STC.static_) ? .objc.isThis(this) : isMemberLocal();
1921 //printf("-FuncDeclaration::isThis() %p\n", ad);
1922 return ad;
1925 override final bool needThis()
1927 //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1928 return toAliasFunc().isThis() !is null;
1931 // Determine if a function is pedantically virtual
1932 final bool isVirtualMethod()
1934 if (toAliasFunc() != this)
1935 return toAliasFunc().isVirtualMethod();
1937 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1938 if (!isVirtual())
1939 return false;
1940 // If it's a final method, and does not override anything, then it is not virtual
1941 if (isFinalFunc() && foverrides.length == 0)
1943 return false;
1945 return true;
1948 // Determine if function goes into virtual function pointer table
1949 bool isVirtual() const
1951 if (toAliasFunc() != this)
1952 return toAliasFunc().isVirtual();
1954 auto p = toParent();
1956 if (!isMember || !p.isClassDeclaration)
1957 return false;
1959 if (p.isClassDeclaration.classKind == ClassKind.objc)
1960 return .objc.isVirtual(this);
1962 version (none)
1964 printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1965 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), visibility == Visibility.Kind.private_, isCtorDeclaration(), linkage != LINK.d);
1966 printf("result is %d\n", isMember() && !(isStatic() || visibility == Visibility.Kind.private_ || visibility == Visibility.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()));
1968 return !(isStatic() || visibility.kind == Visibility.Kind.private_ || visibility.kind == Visibility.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc());
1971 final bool isFinalFunc() const
1973 if (toAliasFunc() != this)
1974 return toAliasFunc().isFinalFunc();
1976 version (none)
1978 auto cd = toParent().isClassDeclaration();
1979 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal());
1980 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_));
1981 printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_)));
1982 if (cd)
1983 printf("\tmember of %s\n", cd.toChars());
1985 if (!isMember())
1986 return false;
1987 if (Declaration.isFinal())
1988 return true;
1989 auto cd = toParent().isClassDeclaration();
1990 return (cd !is null) && (cd.storage_class & STC.final_);
1993 bool addPreInvariant()
1995 auto ad = isThis();
1996 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1997 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());
2000 bool addPostInvariant()
2002 auto ad = isThis();
2003 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
2004 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());
2007 override const(char)* kind() const
2009 return this.isGenerated() ? "generated function" : "function";
2012 /********************************************
2013 * Returns:
2014 * true if there are no overloads of this function
2016 final bool isUnique() const
2018 bool result = false;
2019 overloadApply(cast() this, (Dsymbol s)
2021 auto f = s.isFuncDeclaration();
2022 auto td = s.isTemplateDeclaration();
2023 if (!f && !td)
2024 return 0;
2025 if (result)
2027 result = false;
2028 return 1; // ambiguous, done
2030 else
2032 result = true;
2033 return 0;
2036 return result;
2039 /*********************************************
2040 * In the current function, we are calling 'this' function.
2041 * 1. Check to see if the current function can call 'this' function, issue error if not.
2042 * 2. If the current function is not the parent of 'this' function, then add
2043 * the current function to the list of siblings of 'this' function.
2044 * 3. If the current function is a literal, and it's accessing an uplevel scope,
2045 * then mark it as a delegate.
2046 * Returns true if error occurs.
2048 extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
2050 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
2052 if (auto fld = this.isFuncLiteralDeclaration())
2054 if (fld.tok == TOK.reserved)
2056 fld.tok = TOK.function_;
2057 fld.vthis = null;
2061 if (!parent || parent == sc.parent)
2062 return false;
2063 if (ident == Id.require || ident == Id.ensure)
2064 return false;
2065 if (!isThis() && !isNested())
2066 return false;
2068 // The current function
2069 FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
2070 if (!fdthis)
2071 return false; // out of function scope
2073 Dsymbol p = toParentLocal();
2074 Dsymbol p2 = toParent2();
2076 // Function literals from fdthis to p must be delegates
2077 ensureStaticLinkTo(fdthis, p);
2078 if (p != p2)
2079 ensureStaticLinkTo(fdthis, p2);
2081 if (isNested())
2083 // The function that this function is in
2084 bool checkEnclosing(FuncDeclaration fdv)
2086 if (!fdv)
2087 return false;
2088 if (fdv == fdthis)
2089 return false;
2091 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
2092 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
2093 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
2095 // Add this function to the list of those which called us
2096 if (fdthis != this)
2098 bool found = false;
2099 for (size_t i = 0; i < siblingCallers.length; ++i)
2101 if (siblingCallers[i] == fdthis)
2102 found = true;
2104 if (!found)
2106 //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
2107 if (!sc.intypeof && !(sc.flags & SCOPE.compile))
2109 siblingCallers.push(fdthis);
2110 computedEscapingSiblings = false;
2115 const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this);
2116 if (lv == LevelError)
2117 return true; // error
2118 if (lv == -1)
2119 return false; // downlevel call
2120 if (lv == 0)
2121 return false; // same level call
2123 return false; // Uplevel call
2126 if (checkEnclosing(p.isFuncDeclaration()))
2127 return true;
2128 if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
2129 return true;
2131 return false;
2134 /*******************************
2135 * Look at all the variables in this function that are referenced
2136 * by nested functions, and determine if a closure needs to be
2137 * created for them.
2139 final bool needsClosure()
2141 /* Need a closure for all the closureVars[] if any of the
2142 * closureVars[] are accessed by a
2143 * function that escapes the scope of this function.
2144 * We take the conservative approach and decide that a function needs
2145 * a closure if it:
2146 * 1) is a virtual function
2147 * 2) has its address taken
2148 * 3) has a parent that escapes
2149 * 4) calls another nested function that needs a closure
2151 * Note that since a non-virtual function can be called by
2152 * a virtual one, if that non-virtual function accesses a closure
2153 * var, the closure still has to be taken. Hence, we check for isThis()
2154 * instead of isVirtual(). (thanks to David Friedman)
2156 * When the function returns a local struct or class, `requiresClosure`
2157 * is already set to `true` upon entering this function when the
2158 * struct/class refers to a local variable and a closure is needed.
2160 //printf("FuncDeclaration::needsClosure() %s\n", toPrettyChars());
2162 if (requiresClosure)
2163 goto Lyes;
2165 for (size_t i = 0; i < closureVars.length; i++)
2167 VarDeclaration v = closureVars[i];
2168 //printf("\tv = %s\n", v.toChars());
2170 for (size_t j = 0; j < v.nestedrefs.length; j++)
2172 FuncDeclaration f = v.nestedrefs[j];
2173 assert(f != this);
2175 /* __require and __ensure will always get called directly,
2176 * so they never make outer functions closure.
2178 if (f.ident == Id.require || f.ident == Id.ensure)
2179 continue;
2181 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
2183 /* Look to see if f escapes. We consider all parents of f within
2184 * this, and also all siblings which call f; if any of them escape,
2185 * so does f.
2186 * Mark all affected functions as requiring closures.
2188 for (Dsymbol s = f; s && s != this; s = s.toParentP(this))
2190 FuncDeclaration fx = s.isFuncDeclaration();
2191 if (!fx)
2192 continue;
2193 if (fx.isThis() || fx.tookAddressOf)
2195 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
2197 /* Mark as needing closure any functions between this and f
2199 markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this);
2201 requiresClosure = true;
2204 /* We also need to check if any sibling functions that
2205 * called us, have escaped. This is recursive: we need
2206 * to check the callers of our siblings.
2208 if (checkEscapingSiblings(fx, this))
2209 requiresClosure = true;
2211 /* https://issues.dlang.org/show_bug.cgi?id=12406
2212 * Iterate all closureVars to mark all descendant
2213 * nested functions that access to the closing context of this function.
2218 if (requiresClosure)
2219 goto Lyes;
2221 return false;
2223 Lyes:
2224 return true;
2227 /***********************************************
2228 * Check that the function contains any closure.
2229 * If it's @nogc, report suitable errors.
2230 * This is mostly consistent with FuncDeclaration::needsClosure().
2232 * Returns:
2233 * true if any errors occur.
2235 extern (C++) final bool checkClosure()
2237 //printf("checkClosure() %s\n", toPrettyChars());
2238 if (!needsClosure())
2239 return false;
2241 if (setGC(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", this))
2243 error("is `@nogc` yet allocates closure for `%s()` with the GC", toChars());
2244 if (global.gag) // need not report supplemental errors
2245 return true;
2247 else if (!global.params.useGC)
2249 error("is `-betterC` yet allocates closure for `%s()` with the GC", toChars());
2250 if (global.gag) // need not report supplemental errors
2251 return true;
2253 else
2255 printGCUsage(loc, "using closure causes GC allocation");
2256 return false;
2259 FuncDeclarations a;
2260 foreach (v; closureVars)
2262 foreach (f; v.nestedrefs)
2264 assert(f !is this);
2266 LcheckAncestorsOfANestedRef:
2267 for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
2269 auto fx = s.isFuncDeclaration();
2270 if (!fx)
2271 continue;
2272 if (fx.isThis() ||
2273 fx.tookAddressOf ||
2274 checkEscapingSiblings(fx, this))
2276 foreach (f2; a)
2278 if (f2 == f)
2279 break LcheckAncestorsOfANestedRef;
2281 a.push(f);
2282 .errorSupplemental(f.loc, "`%s` closes over variable `%s` at %s",
2283 f.toPrettyChars(), v.toChars(), v.loc.toChars());
2284 break LcheckAncestorsOfANestedRef;
2290 return true;
2293 /***********************************************
2294 * Determine if function's variables are referenced by a function
2295 * nested within it.
2297 final bool hasNestedFrameRefs()
2299 if (closureVars.length)
2300 return true;
2302 /* If a virtual function has contracts, assume its variables are referenced
2303 * by those contracts, even if they aren't. Because they might be referenced
2304 * by the overridden or overriding function's contracts.
2305 * This can happen because frequire and fensure are implemented as nested functions,
2306 * and they can be called directly by an overriding function and the overriding function's
2307 * context had better match, or
2308 * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
2310 if (fdrequire || fdensure)
2311 return true;
2313 if (foverrides.length && isVirtualMethod())
2315 for (size_t i = 0; i < foverrides.length; i++)
2317 FuncDeclaration fdv = foverrides[i];
2318 if (fdv.hasNestedFrameRefs())
2319 return true;
2322 return false;
2325 /****************************************************
2326 * Check whether result variable can be built.
2327 * Returns:
2328 * `true` if the function has a return type that
2329 * is different from `void`.
2331 extern (D) private bool canBuildResultVar()
2333 auto f = cast(TypeFunction)type;
2334 return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
2337 /****************************************************
2338 * Declare result variable lazily.
2340 extern (D) final void buildResultVar(Scope* sc, Type tret)
2342 if (!vresult)
2344 Loc loc = fensure ? fensure.loc : this.loc;
2346 /* If inferRetType is true, tret may not be a correct return type yet.
2347 * So, in here it may be a temporary type for vresult, and after
2348 * fbody.dsymbolSemantic() running, vresult.type might be modified.
2350 vresult = new VarDeclaration(loc, tret, Id.result, null);
2351 vresult.storage_class |= STC.nodtor | STC.temp;
2352 if (!isVirtual())
2353 vresult.storage_class |= STC.const_;
2354 vresult.storage_class |= STC.result;
2356 // set before the semantic() for checkNestedReference()
2357 vresult.parent = this;
2360 if (sc && vresult.semanticRun == PASS.initial)
2362 TypeFunction tf = type.toTypeFunction();
2363 if (tf.isref)
2364 vresult.storage_class |= STC.ref_;
2365 vresult.type = tret;
2367 vresult.dsymbolSemantic(sc);
2369 if (!sc.insert(vresult))
2370 error("out result %s is already defined", vresult.toChars());
2371 assert(vresult.parent == this);
2375 /****************************************************
2376 * Merge into this function the 'in' contracts of all it overrides.
2377 * 'in's are OR'd together, i.e. only one of them needs to pass.
2379 extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
2381 /* If a base function and its override both have an IN contract, then
2382 * only one of them needs to succeed. This is done by generating:
2384 * void derived.in() {
2385 * try {
2386 * base.in();
2388 * catch () {
2389 * ... body of derived.in() ...
2393 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2394 * If base.in() throws, then derived.in()'s body is executed.
2397 foreach (fdv; foverrides)
2399 /* The semantic pass on the contracts of the overridden functions must
2400 * be completed before code generation occurs.
2401 * https://issues.dlang.org/show_bug.cgi?id=3602
2403 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2405 assert(fdv._scope);
2406 Scope* sc = fdv._scope.push();
2407 sc.stc &= ~STC.override_;
2408 fdv.semantic3(sc);
2409 sc.pop();
2412 sf = fdv.mergeFrequire(sf, params);
2413 if (!sf || !fdv.fdrequire)
2414 return null;
2415 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2416 /* Make the call:
2417 * try { __require(params); }
2418 * catch (Throwable) { frequire; }
2420 params = Expression.arraySyntaxCopy(params);
2421 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2422 Statement s2 = new ExpStatement(loc, e);
2424 auto c = new Catch(loc, getThrowable(), null, sf);
2425 c.internalCatch = true;
2426 auto catches = new Catches();
2427 catches.push(c);
2428 sf = new TryCatchStatement(loc, s2, catches);
2430 return sf;
2433 /****************************************************
2434 * Merge into this function the 'in' contracts of all it overrides.
2436 extern (D) final Statement mergeFrequireInclusivePreview(Statement sf, Expressions* params)
2438 /* If a base function and its override both have an IN contract, then
2439 * the override in contract must widen the guarantee of the base contract.
2440 * This is checked by generating:
2442 * void derived.in() {
2443 * try {
2444 * ... body of derived.in() ...
2446 * catch () {
2447 * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
2448 * base.in();
2449 * assert(false, "Logic error: " ~ thr.msg);
2454 foreach (fdv; foverrides)
2456 /* The semantic pass on the contracts of the overridden functions must
2457 * be completed before code generation occurs.
2458 * https://issues.dlang.org/show_bug.cgi?id=3602
2460 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2462 assert(fdv._scope);
2463 Scope* sc = fdv._scope.push();
2464 sc.stc &= ~STC.override_;
2465 fdv.semantic3(sc);
2466 sc.pop();
2469 sf = fdv.mergeFrequireInclusivePreview(sf, params);
2470 if (sf && fdv.fdrequire)
2472 const loc = this.fdrequire.loc;
2474 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2475 /* Make the call:
2476 * try { frequire; }
2477 * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
2479 Identifier id = Identifier.generateId("thr");
2480 params = Expression.arraySyntaxCopy(params);
2481 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2482 Statement s2 = new ExpStatement(loc, e);
2483 // assert(false, ...)
2484 // TODO make this a runtime helper to allow:
2485 // - chaining the original expression
2486 // - nogc concatenation
2487 Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
2488 Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
2490 Statement s3 = new CompoundStatement(loc, s2, fail);
2492 auto c = new Catch(loc, getThrowable(), id, s3);
2493 c.internalCatch = true;
2494 auto catches = new Catches();
2495 catches.push(c);
2496 sf = new TryCatchStatement(loc, sf, catches);
2498 else
2499 return null;
2501 return sf;
2504 /****************************************************
2505 * Determine whether an 'out' contract is declared inside
2506 * the given function or any of its overrides.
2507 * Params:
2508 * fd = the function to search
2509 * Returns:
2510 * true found an 'out' contract
2512 static bool needsFensure(FuncDeclaration fd)
2514 if (fd.fensures)
2515 return true;
2517 foreach (fdv; fd.foverrides)
2519 if (needsFensure(fdv))
2520 return true;
2522 return false;
2525 /****************************************************
2526 * Rewrite contracts as statements.
2528 final void buildEnsureRequire()
2531 if (frequires)
2533 /* in { statements1... }
2534 * in { statements2... }
2535 * ...
2536 * becomes:
2537 * in { { statements1... } { statements2... } ... }
2539 assert(frequires.length);
2540 auto loc = (*frequires)[0].loc;
2541 auto s = new Statements;
2542 foreach (r; *frequires)
2544 s.push(new ScopeStatement(r.loc, r, r.loc));
2546 frequire = new CompoundStatement(loc, s);
2549 if (fensures)
2551 /* out(id1) { statements1... }
2552 * out(id2) { statements2... }
2553 * ...
2554 * becomes:
2555 * out(__result) { { ref id1 = __result; { statements1... } }
2556 * { ref id2 = __result; { statements2... } } ... }
2558 assert(fensures.length);
2559 auto loc = (*fensures)[0].ensure.loc;
2560 auto s = new Statements;
2561 foreach (r; *fensures)
2563 if (r.id && canBuildResultVar())
2565 auto rloc = r.ensure.loc;
2566 auto resultId = new IdentifierExp(rloc, Id.result);
2567 auto init = new ExpInitializer(rloc, resultId);
2568 auto stc = STC.ref_ | STC.temp | STC.result;
2569 auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
2570 auto sdecl = new ExpStatement(rloc, decl);
2571 s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
2573 else
2575 s.push(r.ensure);
2578 fensure = new CompoundStatement(loc, s);
2581 if (!isVirtual())
2582 return;
2584 /* Rewrite contracts as nested functions, then call them. Doing it as nested
2585 * functions means that overriding functions can call them.
2587 TypeFunction f = cast(TypeFunction) type;
2589 /* Make a copy of the parameters and make them all ref */
2590 static Parameters* toRefCopy(ParameterList parameterList)
2592 auto result = new Parameters();
2594 foreach (n, p; parameterList)
2596 p = p.syntaxCopy();
2597 if (!p.isLazy())
2598 p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
2599 p.defaultArg = null; // won't be the same with ref
2600 result.push(p);
2603 return result;
2606 if (frequire)
2608 /* in { ... }
2609 * becomes:
2610 * void __require(ref params) { ... }
2611 * __require(params);
2613 Loc loc = frequire.loc;
2614 fdrequireParams = new Expressions();
2615 if (parameters)
2617 foreach (vd; *parameters)
2618 fdrequireParams.push(new VarExp(loc, vd));
2620 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2621 auto fparams = toRefCopy(fo.parameterList);
2622 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2623 tf.isnothrow = f.isnothrow;
2624 tf.isnogc = f.isnogc;
2625 tf.purity = f.purity;
2626 tf.trust = f.trust;
2627 auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
2628 fd.fbody = frequire;
2629 Statement s1 = new ExpStatement(loc, fd);
2630 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
2631 Statement s2 = new ExpStatement(loc, e);
2632 frequire = new CompoundStatement(loc, s1, s2);
2633 fdrequire = fd;
2636 /* We need to set fdensureParams here and not in the block below to
2637 * have the parameters available when calling a base class ensure(),
2638 * even if this function doesn't have an out contract.
2640 fdensureParams = new Expressions();
2641 if (canBuildResultVar())
2642 fdensureParams.push(new IdentifierExp(loc, Id.result));
2643 if (parameters)
2645 foreach (vd; *parameters)
2646 fdensureParams.push(new VarExp(loc, vd));
2649 if (fensure)
2651 /* out (result) { ... }
2652 * becomes:
2653 * void __ensure(ref tret result, ref params) { ... }
2654 * __ensure(result, params);
2656 Loc loc = fensure.loc;
2657 auto fparams = new Parameters();
2658 if (canBuildResultVar())
2660 Parameter p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
2661 fparams.push(p);
2663 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2664 fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
2665 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2666 tf.isnothrow = f.isnothrow;
2667 tf.isnogc = f.isnogc;
2668 tf.purity = f.purity;
2669 tf.trust = f.trust;
2670 auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
2671 fd.fbody = fensure;
2672 Statement s1 = new ExpStatement(loc, fd);
2673 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
2674 Statement s2 = new ExpStatement(loc, e);
2675 fensure = new CompoundStatement(loc, s1, s2);
2676 fdensure = fd;
2680 /****************************************************
2681 * Merge into this function the 'out' contracts of all it overrides.
2682 * 'out's are AND'd together, i.e. all of them need to pass.
2684 extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
2686 /* Same comments as for mergeFrequire(), except that we take care
2687 * of generating a consistent reference to the 'result' local by
2688 * explicitly passing 'result' to the nested function as a reference
2689 * argument.
2690 * This won't work for the 'this' parameter as it would require changing
2691 * the semantic code for the nested function so that it looks on the parameter
2692 * list for the 'this' pointer, something that would need an unknown amount
2693 * of tweaking of various parts of the compiler that I'd rather leave alone.
2695 foreach (fdv; foverrides)
2697 /* The semantic pass on the contracts of the overridden functions must
2698 * be completed before code generation occurs.
2699 * https://issues.dlang.org/show_bug.cgi?id=3602 and
2700 * https://issues.dlang.org/show_bug.cgi?id=5230
2702 if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
2704 assert(fdv._scope);
2705 Scope* sc = fdv._scope.push();
2706 sc.stc &= ~STC.override_;
2707 fdv.semantic3(sc);
2708 sc.pop();
2711 sf = fdv.mergeFensure(sf, oid, params);
2712 if (fdv.fdensure)
2714 //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2715 // Make the call: __ensure(result, params)
2716 params = Expression.arraySyntaxCopy(params);
2717 if (canBuildResultVar())
2719 Type t1 = fdv.type.nextOf().toBasetype();
2720 Type t2 = this.type.nextOf().toBasetype();
2721 if (t1.isBaseOf(t2, null))
2723 /* Making temporary reference variable is necessary
2724 * in covariant return.
2725 * https://issues.dlang.org/show_bug.cgi?id=5204
2726 * https://issues.dlang.org/show_bug.cgi?id=10479
2728 Expression* eresult = &(*params)[0];
2729 auto ei = new ExpInitializer(Loc.initial, *eresult);
2730 auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
2731 v.storage_class |= STC.temp;
2732 auto de = new DeclarationExp(Loc.initial, v);
2733 auto ve = new VarExp(Loc.initial, v);
2734 *eresult = new CommaExp(Loc.initial, de, ve);
2737 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
2738 Statement s2 = new ExpStatement(loc, e);
2740 if (sf)
2742 sf = new CompoundStatement(sf.loc, s2, sf);
2744 else
2745 sf = s2;
2748 return sf;
2751 /*********************************************
2752 * Returns: the function's parameter list, and whether
2753 * it is variadic or not.
2755 final ParameterList getParameterList()
2757 if (type)
2759 TypeFunction fdtype = type.isTypeFunction();
2760 if (fdtype) // Could also be TypeError
2761 return fdtype.parameterList;
2764 return ParameterList(null, VarArg.none);
2767 /**********************************
2768 * Generate a FuncDeclaration for a runtime library function.
2770 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
2772 return genCfunc(fparams, treturn, Identifier.idPool(name[0 .. strlen(name)]), stc);
2775 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
2777 FuncDeclaration fd;
2778 TypeFunction tf;
2779 Dsymbol s;
2780 __gshared DsymbolTable st = null;
2782 //printf("genCfunc(name = '%s')\n", id.toChars());
2783 //printf("treturn\n\t"); treturn.print();
2785 // See if already in table
2786 if (!st)
2787 st = new DsymbolTable();
2788 s = st.lookup(id);
2789 if (s)
2791 fd = s.isFuncDeclaration();
2792 assert(fd);
2793 assert(fd.type.nextOf().equals(treturn));
2795 else
2797 tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc);
2798 fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf);
2799 fd.visibility = Visibility(Visibility.Kind.public_);
2800 fd._linkage = LINK.c;
2802 st.insert(fd);
2804 return fd;
2808 + Checks the parameter and return types iff this is a `main` function.
2810 + The following signatures are allowed for a `D main`:
2811 + - Either no or a single parameter of type `string[]`
2812 + - Return type is either `void`, `int` or `noreturn`
2814 + The following signatures are standard C:
2815 + - `int main()`
2816 + - `int main(int, char**)`
2818 + This function accepts the following non-standard extensions:
2819 + - `char** envp` as a third parameter
2820 + - `void` / `noreturn` as return type
2822 + This function will issue errors for unexpected arguments / return types.
2824 extern (D) final void checkMain()
2826 if (ident != Id.main || isMember() || isNested())
2827 return; // Not a main function
2829 TypeFunction tf = type.toTypeFunction();
2831 Type retType = tf.nextOf();
2832 if (!retType)
2834 // auto main(), check after semantic
2835 assert(this.inferRetType);
2836 return;
2839 /// Checks whether `t` is equivalent to `char**`
2840 /// Ignores qualifiers and treats enums according to their base type
2841 static bool isCharPtrPtr(Type t)
2843 auto tp = t.toBasetype().isTypePointer();
2844 if (!tp)
2845 return false;
2847 tp = tp.next.toBasetype().isTypePointer();
2848 if (!tp)
2849 return false;
2851 return tp.next.toBasetype().ty == Tchar;
2854 // Neither of these qualifiers is allowed because they affect the ABI
2855 enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
2857 const nparams = tf.parameterList.length;
2858 bool argerr;
2860 const linkage = resolvedLinkage();
2861 if (linkage == LINK.d)
2863 if (nparams == 1)
2865 auto fparam0 = tf.parameterList[0];
2866 auto t = fparam0.type.toBasetype();
2867 if (t.ty != Tarray ||
2868 t.nextOf().ty != Tarray ||
2869 t.nextOf().nextOf().ty != Tchar ||
2870 fparam0.storageClass & invalidSTC)
2872 argerr = true;
2876 if (tf.parameterList.varargs || nparams >= 2 || argerr)
2877 error("parameter list must be empty or accept one parameter of type `string[]`");
2880 else if (linkage == LINK.c)
2882 if (nparams == 2 || nparams == 3)
2884 // Argument count must be int
2885 auto argCount = tf.parameterList[0];
2886 argerr |= !!(argCount.storageClass & invalidSTC);
2887 argerr |= argCount.type.toBasetype().ty != Tint32;
2889 // Argument pointer must be char**
2890 auto argPtr = tf.parameterList[1];
2891 argerr |= !!(argPtr.storageClass & invalidSTC);
2892 argerr |= !isCharPtrPtr(argPtr.type);
2894 // `char** environ` is a common extension, see J.5.1 of the C standard
2895 if (nparams == 3)
2897 auto envPtr = tf.parameterList[2];
2898 argerr |= !!(envPtr.storageClass & invalidSTC);
2899 argerr |= !isCharPtrPtr(envPtr.type);
2902 else
2903 argerr = nparams != 0;
2905 // Disallow variadic main() - except for K&R declarations in C files.
2906 // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
2907 if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
2908 argerr |= true;
2910 if (argerr)
2912 error("parameters must match one of the following signatures");
2913 loc.errorSupplemental("`main()`");
2914 loc.errorSupplemental("`main(int argc, char** argv)`");
2915 loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
2918 else
2919 return; // Neither C nor D main, ignore (should probably be an error)
2921 // Allow enums with appropriate base types (same ABI)
2922 retType = retType.toBasetype();
2924 if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
2925 error("must return `int`, `void` or `noreturn`, not `%s`", tf.nextOf().toChars());
2928 /***********************************************
2929 * Check all return statements for a function to verify that returning
2930 * using NRVO is possible.
2932 * Returns:
2933 * `false` if the result cannot be returned by hidden reference.
2935 final bool checkNRVO()
2937 if (!isNRVO() || returns is null)
2938 return false;
2940 auto tf = type.toTypeFunction();
2941 if (tf.isref)
2942 return false;
2944 foreach (rs; *returns)
2946 if (auto ve = rs.exp.isVarExp())
2948 auto v = ve.var.isVarDeclaration();
2949 if (!v || v.isReference())
2950 return false;
2951 else if (nrvo_var is null)
2953 // Variables in the data segment (e.g. globals, TLS or not),
2954 // parameters and closure variables cannot be NRVOed.
2955 if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
2956 return false;
2957 if (v.nestedrefs.length && needsClosure())
2958 return false;
2959 // don't know if the return storage is aligned
2960 version (MARS)
2962 if (alignSectionVars && (*alignSectionVars).contains(v))
2963 return false;
2965 // The variable type needs to be equivalent to the return type.
2966 if (!v.type.equivalent(tf.next))
2967 return false;
2968 //printf("Setting nrvo to %s\n", v.toChars());
2969 nrvo_var = v;
2971 else if (nrvo_var != v)
2972 return false;
2974 else //if (!exp.isLvalue()) // keep NRVO-ability
2975 return false;
2977 return true;
2980 override final inout(FuncDeclaration) isFuncDeclaration() inout
2982 return this;
2985 inout(FuncDeclaration) toAliasFunc() inout
2987 return this;
2990 override void accept(Visitor v)
2992 v.visit(this);
2996 /********************************************************
2997 * Generate Expression to call the invariant.
2998 * Input:
2999 * ad aggregate with the invariant
3000 * vthis variable with 'this'
3001 * Returns:
3002 * void expression that calls the invariant
3004 Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
3006 Expression e = null;
3007 // Call invariant directly only if it exists
3008 FuncDeclaration inv = ad.inv;
3009 ClassDeclaration cd = ad.isClassDeclaration();
3011 while (!inv && cd)
3013 cd = cd.baseClass;
3014 if (!cd)
3015 break;
3016 inv = cd.inv;
3018 if (inv)
3020 version (all)
3022 // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
3023 // For the correct mangling,
3024 // run attribute inference on inv if needed.
3025 inv.functionSemantic();
3028 //e = new DsymbolExp(Loc.initial, inv);
3029 //e = new CallExp(Loc.initial, e);
3030 //e = e.semantic(sc2);
3032 /* https://issues.dlang.org/show_bug.cgi?id=13113
3033 * Currently virtual invariant calls completely
3034 * bypass attribute enforcement.
3035 * Change the behavior of pre-invariant call by following it.
3037 e = new ThisExp(Loc.initial);
3038 e.type = ad.type.addMod(vthis.type.mod);
3039 e = new DotVarExp(Loc.initial, e, inv, false);
3040 e.type = inv.type;
3041 e = new CallExp(Loc.initial, e);
3042 e.type = Type.tvoid;
3044 return e;
3047 /***************************************************
3048 * Visit each overloaded function/template in turn, and call dg(s) on it.
3049 * Exit when no more, or dg(s) returns nonzero.
3051 * Params:
3052 * fstart = symbol to start from
3053 * dg = the delegate to be called on the overload
3054 * sc = context used to check if symbol is accessible (and therefore visible),
3055 * can be null
3057 * Returns:
3058 * ==0 continue
3059 * !=0 done (and the return value from the last dg() call)
3061 extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
3063 Dsymbols visited;
3065 int overloadApplyRecurse(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc)
3067 // Detect cyclic calls.
3068 if (visited.contains(fstart))
3069 return 0;
3070 visited.push(fstart);
3072 Dsymbol next;
3073 for (auto d = fstart; d; d = next)
3075 import dmd.access : checkSymbolAccess;
3076 if (auto od = d.isOverDeclaration())
3078 /* The scope is needed here to check whether a function in
3079 an overload set was added by means of a private alias (or a
3080 selective import). If the scope where the alias is created
3081 is imported somewhere, the overload set is visible, but the private
3082 alias is not.
3084 if (sc)
3086 if (checkSymbolAccess(sc, od))
3088 if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
3089 return r;
3092 else if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
3093 return r;
3094 next = od.overnext;
3096 else if (auto fa = d.isFuncAliasDeclaration())
3098 if (fa.hasOverloads)
3100 if (int r = overloadApplyRecurse(fa.funcalias, dg, sc))
3101 return r;
3103 else if (auto fd = fa.toAliasFunc())
3105 if (int r = dg(fd))
3106 return r;
3108 else
3110 d.error("is aliased to a function");
3111 break;
3113 next = fa.overnext;
3115 else if (auto ad = d.isAliasDeclaration())
3117 if (sc)
3119 if (checkSymbolAccess(sc, ad))
3120 next = ad.toAlias();
3122 else
3123 next = ad.toAlias();
3124 if (next == ad)
3125 break;
3126 if (next == fstart)
3127 break;
3129 else if (auto td = d.isTemplateDeclaration())
3131 if (int r = dg(td))
3132 return r;
3133 next = td.overnext;
3135 else if (auto fd = d.isFuncDeclaration())
3137 if (int r = dg(fd))
3138 return r;
3139 next = fd.overnext;
3141 else if (auto os = d.isOverloadSet())
3143 foreach (ds; os.a)
3144 if (int r = dg(ds))
3145 return r;
3147 else
3149 d.error("is aliased to a function");
3150 break;
3151 // BUG: should print error message?
3154 return 0;
3156 return overloadApplyRecurse(fstart, dg, sc);
3160 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
3161 mismatching modifiers to `buf`.
3163 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
3164 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
3166 Params:
3167 buf = output buffer to write to
3168 lhsMod = modifier on the left-hand side
3169 lhsMod = modifier on the right-hand side
3171 Returns:
3173 A tuple with `isMutable` and `isNotShared` set
3174 if the `lhsMod` is missing those modifiers (compared to rhs).
3176 auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod)
3178 static struct Mismatches
3180 bool isNotShared;
3181 bool isMutable;
3184 Mismatches mismatches;
3186 bool bothMutable = ((lhsMod & rhsMod) == 0);
3187 bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0;
3188 bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_);
3190 if (lhsMod & MODFlags.shared_)
3191 buf.writestring("`shared` ");
3192 else if (sharedMismatch && !(lhsMod & MODFlags.immutable_))
3194 buf.writestring("non-shared ");
3195 mismatches.isNotShared = true;
3198 if (bothMutable && sharedMismatchOnly)
3201 else if (lhsMod & MODFlags.immutable_)
3202 buf.writestring("`immutable` ");
3203 else if (lhsMod & MODFlags.const_)
3204 buf.writestring("`const` ");
3205 else if (lhsMod & MODFlags.wild)
3206 buf.writestring("`inout` ");
3207 else
3209 buf.writestring("mutable ");
3210 mismatches.isMutable = true;
3213 return mismatches;
3217 unittest
3219 OutBuffer buf;
3220 auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0);
3221 assert(buf[] == "`shared` ");
3222 assert(!mismatches.isNotShared);
3224 buf.setsize(0);
3225 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_);
3226 assert(buf[] == "non-shared ");
3227 assert(mismatches.isNotShared);
3229 buf.setsize(0);
3230 mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0);
3231 assert(buf[] == "`const` ");
3232 assert(!mismatches.isMutable);
3234 buf.setsize(0);
3235 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_);
3236 assert(buf[] == "mutable ");
3237 assert(mismatches.isMutable);
3240 private const(char)* prependSpace(const(char)* str)
3242 if (!str || !*str) return "";
3244 return (" " ~ str.toDString() ~ "\0").ptr;
3247 /// Flag used by $(LREF resolveFuncCall).
3248 enum FuncResolveFlag : ubyte
3250 standard = 0, /// issue error messages, solve the call.
3251 quiet = 1, /// do not issue error message on no match, just return `null`.
3252 overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous
3253 /// matches and need explicit this.
3254 ufcs = 4, /// trying to resolve UFCS call
3257 /*******************************************
3258 * Given a symbol that could be either a FuncDeclaration or
3259 * a function template, resolve it to a function symbol.
3260 * Params:
3261 * loc = instantiation location
3262 * sc = instantiation scope
3263 * s = instantiation symbol
3264 * tiargs = initial list of template arguments
3265 * tthis = if !NULL, the `this` argument type
3266 * argumentList = arguments to function
3267 * flags = see $(LREF FuncResolveFlag).
3268 * Returns:
3269 * if match is found, then function symbol, else null
3271 FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
3272 Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
3274 auto fargs = argumentList.arguments;
3275 if (!s)
3276 return null; // no match
3278 version (none)
3280 printf("resolveFuncCall('%s')\n", s.toChars());
3281 if (tthis)
3282 printf("\tthis: %s\n", tthis.toChars());
3283 if (fargs)
3285 for (size_t i = 0; i < fargs.length; i++)
3287 Expression arg = (*fargs)[i];
3288 assert(arg.type);
3289 printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
3292 printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
3295 if (tiargs && arrayObjectIsError(tiargs))
3296 return null;
3297 if (fargs !is null)
3298 foreach (arg; *fargs)
3299 if (isError(arg))
3300 return null;
3302 MatchAccumulator m;
3303 functionResolve(m, s, loc, sc, tiargs, tthis, argumentList);
3304 auto orig_s = s;
3306 if (m.last > MATCH.nomatch && m.lastf)
3308 if (m.count == 1) // exactly one match
3310 if (!(flags & FuncResolveFlag.quiet))
3311 m.lastf.functionSemantic();
3312 return m.lastf;
3314 if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
3316 return m.lastf;
3320 /* Failed to find a best match.
3321 * Do nothing or print error.
3323 if (m.last == MATCH.nomatch)
3325 // error was caused on matched function, not on the matching itself,
3326 // so return the function to produce a better diagnostic
3327 if (m.count == 1)
3328 return m.lastf;
3331 // We are done at this point, as the rest of this function generate
3332 // a diagnostic on invalid match
3333 if (flags & FuncResolveFlag.quiet)
3334 return null;
3336 auto fd = s.isFuncDeclaration();
3337 auto od = s.isOverDeclaration();
3338 auto td = s.isTemplateDeclaration();
3339 if (td && td.funcroot)
3340 s = fd = td.funcroot;
3342 OutBuffer tiargsBuf;
3343 arrayObjectsToBuffer(&tiargsBuf, tiargs);
3345 OutBuffer fargsBuf;
3346 fargsBuf.writeByte('(');
3347 argExpTypesToCBuffer(&fargsBuf, fargs);
3348 fargsBuf.writeByte(')');
3349 if (tthis)
3350 tthis.modToBuffer(&fargsBuf);
3352 // The call is ambiguous
3353 if (m.lastf && m.nextf)
3355 TypeFunction tf1 = m.lastf.type.toTypeFunction();
3356 TypeFunction tf2 = m.nextf.type.toTypeFunction();
3357 const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
3358 const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
3360 const(char)* mod1 = prependSpace(MODtoChars(tf1.mod));
3361 const(char)* mod2 = prependSpace(MODtoChars(tf2.mod));
3363 .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
3364 s.parent.toPrettyChars(), s.ident.toChars(),
3365 fargsBuf.peekChars(),
3366 m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1,
3367 m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2);
3368 return null;
3371 // no match, generate an error messages
3372 if (flags & FuncResolveFlag.ufcs)
3374 auto arg = (*fargs)[0];
3375 .error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars());
3376 .errorSupplemental(loc, "the following error occured while looking for a UFCS match");
3379 if (!fd)
3381 // all of overloads are templates
3382 if (td)
3384 const(char)* msg = "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`";
3385 if (!od && !td.overnext)
3386 msg = "%s `%s.%s` is not callable using argument types `!(%s)%s`";
3387 .error(loc, msg,
3388 td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
3389 tiargsBuf.peekChars(), fargsBuf.peekChars());
3391 if (!global.gag || global.params.showGaggedErrors)
3392 printCandidates(loc, td, sc.isDeprecated());
3393 return null;
3395 /* This case used to happen when several ctors are mixed in an agregate.
3396 A (bad) error message is already generated in overloadApply().
3397 see https://issues.dlang.org/show_bug.cgi?id=19729
3398 and https://issues.dlang.org/show_bug.cgi?id=17259
3400 if (!od)
3401 return null;
3404 if (od)
3406 .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
3407 od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
3408 return null;
3411 // remove when deprecation period of class allocators and deallocators is over
3412 if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
3413 return null;
3415 bool hasOverloads = fd.overnext !is null;
3416 auto tf = fd.type.isTypeFunction();
3417 // if type is an error, the original type should be there for better diagnostics
3418 if (!tf)
3419 tf = fd.originalType.toTypeFunction();
3421 if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch
3423 OutBuffer thisBuf, funcBuf;
3424 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
3425 auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
3426 if (hasOverloads)
3428 .error(loc, "none of the overloads of `%s` are callable using a %sobject",
3429 fd.ident.toChars(), thisBuf.peekChars());
3430 if (!global.gag || global.params.showGaggedErrors)
3431 printCandidates(loc, fd, sc.isDeprecated());
3432 return null;
3435 const(char)* failMessage;
3436 functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
3437 if (failMessage)
3439 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3440 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3441 tf.modToChars(), fargsBuf.peekChars());
3442 errorSupplemental(loc, failMessage);
3443 return null;
3446 .error(loc, "%smethod `%s` is not callable using a %sobject",
3447 funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
3449 if (mismatches.isNotShared)
3450 .errorSupplemental(fd.loc, "Consider adding `shared` here");
3451 else if (mismatches.isMutable)
3452 .errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
3453 return null;
3456 //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
3457 if (hasOverloads)
3459 .error(loc, "none of the overloads of `%s` are callable using argument types `%s`",
3460 fd.toChars(), fargsBuf.peekChars());
3461 if (!global.gag || global.params.showGaggedErrors)
3462 printCandidates(loc, fd, sc.isDeprecated());
3463 return null;
3466 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3467 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3468 tf.modToChars(), fargsBuf.peekChars());
3470 // re-resolve to check for supplemental message
3471 if (!global.gag || global.params.showGaggedErrors)
3473 if (tthis)
3475 if (auto classType = tthis.isTypeClass())
3477 if (auto baseClass = classType.sym.baseClass)
3479 if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
3481 MatchAccumulator mErr;
3482 functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
3483 if (mErr.last > MATCH.nomatch && mErr.lastf)
3485 errorSupplemental(loc, "%s `%s` hides base class function `%s`",
3486 fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
3487 errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
3488 fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
3489 return null;
3495 const(char)* failMessage;
3496 functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
3497 if (failMessage)
3498 errorSupplemental(loc, failMessage);
3500 return null;
3503 /*******************************************
3504 * Prints template and function overload candidates as supplemental errors.
3505 * Params:
3506 * loc = instantiation location
3507 * declaration = the declaration to print overload candidates for
3508 * showDeprecated = If `false`, `deprecated` function won't be shown
3510 private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
3511 if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
3513 // max num of overloads to print (-v or -verror-supplements overrides this).
3514 const int DisplayLimit = !global.params.verbose ?
3515 (global.params.errorSupplementLimit ? global.params.errorSupplementLimit : int.max)
3516 : int.max;
3517 const(char)* constraintsTip;
3518 // determine if the first candidate was printed
3519 int printed;
3521 bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false)
3523 if (auto fd = s.isFuncDeclaration())
3525 // Don't print overloads which have errors.
3526 // Not that if the whole overload set has errors, we'll never reach
3527 // this point so there's no risk of printing no candidate
3528 if (fd.errors || fd.type.ty == Terror)
3529 return false;
3530 // Don't print disabled functions, or `deprecated` outside of deprecated scope
3531 if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
3532 return false;
3533 if (!print)
3534 return true;
3535 auto tf = cast(TypeFunction) fd.type;
3536 .errorSupplemental(fd.loc,
3537 printed ? " `%s%s`" :
3538 single_candidate ? "Candidate is: `%s%s`" : "Candidates are: `%s%s`",
3539 fd.toPrettyChars(),
3540 parametersTypeToChars(tf.parameterList));
3542 else if (auto td = s.isTemplateDeclaration())
3544 import dmd.staticcond;
3546 if (!print)
3547 return true;
3548 const tmsg = td.toCharsNoConstraints();
3549 const cmsg = td.getConstraintEvalError(constraintsTip);
3551 // add blank space if there are multiple candidates
3552 // the length of the blank space is `strlen("Candidates are: ")`
3554 if (cmsg)
3556 .errorSupplemental(td.loc,
3557 printed ? " `%s`\n%s" :
3558 single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
3559 tmsg, cmsg);
3561 else
3563 .errorSupplemental(td.loc,
3564 printed ? " `%s`" :
3565 single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
3566 tmsg);
3569 return true;
3571 // determine if there's > 1 candidate
3572 int count = 0;
3573 overloadApply(declaration, (s) {
3574 if (matchSymbol(s, false))
3575 count++;
3576 return count > 1;
3578 int skipped = 0;
3579 overloadApply(declaration, (s) {
3580 if (global.params.verbose || printed < DisplayLimit)
3582 if (matchSymbol(s, true, count == 1))
3583 printed++;
3585 else
3587 // Too many overloads to sensibly display.
3588 // Just show count of remaining overloads.
3589 if (matchSymbol(s, false))
3590 skipped++;
3592 return 0;
3594 if (skipped > 0)
3595 .errorSupplemental(loc, "... (%d more, -v to show) ...", skipped);
3597 // Nothing was displayed, all overloads are either disabled or deprecated
3598 if (!printed)
3599 .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
3600 // should be only in verbose mode
3601 if (constraintsTip)
3602 .tip(constraintsTip);
3605 /**************************************
3606 * Returns an indirect type one step from t.
3608 Type getIndirection(Type t)
3610 t = t.baseElemOf();
3611 if (t.ty == Tarray || t.ty == Tpointer)
3612 return t.nextOf().toBasetype();
3613 if (t.ty == Taarray || t.ty == Tclass)
3614 return t;
3615 if (t.ty == Tstruct)
3616 return t.hasPointers() ? t : null; // TODO
3618 // should consider TypeDelegate?
3619 return null;
3622 /**************************************
3623 * Performs type-based alias analysis between a newly created value and a pre-
3624 * existing memory reference:
3626 * Assuming that a reference A to a value of type `ta` was available to the code
3627 * that created a reference B to a value of type `tb`, it returns whether B
3628 * might alias memory reachable from A based on the types involved (either
3629 * directly or via any number of indirections in either A or B).
3631 * This relation is not symmetric in the two arguments. For example, a
3632 * a `const(int)` reference can point to a pre-existing `int`, but not the other
3633 * way round.
3635 * Examples:
3637 * ta, tb, result
3638 * `const(int)`, `int`, `false`
3639 * `int`, `const(int)`, `true`
3640 * `int`, `immutable(int)`, `false`
3641 * const(immutable(int)*), immutable(int)*, false // BUG: returns true
3643 * Params:
3644 * ta = value type being referred to
3645 * tb = referred to value type that could be constructed from ta
3647 * Returns:
3648 * true if reference to `tb` is isolated from reference to `ta`
3650 private bool traverseIndirections(Type ta, Type tb)
3652 //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
3654 static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
3656 //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
3657 ta = ta.baseElemOf();
3658 tb = tb.baseElemOf();
3660 // First, check if the pointed-to types are convertible to each other such
3661 // that they might alias directly.
3662 static bool mayAliasDirect(Type source, Type target)
3664 return
3665 // if source is the same as target or can be const-converted to target
3666 source.constConv(target) != MATCH.nomatch ||
3667 // if target is void and source can be const-converted to target
3668 (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
3671 if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
3673 //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3674 return false;
3676 if (ta.nextOf() && ta.nextOf() == tb.nextOf())
3678 //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3679 return true;
3682 if (tb.ty == Tclass || tb.ty == Tstruct)
3684 /* Traverse the type of each field of the aggregate
3686 bool* found = table.getLvalue(tb.deco);
3687 if (*found == true)
3688 return true; // We have already seen this symbol, break the cycle
3689 else
3690 *found = true;
3692 AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
3693 foreach (v; sym.fields)
3695 Type tprmi = v.type.addMod(tb.mod);
3696 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
3697 if (!traverse(ta, tprmi, table, reversePass))
3698 return false;
3701 else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
3703 Type tind = tb.nextOf();
3704 if (!traverse(ta, tind, table, reversePass))
3705 return false;
3707 else if (tb.hasPointers())
3709 // BUG: consider the context pointer of delegate types
3710 return false;
3713 // Still no match, so try breaking up ta if we have not done so yet.
3714 if (!reversePass)
3716 scope newTable = AssocArray!(const(char)*, bool)();
3717 return traverse(tb, ta, newTable, true);
3720 return true;
3723 // To handle arbitrary levels of indirections in both parameters, we
3724 // recursively descend into aggregate members/levels of indirection in both
3725 // `ta` and `tb` while avoiding cycles. Start with the original types.
3726 scope table = AssocArray!(const(char)*, bool)();
3727 const result = traverse(ta, tb, table, false);
3728 //printf(" returns %d\n", result);
3729 return result;
3732 /* For all functions between outerFunc and f, mark them as needing
3733 * a closure.
3735 private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc)
3737 for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc))
3739 FuncDeclaration fy = sx.isFuncDeclaration();
3740 if (fy && fy.closureVars.length)
3742 /* fy needs a closure if it has closureVars[],
3743 * because the frame pointer in the closure will be accessed.
3745 fy.requiresClosure = true;
3750 /********
3751 * Given a nested function f inside a function outerFunc, check
3752 * if any sibling callers of f have escaped. If so, mark
3753 * all the enclosing functions as needing closures.
3754 * This is recursive: we need to check the callers of our siblings.
3755 * Note that nested functions can only call lexically earlier nested
3756 * functions, so loops are impossible.
3757 * Params:
3758 * f = inner function (nested within outerFunc)
3759 * outerFunc = outer function
3760 * p = for internal recursion use
3761 * Returns:
3762 * true if any closures were needed
3764 private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
3766 static struct PrevSibling
3768 PrevSibling* p;
3769 FuncDeclaration f;
3772 if (f.computedEscapingSiblings)
3773 return f.hasEscapingSiblings;
3775 PrevSibling ps;
3776 ps.p = cast(PrevSibling*)p;
3777 ps.f = f;
3779 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
3780 bool bAnyClosures = false;
3781 for (size_t i = 0; i < f.siblingCallers.length; ++i)
3783 FuncDeclaration g = f.siblingCallers[i];
3784 if (g.isThis() || g.tookAddressOf)
3786 markAsNeedingClosure(g, outerFunc);
3787 bAnyClosures = true;
3790 for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc))
3792 // A parent of the sibling had its address taken.
3793 // Assume escaping of parent affects its children, so needs propagating.
3794 // see https://issues.dlang.org/show_bug.cgi?id=19679
3795 FuncDeclaration parentFunc = parent.isFuncDeclaration;
3796 if (parentFunc && parentFunc.tookAddressOf)
3798 markAsNeedingClosure(parentFunc, outerFunc);
3799 bAnyClosures = true;
3803 PrevSibling* prev = cast(PrevSibling*)p;
3804 while (1)
3806 if (!prev)
3808 bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
3809 break;
3811 if (prev.f == g)
3812 break;
3813 prev = prev.p;
3816 f.hasEscapingSiblings = bAnyClosures;
3817 f.computedEscapingSiblings = true;
3818 //printf("\t%d\n", bAnyClosures);
3819 return bAnyClosures;
3822 /***********************************************************
3823 * Used as a way to import a set of functions from another scope into this one.
3825 extern (C++) final class FuncAliasDeclaration : FuncDeclaration
3827 FuncDeclaration funcalias;
3828 bool hasOverloads;
3830 extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true)
3832 super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type);
3833 assert(funcalias != this);
3834 this.funcalias = funcalias;
3836 this.hasOverloads = hasOverloads;
3837 if (hasOverloads)
3839 if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration())
3840 this.hasOverloads = fad.hasOverloads;
3842 else
3844 // for internal use
3845 assert(!funcalias.isFuncAliasDeclaration());
3846 this.hasOverloads = false;
3848 userAttribDecl = funcalias.userAttribDecl;
3851 override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
3853 return this;
3856 override const(char)* kind() const
3858 return "function alias";
3861 override inout(FuncDeclaration) toAliasFunc() inout
3863 return funcalias.toAliasFunc();
3866 override void accept(Visitor v)
3868 v.visit(this);
3872 /***********************************************************
3874 extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
3876 TOK tok; // TOK.function_ or TOK.delegate_
3877 Type treq; // target of return type inference
3879 // backend
3880 bool deferToObj;
3882 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_)
3884 super(loc, endloc, null, storage_class, type);
3885 this.ident = id ? id : Id.empty;
3886 this.tok = tok;
3887 this.fes = fes;
3888 // Always infer scope for function literals
3889 // See https://issues.dlang.org/show_bug.cgi?id=20362
3890 this.inferScope = true;
3891 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
3894 override FuncLiteralDeclaration syntaxCopy(Dsymbol s)
3896 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
3897 assert(!s);
3898 auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident, storage_class & STC.auto_);
3899 f.treq = treq; // don't need to copy
3900 FuncDeclaration.syntaxCopy(f);
3901 return f;
3904 override bool isNested() const
3906 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
3907 return (tok != TOK.function_) && !isThis();
3910 override inout(AggregateDeclaration) isThis() inout
3912 return tok == TOK.delegate_ ? super.isThis() : null;
3915 override bool isVirtual() const
3917 return false;
3920 override bool addPreInvariant()
3922 return false;
3925 override bool addPostInvariant()
3927 return false;
3930 /*******************************
3931 * Modify all expression type of return statements to tret.
3933 * On function literals, return type may be modified based on the context type
3934 * after its semantic3 is done, in FuncExp::implicitCastTo.
3936 * A function() dg = (){ return new B(); } // OK if is(B : A) == true
3938 * If B to A conversion is convariant that requires offseet adjusting,
3939 * all return statements should be adjusted to return expressions typed A.
3941 void modifyReturns(Scope* sc, Type tret)
3943 import dmd.statement_rewrite_walker;
3945 extern (C++) final class RetWalker : StatementRewriteWalker
3947 alias visit = typeof(super).visit;
3948 public:
3949 Scope* sc;
3950 Type tret;
3951 FuncLiteralDeclaration fld;
3953 override void visit(ReturnStatement s)
3955 Expression exp = s.exp;
3956 if (exp && !exp.type.equals(tret))
3957 s.exp = exp.implicitCastTo(sc, tret);
3961 if (semanticRun < PASS.semantic3done)
3962 return;
3964 if (fes)
3965 return;
3967 scope RetWalker w = new RetWalker();
3968 w.sc = sc;
3969 w.tret = tret;
3970 w.fld = this;
3971 fbody.accept(w);
3973 // Also update the inferred function type to match the new return type.
3974 // This is required so the code generator does not try to cast the
3975 // modified returns back to the original type.
3976 if (inferRetType && type.nextOf() != tret)
3977 type.toTypeFunction().next = tret;
3980 override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
3982 return this;
3985 override const(char)* kind() const
3987 // GCC requires the (char*) casts
3988 return (tok != TOK.function_) ? "delegate" : "function";
3991 override const(char)* toPrettyChars(bool QualifyTypes = false)
3993 if (parent)
3995 TemplateInstance ti = parent.isTemplateInstance();
3996 if (ti)
3997 return ti.tempdecl.toPrettyChars(QualifyTypes);
3999 return Dsymbol.toPrettyChars(QualifyTypes);
4002 override void accept(Visitor v)
4004 v.visit(this);
4008 /***********************************************************
4010 extern (C++) final class CtorDeclaration : FuncDeclaration
4012 bool isCpCtor;
4013 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
4015 super(loc, endloc, Id.ctor, stc, type);
4016 this.isCpCtor = isCpCtor;
4017 //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
4020 override CtorDeclaration syntaxCopy(Dsymbol s)
4022 assert(!s);
4023 auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy());
4024 FuncDeclaration.syntaxCopy(f);
4025 return f;
4028 override const(char)* kind() const
4030 return isCpCtor ? "copy constructor" : "constructor";
4033 override const(char)* toChars() const
4035 return "this";
4038 override bool isVirtual() const
4040 return false;
4043 override bool addPreInvariant()
4045 return false;
4048 override bool addPostInvariant()
4050 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
4053 override inout(CtorDeclaration) isCtorDeclaration() inout
4055 return this;
4058 override void accept(Visitor v)
4060 v.visit(this);
4064 /***********************************************************
4066 extern (C++) final class PostBlitDeclaration : FuncDeclaration
4068 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
4070 super(loc, endloc, id, stc, null);
4073 override PostBlitDeclaration syntaxCopy(Dsymbol s)
4075 assert(!s);
4076 auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
4077 FuncDeclaration.syntaxCopy(dd);
4078 return dd;
4081 override bool isVirtual() const
4083 return false;
4086 override bool addPreInvariant()
4088 return false;
4091 override bool addPostInvariant()
4093 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
4096 override bool overloadInsert(Dsymbol s)
4098 return false; // cannot overload postblits
4101 override inout(PostBlitDeclaration) isPostBlitDeclaration() inout
4103 return this;
4106 override void accept(Visitor v)
4108 v.visit(this);
4112 /***********************************************************
4114 extern (C++) final class DtorDeclaration : FuncDeclaration
4116 extern (D) this(const ref Loc loc, const ref Loc endloc)
4118 super(loc, endloc, Id.dtor, STC.undefined_, null);
4121 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
4123 super(loc, endloc, id, stc, null);
4126 override DtorDeclaration syntaxCopy(Dsymbol s)
4128 assert(!s);
4129 auto dd = new DtorDeclaration(loc, endloc, storage_class, ident);
4130 FuncDeclaration.syntaxCopy(dd);
4131 return dd;
4134 override const(char)* kind() const
4136 return "destructor";
4139 override const(char)* toChars() const
4141 return "~this";
4144 override bool isVirtual() const
4146 // D dtor's don't get put into the vtbl[]
4147 // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
4148 return vtblIndex != -1;
4151 override bool addPreInvariant()
4153 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
4156 override bool addPostInvariant()
4158 return false;
4161 override bool overloadInsert(Dsymbol s)
4163 return false; // cannot overload destructors
4166 override inout(DtorDeclaration) isDtorDeclaration() inout
4168 return this;
4171 override void accept(Visitor v)
4173 v.visit(this);
4177 /***********************************************************
4179 extern (C++) class StaticCtorDeclaration : FuncDeclaration
4181 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4183 super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null);
4186 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
4188 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
4191 override StaticCtorDeclaration syntaxCopy(Dsymbol s)
4193 assert(!s);
4194 auto scd = new StaticCtorDeclaration(loc, endloc, storage_class);
4195 FuncDeclaration.syntaxCopy(scd);
4196 return scd;
4199 override final inout(AggregateDeclaration) isThis() inout @nogc nothrow pure @safe
4201 return null;
4204 override final bool isVirtual() const @nogc nothrow pure @safe
4206 return false;
4209 override final bool addPreInvariant() @nogc nothrow pure @safe
4211 return false;
4214 override final bool addPostInvariant() @nogc nothrow pure @safe
4216 return false;
4219 override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
4221 return true;
4224 override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
4226 return this;
4229 override void accept(Visitor v)
4231 v.visit(this);
4235 /***********************************************************
4237 extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
4239 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4241 super(loc, endloc, "_sharedStaticCtor", stc);
4244 override SharedStaticCtorDeclaration syntaxCopy(Dsymbol s)
4246 assert(!s);
4247 auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
4248 FuncDeclaration.syntaxCopy(scd);
4249 return scd;
4252 override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
4254 return this;
4257 override void accept(Visitor v)
4259 v.visit(this);
4263 /***********************************************************
4265 extern (C++) class StaticDtorDeclaration : FuncDeclaration
4267 VarDeclaration vgate; // 'gate' variable
4269 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4271 super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null);
4274 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
4276 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
4279 override StaticDtorDeclaration syntaxCopy(Dsymbol s)
4281 assert(!s);
4282 auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
4283 FuncDeclaration.syntaxCopy(sdd);
4284 return sdd;
4287 override final inout(AggregateDeclaration) isThis() inout
4289 return null;
4292 override final bool isVirtual() const
4294 return false;
4297 override final bool hasStaticCtorOrDtor()
4299 return true;
4302 override final bool addPreInvariant()
4304 return false;
4307 override final bool addPostInvariant()
4309 return false;
4312 override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
4314 return this;
4317 override void accept(Visitor v)
4319 v.visit(this);
4323 /***********************************************************
4325 extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
4327 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4329 super(loc, endloc, "_sharedStaticDtor", stc);
4332 override SharedStaticDtorDeclaration syntaxCopy(Dsymbol s)
4334 assert(!s);
4335 auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
4336 FuncDeclaration.syntaxCopy(sdd);
4337 return sdd;
4340 override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
4342 return this;
4345 override void accept(Visitor v)
4347 v.visit(this);
4351 /***********************************************************
4353 extern (C++) final class InvariantDeclaration : FuncDeclaration
4355 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
4357 // Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list.
4358 super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
4359 this.fbody = fbody;
4362 override InvariantDeclaration syntaxCopy(Dsymbol s)
4364 assert(!s);
4365 auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null);
4366 FuncDeclaration.syntaxCopy(id);
4367 return id;
4370 override bool isVirtual() const
4372 return false;
4375 override bool addPreInvariant()
4377 return false;
4380 override bool addPostInvariant()
4382 return false;
4385 override inout(InvariantDeclaration) isInvariantDeclaration() inout
4387 return this;
4390 override void accept(Visitor v)
4392 v.visit(this);
4395 extern (D) void fixupInvariantIdent(size_t offset)
4397 OutBuffer idBuf;
4398 idBuf.writestring("__invariant");
4399 idBuf.print(offset);
4401 ident = Identifier.idPool(idBuf[]);
4406 /***********************************************************
4408 extern (C++) final class UnitTestDeclaration : FuncDeclaration
4410 char* codedoc; // for documented unittest
4412 // toObjFile() these nested functions after this one
4413 FuncDeclarations deferredNested;
4415 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
4417 super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null);
4418 this.codedoc = codedoc;
4421 override UnitTestDeclaration syntaxCopy(Dsymbol s)
4423 assert(!s);
4424 auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
4425 FuncDeclaration.syntaxCopy(utd);
4426 return utd;
4429 override inout(AggregateDeclaration) isThis() inout
4431 return null;
4434 override bool isVirtual() const
4436 return false;
4439 override bool addPreInvariant()
4441 return false;
4444 override bool addPostInvariant()
4446 return false;
4449 override inout(UnitTestDeclaration) isUnitTestDeclaration() inout
4451 return this;
4454 override void accept(Visitor v)
4456 v.visit(this);
4460 /***********************************************************
4462 extern (C++) final class NewDeclaration : FuncDeclaration
4464 extern (D) this(const ref Loc loc, StorageClass stc)
4466 super(loc, Loc.initial, Id.classNew, STC.static_ | stc, null);
4469 override NewDeclaration syntaxCopy(Dsymbol s)
4471 assert(!s);
4472 auto f = new NewDeclaration(loc, storage_class);
4473 FuncDeclaration.syntaxCopy(f);
4474 return f;
4477 override const(char)* kind() const
4479 return "allocator";
4482 override bool isVirtual() const
4484 return false;
4487 override bool addPreInvariant()
4489 return false;
4492 override bool addPostInvariant()
4494 return false;
4497 override inout(NewDeclaration) isNewDeclaration() inout
4499 return this;
4502 override void accept(Visitor v)
4504 v.visit(this);
4508 /**************************************
4509 * When a traits(compiles) is used on a function literal call
4510 * we need to take into account if the body of the function
4511 * violates any attributes, however, we must not affect the
4512 * attribute inference on the outer function. The attributes
4513 * of the function literal still need to be inferred, therefore
4514 * we need a way to check for the scope that the traits compiles
4515 * introduces.
4517 * Params:
4518 * sc = scope to be checked for
4520 * Returns: `true` if the provided scope is the root
4521 * of the traits compiles list of scopes.
4523 bool isRootTraitsCompilesScope(Scope* sc)
4525 return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
4528 /**************************************
4529 * A statement / expression in this scope is not `@safe`,
4530 * so mark the enclosing function as `@system`
4532 * Params:
4533 * sc = scope that the unsafe statement / expression is in
4534 * gag = surpress error message (used in escape.d)
4535 * loc = location of error
4536 * fmt = printf-style format string
4537 * arg0 = (optional) argument for first %s format specifier
4538 * arg1 = (optional) argument for second %s format specifier
4539 * arg2 = (optional) argument for third %s format specifier
4540 * Returns: whether there's a safe error
4542 bool setUnsafe(Scope* sc,
4543 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
4544 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
4546 if (sc.intypeof)
4547 return false; // typeof(cast(int*)0) is safe
4549 if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
4550 return false;
4552 if (!sc.func)
4554 if (sc.varDecl)
4556 if (sc.varDecl.storage_class & STC.safe)
4558 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4559 return true;
4561 else if (!(sc.varDecl.storage_class & STC.system))
4563 sc.varDecl.storage_class |= STC.system;
4566 return false;
4570 if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
4572 if (sc.func.isSafeBypassingInference())
4574 // Message wil be gagged, but still call error() to update global.errors and for
4575 // -verrors=spec
4576 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4577 return true;
4579 return false;
4582 return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
4585 /***************************************
4586 * Like `setUnsafe`, but for safety errors still behind preview switches
4588 * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
4589 * the behavior changes based on the setting:
4591 * - In case of `-revert=fs`, it does nothing.
4592 * - In case of `-preview=fs`, it's the same as `setUnsafe`
4593 * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
4595 * Params:
4596 * sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
4597 * fs = feature state from the preview flag
4598 * gag = surpress error message
4599 * loc = location of error
4600 * msg = printf-style format string
4601 * arg0 = (optional) argument for first %s format specifier
4602 * arg1 = (optional) argument for second %s format specifier
4603 * arg2 = (optional) argument for third %s format specifier
4604 * Returns: whether an actual safe error (not deprecation) occured
4606 bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
4607 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
4609 with (FeatureState) final switch (fs)
4611 case disabled:
4612 return false;
4614 case enabled:
4615 return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
4617 case default_:
4618 if (!sc.func)
4619 return false;
4620 if (sc.func.isSafeBypassingInference())
4622 if (!gag)
4623 previewErrorFunc(sc.isDeprecated(), fs)(
4624 loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : ""
4627 else if (!sc.func.safetyViolation)
4629 import dmd.func : AttributeViolation;
4630 sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
4632 return false;
4636 /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
4638 /// Has two modes:
4639 /// - a regular safety error, stored in (fmtStr, arg0, arg1)
4640 /// - a call to a function without the attribute, which is a special case, because in that case,
4641 /// that function might recursively also have a `AttributeViolation`. This way, in case
4642 /// of a big call stack, the error can go down all the way to the root cause.
4643 /// The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`.
4644 struct AttributeViolation
4646 /// location of error
4647 Loc loc = Loc.init;
4648 /// printf-style format string
4649 const(char)* fmtStr = null;
4650 /// Arguments for up to two `%s` format specifiers in format string
4651 RootObject arg0 = null;
4652 /// ditto
4653 RootObject arg1 = null;
4654 /// ditto
4655 RootObject arg2 = null;
4658 /// Print the reason why `fd` was inferred `@system` as a supplemental error
4659 /// Params:
4660 /// fd = function to check
4661 /// maxDepth = up to how many functions deep to report errors
4662 /// deprecation = print deprecations instead of errors
4663 /// stc = storage class of attribute to check
4664 void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc)
4666 auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
4668 AttributeViolation* s;
4669 const(char)* attr;
4670 if (stc & STC.safe)
4672 s = fd.safetyViolation;
4673 attr = "@safe";
4675 else if (stc & STC.pure_)
4677 s = fd.pureViolation;
4678 attr = "pure";
4680 else if (stc & STC.nothrow_)
4682 s = fd.nothrowViolation;
4683 attr = "nothrow";
4685 else if (stc & STC.nogc)
4687 s = fd.nogcViolation;
4688 attr = "@nogc";
4691 if (s)
4693 if (s.fmtStr)
4695 errorFunc(s.loc, deprecation ?
4696 "which wouldn't be `%s` because of:" :
4697 "which wasn't inferred `%s` because of:", attr);
4698 if (stc == STC.nogc || stc == STC.pure_)
4700 auto f = (cast(Dsymbol) s.arg0).isFuncDeclaration();
4701 errorFunc(s.loc, s.fmtStr, f.kind(), f.toPrettyChars(), s.arg1 ? s.arg1.toChars() : "");
4703 else
4705 errorFunc(s.loc, s.fmtStr,
4706 s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
4709 else if (s.arg0.dyncast() == DYNCAST.dsymbol)
4711 if (FuncDeclaration fd2 = (cast(Dsymbol) s.arg0).isFuncDeclaration())
4713 if (maxDepth > 0)
4715 errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
4716 errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc);