d: Merge dmd, druntime d8e3976a58, phobos 7a6e95688
[official-gcc.git] / gcc / d / dmd / func.d
blob242b4dc99f9cefc3662e16cc96729a91586012ae
1 /**
2 * Defines a function declaration.
4 * Includes:
5 * - function/delegate literals
6 * - function aliases
7 * - (static/shared) constructors/destructors/post-blits
8 * - `invariant`
9 * - `unittest`
11 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
12 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
13 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
14 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d)
15 * Documentation: https://dlang.org/phobos/dmd_func.html
16 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d
19 module dmd.func;
21 import core.stdc.stdio;
22 import core.stdc.string;
23 import dmd.aggregate;
24 import dmd.arraytypes;
25 import dmd.astenums;
26 import dmd.blockexit;
27 import dmd.gluelayer;
28 import dmd.dcast;
29 import dmd.dclass;
30 import dmd.declaration;
31 import dmd.delegatize;
32 import dmd.dinterpret;
33 import dmd.dmodule;
34 import dmd.dscope;
35 import dmd.dstruct;
36 import dmd.dsymbol;
37 import dmd.dsymbolsem;
38 import dmd.dtemplate;
39 import dmd.errors;
40 import dmd.escape;
41 import dmd.expression;
42 import dmd.globals;
43 import dmd.hdrgen;
44 import dmd.id;
45 import dmd.identifier;
46 import dmd.init;
47 import dmd.location;
48 import dmd.mtype;
49 import dmd.objc;
50 import dmd.root.aav;
51 import dmd.common.outbuffer;
52 import dmd.rootobject;
53 import dmd.root.string;
54 import dmd.root.stringtable;
55 import dmd.semantic2;
56 import dmd.semantic3;
57 import dmd.statement_rewrite_walker;
58 import dmd.statement;
59 import dmd.statementsem;
60 import dmd.tokens;
61 import dmd.visitor;
63 version (IN_GCC) {}
64 else version (IN_LLVM) {}
65 else version = MARS;
67 /// Inline Status
68 enum ILS : ubyte
70 uninitialized, /// not computed yet
71 no, /// cannot inline
72 yes, /// can inline
75 enum BUILTIN : ubyte
77 unknown = 255, /// not known if this is a builtin
78 unimp = 0, /// this is not a builtin
79 gcc, /// this is a GCC builtin
80 llvm, /// this is an LLVM builtin
81 sin,
82 cos,
83 tan,
84 sqrt,
85 fabs,
86 ldexp,
87 log,
88 log2,
89 log10,
90 exp,
91 expm1,
92 exp2,
93 round,
94 floor,
95 ceil,
96 trunc,
97 copysign,
98 pow,
99 fmin,
100 fmax,
101 fma,
102 isnan,
103 isinfinity,
104 isfinite,
105 bsf,
106 bsr,
107 bswap,
108 popcnt,
109 yl2x,
110 yl2xp1,
111 toPrecFloat,
112 toPrecDouble,
113 toPrecReal
116 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
118 extern (C++) final class NrvoWalker : StatementRewriteWalker
120 alias visit = typeof(super).visit;
121 public:
122 FuncDeclaration fd;
123 Scope* sc;
125 override void visit(ReturnStatement s)
127 // See if all returns are instead to be replaced with a goto returnLabel;
128 if (fd.returnLabel)
130 /* Rewrite:
131 * return exp;
132 * as:
133 * vresult = exp; goto Lresult;
135 auto gs = new GotoStatement(s.loc, Id.returnLabel);
136 gs.label = fd.returnLabel;
138 Statement s1 = gs;
139 if (s.exp)
140 s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
142 replaceCurrent(s1);
146 override void visit(TryFinallyStatement s)
148 DtorExpStatement des;
149 if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
150 fd.nrvo_var == des.var)
152 if (!(global.params.useExceptions && ClassDeclaration.throwable))
154 /* Don't need to call destructor at all, since it is nrvo
156 replaceCurrent(s._body);
157 s._body.accept(this);
158 return;
161 /* Normally local variable dtors are called regardless exceptions.
162 * But for nrvo_var, its dtor should be called only when exception is thrown.
164 * Rewrite:
165 * try { s.body; } finally { nrvo_var.edtor; }
166 * // equivalent with:
167 * // s.body; scope(exit) nrvo_var.edtor;
168 * as:
169 * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
170 * // equivalent with:
171 * // s.body; scope(failure) nrvo_var.edtor;
173 Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
174 Identifier id = Identifier.generateId("__o");
176 Statement handler = new PeelStatement(sexception);
177 if (sexception.blockExit(fd, null) & BE.fallthru)
179 auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
180 ts.internalThrow = true;
181 handler = new CompoundStatement(Loc.initial, handler, ts);
184 auto catches = new Catches();
185 auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
186 ctch.internalCatch = true;
187 ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
188 catches.push(ctch);
190 Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
191 fd.hasNoEH = false;
192 replaceCurrent(s2);
193 s2.accept(this);
195 else
196 StatementRewriteWalker.visit(s);
200 private struct FUNCFLAG
202 bool purityInprocess; /// working on determining purity
203 bool safetyInprocess; /// working on determining safety
204 bool nothrowInprocess; /// working on determining nothrow
205 bool nogcInprocess; /// working on determining @nogc
206 bool returnInprocess; /// working on inferring 'return' for parameters
207 bool inlineScanned; /// function has been scanned for inline possibilities
208 bool inferScope; /// infer 'scope' for parameters
209 bool hasCatches; /// function has try-catch statements
210 bool skipCodegen; /// do not generate code for this function.
211 bool printf; /// is a printf-like function
213 bool scanf; /// is a scanf-like function
214 bool noreturn; /// the function does not return
215 bool isNRVO = true; /// Support for named return value optimization
216 bool isNaked; /// The function is 'naked' (see inline ASM)
217 bool isGenerated; /// The function is compiler generated (e.g. `opCmp`)
218 bool isIntroducing; /// If this function introduces the overload set
219 bool hasSemantic3Errors; /// If errors in semantic3 this function's frame ptr
220 bool hasNoEH; /// No exception unwinding is needed
221 bool inferRetType; /// Return type is to be inferred
222 bool hasDualContext; /// has a dual-context 'this' parameter
224 bool hasAlwaysInlines; /// Contains references to functions that must be inlined
225 bool isCrtCtor; /// Has attribute pragma(crt_constructor)
226 bool isCrtDtor; /// Has attribute pragma(crt_destructor)
227 bool hasEscapingSiblings;/// Has sibling functions that escape
228 bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed
229 bool dllImport; /// __declspec(dllimport)
230 bool dllExport; /// __declspec(dllexport)
233 /***********************************************************
234 * Tuple of result identifier (possibly null) and statement.
235 * This is used to store out contracts: out(id){ ensure }
237 extern (C++) struct Ensure
239 Identifier id;
240 Statement ensure;
242 Ensure syntaxCopy()
244 return Ensure(id, ensure.syntaxCopy());
247 /*****************************************
248 * Do syntax copy of an array of Ensure's.
250 static Ensures* arraySyntaxCopy(Ensures* a)
252 Ensures* b = null;
253 if (a)
255 b = a.copy();
256 foreach (i, e; *a)
258 (*b)[i] = e.syntaxCopy();
261 return b;
266 /***********************************************************
267 * Most functions don't have contracts, so save memory by grouping
268 * this information into a separate struct
270 private struct ContractInfo
272 Statements* frequires; /// in contracts
273 Ensures* fensures; /// out contracts
274 Statement frequire; /// lowered in contract
275 Statement fensure; /// lowered out contract
276 FuncDeclaration fdrequire; /// function that does the in contract
277 FuncDeclaration fdensure; /// function that does the out contract
278 Expressions* fdrequireParams; /// argument list for __require
279 Expressions* fdensureParams; /// argument list for __ensure
282 /***********************************************************
284 extern (C++) class FuncDeclaration : Declaration
286 Statement fbody; /// function body
288 FuncDeclarations foverrides; /// functions this function overrides
290 private ContractInfo* contracts; /// contract information
292 const(char)* mangleString; /// mangled symbol created from mangleExact()
294 VarDeclaration vresult; /// result variable for out contracts
295 LabelDsymbol returnLabel; /// where the return goes
297 bool[size_t] isTypeIsolatedCache; /// cache for the potentially very expensive isTypeIsolated check
299 // used to prevent symbols in different
300 // scopes from having the same name
301 DsymbolTable localsymtab;
302 VarDeclaration vthis; /// 'this' parameter (member and nested)
303 VarDeclaration v_arguments; /// '_arguments' parameter
305 VarDeclaration v_argptr; /// '_argptr' variable
306 VarDeclarations* parameters; /// Array of VarDeclaration's for parameters
307 DsymbolTable labtab; /// statement label symbol table
308 Dsymbol overnext; /// next in overload list
309 FuncDeclaration overnext0; /// next in overload list (only used during IFTI)
310 Loc endloc; /// location of closing curly bracket
311 int vtblIndex = -1; /// for member functions, index into vtbl[]
313 ILS inlineStatusStmt = ILS.uninitialized;
314 ILS inlineStatusExp = ILS.uninitialized;
315 PINLINE inlining = PINLINE.default_;
317 int inlineNest; /// !=0 if nested inline
319 ForeachStatement fes; /// if foreach body, this is the foreach
320 BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[]
321 /** if !=NULL, then this is the type
322 of the 'introducing' function
323 this one is overriding
325 Type tintro;
327 StorageClass storage_class2; /// storage class for template onemember's
329 // Things that should really go into Scope
331 /// 1 if there's a return exp; statement
332 /// 2 if there's a throw statement
333 /// 4 if there's an assert(0)
334 /// 8 if there's inline asm
335 /// 16 if there are multiple return statements
336 int hasReturnExp;
338 VarDeclaration nrvo_var; /// variable to replace with shidden
339 Symbol* shidden; /// hidden pointer passed to function
341 ReturnStatements* returns;
343 GotoStatements* gotos; /// Gotos with forward references
345 version (MARS)
347 VarDeclarations* alignSectionVars; /// local variables with alignment needs larger than stackAlign
348 Symbol* salignSection; /// pointer to aligned section, if any
351 /// set if this is a known, builtin function we can evaluate at compile time
352 BUILTIN builtin = BUILTIN.unknown;
354 /// set if someone took the address of this function
355 int tookAddressOf;
357 bool requiresClosure; // this function needs a closure
359 /** local variables in this function which are referenced by nested functions
360 * (They'll get put into the "closure" for this function.)
362 VarDeclarations closureVars;
364 /** Outer variables which are referenced by this nested function
365 * (the inverse of closureVars)
367 VarDeclarations outerVars;
369 /// Sibling nested functions which called this one
370 FuncDeclarations siblingCallers;
372 FuncDeclarations *inlinedNestedCallees;
374 /// In case of failed `@safe` inference, store the error that made the function `@system` for
375 /// better diagnostics
376 AttributeViolation* safetyViolation;
377 AttributeViolation* nogcViolation;
378 AttributeViolation* pureViolation;
379 AttributeViolation* nothrowViolation;
381 /// See the `FUNCFLAG` struct
382 import dmd.common.bitfields;
383 mixin(generateBitFields!(FUNCFLAG, uint));
386 * Data for a function declaration that is needed for the Objective-C
387 * integration.
389 ObjcFuncDeclaration objc;
391 extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false)
393 super(loc, ident);
394 //.printf("FuncDeclaration(id = '%s', type = %s)\n", ident.toChars(), type.toChars());
395 //.printf("storage_class = x%llx\n", storage_class);
396 this.storage_class = storage_class;
397 this.type = type;
398 if (type)
400 // Normalize storage_class, because function-type related attributes
401 // are already set in the 'type' in parsing phase.
402 this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
404 this.endloc = endloc;
405 if (noreturn)
406 this.noreturn = true;
408 /* The type given for "infer the return type" is a TypeFunction with
409 * NULL for the return type.
411 if (type && type.nextOf() is null)
412 this.inferRetType = true;
415 static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
417 return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn);
420 final nothrow pure @safe
422 private ref ContractInfo getContracts()
424 if (!contracts)
425 contracts = new ContractInfo();
426 return *contracts;
429 // getters
430 inout(Statements*) frequires() inout { return contracts ? contracts.frequires : null; }
431 inout(Ensures*) fensures() inout { return contracts ? contracts.fensures : null; }
432 inout(Statement) frequire() inout { return contracts ? contracts.frequire: null; }
433 inout(Statement) fensure() inout { return contracts ? contracts.fensure : null; }
434 inout(FuncDeclaration) fdrequire() inout { return contracts ? contracts.fdrequire : null; }
435 inout(FuncDeclaration) fdensure() inout { return contracts ? contracts.fdensure: null; }
436 inout(Expressions*) fdrequireParams() inout { return contracts ? contracts.fdrequireParams: null; }
437 inout(Expressions*) fdensureParams() inout { return contracts ? contracts.fdensureParams: null; }
439 extern (D) private static string generateContractSetter(string field, string type)
441 return type ~ " " ~ field ~ "(" ~ type ~ " param)" ~
443 if (!param && !contracts) return null;
444 return getContracts()." ~ field ~ " = param;
448 mixin(generateContractSetter("frequires", "Statements*"));
449 mixin(generateContractSetter("fensures", "Ensures*"));
450 mixin(generateContractSetter("frequire", "Statement"));
451 mixin(generateContractSetter("fensure", "Statement"));
452 mixin(generateContractSetter("fdrequire", "FuncDeclaration"));
453 mixin(generateContractSetter("fdensure", "FuncDeclaration"));
454 mixin(generateContractSetter("fdrequireParams", "Expressions*"));
455 mixin(generateContractSetter("fdensureParams", "Expressions*"));
458 override FuncDeclaration syntaxCopy(Dsymbol s)
460 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
461 FuncDeclaration f = s ? cast(FuncDeclaration)s
462 : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), this.noreturn != 0);
463 f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
464 f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
465 f.fbody = fbody ? fbody.syntaxCopy() : null;
466 return f;
469 /****************************************************
470 * Resolve forward reference of function signature -
471 * parameter types, return type, and attributes.
472 * Returns:
473 * false if any errors exist in the signature.
475 final bool functionSemantic()
477 //printf("functionSemantic() %p %s\n", this, toChars());
478 if (!_scope)
479 return !errors;
481 this.cppnamespace = _scope.namespace;
483 if (!originalType) // semantic not yet run
485 TemplateInstance spec = isSpeculative();
486 uint olderrs = global.errors;
487 uint oldgag = global.gag;
488 if (global.gag && !spec)
489 global.gag = 0;
490 dsymbolSemantic(this, _scope);
491 global.gag = oldgag;
492 if (spec && global.errors != olderrs)
493 spec.errors = (global.errors - olderrs != 0);
494 if (olderrs != global.errors) // if errors compiling this function
495 return false;
498 // if inferring return type, sematic3 needs to be run
499 // - When the function body contains any errors, we cannot assume
500 // the inferred return type is valid.
501 // So, the body errors should become the function signature error.
502 if (inferRetType && type && !type.nextOf())
503 return functionSemantic3();
505 TemplateInstance ti;
506 if (isInstantiated() && !isVirtualMethod() &&
507 ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident))
509 AggregateDeclaration ad = isMemberLocal();
510 if (ad && ad.sizeok != Sizeok.done)
512 /* Currently dmd cannot resolve forward references per methods,
513 * then setting SIZOKfwd is too conservative and would break existing code.
514 * So, just stop method attributes inference until ad.dsymbolSemantic() done.
516 //ad.sizeok = Sizeok.fwd;
518 else
519 return functionSemantic3() || !errors;
522 if (storage_class & STC.inference)
523 return functionSemantic3() || !errors;
525 return !errors;
528 /****************************************************
529 * Resolve forward reference of function body.
530 * Returns false if any errors exist in the body.
532 final bool functionSemantic3()
534 if (semanticRun < PASS.semantic3 && _scope)
536 /* Forward reference - we need to run semantic3 on this function.
537 * If errors are gagged, and it's not part of a template instance,
538 * we need to temporarily ungag errors.
540 TemplateInstance spec = isSpeculative();
541 uint olderrs = global.errors;
542 uint oldgag = global.gag;
543 if (global.gag && !spec)
544 global.gag = 0;
545 semantic3(this, _scope);
546 global.gag = oldgag;
548 // If it is a speculatively-instantiated template, and errors occur,
549 // we need to mark the template as having errors.
550 if (spec && global.errors != olderrs)
551 spec.errors = (global.errors - olderrs != 0);
552 if (olderrs != global.errors) // if errors compiling this function
553 return false;
556 return !errors && !this.hasSemantic3Errors();
559 /****************************************************
560 * Check that this function type is properly resolved.
561 * If not, report "forward reference error" and return true.
563 extern (D) final bool checkForwardRef(const ref Loc loc)
565 if (!functionSemantic())
566 return true;
568 /* No deco means the functionSemantic() call could not resolve
569 * forward referenes in the type of this function.
571 if (!type.deco)
573 bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3);
574 .error(loc, "forward reference to %s`%s`",
575 (inSemantic3 ? "inferred return type of function " : "").ptr,
576 toChars());
577 return true;
579 return false;
582 // called from semantic3
584 * Creates and returns the hidden parameters for this function declaration.
586 * Hidden parameters include the `this` parameter of a class, struct or
587 * nested function and the selector parameter for Objective-C methods.
589 extern (D) final void declareThis(Scope* sc)
591 const bool dualCtx = (toParent2() != toParentLocal());
592 if (dualCtx)
593 this.hasDualContext = true;
594 auto ad = isThis();
595 if (!dualCtx && !ad && !isNested())
597 vthis = null;
598 objc.selectorParameter = null;
599 return;
602 Type addModStc(Type t)
604 return t.addMod(type.mod).addStorageClass(storage_class);
607 if (dualCtx || isNested())
609 /* The 'this' for a nested function is the link to the
610 * enclosing function's stack frame.
611 * Note that nested functions and member functions are disjoint.
613 Type tthis = addModStc(dualCtx ?
614 Type.tvoidptr.sarrayOf(2).pointerTo() :
615 Type.tvoid.pointerTo());
616 vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null);
617 vthis.storage_class |= STC.parameter | STC.nodtor;
619 else if (ad)
621 Type thandle = addModStc(ad.handleType());
622 vthis = new ThisDeclaration(loc, thandle);
623 vthis.storage_class |= STC.parameter;
624 if (thandle.ty == Tstruct)
626 vthis.storage_class |= STC.ref_;
630 if (auto tf = type.isTypeFunction())
632 if (tf.isreturn)
633 vthis.storage_class |= STC.return_;
634 if (tf.isScopeQual)
635 vthis.storage_class |= STC.scope_;
636 if (tf.isreturnscope)
637 vthis.storage_class |= STC.returnScope;
640 vthis.dsymbolSemantic(sc);
641 if (!sc.insert(vthis))
642 assert(0);
643 vthis.parent = this;
644 if (ad)
645 objc.selectorParameter = .objc.createSelectorParameter(this, sc);
648 override final bool equals(const RootObject o) const
650 if (this == o)
651 return true;
653 if (auto s = isDsymbol(o))
655 auto fd1 = this;
656 auto fd2 = s.isFuncDeclaration();
657 if (!fd2)
658 return false;
660 auto fa1 = fd1.isFuncAliasDeclaration();
661 auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
663 auto fa2 = fd2.isFuncAliasDeclaration();
664 auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
666 if (fa1 && fa2)
668 return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
671 bool b1 = fa1 !is null;
672 if (b1 && faf1.isUnique() && !fa1.hasOverloads)
673 b1 = false;
675 bool b2 = fa2 !is null;
676 if (b2 && faf2.isUnique() && !fa2.hasOverloads)
677 b2 = false;
679 if (b1 != b2)
680 return false;
682 return faf1.toParent().equals(faf2.toParent()) &&
683 faf1.ident.equals(faf2.ident) &&
684 faf1.type.equals(faf2.type);
686 return false;
689 /****************************************************
690 * Determine if 'this' overrides fd.
691 * Return !=0 if it does.
693 extern (D) final int overrides(FuncDeclaration fd)
695 int result = 0;
696 if (fd.ident == ident)
698 import dmd.typesem : covariant;
699 const cov = type.covariant(fd.type);
700 if (cov != Covariant.distinct)
702 ClassDeclaration cd1 = toParent().isClassDeclaration();
703 ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
704 if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
705 result = 1;
708 return result;
711 /*************************************************
712 * Find index of function in vtbl[0..length] that
713 * this function overrides.
714 * Prefer an exact match to a covariant one.
715 * Params:
716 * vtbl = vtable to use
717 * dim = maximal vtable dimension
718 * Returns:
719 * -1 didn't find one
720 * -2 can't determine because of forward references
722 final int findVtblIndex(Dsymbols* vtbl, int dim)
724 //printf("findVtblIndex() %s\n", toChars());
725 import dmd.typesem : covariant;
727 FuncDeclaration mismatch = null;
728 StorageClass mismatchstc = 0;
729 int mismatchvi = -1;
730 int exactvi = -1;
731 int bestvi = -1;
732 for (int vi = 0; vi < dim; vi++)
734 FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration();
735 if (fdv && fdv.ident == ident)
737 if (type.equals(fdv.type)) // if exact match
739 if (fdv.parent.isClassDeclaration())
741 if (fdv.isFuture())
743 bestvi = vi;
744 continue; // keep looking
746 return vi; // no need to look further
749 if (exactvi >= 0)
751 .error(loc, "%s `%s` cannot determine overridden function", kind, toPrettyChars);
752 return exactvi;
754 exactvi = vi;
755 bestvi = vi;
756 continue;
759 StorageClass stc = 0;
760 const cov = type.covariant(fdv.type, &stc);
761 //printf("\tbaseclass cov = %d\n", cov);
762 final switch (cov)
764 case Covariant.distinct:
765 // types are distinct
766 break;
768 case Covariant.yes:
769 bestvi = vi; // covariant, but not identical
770 break;
771 // keep looking for an exact match
773 case Covariant.no:
774 mismatchvi = vi;
775 mismatchstc = stc;
776 mismatch = fdv; // overrides, but is not covariant
777 break;
778 // keep looking for an exact match
780 case Covariant.fwdref:
781 return -2; // forward references
785 if (_linkage == LINK.cpp && bestvi != -1)
787 StorageClass stc = 0;
788 FuncDeclaration fdv = (*vtbl)[bestvi].isFuncDeclaration();
789 assert(fdv && fdv.ident == ident);
790 if (type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no)
792 /* https://issues.dlang.org/show_bug.cgi?id=22351
793 * Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not.
794 * For now, continue to allow D covariant rules to apply when `override` has been used,
795 * but issue a deprecation warning that this behaviour will change in the future.
796 * Otherwise, follow the C++ covariant rules, which will create a new vtable entry.
798 if (isOverride())
800 /* @@@DEPRECATED_2.110@@@
801 * After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch,
802 * but also the `cppCovariant` parameter from Type.covariant, and update the function
803 * so that both `LINK.cpp` covariant conditions within are always checked.
805 .deprecation(loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated",
806 fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(),
807 toPrettyChars(), type.toTypeFunction().parameterList.parametersTypeToChars(), type.modToChars());
809 const char* where = type.isNaked() ? "parameters" : "type";
810 deprecationSupplemental(loc, "Either remove `override`, or adjust the `const` qualifiers of the "
811 ~ "overriding function %s", where);
813 else
815 // Treat as if Covariant.no
816 mismatchvi = bestvi;
817 mismatchstc = stc;
818 mismatch = fdv;
819 bestvi = -1;
823 if (bestvi == -1 && mismatch)
825 //type.print();
826 //mismatch.type.print();
827 //printf("%s %s\n", type.deco, mismatch.type.deco);
828 //printf("stc = %llx\n", mismatchstc);
829 if (mismatchstc)
831 // Fix it by modifying the type to add the storage classes
832 type = type.addStorageClass(mismatchstc);
833 bestvi = mismatchvi;
836 return bestvi;
839 /*********************************
840 * If function a function in a base class,
841 * return that base class.
842 * Returns:
843 * base class if overriding, null if not
845 extern (D) final BaseClass* overrideInterface()
847 for (ClassDeclaration cd = toParent2().isClassDeclaration(); cd; cd = cd.baseClass)
849 foreach (b; cd.interfaces)
851 auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length);
852 if (v >= 0)
853 return b;
856 return null;
859 /****************************************************
860 * Overload this FuncDeclaration with the new one f.
861 * Return true if successful; i.e. no conflict.
863 override bool overloadInsert(Dsymbol s)
865 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
866 assert(s != this);
867 AliasDeclaration ad = s.isAliasDeclaration();
868 if (ad)
870 if (overnext)
871 return overnext.overloadInsert(ad);
872 if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof)
874 //printf("\tad = '%s'\n", ad.type.toChars());
875 return false;
877 overnext = ad;
878 //printf("\ttrue: no conflict\n");
879 return true;
881 TemplateDeclaration td = s.isTemplateDeclaration();
882 if (td)
884 if (!td.funcroot)
885 td.funcroot = this;
886 if (overnext)
887 return overnext.overloadInsert(td);
888 overnext = td;
889 return true;
891 FuncDeclaration fd = s.isFuncDeclaration();
892 if (!fd)
893 return false;
895 version (none)
897 /* Disable this check because:
898 * const void foo();
899 * semantic() isn't run yet on foo(), so the const hasn't been
900 * applied yet.
902 if (type)
904 printf("type = %s\n", type.toChars());
905 printf("fd.type = %s\n", fd.type.toChars());
907 // fd.type can be NULL for overloaded constructors
908 if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
910 //printf("\tfalse: conflict %s\n", kind());
911 return false;
915 if (overnext)
917 td = overnext.isTemplateDeclaration();
918 if (td)
919 fd.overloadInsert(td);
920 else
921 return overnext.overloadInsert(fd);
923 overnext = fd;
924 //printf("\ttrue: no conflict\n");
925 return true;
928 /********************************************
929 * Find function in overload list that exactly matches t.
931 extern (D) final FuncDeclaration overloadExactMatch(Type t)
933 FuncDeclaration fd;
934 overloadApply(this, (Dsymbol s)
936 auto f = s.isFuncDeclaration();
937 if (!f)
938 return 0;
939 if (f.storage_class & STC.disable)
940 return 0;
941 if (t.equals(f.type))
943 fd = f;
944 return 1;
947 /* Allow covariant matches, as long as the return type
948 * is just a const conversion.
949 * This allows things like pure functions to match with an impure function type.
951 if (t.ty == Tfunction)
953 import dmd.typesem : covariant;
954 auto tf = cast(TypeFunction)f.type;
955 if (tf.covariant(t) == Covariant.yes &&
956 tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
958 fd = f;
959 return 1;
962 return 0;
964 return fd;
967 /********************************************
968 * Find function in overload list that matches to the 'this' modifier.
969 * There's four result types.
971 * 1. If the 'tthis' matches only one candidate, it's an "exact match".
972 * Returns the function and 'hasOverloads' is set to false.
973 * eg. If 'tthis" is mutable and there's only one mutable method.
974 * 2. If there's two or more match candidates, but a candidate function will be
975 * a "better match".
976 * Returns the better match function but 'hasOverloads' is set to true.
977 * eg. If 'tthis' is mutable, and there's both mutable and const methods,
978 * the mutable method will be a better match.
979 * 3. If there's two or more match candidates, but there's no better match,
980 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
981 * eg. If 'tthis' is mutable, and there's two or more mutable methods.
982 * 4. If there's no candidates, it's "no match" and returns null with error report.
983 * e.g. If 'tthis' is const but there's no const methods.
985 extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
987 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
988 MatchAccumulator m;
989 overloadApply(this, (Dsymbol s)
991 auto f = s.isFuncDeclaration();
992 if (!f || f == m.lastf) // skip duplicates
993 return 0;
995 auto tf = f.type.toTypeFunction();
996 //printf("tf = %s\n", tf.toChars());
998 MATCH match;
999 if (tthis) // non-static functions are preferred than static ones
1001 if (f.needThis())
1002 match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
1003 else
1004 match = MATCH.constant; // keep static function in overload candidates
1006 else // static functions are preferred than non-static ones
1008 if (f.needThis())
1009 match = MATCH.convert;
1010 else
1011 match = MATCH.exact;
1013 if (match == MATCH.nomatch)
1014 return 0;
1016 if (match > m.last) goto LcurrIsBetter;
1017 if (match < m.last) goto LlastIsBetter;
1019 // See if one of the matches overrides the other.
1020 if (m.lastf.overrides(f)) goto LlastIsBetter;
1021 if (f.overrides(m.lastf)) goto LcurrIsBetter;
1023 //printf("\tambiguous\n");
1024 m.nextf = f;
1025 m.count++;
1026 return 0;
1028 LlastIsBetter:
1029 //printf("\tlastbetter\n");
1030 m.count++; // count up
1031 return 0;
1033 LcurrIsBetter:
1034 //printf("\tisbetter\n");
1035 if (m.last <= MATCH.convert)
1037 // clear last secondary matching
1038 m.nextf = null;
1039 m.count = 0;
1041 m.last = match;
1042 m.lastf = f;
1043 m.count++; // count up
1044 return 0;
1047 if (m.count == 1) // exact match
1049 hasOverloads = false;
1051 else if (m.count > 1) // better or ambiguous match
1053 hasOverloads = true;
1055 else // no match
1057 hasOverloads = true;
1058 auto tf = this.type.toTypeFunction();
1059 assert(tthis);
1060 assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
1062 OutBuffer thisBuf, funcBuf;
1063 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
1064 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
1065 .error(loc, "%smethod %s is not callable using a %sobject", kind, toPrettyChars,
1066 funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
1069 return m.lastf;
1072 /********************************************
1073 * find function template root in overload list
1075 extern (D) final TemplateDeclaration findTemplateDeclRoot()
1077 FuncDeclaration f = this;
1078 while (f && f.overnext)
1080 //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
1081 TemplateDeclaration td = f.overnext.isTemplateDeclaration();
1082 if (td)
1083 return td;
1084 f = f.overnext.isFuncDeclaration();
1086 return null;
1089 /********************************************
1090 * Returns true if function was declared
1091 * directly or indirectly in a unittest block
1093 final bool inUnittest()
1095 Dsymbol f = this;
1098 if (f.isUnitTestDeclaration())
1099 return true;
1100 f = f.toParent();
1102 while (f);
1103 return false;
1106 /*************************************
1107 * Determine partial specialization order of 'this' vs g.
1108 * This is very similar to TemplateDeclaration::leastAsSpecialized().
1109 * Returns:
1110 * match 'this' is at least as specialized as g
1111 * 0 g is more specialized than 'this'
1113 final MATCH leastAsSpecialized(FuncDeclaration g, Identifiers* names)
1115 enum LOG_LEASTAS = 0;
1116 static if (LOG_LEASTAS)
1118 import core.stdc.stdio : printf;
1119 printf("%s.leastAsSpecialized(%s, %s)\n", toChars(), g.toChars(), names ? names.toChars() : "null");
1120 printf("%s, %s\n", type.toChars(), g.type.toChars());
1123 /* This works by calling g() with f()'s parameters, and
1124 * if that is possible, then f() is at least as specialized
1125 * as g() is.
1128 TypeFunction tf = type.toTypeFunction();
1129 TypeFunction tg = g.type.toTypeFunction();
1131 /* If both functions have a 'this' pointer, and the mods are not
1132 * the same and g's is not const, then this is less specialized.
1134 if (needThis() && g.needThis() && tf.mod != tg.mod)
1136 if (isCtorDeclaration())
1138 if (!MODimplicitConv(tg.mod, tf.mod))
1139 return MATCH.nomatch;
1141 else
1143 if (!MODimplicitConv(tf.mod, tg.mod))
1144 return MATCH.nomatch;
1148 /* Create a dummy array of arguments out of the parameters to f()
1150 Expressions args;
1151 foreach (u, p; tf.parameterList)
1153 Expression e;
1154 if (p.isReference())
1156 e = new IdentifierExp(Loc.initial, p.ident);
1157 e.type = p.type;
1159 else
1160 e = p.type.defaultInitLiteral(Loc.initial);
1161 args.push(e);
1164 import dmd.typesem : callMatch;
1165 MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
1166 if (m > MATCH.nomatch)
1168 /* A variadic parameter list is less specialized than a
1169 * non-variadic one.
1171 if (tf.parameterList.varargs && !tg.parameterList.varargs)
1172 goto L1; // less specialized
1174 static if (LOG_LEASTAS)
1176 printf(" matches %d, so is least as specialized\n", m);
1178 return m;
1181 static if (LOG_LEASTAS)
1183 printf(" doesn't match, so is not as specialized\n");
1185 return MATCH.nomatch;
1188 /********************************
1189 * Searches for a label with the given identifier. This function will insert a new
1190 * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
1192 * Params:
1193 * ident = identifier of the requested label
1194 * loc = location used when creating a new `LabelDsymbol`
1196 * Returns: the `LabelDsymbol` for `ident`
1198 final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial)
1200 Dsymbol s;
1201 if (!labtab)
1202 labtab = new DsymbolTable(); // guess we need one
1204 s = labtab.lookup(ident);
1205 if (!s)
1207 s = new LabelDsymbol(ident, loc);
1208 labtab.insert(s);
1210 return cast(LabelDsymbol)s;
1213 /*****************************************
1214 * Determine lexical level difference from `this` to nested function `fd`.
1215 * Params:
1216 * fd = target of call
1217 * intypeof = !=0 if inside typeof
1218 * Returns:
1219 * 0 same level
1220 * >0 decrease nesting by number
1221 * -1 increase nesting by 1 (`fd` is nested within `this`)
1222 * LevelError error, `this` cannot call `fd`
1224 extern (D) final int getLevel(FuncDeclaration fd, int intypeof)
1226 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
1227 Dsymbol fdparent = fd.toParent2();
1228 if (fdparent == this)
1229 return -1;
1231 Dsymbol s = this;
1232 int level = 0;
1233 while (fd != s && fdparent != s.toParent2())
1235 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
1236 if (auto thisfd = s.isFuncDeclaration())
1238 if (!thisfd.isNested() && !thisfd.vthis && !intypeof)
1239 return LevelError;
1241 else
1243 if (auto thiscd = s.isAggregateDeclaration())
1245 /* AggregateDeclaration::isNested returns true only when
1246 * it has a hidden pointer.
1247 * But, calling the function belongs unrelated lexical scope
1248 * is still allowed inside typeof.
1250 * struct Map(alias fun) {
1251 * typeof({ return fun(); }) RetType;
1252 * // No member function makes Map struct 'not nested'.
1255 if (!thiscd.isNested() && !intypeof)
1256 return LevelError;
1258 else
1259 return LevelError;
1262 s = s.toParentP(fd);
1263 assert(s);
1264 level++;
1266 return level;
1269 /***********************************
1270 * Determine lexical level difference from `this` to nested function `fd`.
1271 * Issue error if `this` cannot call `fd`.
1273 * Params:
1274 * loc = location for error messages
1275 * sc = context
1276 * fd = target of call
1277 * decl = The `Declaration` that triggered this check.
1278 * Used to provide a better error message only.
1279 * Returns:
1280 * 0 same level
1281 * >0 decrease nesting by number
1282 * -1 increase nesting by 1 (`fd` is nested within 'this')
1283 * LevelError error
1285 extern (D) final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd,
1286 Declaration decl)
1288 int level = getLevel(fd, sc.intypeof);
1289 if (level != LevelError)
1290 return level;
1292 // Don't give error if in template constraint
1293 if (!(sc.flags & SCOPE.constraint))
1295 const(char)* xstatic = isStatic() ? "`static` " : "";
1296 // better diagnostics for static functions
1297 .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
1298 xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(),
1299 fd.toPrettyChars());
1300 .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
1301 return LevelError;
1303 return 1;
1306 enum LevelError = -2;
1308 override const(char)* toPrettyChars(bool QualifyTypes = false)
1310 if (isMain())
1311 return "D main";
1312 else
1313 return Dsymbol.toPrettyChars(QualifyTypes);
1316 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
1317 final const(char)* toFullSignature()
1319 OutBuffer buf;
1320 functionToBufferWithIdent(type.toTypeFunction(), buf, toChars(), isStatic);
1321 return buf.extractChars();
1324 final bool isMain() const
1326 return ident == Id.main && resolvedLinkage() != LINK.c && !isMember() && !isNested();
1329 final bool isCMain() const
1331 return ident == Id.main && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1334 final bool isWinMain() const
1336 //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1337 version (none)
1339 bool x = ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1340 printf("%s\n", x ? "yes" : "no");
1341 return x;
1343 else
1345 return ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1349 final bool isDllMain() const
1351 return ident == Id.DllMain && resolvedLinkage() != LINK.c && !isMember();
1354 final bool isRtInit() const
1356 return ident == Id.rt_init && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1359 override final bool isExport() const
1361 return visibility.kind == Visibility.Kind.export_ || dllExport;
1364 override final bool isImportedSymbol() const
1366 //printf("isImportedSymbol()\n");
1367 //printf("protection = %d\n", visibility);
1368 return (visibility.kind == Visibility.Kind.export_ || dllImport) && !fbody;
1371 override final bool isCodeseg() const pure nothrow @nogc @safe
1373 return true; // functions are always in the code segment
1376 override final bool isOverloadable() const
1378 return true; // functions can be overloaded
1381 /***********************************
1382 * Override so it can work even if semantic() hasn't yet
1383 * been run.
1385 override final bool isAbstract()
1387 if (storage_class & STC.abstract_)
1388 return true;
1389 if (semanticRun >= PASS.semanticdone)
1390 return false;
1392 if (_scope)
1394 if (_scope.stc & STC.abstract_)
1395 return true;
1396 parent = _scope.parent;
1397 Dsymbol parent = toParent();
1398 if (parent.isInterfaceDeclaration())
1399 return true;
1401 return false;
1404 /**********************************
1405 * Decide if attributes for this function can be inferred from examining
1406 * the function body.
1407 * Returns:
1408 * true if can
1410 final bool canInferAttributes(Scope* sc)
1412 if (!fbody)
1413 return false;
1415 if (isVirtualMethod() &&
1417 * https://issues.dlang.org/show_bug.cgi?id=21719
1419 * If we have an auto virtual function we can infer
1420 * the attributes.
1422 !(inferRetType && !isCtorDeclaration()))
1423 return false; // since they may be overridden
1425 if (sc.func &&
1426 /********** this is for backwards compatibility for the moment ********/
1427 (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
1428 return true;
1430 if (isFuncLiteralDeclaration() || // externs are not possible with literals
1431 (storage_class & STC.inference) || // do attribute inference
1432 (inferRetType && !isCtorDeclaration()))
1433 return true;
1435 if (isInstantiated())
1437 auto ti = parent.isTemplateInstance();
1438 if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
1439 return true;
1442 return false;
1445 /*****************************************
1446 * Initialize for inferring the attributes of this function.
1448 final void initInferAttributes()
1450 //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1451 TypeFunction tf = type.toTypeFunction();
1452 if (tf.purity == PURE.impure) // purity not specified
1453 purityInprocess = true;
1455 if (tf.trust == TRUST.default_)
1456 safetyInprocess = true;
1458 if (!tf.isnothrow)
1459 nothrowInprocess = true;
1461 if (!tf.isnogc)
1462 nogcInprocess = true;
1464 if (!isVirtual() || this.isIntroducing())
1465 returnInprocess = true;
1467 // Initialize for inferring STC.scope_
1468 inferScope = true;
1471 final PURE isPure()
1473 //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1474 TypeFunction tf = type.toTypeFunction();
1475 if (purityInprocess)
1476 setImpure();
1477 if (tf.purity == PURE.fwdref)
1478 tf.purityLevel();
1479 PURE purity = tf.purity;
1480 if (purity > PURE.weak && isNested())
1481 purity = PURE.weak;
1482 if (purity > PURE.weak && needThis())
1484 // The attribute of the 'this' reference affects purity strength
1485 if (type.mod & MODFlags.immutable_)
1488 else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
1489 purity = PURE.const_;
1490 else
1491 purity = PURE.weak;
1493 tf.purity = purity;
1494 // ^ This rely on the current situation that every FuncDeclaration has a
1495 // unique TypeFunction.
1496 return purity;
1499 extern (D) final PURE isPureBypassingInference()
1501 if (purityInprocess)
1502 return PURE.fwdref;
1503 else
1504 return isPure();
1507 /**************************************
1508 * The function is doing something impure, so mark it as impure.
1510 * Params:
1511 * loc = location of impure action
1512 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1513 * arg0 = (optional) argument to format string
1515 * Returns: `true` if there's a purity error
1517 extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
1519 if (purityInprocess)
1521 purityInprocess = false;
1522 if (fmt)
1523 pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action
1524 else if (arg0)
1525 pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
1527 if (fes)
1528 fes.func.setImpure(loc, fmt, arg0);
1530 else if (isPure())
1531 return true;
1532 return false;
1535 extern (D) final uint flags()
1537 return bitFields;
1540 extern (D) final uint flags(uint f)
1542 bitFields = f;
1543 return bitFields;
1546 final bool isSafe()
1548 if (safetyInprocess)
1549 setUnsafe();
1550 return type.toTypeFunction().trust == TRUST.safe;
1553 extern (D) final bool isSafeBypassingInference()
1555 return !(safetyInprocess) && isSafe();
1558 final bool isTrusted()
1560 if (safetyInprocess)
1561 setUnsafe();
1562 return type.toTypeFunction().trust == TRUST.trusted;
1565 /**************************************
1566 * The function is doing something unsafe, so mark it as unsafe.
1568 * Params:
1569 * gag = surpress error message (used in escape.d)
1570 * loc = location of error
1571 * fmt = printf-style format string
1572 * arg0 = (optional) argument for first %s format specifier
1573 * arg1 = (optional) argument for second %s format specifier
1574 * arg2 = (optional) argument for third %s format specifier
1575 * Returns: whether there's a safe error
1577 extern (D) final bool setUnsafe(
1578 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
1579 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
1581 if (safetyInprocess)
1583 safetyInprocess = false;
1584 type.toTypeFunction().trust = TRUST.system;
1585 if (fmt || arg0)
1586 safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);
1588 if (fes)
1589 fes.func.setUnsafe();
1591 else if (isSafe())
1593 if (!gag && fmt)
1594 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
1596 return true;
1598 return false;
1601 /**************************************
1602 * The function is calling `@system` function `f`, so mark it as unsafe.
1604 * Params:
1605 * f = function being called (needed for diagnostic of inferred functions)
1606 * Returns: whether there's a safe error
1608 extern (D) final bool setUnsafeCall(FuncDeclaration f)
1610 return setUnsafe(false, f.loc, null, f, null);
1613 final bool isNogc()
1615 //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1616 if (nogcInprocess)
1617 setGC(loc, null);
1618 return type.toTypeFunction().isnogc;
1621 extern (D) final bool isNogcBypassingInference()
1623 return !nogcInprocess && isNogc();
1626 /**************************************
1627 * The function is doing something that may allocate with the GC,
1628 * so mark it as not nogc (not no-how).
1630 * Params:
1631 * loc = location of impure action
1632 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1633 * arg0 = (optional) argument to format string
1635 * Returns:
1636 * true if function is marked as @nogc, meaning a user error occurred
1638 extern (D) final bool setGC(Loc loc, const(char)* fmt, RootObject arg0 = null)
1640 //printf("setGC() %s\n", toChars());
1641 if (nogcInprocess && semanticRun < PASS.semantic3 && _scope)
1643 this.semantic2(_scope);
1644 this.semantic3(_scope);
1647 if (nogcInprocess)
1649 nogcInprocess = false;
1650 if (fmt)
1651 nogcViolation = new AttributeViolation(loc, fmt, this, arg0); // action that requires GC
1652 else if (arg0)
1653 nogcViolation = new AttributeViolation(loc, fmt, arg0); // call to non-@nogc function
1655 type.toTypeFunction().isnogc = false;
1656 if (fes)
1657 fes.func.setGC(Loc.init, null, null);
1659 else if (isNogc())
1660 return true;
1661 return false;
1664 /**************************************
1665 * The function calls non-`@nogc` function f, mark it as not nogc.
1666 * Params:
1667 * f = function being called
1668 * Returns:
1669 * true if function is marked as @nogc, meaning a user error occurred
1671 extern (D) final bool setGCCall(FuncDeclaration f)
1673 return setGC(loc, null, f);
1676 /**************************************
1677 * The function is doing something that may throw an exception, register that in case nothrow is being inferred
1679 * Params:
1680 * loc = location of action
1681 * fmt = format string for error message
1682 * arg0 = (optional) argument to format string
1684 extern (D) final void setThrow(Loc loc, const(char)* fmt, RootObject arg0 = null)
1686 if (nothrowInprocess && !nothrowViolation)
1688 nothrowViolation = new AttributeViolation(loc, fmt, arg0); // action that requires GC
1692 /**************************************
1693 * The function calls non-`nothrow` function f, register that in case nothrow is being inferred
1694 * Params:
1695 * loc = location of call
1696 * f = function being called
1698 extern (D) final void setThrowCall(Loc loc, FuncDeclaration f)
1700 return setThrow(loc, null, f);
1703 extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
1705 if (!global.params.v.gc)
1706 return;
1708 Module m = getModule();
1709 if (m && m.isRoot() && !inUnittest())
1711 message(loc, "vgc: %s", warn);
1715 /********************************************
1716 * See if pointers from function parameters, mutable globals, or uplevel functions
1717 * could leak into return value.
1718 * Returns:
1719 * true if the function return value is isolated from
1720 * any inputs to the function
1722 extern (D) final bool isReturnIsolated()
1724 //printf("isReturnIsolated(this: %s)\n", this.toChars);
1725 TypeFunction tf = type.toTypeFunction();
1726 assert(tf.next);
1728 Type treti = tf.next;
1729 if (tf.isref)
1730 return isTypeIsolatedIndirect(treti); // check influence from parameters
1732 return isTypeIsolated(treti);
1735 /********************
1736 * See if pointers from function parameters, mutable globals, or uplevel functions
1737 * could leak into type `t`.
1738 * Params:
1739 * t = type to check if it is isolated
1740 * Returns:
1741 * true if `t` is isolated from
1742 * any inputs to the function
1744 extern (D) final bool isTypeIsolated(Type t)
1746 StringTable!Type parentTypes;
1747 const uniqueTypeID = t.getUniqueID();
1748 if (uniqueTypeID)
1750 const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
1751 if (cacheResultPtr !is null)
1752 return *cacheResultPtr;
1754 parentTypes._init();
1755 const isIsolated = isTypeIsolated(t, parentTypes);
1756 isTypeIsolatedCache[uniqueTypeID] = isIsolated;
1757 return isIsolated;
1759 else
1761 parentTypes._init();
1762 return isTypeIsolated(t, parentTypes);
1766 ///ditto
1767 extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
1769 //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
1771 t = t.baseElemOf();
1772 switch (t.ty)
1774 case Tarray:
1775 case Tpointer:
1776 return isTypeIsolatedIndirect(t.nextOf()); // go down one level
1778 case Taarray:
1779 case Tclass:
1780 return isTypeIsolatedIndirect(t);
1782 case Tstruct:
1783 /* Drill down and check the struct's fields
1785 auto sym = t.toDsymbol(null).isStructDeclaration();
1786 const tName = t.toChars.toDString;
1787 const entry = parentTypes.insert(tName, t);
1788 if (entry == null)
1790 //we've already seen this type in a parent, not isolated
1791 return false;
1793 foreach (v; sym.fields)
1795 Type tmi = v.type.addMod(t.mod);
1796 //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
1797 // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
1798 if (!isTypeIsolated(tmi, parentTypes))
1799 return false;
1801 return true;
1803 default:
1804 return true;
1808 /********************************************
1809 * Params:
1810 * t = type of object to test one level of indirection down
1811 * Returns:
1812 * true if an object typed `t` has no indirections
1813 * which could have come from the function's parameters, mutable
1814 * globals, or uplevel functions.
1816 private bool isTypeIsolatedIndirect(Type t)
1818 //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1819 assert(t);
1821 /* Since `t` is one level down from an indirection, it could pick
1822 * up a reference to a mutable global or an outer function, so
1823 * return false.
1825 if (!isPureBypassingInference() || isNested())
1826 return false;
1828 TypeFunction tf = type.toTypeFunction();
1830 //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1832 foreach (i, fparam; tf.parameterList)
1834 Type tp = fparam.type;
1835 if (!tp)
1836 continue;
1838 if (fparam.isLazy() || fparam.isReference())
1840 if (!traverseIndirections(tp, t))
1841 return false;
1842 continue;
1845 /* Goes down one level of indirection, then calls traverseIndirection() on
1846 * the result.
1847 * Returns:
1848 * true if t is isolated from tp
1850 static bool traverse(Type tp, Type t)
1852 tp = tp.baseElemOf();
1853 switch (tp.ty)
1855 case Tarray:
1856 case Tpointer:
1857 return traverseIndirections(tp.nextOf(), t);
1859 case Taarray:
1860 case Tclass:
1861 return traverseIndirections(tp, t);
1863 case Tstruct:
1864 /* Drill down and check the struct's fields
1866 auto sym = tp.toDsymbol(null).isStructDeclaration();
1867 foreach (v; sym.fields)
1869 Type tprmi = v.type.addMod(tp.mod);
1870 //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1871 if (!traverse(tprmi, t))
1872 return false;
1874 return true;
1876 default:
1877 return true;
1881 if (!traverse(tp, t))
1882 return false;
1884 // The 'this' reference is a parameter, too
1885 if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
1887 Type tthis = ad.getType().addMod(tf.mod);
1888 //printf("\ttthis = %s\n", tthis.toChars());
1889 if (!traverseIndirections(tthis, t))
1890 return false;
1893 return true;
1896 /****************************************
1897 * Determine if function needs a static frame pointer.
1898 * Returns:
1899 * `true` if function is really nested within other function.
1900 * Contracts:
1901 * If isNested() returns true, isThis() should return false,
1902 * unless the function needs a dual-context pointer.
1904 bool isNested() const
1906 auto f = toAliasFunc();
1907 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1908 return ((f.storage_class & STC.static_) == 0) &&
1909 (f._linkage == LINK.d) &&
1910 (f.toParent2().isFuncDeclaration() !is null ||
1911 f.toParent2() !is f.toParentLocal());
1914 /****************************************
1915 * Determine if function is a non-static member function
1916 * that has an implicit 'this' expression.
1917 * Returns:
1918 * The aggregate it is a member of, or null.
1919 * Contracts:
1920 * Both isThis() and isNested() should return true if function needs a dual-context pointer,
1921 * otherwise if isThis() returns true, isNested() should return false.
1923 override inout(AggregateDeclaration) isThis() inout
1925 //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1926 auto ad = (storage_class & STC.static_) ? .objc.isThis(this) : isMemberLocal();
1927 //printf("-FuncDeclaration::isThis() %p\n", ad);
1928 return ad;
1931 override final bool needThis()
1933 //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1934 return toAliasFunc().isThis() !is null;
1937 // Determine if a function is pedantically virtual
1938 final bool isVirtualMethod()
1940 if (toAliasFunc() != this)
1941 return toAliasFunc().isVirtualMethod();
1943 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1944 if (!isVirtual())
1945 return false;
1946 // If it's a final method, and does not override anything, then it is not virtual
1947 if (isFinalFunc() && foverrides.length == 0)
1949 return false;
1951 return true;
1954 // Determine if function goes into virtual function pointer table
1955 bool isVirtual() const
1957 if (toAliasFunc() != this)
1958 return toAliasFunc().isVirtual();
1960 auto p = toParent();
1962 if (!isMember || !p.isClassDeclaration)
1963 return false;
1965 if (p.isClassDeclaration.classKind == ClassKind.objc)
1966 return .objc.isVirtual(this);
1968 version (none)
1970 printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1971 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), visibility == Visibility.Kind.private_, isCtorDeclaration(), linkage != LINK.d);
1972 printf("result is %d\n", isMember() && !(isStatic() || visibility == Visibility.Kind.private_ || visibility == Visibility.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()));
1974 return !(isStatic() || visibility.kind == Visibility.Kind.private_ || visibility.kind == Visibility.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc());
1977 final bool isFinalFunc() const
1979 if (toAliasFunc() != this)
1980 return toAliasFunc().isFinalFunc();
1982 version (none)
1984 auto cd = toParent().isClassDeclaration();
1985 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal());
1986 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_));
1987 printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_)));
1988 if (cd)
1989 printf("\tmember of %s\n", cd.toChars());
1991 if (!isMember())
1992 return false;
1993 if (Declaration.isFinal())
1994 return true;
1995 auto cd = toParent().isClassDeclaration();
1996 return (cd !is null) && (cd.storage_class & STC.final_);
1999 bool addPreInvariant()
2001 auto ad = isThis();
2002 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
2003 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());
2006 bool addPostInvariant()
2008 auto ad = isThis();
2009 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
2010 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());
2013 override const(char)* kind() const
2015 return this.isGenerated() ? "generated function" : "function";
2018 /********************************************
2019 * Returns:
2020 * true if there are no overloads of this function
2022 final bool isUnique() const
2024 bool result = false;
2025 overloadApply(cast() this, (Dsymbol s)
2027 auto f = s.isFuncDeclaration();
2028 auto td = s.isTemplateDeclaration();
2029 if (!f && !td)
2030 return 0;
2031 if (result)
2033 result = false;
2034 return 1; // ambiguous, done
2036 else
2038 result = true;
2039 return 0;
2042 return result;
2045 /*********************************************
2046 * In the current function, we are calling 'this' function.
2047 * 1. Check to see if the current function can call 'this' function, issue error if not.
2048 * 2. If the current function is not the parent of 'this' function, then add
2049 * the current function to the list of siblings of 'this' function.
2050 * 3. If the current function is a literal, and it's accessing an uplevel scope,
2051 * then mark it as a delegate.
2052 * Returns true if error occurs.
2054 extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
2056 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
2058 if (auto fld = this.isFuncLiteralDeclaration())
2060 if (fld.tok == TOK.reserved)
2062 fld.tok = TOK.function_;
2063 fld.vthis = null;
2067 if (!parent || parent == sc.parent)
2068 return false;
2069 if (ident == Id.require || ident == Id.ensure)
2070 return false;
2071 if (!isThis() && !isNested())
2072 return false;
2074 // The current function
2075 FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
2076 if (!fdthis)
2077 return false; // out of function scope
2079 Dsymbol p = toParentLocal();
2080 Dsymbol p2 = toParent2();
2082 // Function literals from fdthis to p must be delegates
2083 ensureStaticLinkTo(fdthis, p);
2084 if (p != p2)
2085 ensureStaticLinkTo(fdthis, p2);
2087 if (isNested())
2089 // The function that this function is in
2090 bool checkEnclosing(FuncDeclaration fdv)
2092 if (!fdv)
2093 return false;
2094 if (fdv == fdthis)
2095 return false;
2097 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
2098 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
2099 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
2101 // Add this function to the list of those which called us
2102 if (fdthis != this)
2104 bool found = false;
2105 for (size_t i = 0; i < siblingCallers.length; ++i)
2107 if (siblingCallers[i] == fdthis)
2108 found = true;
2110 if (!found)
2112 //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
2113 if (!sc.intypeof && !(sc.flags & SCOPE.compile))
2115 siblingCallers.push(fdthis);
2116 computedEscapingSiblings = false;
2121 const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this);
2122 if (lv == LevelError)
2123 return true; // error
2124 if (lv == -1)
2125 return false; // downlevel call
2126 if (lv == 0)
2127 return false; // same level call
2129 return false; // Uplevel call
2132 if (checkEnclosing(p.isFuncDeclaration()))
2133 return true;
2134 if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
2135 return true;
2137 return false;
2140 /*******************************
2141 * Look at all the variables in this function that are referenced
2142 * by nested functions, and determine if a closure needs to be
2143 * created for them.
2145 final bool needsClosure()
2147 /* Need a closure for all the closureVars[] if any of the
2148 * closureVars[] are accessed by a
2149 * function that escapes the scope of this function.
2150 * We take the conservative approach and decide that a function needs
2151 * a closure if it:
2152 * 1) is a virtual function
2153 * 2) has its address taken
2154 * 3) has a parent that escapes
2155 * 4) calls another nested function that needs a closure
2157 * Note that since a non-virtual function can be called by
2158 * a virtual one, if that non-virtual function accesses a closure
2159 * var, the closure still has to be taken. Hence, we check for isThis()
2160 * instead of isVirtual(). (thanks to David Friedman)
2162 * When the function returns a local struct or class, `requiresClosure`
2163 * is already set to `true` upon entering this function when the
2164 * struct/class refers to a local variable and a closure is needed.
2166 //printf("FuncDeclaration::needsClosure() %s\n", toPrettyChars());
2168 if (requiresClosure)
2169 goto Lyes;
2171 for (size_t i = 0; i < closureVars.length; i++)
2173 VarDeclaration v = closureVars[i];
2174 //printf("\tv = %s\n", v.toChars());
2176 for (size_t j = 0; j < v.nestedrefs.length; j++)
2178 FuncDeclaration f = v.nestedrefs[j];
2179 assert(f != this);
2181 /* __require and __ensure will always get called directly,
2182 * so they never make outer functions closure.
2184 if (f.ident == Id.require || f.ident == Id.ensure)
2185 continue;
2187 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
2189 /* Look to see if f escapes. We consider all parents of f within
2190 * this, and also all siblings which call f; if any of them escape,
2191 * so does f.
2192 * Mark all affected functions as requiring closures.
2194 for (Dsymbol s = f; s && s != this; s = s.toParentP(this))
2196 FuncDeclaration fx = s.isFuncDeclaration();
2197 if (!fx)
2198 continue;
2199 if (fx.isThis() || fx.tookAddressOf)
2201 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
2203 /* Mark as needing closure any functions between this and f
2205 markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this);
2207 requiresClosure = true;
2210 /* We also need to check if any sibling functions that
2211 * called us, have escaped. This is recursive: we need
2212 * to check the callers of our siblings.
2214 if (checkEscapingSiblings(fx, this))
2215 requiresClosure = true;
2217 /* https://issues.dlang.org/show_bug.cgi?id=12406
2218 * Iterate all closureVars to mark all descendant
2219 * nested functions that access to the closing context of this function.
2224 if (requiresClosure)
2225 goto Lyes;
2227 return false;
2229 Lyes:
2230 return true;
2233 /***********************************************
2234 * Check that the function contains any closure.
2235 * If it's @nogc, report suitable errors.
2236 * This is mostly consistent with FuncDeclaration::needsClosure().
2238 * Returns:
2239 * true if any errors occur.
2241 extern (C++) final bool checkClosure()
2243 //printf("checkClosure() %s\n", toPrettyChars());
2244 if (!needsClosure())
2245 return false;
2247 if (setGC(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", this))
2249 .error(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", kind, toPrettyChars, toChars());
2250 if (global.gag) // need not report supplemental errors
2251 return true;
2253 else if (!global.params.useGC)
2255 .error(loc, "%s `%s` is `-betterC` yet allocates closure for `%s()` with the GC", kind, toPrettyChars, toChars());
2256 if (global.gag) // need not report supplemental errors
2257 return true;
2259 else
2261 printGCUsage(loc, "using closure causes GC allocation");
2262 return false;
2265 FuncDeclarations a;
2266 foreach (v; closureVars)
2268 foreach (f; v.nestedrefs)
2270 assert(f !is this);
2272 LcheckAncestorsOfANestedRef:
2273 for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
2275 auto fx = s.isFuncDeclaration();
2276 if (!fx)
2277 continue;
2278 if (fx.isThis() ||
2279 fx.tookAddressOf ||
2280 checkEscapingSiblings(fx, this))
2282 foreach (f2; a)
2284 if (f2 == f)
2285 break LcheckAncestorsOfANestedRef;
2287 a.push(f);
2288 .errorSupplemental(f.loc, "%s `%s` closes over variable `%s`",
2289 f.kind, f.toPrettyChars(), v.toChars());
2290 if (v.ident != Id.This)
2291 .errorSupplemental(v.loc, "`%s` declared here", v.toChars());
2293 break LcheckAncestorsOfANestedRef;
2299 return true;
2302 /***********************************************
2303 * Determine if function's variables are referenced by a function
2304 * nested within it.
2306 final bool hasNestedFrameRefs()
2308 if (closureVars.length)
2309 return true;
2311 /* If a virtual function has contracts, assume its variables are referenced
2312 * by those contracts, even if they aren't. Because they might be referenced
2313 * by the overridden or overriding function's contracts.
2314 * This can happen because frequire and fensure are implemented as nested functions,
2315 * and they can be called directly by an overriding function and the overriding function's
2316 * context had better match, or
2317 * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
2319 if (fdrequire || fdensure)
2320 return true;
2322 if (foverrides.length && isVirtualMethod())
2324 for (size_t i = 0; i < foverrides.length; i++)
2326 FuncDeclaration fdv = foverrides[i];
2327 if (fdv.hasNestedFrameRefs())
2328 return true;
2331 return false;
2334 /****************************************************
2335 * Check whether result variable can be built.
2336 * Returns:
2337 * `true` if the function has a return type that
2338 * is different from `void`.
2340 extern (D) private bool canBuildResultVar()
2342 auto f = cast(TypeFunction)type;
2343 return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
2346 /****************************************************
2347 * Declare result variable lazily.
2349 extern (D) final void buildResultVar(Scope* sc, Type tret)
2351 if (!vresult)
2353 Loc loc = fensure ? fensure.loc : this.loc;
2355 /* If inferRetType is true, tret may not be a correct return type yet.
2356 * So, in here it may be a temporary type for vresult, and after
2357 * fbody.dsymbolSemantic() running, vresult.type might be modified.
2359 vresult = new VarDeclaration(loc, tret, Id.result, null);
2360 vresult.storage_class |= STC.nodtor | STC.temp;
2361 if (!isVirtual())
2362 vresult.storage_class |= STC.const_;
2363 vresult.storage_class |= STC.result;
2365 // set before the semantic() for checkNestedReference()
2366 vresult.parent = this;
2369 if (sc && vresult.semanticRun == PASS.initial)
2371 TypeFunction tf = type.toTypeFunction();
2372 if (tf.isref)
2373 vresult.storage_class |= STC.ref_;
2374 vresult.type = tret;
2376 vresult.dsymbolSemantic(sc);
2378 if (!sc.insert(vresult))
2379 .error(loc, "%s `%s` out result %s is already defined", kind, toPrettyChars, vresult.toChars());
2380 assert(vresult.parent == this);
2384 /****************************************************
2385 * Merge into this function the 'in' contracts of all it overrides.
2386 * 'in's are OR'd together, i.e. only one of them needs to pass.
2388 extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
2390 /* If a base function and its override both have an IN contract, then
2391 * only one of them needs to succeed. This is done by generating:
2393 * void derived.in() {
2394 * try {
2395 * base.in();
2397 * catch () {
2398 * ... body of derived.in() ...
2402 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2403 * If base.in() throws, then derived.in()'s body is executed.
2406 foreach (fdv; foverrides)
2408 /* The semantic pass on the contracts of the overridden functions must
2409 * be completed before code generation occurs.
2410 * https://issues.dlang.org/show_bug.cgi?id=3602
2412 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2414 assert(fdv._scope);
2415 Scope* sc = fdv._scope.push();
2416 sc.stc &= ~STC.override_;
2417 fdv.semantic3(sc);
2418 sc.pop();
2421 sf = fdv.mergeFrequire(sf, params);
2422 if (!sf || !fdv.fdrequire)
2423 return null;
2424 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2425 /* Make the call:
2426 * try { __require(params); }
2427 * catch (Throwable) { frequire; }
2429 params = Expression.arraySyntaxCopy(params);
2430 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2431 Statement s2 = new ExpStatement(loc, e);
2433 auto c = new Catch(loc, getThrowable(), null, sf);
2434 c.internalCatch = true;
2435 auto catches = new Catches();
2436 catches.push(c);
2437 sf = new TryCatchStatement(loc, s2, catches);
2439 return sf;
2442 /****************************************************
2443 * Merge into this function the 'in' contracts of all it overrides.
2445 extern (D) final Statement mergeFrequireInclusivePreview(Statement sf, Expressions* params)
2447 /* If a base function and its override both have an IN contract, then
2448 * the override in contract must widen the guarantee of the base contract.
2449 * This is checked by generating:
2451 * void derived.in() {
2452 * try {
2453 * ... body of derived.in() ...
2455 * catch () {
2456 * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
2457 * base.in();
2458 * assert(false, "Logic error: " ~ thr.msg);
2463 foreach (fdv; foverrides)
2465 /* The semantic pass on the contracts of the overridden functions must
2466 * be completed before code generation occurs.
2467 * https://issues.dlang.org/show_bug.cgi?id=3602
2469 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2471 assert(fdv._scope);
2472 Scope* sc = fdv._scope.push();
2473 sc.stc &= ~STC.override_;
2474 fdv.semantic3(sc);
2475 sc.pop();
2478 sf = fdv.mergeFrequireInclusivePreview(sf, params);
2479 if (sf && fdv.fdrequire)
2481 const loc = this.fdrequire.loc;
2483 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2484 /* Make the call:
2485 * try { frequire; }
2486 * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
2488 Identifier id = Identifier.generateId("thr");
2489 params = Expression.arraySyntaxCopy(params);
2490 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2491 Statement s2 = new ExpStatement(loc, e);
2492 // assert(false, ...)
2493 // TODO make this a runtime helper to allow:
2494 // - chaining the original expression
2495 // - nogc concatenation
2496 Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
2497 Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
2499 Statement s3 = new CompoundStatement(loc, s2, fail);
2501 auto c = new Catch(loc, getThrowable(), id, s3);
2502 c.internalCatch = true;
2503 auto catches = new Catches();
2504 catches.push(c);
2505 sf = new TryCatchStatement(loc, sf, catches);
2507 else
2508 return null;
2510 return sf;
2513 /****************************************************
2514 * Determine whether an 'out' contract is declared inside
2515 * the given function or any of its overrides.
2516 * Params:
2517 * fd = the function to search
2518 * Returns:
2519 * true found an 'out' contract
2521 static bool needsFensure(FuncDeclaration fd) @safe
2523 if (fd.fensures)
2524 return true;
2526 foreach (fdv; fd.foverrides)
2528 if (needsFensure(fdv))
2529 return true;
2531 return false;
2534 /****************************************************
2535 * Rewrite contracts as statements.
2537 final void buildEnsureRequire()
2540 if (frequires)
2542 /* in { statements1... }
2543 * in { statements2... }
2544 * ...
2545 * becomes:
2546 * in { { statements1... } { statements2... } ... }
2548 assert(frequires.length);
2549 auto loc = (*frequires)[0].loc;
2550 auto s = new Statements;
2551 foreach (r; *frequires)
2553 s.push(new ScopeStatement(r.loc, r, r.loc));
2555 frequire = new CompoundStatement(loc, s);
2558 if (fensures)
2560 /* out(id1) { statements1... }
2561 * out(id2) { statements2... }
2562 * ...
2563 * becomes:
2564 * out(__result) { { ref id1 = __result; { statements1... } }
2565 * { ref id2 = __result; { statements2... } } ... }
2567 assert(fensures.length);
2568 auto loc = (*fensures)[0].ensure.loc;
2569 auto s = new Statements;
2570 foreach (r; *fensures)
2572 if (r.id && canBuildResultVar())
2574 auto rloc = r.ensure.loc;
2575 auto resultId = new IdentifierExp(rloc, Id.result);
2576 auto init = new ExpInitializer(rloc, resultId);
2577 auto stc = STC.ref_ | STC.temp | STC.result;
2578 auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
2579 auto sdecl = new ExpStatement(rloc, decl);
2580 s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
2582 else
2584 s.push(r.ensure);
2587 fensure = new CompoundStatement(loc, s);
2590 if (!isVirtual())
2591 return;
2593 /* Rewrite contracts as nested functions, then call them. Doing it as nested
2594 * functions means that overriding functions can call them.
2596 TypeFunction f = cast(TypeFunction) type;
2598 /* Make a copy of the parameters and make them all ref */
2599 static Parameters* toRefCopy(ParameterList parameterList)
2601 auto result = new Parameters();
2603 foreach (n, p; parameterList)
2605 p = p.syntaxCopy();
2606 if (!p.isLazy())
2607 p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
2608 p.defaultArg = null; // won't be the same with ref
2609 result.push(p);
2612 return result;
2615 if (frequire)
2617 /* in { ... }
2618 * becomes:
2619 * void __require(ref params) { ... }
2620 * __require(params);
2622 Loc loc = frequire.loc;
2623 fdrequireParams = new Expressions();
2624 if (parameters)
2626 foreach (vd; *parameters)
2627 fdrequireParams.push(new VarExp(loc, vd));
2629 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2630 auto fparams = toRefCopy(fo.parameterList);
2631 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2632 tf.isnothrow = f.isnothrow;
2633 tf.isnogc = f.isnogc;
2634 tf.purity = f.purity;
2635 tf.trust = f.trust;
2636 auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
2637 fd.fbody = frequire;
2638 Statement s1 = new ExpStatement(loc, fd);
2639 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
2640 Statement s2 = new ExpStatement(loc, e);
2641 frequire = new CompoundStatement(loc, s1, s2);
2642 fdrequire = fd;
2645 /* We need to set fdensureParams here and not in the block below to
2646 * have the parameters available when calling a base class ensure(),
2647 * even if this function doesn't have an out contract.
2649 fdensureParams = new Expressions();
2650 if (canBuildResultVar())
2651 fdensureParams.push(new IdentifierExp(loc, Id.result));
2652 if (parameters)
2654 foreach (vd; *parameters)
2655 fdensureParams.push(new VarExp(loc, vd));
2658 if (fensure)
2660 /* out (result) { ... }
2661 * becomes:
2662 * void __ensure(ref tret result, ref params) { ... }
2663 * __ensure(result, params);
2665 Loc loc = fensure.loc;
2666 auto fparams = new Parameters();
2667 if (canBuildResultVar())
2669 Parameter p = new Parameter(loc, STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
2670 fparams.push(p);
2672 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2673 fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
2674 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2675 tf.isnothrow = f.isnothrow;
2676 tf.isnogc = f.isnogc;
2677 tf.purity = f.purity;
2678 tf.trust = f.trust;
2679 auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
2680 fd.fbody = fensure;
2681 Statement s1 = new ExpStatement(loc, fd);
2682 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
2683 Statement s2 = new ExpStatement(loc, e);
2684 fensure = new CompoundStatement(loc, s1, s2);
2685 fdensure = fd;
2689 /****************************************************
2690 * Merge into this function the 'out' contracts of all it overrides.
2691 * 'out's are AND'd together, i.e. all of them need to pass.
2693 extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
2695 /* Same comments as for mergeFrequire(), except that we take care
2696 * of generating a consistent reference to the 'result' local by
2697 * explicitly passing 'result' to the nested function as a reference
2698 * argument.
2699 * This won't work for the 'this' parameter as it would require changing
2700 * the semantic code for the nested function so that it looks on the parameter
2701 * list for the 'this' pointer, something that would need an unknown amount
2702 * of tweaking of various parts of the compiler that I'd rather leave alone.
2704 foreach (fdv; foverrides)
2706 /* The semantic pass on the contracts of the overridden functions must
2707 * be completed before code generation occurs.
2708 * https://issues.dlang.org/show_bug.cgi?id=3602 and
2709 * https://issues.dlang.org/show_bug.cgi?id=5230
2711 if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
2713 assert(fdv._scope);
2714 Scope* sc = fdv._scope.push();
2715 sc.stc &= ~STC.override_;
2716 fdv.semantic3(sc);
2717 sc.pop();
2720 sf = fdv.mergeFensure(sf, oid, params);
2721 if (fdv.fdensure)
2723 //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2724 // Make the call: __ensure(result, params)
2725 params = Expression.arraySyntaxCopy(params);
2726 if (canBuildResultVar())
2728 Type t1 = fdv.type.nextOf().toBasetype();
2729 Type t2 = this.type.nextOf().toBasetype();
2730 if (t1.isBaseOf(t2, null))
2732 /* Making temporary reference variable is necessary
2733 * in covariant return.
2734 * https://issues.dlang.org/show_bug.cgi?id=5204
2735 * https://issues.dlang.org/show_bug.cgi?id=10479
2737 Expression* eresult = &(*params)[0];
2738 auto ei = new ExpInitializer(Loc.initial, *eresult);
2739 auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
2740 v.storage_class |= STC.temp;
2741 auto de = new DeclarationExp(Loc.initial, v);
2742 auto ve = new VarExp(Loc.initial, v);
2743 *eresult = new CommaExp(Loc.initial, de, ve);
2746 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
2747 Statement s2 = new ExpStatement(loc, e);
2749 if (sf)
2751 sf = new CompoundStatement(sf.loc, s2, sf);
2753 else
2754 sf = s2;
2757 return sf;
2760 /*********************************************
2761 * Returns: the function's parameter list, and whether
2762 * it is variadic or not.
2764 final ParameterList getParameterList()
2766 if (type)
2768 TypeFunction fdtype = type.isTypeFunction();
2769 if (fdtype) // Could also be TypeError
2770 return fdtype.parameterList;
2773 return ParameterList(null, VarArg.none);
2776 /**********************************
2777 * Generate a FuncDeclaration for a runtime library function.
2779 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
2781 return genCfunc(fparams, treturn, Identifier.idPool(name[0 .. strlen(name)]), stc);
2784 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
2786 FuncDeclaration fd;
2787 TypeFunction tf;
2788 Dsymbol s;
2789 __gshared DsymbolTable st = null;
2791 //printf("genCfunc(name = '%s')\n", id.toChars());
2792 //printf("treturn\n\t"); treturn.print();
2794 // See if already in table
2795 if (!st)
2796 st = new DsymbolTable();
2797 s = st.lookup(id);
2798 if (s)
2800 fd = s.isFuncDeclaration();
2801 assert(fd);
2802 assert(fd.type.nextOf().equals(treturn));
2804 else
2806 tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc);
2807 fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf);
2808 fd.visibility = Visibility(Visibility.Kind.public_);
2809 fd._linkage = LINK.c;
2811 st.insert(fd);
2813 return fd;
2817 + Checks the parameter and return types iff this is a `main` function.
2819 + The following signatures are allowed for a `D main`:
2820 + - Either no or a single parameter of type `string[]`
2821 + - Return type is either `void`, `int` or `noreturn`
2823 + The following signatures are standard C:
2824 + - `int main()`
2825 + - `int main(int, char**)`
2827 + This function accepts the following non-standard extensions:
2828 + - `char** envp` as a third parameter
2829 + - `void` / `noreturn` as return type
2831 + This function will issue errors for unexpected arguments / return types.
2833 extern (D) final void checkMain()
2835 if (ident != Id.main || isMember() || isNested())
2836 return; // Not a main function
2838 TypeFunction tf = type.toTypeFunction();
2840 Type retType = tf.nextOf();
2841 if (!retType)
2843 // auto main(), check after semantic
2844 assert(this.inferRetType);
2845 return;
2848 /// Checks whether `t` is equivalent to `char**`
2849 /// Ignores qualifiers and treats enums according to their base type
2850 static bool isCharPtrPtr(Type t)
2852 auto tp = t.toBasetype().isTypePointer();
2853 if (!tp)
2854 return false;
2856 tp = tp.next.toBasetype().isTypePointer();
2857 if (!tp)
2858 return false;
2860 return tp.next.toBasetype().ty == Tchar;
2863 // Neither of these qualifiers is allowed because they affect the ABI
2864 enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
2866 const nparams = tf.parameterList.length;
2867 bool argerr;
2869 const linkage = resolvedLinkage();
2870 if (linkage == LINK.d)
2872 if (nparams == 1)
2874 auto fparam0 = tf.parameterList[0];
2875 auto t = fparam0.type.toBasetype();
2876 if (t.ty != Tarray ||
2877 t.nextOf().ty != Tarray ||
2878 t.nextOf().nextOf().ty != Tchar ||
2879 fparam0.storageClass & invalidSTC)
2881 argerr = true;
2885 if (tf.parameterList.varargs || nparams >= 2 || argerr)
2886 .error(loc, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", kind, toPrettyChars);
2889 else if (linkage == LINK.c)
2891 if (nparams == 2 || nparams == 3)
2893 // Argument count must be int
2894 auto argCount = tf.parameterList[0];
2895 argerr |= !!(argCount.storageClass & invalidSTC);
2896 argerr |= argCount.type.toBasetype().ty != Tint32;
2898 // Argument pointer must be char**
2899 auto argPtr = tf.parameterList[1];
2900 argerr |= !!(argPtr.storageClass & invalidSTC);
2901 argerr |= !isCharPtrPtr(argPtr.type);
2903 // `char** environ` is a common extension, see J.5.1 of the C standard
2904 if (nparams == 3)
2906 auto envPtr = tf.parameterList[2];
2907 argerr |= !!(envPtr.storageClass & invalidSTC);
2908 argerr |= !isCharPtrPtr(envPtr.type);
2911 else
2912 argerr = nparams != 0;
2914 // Disallow variadic main() - except for K&R declarations in C files.
2915 // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
2916 if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
2917 argerr |= true;
2919 if (argerr)
2921 .error(loc, "%s `%s` parameters must match one of the following signatures", kind, toPrettyChars);
2922 loc.errorSupplemental("`main()`");
2923 loc.errorSupplemental("`main(int argc, char** argv)`");
2924 loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
2927 else
2928 return; // Neither C nor D main, ignore (should probably be an error)
2930 // Allow enums with appropriate base types (same ABI)
2931 retType = retType.toBasetype();
2933 if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
2934 .error(loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", kind, toPrettyChars, tf.nextOf().toChars());
2937 /***********************************************
2938 * Check all return statements for a function to verify that returning
2939 * using NRVO is possible.
2941 * Returns:
2942 * `false` if the result cannot be returned by hidden reference.
2944 extern (D) final bool checkNRVO()
2946 if (!isNRVO() || returns is null)
2947 return false;
2949 auto tf = type.toTypeFunction();
2950 if (tf.isref)
2951 return false;
2953 foreach (rs; *returns)
2955 if (auto ve = rs.exp.isVarExp())
2957 auto v = ve.var.isVarDeclaration();
2958 if (!v || v.isReference())
2959 return false;
2960 else if (nrvo_var is null)
2962 // Variables in the data segment (e.g. globals, TLS or not),
2963 // parameters and closure variables cannot be NRVOed.
2964 if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
2965 return false;
2966 if (v.nestedrefs.length && needsClosure())
2967 return false;
2968 // don't know if the return storage is aligned
2969 version (MARS)
2971 if (alignSectionVars && (*alignSectionVars).contains(v))
2972 return false;
2974 // The variable type needs to be equivalent to the return type.
2975 if (!v.type.equivalent(tf.next))
2976 return false;
2977 //printf("Setting nrvo to %s\n", v.toChars());
2978 nrvo_var = v;
2980 else if (nrvo_var != v)
2981 return false;
2983 else //if (!exp.isLvalue()) // keep NRVO-ability
2984 return false;
2986 return true;
2989 override final inout(FuncDeclaration) isFuncDeclaration() inout
2991 return this;
2994 inout(FuncDeclaration) toAliasFunc() inout
2996 return this;
2999 override void accept(Visitor v)
3001 v.visit(this);
3005 /********************************************************
3006 * Generate Expression to call the invariant.
3007 * Input:
3008 * ad aggregate with the invariant
3009 * vthis variable with 'this'
3010 * Returns:
3011 * void expression that calls the invariant
3013 Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
3015 Expression e = null;
3016 // Call invariant directly only if it exists
3017 FuncDeclaration inv = ad.inv;
3018 ClassDeclaration cd = ad.isClassDeclaration();
3020 while (!inv && cd)
3022 cd = cd.baseClass;
3023 if (!cd)
3024 break;
3025 inv = cd.inv;
3027 if (inv)
3029 version (all)
3031 // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
3032 // For the correct mangling,
3033 // run attribute inference on inv if needed.
3034 inv.functionSemantic();
3037 //e = new DsymbolExp(Loc.initial, inv);
3038 //e = new CallExp(Loc.initial, e);
3039 //e = e.semantic(sc2);
3041 /* https://issues.dlang.org/show_bug.cgi?id=13113
3042 * Currently virtual invariant calls completely
3043 * bypass attribute enforcement.
3044 * Change the behavior of pre-invariant call by following it.
3046 e = new ThisExp(Loc.initial);
3047 e.type = ad.type.addMod(vthis.type.mod);
3048 e = new DotVarExp(Loc.initial, e, inv, false);
3049 e.type = inv.type;
3050 e = new CallExp(Loc.initial, e);
3051 e.type = Type.tvoid;
3053 return e;
3056 /***************************************************
3057 * Visit each overloaded function/template in turn, and call dg(s) on it.
3058 * Exit when no more, or dg(s) returns nonzero.
3060 * Params:
3061 * fstart = symbol to start from
3062 * dg = the delegate to be called on the overload
3063 * sc = context used to check if symbol is accessible (and therefore visible),
3064 * can be null
3066 * Returns:
3067 * ==0 continue
3068 * !=0 done (and the return value from the last dg() call)
3070 extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
3072 Dsymbols visited;
3074 int overloadApplyRecurse(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc)
3076 // Detect cyclic calls.
3077 if (visited.contains(fstart))
3078 return 0;
3079 visited.push(fstart);
3081 Dsymbol next;
3082 for (auto d = fstart; d; d = next)
3084 import dmd.access : checkSymbolAccess;
3085 if (auto od = d.isOverDeclaration())
3087 /* The scope is needed here to check whether a function in
3088 an overload set was added by means of a private alias (or a
3089 selective import). If the scope where the alias is created
3090 is imported somewhere, the overload set is visible, but the private
3091 alias is not.
3093 if (sc)
3095 if (checkSymbolAccess(sc, od))
3097 if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
3098 return r;
3101 else if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
3102 return r;
3103 next = od.overnext;
3105 else if (auto fa = d.isFuncAliasDeclaration())
3107 if (fa.hasOverloads)
3109 if (int r = overloadApplyRecurse(fa.funcalias, dg, sc))
3110 return r;
3112 else if (auto fd = fa.toAliasFunc())
3114 if (int r = dg(fd))
3115 return r;
3117 else
3119 .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
3120 break;
3122 next = fa.overnext;
3124 else if (auto ad = d.isAliasDeclaration())
3126 if (sc)
3128 if (checkSymbolAccess(sc, ad))
3129 next = ad.toAlias();
3131 else
3132 next = ad.toAlias();
3133 if (next == ad)
3134 break;
3135 if (next == fstart)
3136 break;
3138 else if (auto td = d.isTemplateDeclaration())
3140 if (int r = dg(td))
3141 return r;
3142 next = td.overnext;
3144 else if (auto fd = d.isFuncDeclaration())
3146 if (int r = dg(fd))
3147 return r;
3148 next = fd.overnext;
3150 else if (auto os = d.isOverloadSet())
3152 foreach (ds; os.a)
3153 if (int r = dg(ds))
3154 return r;
3156 else
3158 .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
3159 break;
3160 // BUG: should print error message?
3163 return 0;
3165 return overloadApplyRecurse(fstart, dg, sc);
3169 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
3170 mismatching modifiers to `buf`.
3172 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
3173 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
3175 Params:
3176 buf = output buffer to write to
3177 lhsMod = modifier on the left-hand side
3178 lhsMod = modifier on the right-hand side
3180 Returns:
3182 A tuple with `isMutable` and `isNotShared` set
3183 if the `lhsMod` is missing those modifiers (compared to rhs).
3185 auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod)
3187 static struct Mismatches
3189 bool isNotShared;
3190 bool isMutable;
3193 Mismatches mismatches;
3195 bool bothMutable = ((lhsMod & rhsMod) == 0);
3196 bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0;
3197 bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_);
3199 if (lhsMod & MODFlags.shared_)
3200 buf.writestring("`shared` ");
3201 else if (sharedMismatch && !(lhsMod & MODFlags.immutable_))
3203 buf.writestring("non-shared ");
3204 mismatches.isNotShared = true;
3207 if (bothMutable && sharedMismatchOnly)
3210 else if (lhsMod & MODFlags.immutable_)
3211 buf.writestring("`immutable` ");
3212 else if (lhsMod & MODFlags.const_)
3213 buf.writestring("`const` ");
3214 else if (lhsMod & MODFlags.wild)
3215 buf.writestring("`inout` ");
3216 else
3218 buf.writestring("mutable ");
3219 mismatches.isMutable = true;
3222 return mismatches;
3226 unittest
3228 OutBuffer buf;
3229 auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0);
3230 assert(buf[] == "`shared` ");
3231 assert(!mismatches.isNotShared);
3233 buf.setsize(0);
3234 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_);
3235 assert(buf[] == "non-shared ");
3236 assert(mismatches.isNotShared);
3238 buf.setsize(0);
3239 mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0);
3240 assert(buf[] == "`const` ");
3241 assert(!mismatches.isMutable);
3243 buf.setsize(0);
3244 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_);
3245 assert(buf[] == "mutable ");
3246 assert(mismatches.isMutable);
3249 /// Flag used by $(LREF resolveFuncCall).
3250 enum FuncResolveFlag : ubyte
3252 standard = 0, /// issue error messages, solve the call.
3253 quiet = 1, /// do not issue error message on no match, just return `null`.
3254 overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous
3255 /// matches and need explicit this.
3256 ufcs = 4, /// trying to resolve UFCS call
3259 /*******************************************
3260 * Given a symbol that could be either a FuncDeclaration or
3261 * a function template, resolve it to a function symbol.
3262 * Params:
3263 * loc = instantiation location
3264 * sc = instantiation scope
3265 * s = instantiation symbol
3266 * tiargs = initial list of template arguments
3267 * tthis = if !NULL, the `this` argument type
3268 * argumentList = arguments to function
3269 * flags = see $(LREF FuncResolveFlag).
3270 * Returns:
3271 * if match is found, then function symbol, else null
3273 FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
3274 Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
3276 auto fargs = argumentList.arguments;
3277 if (!s)
3278 return null; // no match
3280 version (none)
3282 printf("resolveFuncCall('%s')\n", s.toChars());
3283 if (tthis)
3284 printf("\tthis: %s\n", tthis.toChars());
3285 if (fargs)
3287 for (size_t i = 0; i < fargs.length; i++)
3289 Expression arg = (*fargs)[i];
3290 assert(arg.type);
3291 printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
3294 printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
3297 if (tiargs && arrayObjectIsError(tiargs))
3298 return null;
3299 if (fargs !is null)
3300 foreach (arg; *fargs)
3301 if (isError(arg))
3302 return null;
3304 MatchAccumulator m;
3305 functionResolve(m, s, loc, sc, tiargs, tthis, argumentList);
3306 auto orig_s = s;
3308 if (m.last > MATCH.nomatch && m.lastf)
3310 if (m.count == 1) // exactly one match
3312 if (!(flags & FuncResolveFlag.quiet))
3313 m.lastf.functionSemantic();
3314 return m.lastf;
3316 if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
3318 return m.lastf;
3322 /* Failed to find a best match.
3323 * Do nothing or print error.
3325 if (m.last == MATCH.nomatch)
3327 // error was caused on matched function, not on the matching itself,
3328 // so return the function to produce a better diagnostic
3329 if (m.count == 1)
3330 return m.lastf;
3333 // We are done at this point, as the rest of this function generate
3334 // a diagnostic on invalid match
3335 if (flags & FuncResolveFlag.quiet)
3336 return null;
3338 auto fd = s.isFuncDeclaration();
3339 auto od = s.isOverDeclaration();
3340 auto td = s.isTemplateDeclaration();
3341 if (td && td.funcroot)
3342 s = fd = td.funcroot;
3344 OutBuffer tiargsBuf;
3345 arrayObjectsToBuffer(tiargsBuf, tiargs);
3347 OutBuffer fargsBuf;
3348 fargsBuf.writeByte('(');
3349 argExpTypesToCBuffer(fargsBuf, fargs);
3350 fargsBuf.writeByte(')');
3351 if (tthis)
3352 tthis.modToBuffer(fargsBuf);
3354 // The call is ambiguous
3355 if (m.lastf && m.nextf)
3357 TypeFunction tf1 = m.lastf.type.toTypeFunction();
3358 TypeFunction tf2 = m.nextf.type.toTypeFunction();
3359 const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
3360 const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
3362 .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
3363 s.parent.toPrettyChars(), s.ident.toChars(),
3364 fargsBuf.peekChars(),
3365 m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(),
3366 m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars());
3367 return null;
3370 // no match, generate an error messages
3371 if (flags & FuncResolveFlag.ufcs)
3373 auto arg = (*fargs)[0];
3374 .error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars());
3375 .errorSupplemental(loc, "the following error occured while looking for a UFCS match");
3378 if (!fd)
3380 // all of overloads are templates
3381 if (td)
3383 const(char)* msg = "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`";
3384 if (!od && !td.overnext)
3385 msg = "%s `%s.%s` is not callable using argument types `!(%s)%s`";
3386 .error(loc, msg,
3387 td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
3388 tiargsBuf.peekChars(), fargsBuf.peekChars());
3390 if (!global.gag || global.params.v.showGaggedErrors)
3391 printCandidates(loc, td, sc.isDeprecated());
3392 return null;
3394 /* This case used to happen when several ctors are mixed in an agregate.
3395 A (bad) error message is already generated in overloadApply().
3396 see https://issues.dlang.org/show_bug.cgi?id=19729
3397 and https://issues.dlang.org/show_bug.cgi?id=17259
3399 if (!od)
3400 return null;
3403 if (od)
3405 .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
3406 od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
3407 return null;
3410 // remove when deprecation period of class allocators and deallocators is over
3411 if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
3412 return null;
3414 bool hasOverloads = fd.overnext !is null;
3415 auto tf = fd.type.isTypeFunction();
3416 // if type is an error, the original type should be there for better diagnostics
3417 if (!tf)
3418 tf = fd.originalType.toTypeFunction();
3420 // modifier mismatch
3421 if (tthis && (fd.isCtorDeclaration() ?
3422 !MODimplicitConv(tf.mod, tthis.mod) :
3423 !MODimplicitConv(tthis.mod, tf.mod)))
3425 OutBuffer thisBuf, funcBuf;
3426 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
3427 auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
3428 if (hasOverloads)
3430 OutBuffer buf;
3431 buf.argExpTypesToCBuffer(fargs);
3432 if (fd.isCtorDeclaration())
3433 .error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`",
3434 fd.toChars(), thisBuf.peekChars(), buf.peekChars());
3435 else
3436 .error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`",
3437 fd.toChars(), thisBuf.peekChars(), buf.peekChars());
3439 if (!global.gag || global.params.v.showGaggedErrors)
3440 printCandidates(loc, fd, sc.isDeprecated());
3441 return null;
3444 const(char)* failMessage;
3445 functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
3446 if (failMessage)
3448 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3449 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3450 tf.modToChars(), fargsBuf.peekChars());
3451 errorSupplemental(loc, failMessage);
3452 return null;
3455 if (fd.isCtorDeclaration())
3456 .error(loc, "%s%s `%s` cannot construct a %sobject",
3457 funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars());
3458 else
3459 .error(loc, "%smethod `%s` is not callable using a %sobject",
3460 funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
3462 if (mismatches.isNotShared)
3463 .errorSupplemental(fd.loc, "Consider adding `shared` here");
3464 else if (mismatches.isMutable)
3465 .errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
3466 return null;
3469 //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
3470 if (hasOverloads)
3472 .error(loc, "none of the overloads of `%s` are callable using argument types `%s`",
3473 fd.toChars(), fargsBuf.peekChars());
3474 if (!global.gag || global.params.v.showGaggedErrors)
3475 printCandidates(loc, fd, sc.isDeprecated());
3476 return null;
3479 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3480 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3481 tf.modToChars(), fargsBuf.peekChars());
3483 // re-resolve to check for supplemental message
3484 if (!global.gag || global.params.v.showGaggedErrors)
3486 if (tthis)
3488 if (auto classType = tthis.isTypeClass())
3490 if (auto baseClass = classType.sym.baseClass)
3492 if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
3494 MatchAccumulator mErr;
3495 functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
3496 if (mErr.last > MATCH.nomatch && mErr.lastf)
3498 errorSupplemental(loc, "%s `%s` hides base class function `%s`",
3499 fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
3500 errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
3501 fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
3502 return null;
3508 const(char)* failMessage;
3509 functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
3510 if (failMessage)
3511 errorSupplemental(loc, failMessage);
3513 return null;
3516 /*******************************************
3517 * Prints template and function overload candidates as supplemental errors.
3518 * Params:
3519 * loc = instantiation location
3520 * declaration = the declaration to print overload candidates for
3521 * showDeprecated = If `false`, `deprecated` function won't be shown
3523 private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
3524 if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
3526 // max num of overloads to print (-v or -verror-supplements overrides this).
3527 const uint DisplayLimit = global.params.v.errorSupplementCount();
3528 const(char)* constraintsTip;
3529 // determine if the first candidate was printed
3530 int printed;
3532 bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false)
3534 if (auto fd = s.isFuncDeclaration())
3536 // Don't print overloads which have errors.
3537 // Not that if the whole overload set has errors, we'll never reach
3538 // this point so there's no risk of printing no candidate
3539 if (fd.errors || fd.type.ty == Terror)
3540 return false;
3541 // Don't print disabled functions, or `deprecated` outside of deprecated scope
3542 if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
3543 return false;
3544 if (!print)
3545 return true;
3546 auto tf = cast(TypeFunction) fd.type;
3547 OutBuffer buf;
3548 buf.writestring(fd.toPrettyChars());
3549 buf.writestring(parametersTypeToChars(tf.parameterList));
3550 if (tf.mod)
3552 buf.writeByte(' ');
3553 buf.MODtoBuffer(tf.mod);
3555 .errorSupplemental(fd.loc,
3556 printed ? " `%s`" :
3557 single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars());
3559 else if (auto td = s.isTemplateDeclaration())
3561 import dmd.staticcond;
3563 if (!print)
3564 return true;
3565 const tmsg = td.toCharsNoConstraints();
3566 const cmsg = td.getConstraintEvalError(constraintsTip);
3568 // add blank space if there are multiple candidates
3569 // the length of the blank space is `strlen("Candidates are: ")`
3571 if (cmsg)
3573 .errorSupplemental(td.loc,
3574 printed ? " `%s`\n%s" :
3575 single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
3576 tmsg, cmsg);
3578 else
3580 .errorSupplemental(td.loc,
3581 printed ? " `%s`" :
3582 single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
3583 tmsg);
3586 return true;
3588 // determine if there's > 1 candidate
3589 int count = 0;
3590 overloadApply(declaration, (s) {
3591 if (matchSymbol(s, false))
3592 count++;
3593 return count > 1;
3595 int skipped = 0;
3596 overloadApply(declaration, (s) {
3597 if (global.params.v.verbose || printed < DisplayLimit)
3599 if (matchSymbol(s, true, count == 1))
3600 printed++;
3602 else
3604 // Too many overloads to sensibly display.
3605 // Just show count of remaining overloads.
3606 if (matchSymbol(s, false))
3607 skipped++;
3609 return 0;
3611 if (skipped > 0)
3612 .errorSupplemental(loc, "... (%d more, -v to show) ...", skipped);
3614 // Nothing was displayed, all overloads are either disabled or deprecated
3615 if (!printed)
3616 .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
3617 // should be only in verbose mode
3618 if (constraintsTip)
3619 .tip(constraintsTip);
3622 /**************************************
3623 * Returns an indirect type one step from t.
3625 Type getIndirection(Type t)
3627 t = t.baseElemOf();
3628 if (t.ty == Tarray || t.ty == Tpointer)
3629 return t.nextOf().toBasetype();
3630 if (t.ty == Taarray || t.ty == Tclass)
3631 return t;
3632 if (t.ty == Tstruct)
3633 return t.hasPointers() ? t : null; // TODO
3635 // should consider TypeDelegate?
3636 return null;
3639 /**************************************
3640 * Performs type-based alias analysis between a newly created value and a pre-
3641 * existing memory reference:
3643 * Assuming that a reference A to a value of type `ta` was available to the code
3644 * that created a reference B to a value of type `tb`, it returns whether B
3645 * might alias memory reachable from A based on the types involved (either
3646 * directly or via any number of indirections in either A or B).
3648 * This relation is not symmetric in the two arguments. For example, a
3649 * a `const(int)` reference can point to a pre-existing `int`, but not the other
3650 * way round.
3652 * Examples:
3654 * ta, tb, result
3655 * `const(int)`, `int`, `false`
3656 * `int`, `const(int)`, `true`
3657 * `int`, `immutable(int)`, `false`
3658 * const(immutable(int)*), immutable(int)*, false // BUG: returns true
3660 * Params:
3661 * ta = value type being referred to
3662 * tb = referred to value type that could be constructed from ta
3664 * Returns:
3665 * true if reference to `tb` is isolated from reference to `ta`
3667 private bool traverseIndirections(Type ta, Type tb)
3669 //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
3671 static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
3673 //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
3674 ta = ta.baseElemOf();
3675 tb = tb.baseElemOf();
3677 // First, check if the pointed-to types are convertible to each other such
3678 // that they might alias directly.
3679 static bool mayAliasDirect(Type source, Type target)
3681 return
3682 // if source is the same as target or can be const-converted to target
3683 source.constConv(target) != MATCH.nomatch ||
3684 // if target is void and source can be const-converted to target
3685 (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
3688 if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
3690 //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3691 return false;
3693 if (ta.nextOf() && ta.nextOf() == tb.nextOf())
3695 //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3696 return true;
3699 if (tb.ty == Tclass || tb.ty == Tstruct)
3701 /* Traverse the type of each field of the aggregate
3703 bool* found = table.getLvalue(tb.deco);
3704 if (*found == true)
3705 return true; // We have already seen this symbol, break the cycle
3706 else
3707 *found = true;
3709 AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
3710 foreach (v; sym.fields)
3712 Type tprmi = v.type.addMod(tb.mod);
3713 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
3714 if (!traverse(ta, tprmi, table, reversePass))
3715 return false;
3718 else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
3720 Type tind = tb.nextOf();
3721 if (!traverse(ta, tind, table, reversePass))
3722 return false;
3724 else if (tb.hasPointers())
3726 // BUG: consider the context pointer of delegate types
3727 return false;
3730 // Still no match, so try breaking up ta if we have not done so yet.
3731 if (!reversePass)
3733 scope newTable = AssocArray!(const(char)*, bool)();
3734 return traverse(tb, ta, newTable, true);
3737 return true;
3740 // To handle arbitrary levels of indirections in both parameters, we
3741 // recursively descend into aggregate members/levels of indirection in both
3742 // `ta` and `tb` while avoiding cycles. Start with the original types.
3743 scope table = AssocArray!(const(char)*, bool)();
3744 const result = traverse(ta, tb, table, false);
3745 //printf(" returns %d\n", result);
3746 return result;
3749 /* For all functions between outerFunc and f, mark them as needing
3750 * a closure.
3752 private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc)
3754 for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc))
3756 FuncDeclaration fy = sx.isFuncDeclaration();
3757 if (fy && fy.closureVars.length)
3759 /* fy needs a closure if it has closureVars[],
3760 * because the frame pointer in the closure will be accessed.
3762 fy.requiresClosure = true;
3767 /********
3768 * Given a nested function f inside a function outerFunc, check
3769 * if any sibling callers of f have escaped. If so, mark
3770 * all the enclosing functions as needing closures.
3771 * This is recursive: we need to check the callers of our siblings.
3772 * Note that nested functions can only call lexically earlier nested
3773 * functions, so loops are impossible.
3774 * Params:
3775 * f = inner function (nested within outerFunc)
3776 * outerFunc = outer function
3777 * p = for internal recursion use
3778 * Returns:
3779 * true if any closures were needed
3781 private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
3783 static struct PrevSibling
3785 PrevSibling* p;
3786 FuncDeclaration f;
3789 if (f.computedEscapingSiblings)
3790 return f.hasEscapingSiblings;
3792 PrevSibling ps;
3793 ps.p = cast(PrevSibling*)p;
3794 ps.f = f;
3796 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
3797 bool bAnyClosures = false;
3798 for (size_t i = 0; i < f.siblingCallers.length; ++i)
3800 FuncDeclaration g = f.siblingCallers[i];
3801 if (g.isThis() || g.tookAddressOf)
3803 markAsNeedingClosure(g, outerFunc);
3804 bAnyClosures = true;
3807 for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc))
3809 // A parent of the sibling had its address taken.
3810 // Assume escaping of parent affects its children, so needs propagating.
3811 // see https://issues.dlang.org/show_bug.cgi?id=19679
3812 FuncDeclaration parentFunc = parent.isFuncDeclaration;
3813 if (parentFunc && parentFunc.tookAddressOf)
3815 markAsNeedingClosure(parentFunc, outerFunc);
3816 bAnyClosures = true;
3820 PrevSibling* prev = cast(PrevSibling*)p;
3821 while (1)
3823 if (!prev)
3825 bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
3826 break;
3828 if (prev.f == g)
3829 break;
3830 prev = prev.p;
3833 f.hasEscapingSiblings = bAnyClosures;
3834 f.computedEscapingSiblings = true;
3835 //printf("\t%d\n", bAnyClosures);
3836 return bAnyClosures;
3839 /***********************************************************
3840 * Used as a way to import a set of functions from another scope into this one.
3842 extern (C++) final class FuncAliasDeclaration : FuncDeclaration
3844 FuncDeclaration funcalias;
3845 bool hasOverloads;
3847 extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true)
3849 super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type);
3850 assert(funcalias != this);
3851 this.funcalias = funcalias;
3853 this.hasOverloads = hasOverloads;
3854 if (hasOverloads)
3856 if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration())
3857 this.hasOverloads = fad.hasOverloads;
3859 else
3861 // for internal use
3862 assert(!funcalias.isFuncAliasDeclaration());
3863 this.hasOverloads = false;
3865 userAttribDecl = funcalias.userAttribDecl;
3868 override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
3870 return this;
3873 override const(char)* kind() const
3875 return "function alias";
3878 override inout(FuncDeclaration) toAliasFunc() inout
3880 return funcalias.toAliasFunc();
3883 override void accept(Visitor v)
3885 v.visit(this);
3889 /***********************************************************
3891 extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
3893 TOK tok; // TOK.function_ or TOK.delegate_
3894 Type treq; // target of return type inference
3896 // backend
3897 bool deferToObj;
3899 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_)
3901 super(loc, endloc, null, storage_class, type);
3902 this.ident = id ? id : Id.empty;
3903 this.tok = tok;
3904 this.fes = fes;
3905 // Always infer scope for function literals
3906 // See https://issues.dlang.org/show_bug.cgi?id=20362
3907 this.inferScope = true;
3908 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
3911 override FuncLiteralDeclaration syntaxCopy(Dsymbol s)
3913 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
3914 assert(!s);
3915 auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident, storage_class & STC.auto_);
3916 f.treq = treq; // don't need to copy
3917 FuncDeclaration.syntaxCopy(f);
3918 return f;
3921 override bool isNested() const
3923 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
3924 return (tok != TOK.function_) && !isThis();
3927 override inout(AggregateDeclaration) isThis() inout
3929 return tok == TOK.delegate_ ? super.isThis() : null;
3932 override bool isVirtual() const
3934 return false;
3937 override bool addPreInvariant()
3939 return false;
3942 override bool addPostInvariant()
3944 return false;
3947 /*******************************
3948 * Modify all expression type of return statements to tret.
3950 * On function literals, return type may be modified based on the context type
3951 * after its semantic3 is done, in FuncExp::implicitCastTo.
3953 * A function() dg = (){ return new B(); } // OK if is(B : A) == true
3955 * If B to A conversion is convariant that requires offseet adjusting,
3956 * all return statements should be adjusted to return expressions typed A.
3958 extern (D) void modifyReturns(Scope* sc, Type tret)
3960 import dmd.statement_rewrite_walker;
3962 extern (C++) final class RetWalker : StatementRewriteWalker
3964 alias visit = typeof(super).visit;
3965 public:
3966 Scope* sc;
3967 Type tret;
3968 FuncLiteralDeclaration fld;
3970 override void visit(ReturnStatement s)
3972 Expression exp = s.exp;
3973 if (exp && !exp.type.equals(tret))
3974 s.exp = exp.implicitCastTo(sc, tret);
3978 if (semanticRun < PASS.semantic3done)
3979 return;
3981 if (fes)
3982 return;
3984 scope RetWalker w = new RetWalker();
3985 w.sc = sc;
3986 w.tret = tret;
3987 w.fld = this;
3988 fbody.accept(w);
3990 // Also update the inferred function type to match the new return type.
3991 // This is required so the code generator does not try to cast the
3992 // modified returns back to the original type.
3993 if (inferRetType && type.nextOf() != tret)
3994 type.toTypeFunction().next = tret;
3997 override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
3999 return this;
4002 override const(char)* kind() const
4004 // GCC requires the (char*) casts
4005 return (tok != TOK.function_) ? "delegate" : "function";
4008 override const(char)* toPrettyChars(bool QualifyTypes = false)
4010 if (parent)
4012 TemplateInstance ti = parent.isTemplateInstance();
4013 if (ti)
4014 return ti.tempdecl.toPrettyChars(QualifyTypes);
4016 return Dsymbol.toPrettyChars(QualifyTypes);
4019 override void accept(Visitor v)
4021 v.visit(this);
4025 /***********************************************************
4027 extern (C++) final class CtorDeclaration : FuncDeclaration
4029 bool isCpCtor;
4030 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
4032 super(loc, endloc, Id.ctor, stc, type);
4033 this.isCpCtor = isCpCtor;
4034 //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
4037 override CtorDeclaration syntaxCopy(Dsymbol s)
4039 assert(!s);
4040 auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy());
4041 FuncDeclaration.syntaxCopy(f);
4042 return f;
4045 override const(char)* kind() const
4047 return isCpCtor ? "copy constructor" : "constructor";
4050 override const(char)* toChars() const
4052 return "this";
4055 override bool isVirtual() const
4057 return false;
4060 override bool addPreInvariant()
4062 return false;
4065 override bool addPostInvariant()
4067 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
4070 override inout(CtorDeclaration) isCtorDeclaration() inout
4072 return this;
4075 override void accept(Visitor v)
4077 v.visit(this);
4081 /***********************************************************
4083 extern (C++) final class PostBlitDeclaration : FuncDeclaration
4085 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
4087 super(loc, endloc, id, stc, null);
4090 override PostBlitDeclaration syntaxCopy(Dsymbol s)
4092 assert(!s);
4093 auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
4094 FuncDeclaration.syntaxCopy(dd);
4095 return dd;
4098 override bool isVirtual() const
4100 return false;
4103 override bool addPreInvariant()
4105 return false;
4108 override bool addPostInvariant()
4110 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
4113 override bool overloadInsert(Dsymbol s)
4115 return false; // cannot overload postblits
4118 override inout(PostBlitDeclaration) isPostBlitDeclaration() inout
4120 return this;
4123 override void accept(Visitor v)
4125 v.visit(this);
4129 /***********************************************************
4131 extern (C++) final class DtorDeclaration : FuncDeclaration
4133 extern (D) this(const ref Loc loc, const ref Loc endloc)
4135 super(loc, endloc, Id.dtor, STC.undefined_, null);
4138 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
4140 super(loc, endloc, id, stc, null);
4143 override DtorDeclaration syntaxCopy(Dsymbol s)
4145 assert(!s);
4146 auto dd = new DtorDeclaration(loc, endloc, storage_class, ident);
4147 FuncDeclaration.syntaxCopy(dd);
4148 return dd;
4151 override const(char)* kind() const
4153 return "destructor";
4156 override const(char)* toChars() const
4158 return "~this";
4161 override bool isVirtual() const
4163 // D dtor's don't get put into the vtbl[]
4164 // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
4165 return vtblIndex != -1;
4168 override bool addPreInvariant()
4170 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
4173 override bool addPostInvariant()
4175 return false;
4178 override bool overloadInsert(Dsymbol s)
4180 return false; // cannot overload destructors
4183 override inout(DtorDeclaration) isDtorDeclaration() inout
4185 return this;
4188 override void accept(Visitor v)
4190 v.visit(this);
4194 /***********************************************************
4196 extern (C++) class StaticCtorDeclaration : FuncDeclaration
4198 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4200 super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null);
4203 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
4205 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
4208 override StaticCtorDeclaration syntaxCopy(Dsymbol s)
4210 assert(!s);
4211 auto scd = new StaticCtorDeclaration(loc, endloc, storage_class);
4212 FuncDeclaration.syntaxCopy(scd);
4213 return scd;
4216 override final inout(AggregateDeclaration) isThis() inout @nogc nothrow pure @safe
4218 return null;
4221 override final bool isVirtual() const @nogc nothrow pure @safe
4223 return false;
4226 override final bool addPreInvariant() @nogc nothrow pure @safe
4228 return false;
4231 override final bool addPostInvariant() @nogc nothrow pure @safe
4233 return false;
4236 override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
4238 return true;
4241 override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
4243 return this;
4246 override void accept(Visitor v)
4248 v.visit(this);
4252 /***********************************************************
4254 extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
4256 /// Exclude this constructor from cyclic dependency check
4257 bool standalone;
4259 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4261 super(loc, endloc, "_sharedStaticCtor", stc);
4264 override SharedStaticCtorDeclaration syntaxCopy(Dsymbol s)
4266 assert(!s);
4267 auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
4268 FuncDeclaration.syntaxCopy(scd);
4269 return scd;
4272 override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
4274 return this;
4277 override void accept(Visitor v)
4279 v.visit(this);
4283 /***********************************************************
4285 extern (C++) class StaticDtorDeclaration : FuncDeclaration
4287 VarDeclaration vgate; // 'gate' variable
4289 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4291 super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null);
4294 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
4296 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
4299 override StaticDtorDeclaration syntaxCopy(Dsymbol s)
4301 assert(!s);
4302 auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
4303 FuncDeclaration.syntaxCopy(sdd);
4304 return sdd;
4307 override final inout(AggregateDeclaration) isThis() inout
4309 return null;
4312 override final bool isVirtual() const
4314 return false;
4317 override final bool hasStaticCtorOrDtor()
4319 return true;
4322 override final bool addPreInvariant()
4324 return false;
4327 override final bool addPostInvariant()
4329 return false;
4332 override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
4334 return this;
4337 override void accept(Visitor v)
4339 v.visit(this);
4343 /***********************************************************
4345 extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
4347 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4349 super(loc, endloc, "_sharedStaticDtor", stc);
4352 override SharedStaticDtorDeclaration syntaxCopy(Dsymbol s)
4354 assert(!s);
4355 auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
4356 FuncDeclaration.syntaxCopy(sdd);
4357 return sdd;
4360 override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
4362 return this;
4365 override void accept(Visitor v)
4367 v.visit(this);
4371 /***********************************************************
4373 extern (C++) final class InvariantDeclaration : FuncDeclaration
4375 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
4377 // Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list.
4378 super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
4379 this.fbody = fbody;
4382 override InvariantDeclaration syntaxCopy(Dsymbol s)
4384 assert(!s);
4385 auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null);
4386 FuncDeclaration.syntaxCopy(id);
4387 return id;
4390 override bool isVirtual() const
4392 return false;
4395 override bool addPreInvariant()
4397 return false;
4400 override bool addPostInvariant()
4402 return false;
4405 override inout(InvariantDeclaration) isInvariantDeclaration() inout
4407 return this;
4410 override void accept(Visitor v)
4412 v.visit(this);
4415 extern (D) void fixupInvariantIdent(size_t offset)
4417 OutBuffer idBuf;
4418 idBuf.writestring("__invariant");
4419 idBuf.print(offset);
4421 ident = Identifier.idPool(idBuf[]);
4426 /***********************************************************
4428 extern (C++) final class UnitTestDeclaration : FuncDeclaration
4430 char* codedoc; // for documented unittest
4432 // toObjFile() these nested functions after this one
4433 FuncDeclarations deferredNested;
4435 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
4437 super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null);
4438 this.codedoc = codedoc;
4441 override UnitTestDeclaration syntaxCopy(Dsymbol s)
4443 assert(!s);
4444 auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
4445 FuncDeclaration.syntaxCopy(utd);
4446 return utd;
4449 override inout(AggregateDeclaration) isThis() inout
4451 return null;
4454 override bool isVirtual() const
4456 return false;
4459 override bool addPreInvariant()
4461 return false;
4464 override bool addPostInvariant()
4466 return false;
4469 override inout(UnitTestDeclaration) isUnitTestDeclaration() inout
4471 return this;
4474 override void accept(Visitor v)
4476 v.visit(this);
4480 /***********************************************************
4482 extern (C++) final class NewDeclaration : FuncDeclaration
4484 extern (D) this(const ref Loc loc, StorageClass stc)
4486 super(loc, Loc.initial, Id.classNew, STC.static_ | stc, null);
4489 override NewDeclaration syntaxCopy(Dsymbol s)
4491 assert(!s);
4492 auto f = new NewDeclaration(loc, storage_class);
4493 FuncDeclaration.syntaxCopy(f);
4494 return f;
4497 override const(char)* kind() const
4499 return "allocator";
4502 override bool isVirtual() const
4504 return false;
4507 override bool addPreInvariant()
4509 return false;
4512 override bool addPostInvariant()
4514 return false;
4517 override inout(NewDeclaration) isNewDeclaration() inout
4519 return this;
4522 override void accept(Visitor v)
4524 v.visit(this);
4528 /**************************************
4529 * When a traits(compiles) is used on a function literal call
4530 * we need to take into account if the body of the function
4531 * violates any attributes, however, we must not affect the
4532 * attribute inference on the outer function. The attributes
4533 * of the function literal still need to be inferred, therefore
4534 * we need a way to check for the scope that the traits compiles
4535 * introduces.
4537 * Params:
4538 * sc = scope to be checked for
4540 * Returns: `true` if the provided scope is the root
4541 * of the traits compiles list of scopes.
4543 bool isRootTraitsCompilesScope(Scope* sc)
4545 return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
4548 /**************************************
4549 * A statement / expression in this scope is not `@safe`,
4550 * so mark the enclosing function as `@system`
4552 * Params:
4553 * sc = scope that the unsafe statement / expression is in
4554 * gag = surpress error message (used in escape.d)
4555 * loc = location of error
4556 * fmt = printf-style format string
4557 * arg0 = (optional) argument for first %s format specifier
4558 * arg1 = (optional) argument for second %s format specifier
4559 * arg2 = (optional) argument for third %s format specifier
4560 * Returns: whether there's a safe error
4562 bool setUnsafe(Scope* sc,
4563 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
4564 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
4566 if (sc.intypeof)
4567 return false; // typeof(cast(int*)0) is safe
4569 if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
4570 return false;
4572 if (!sc.func)
4574 if (sc.varDecl)
4576 if (sc.varDecl.storage_class & STC.safe)
4578 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4579 return true;
4581 else if (!(sc.varDecl.storage_class & STC.trusted))
4583 sc.varDecl.storage_class |= STC.system;
4584 sc.varDecl.systemInferred = true;
4587 return false;
4591 if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
4593 if (sc.func.isSafeBypassingInference())
4595 // Message wil be gagged, but still call error() to update global.errors and for
4596 // -verrors=spec
4597 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4598 return true;
4600 return false;
4603 return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
4606 /***************************************
4607 * Like `setUnsafe`, but for safety errors still behind preview switches
4609 * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
4610 * the behavior changes based on the setting:
4612 * - In case of `-revert=fs`, it does nothing.
4613 * - In case of `-preview=fs`, it's the same as `setUnsafe`
4614 * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
4616 * Params:
4617 * sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
4618 * fs = feature state from the preview flag
4619 * gag = surpress error message
4620 * loc = location of error
4621 * msg = printf-style format string
4622 * arg0 = (optional) argument for first %s format specifier
4623 * arg1 = (optional) argument for second %s format specifier
4624 * arg2 = (optional) argument for third %s format specifier
4625 * Returns: whether an actual safe error (not deprecation) occured
4627 bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
4628 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
4630 //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
4631 with (FeatureState) final switch (fs)
4633 case disabled:
4634 return false;
4636 case enabled:
4637 return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
4639 case default_:
4640 if (!sc.func)
4641 return false;
4642 if (sc.func.isSafeBypassingInference())
4644 if (!gag)
4646 warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4649 else if (!sc.func.safetyViolation)
4651 import dmd.func : AttributeViolation;
4652 sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
4654 return false;
4658 /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
4660 /// Has two modes:
4661 /// - a regular safety error, stored in (fmtStr, arg0, arg1)
4662 /// - a call to a function without the attribute, which is a special case, because in that case,
4663 /// that function might recursively also have a `AttributeViolation`. This way, in case
4664 /// of a big call stack, the error can go down all the way to the root cause.
4665 /// The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`.
4666 struct AttributeViolation
4668 /// location of error
4669 Loc loc = Loc.init;
4670 /// printf-style format string
4671 const(char)* fmtStr = null;
4672 /// Arguments for up to two `%s` format specifiers in format string
4673 RootObject arg0 = null;
4674 /// ditto
4675 RootObject arg1 = null;
4676 /// ditto
4677 RootObject arg2 = null;
4680 /// Print the reason why `fd` was inferred `@system` as a supplemental error
4681 /// Params:
4682 /// fd = function to check
4683 /// maxDepth = up to how many functions deep to report errors
4684 /// deprecation = print deprecations instead of errors
4685 /// stc = storage class of attribute to check
4686 void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc)
4688 auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
4690 AttributeViolation* s;
4691 const(char)* attr;
4692 if (stc & STC.safe)
4694 s = fd.safetyViolation;
4695 attr = "@safe";
4697 else if (stc & STC.pure_)
4699 s = fd.pureViolation;
4700 attr = "pure";
4702 else if (stc & STC.nothrow_)
4704 s = fd.nothrowViolation;
4705 attr = "nothrow";
4707 else if (stc & STC.nogc)
4709 s = fd.nogcViolation;
4710 attr = "@nogc";
4713 if (s)
4715 if (s.fmtStr)
4717 errorFunc(s.loc, deprecation ?
4718 "which wouldn't be `%s` because of:" :
4719 "which wasn't inferred `%s` because of:", attr);
4720 if (stc == STC.nogc || stc == STC.pure_)
4722 auto f = (cast(Dsymbol) s.arg0).isFuncDeclaration();
4723 errorFunc(s.loc, s.fmtStr, f.kind(), f.toPrettyChars(), s.arg1 ? s.arg1.toChars() : "");
4725 else
4727 errorFunc(s.loc, s.fmtStr,
4728 s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
4731 else if (auto sa = s.arg0.isDsymbol())
4733 if (FuncDeclaration fd2 = sa.isFuncDeclaration())
4735 if (maxDepth > 0)
4737 errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
4738 errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc);