d: Merge upstream dmd, druntime 4c18eed967, phobos d945686a4.
[official-gcc.git] / gcc / d / dmd / func.d
blob81bb028964fb35b5daa62cc3ea295c362906adf6
1 /**
2 * Defines a function declaration.
4 * Includes:
5 * - function/delegate literals
6 * - function aliases
7 * - (static/shared) constructors/destructors/post-blits
8 * - `invariant`
9 * - `unittest`
11 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
12 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
13 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
14 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d)
15 * Documentation: https://dlang.org/phobos/dmd_func.html
16 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d
19 module dmd.func;
21 import core.stdc.stdio;
22 import core.stdc.string;
23 import dmd.aggregate;
24 import dmd.arraytypes;
25 import dmd.astenums;
26 import dmd.blockexit;
27 import dmd.gluelayer;
28 import dmd.dclass;
29 import dmd.declaration;
30 import dmd.delegatize;
31 import dmd.dinterpret;
32 import dmd.dmodule;
33 import dmd.dscope;
34 import dmd.dstruct;
35 import dmd.dsymbol;
36 import dmd.dsymbolsem;
37 import dmd.dtemplate;
38 import dmd.errors;
39 import dmd.escape;
40 import dmd.expression;
41 import dmd.globals;
42 import dmd.hdrgen;
43 import dmd.id;
44 import dmd.identifier;
45 import dmd.init;
46 import dmd.location;
47 import dmd.mtype;
48 import dmd.objc;
49 import dmd.root.aav;
50 import dmd.common.outbuffer;
51 import dmd.root.rootobject;
52 import dmd.root.string;
53 import dmd.root.stringtable;
54 import dmd.semantic2;
55 import dmd.semantic3;
56 import dmd.statement_rewrite_walker;
57 import dmd.statement;
58 import dmd.statementsem;
59 import dmd.tokens;
60 import dmd.visitor;
62 version (IN_GCC) {}
63 else version (IN_LLVM) {}
64 else version = MARS;
66 /// Inline Status
67 enum ILS : ubyte
69 uninitialized, /// not computed yet
70 no, /// cannot inline
71 yes, /// can inline
74 enum BUILTIN : ubyte
76 unknown = 255, /// not known if this is a builtin
77 unimp = 0, /// this is not a builtin
78 gcc, /// this is a GCC builtin
79 llvm, /// this is an LLVM builtin
80 sin,
81 cos,
82 tan,
83 sqrt,
84 fabs,
85 ldexp,
86 log,
87 log2,
88 log10,
89 exp,
90 expm1,
91 exp2,
92 round,
93 floor,
94 ceil,
95 trunc,
96 copysign,
97 pow,
98 fmin,
99 fmax,
100 fma,
101 isnan,
102 isinfinity,
103 isfinite,
104 bsf,
105 bsr,
106 bswap,
107 popcnt,
108 yl2x,
109 yl2xp1,
110 toPrecFloat,
111 toPrecDouble,
112 toPrecReal
115 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
117 extern (C++) final class NrvoWalker : StatementRewriteWalker
119 alias visit = typeof(super).visit;
120 public:
121 FuncDeclaration fd;
122 Scope* sc;
124 override void visit(ReturnStatement s)
126 // See if all returns are instead to be replaced with a goto returnLabel;
127 if (fd.returnLabel)
129 /* Rewrite:
130 * return exp;
131 * as:
132 * vresult = exp; goto Lresult;
134 auto gs = new GotoStatement(s.loc, Id.returnLabel);
135 gs.label = fd.returnLabel;
137 Statement s1 = gs;
138 if (s.exp)
139 s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
141 replaceCurrent(s1);
145 override void visit(TryFinallyStatement s)
147 DtorExpStatement des;
148 if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
149 fd.nrvo_var == des.var)
151 if (!(global.params.useExceptions && ClassDeclaration.throwable))
153 /* Don't need to call destructor at all, since it is nrvo
155 replaceCurrent(s._body);
156 s._body.accept(this);
157 return;
160 /* Normally local variable dtors are called regardless exceptions.
161 * But for nrvo_var, its dtor should be called only when exception is thrown.
163 * Rewrite:
164 * try { s.body; } finally { nrvo_var.edtor; }
165 * // equivalent with:
166 * // s.body; scope(exit) nrvo_var.edtor;
167 * as:
168 * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
169 * // equivalent with:
170 * // s.body; scope(failure) nrvo_var.edtor;
172 Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
173 Identifier id = Identifier.generateId("__o");
175 Statement handler = new PeelStatement(sexception);
176 if (sexception.blockExit(fd, null) & BE.fallthru)
178 auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
179 ts.internalThrow = true;
180 handler = new CompoundStatement(Loc.initial, handler, ts);
183 auto catches = new Catches();
184 auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
185 ctch.internalCatch = true;
186 ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
187 catches.push(ctch);
189 Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
190 fd.hasNoEH = false;
191 replaceCurrent(s2);
192 s2.accept(this);
194 else
195 StatementRewriteWalker.visit(s);
199 private struct FUNCFLAG
201 bool purityInprocess; /// working on determining purity
202 bool safetyInprocess; /// working on determining safety
203 bool nothrowInprocess; /// working on determining nothrow
204 bool nogcInprocess; /// working on determining @nogc
205 bool returnInprocess; /// working on inferring 'return' for parameters
206 bool inlineScanned; /// function has been scanned for inline possibilities
207 bool inferScope; /// infer 'scope' for parameters
208 bool hasCatches; /// function has try-catch statements
209 bool skipCodegen; /// do not generate code for this function.
210 bool printf; /// is a printf-like function
212 bool scanf; /// is a scanf-like function
213 bool noreturn; /// the function does not return
214 bool isNRVO = true; /// Support for named return value optimization
215 bool isNaked; /// The function is 'naked' (see inline ASM)
216 bool isGenerated; /// The function is compiler generated (e.g. `opCmp`)
217 bool isIntroducing; /// If this function introduces the overload set
218 bool hasSemantic3Errors; /// If errors in semantic3 this function's frame ptr
219 bool hasNoEH; /// No exception unwinding is needed
220 bool inferRetType; /// Return type is to be inferred
221 bool hasDualContext; /// has a dual-context 'this' parameter
223 bool hasAlwaysInlines; /// Contains references to functions that must be inlined
224 bool isCrtCtor; /// Has attribute pragma(crt_constructor)
225 bool isCrtDtor; /// Has attribute pragma(crt_destructor)
226 bool hasEscapingSiblings;/// Has sibling functions that escape
227 bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed
228 bool dllImport; /// __declspec(dllimport)
229 bool dllExport; /// __declspec(dllexport)
232 /***********************************************************
233 * Tuple of result identifier (possibly null) and statement.
234 * This is used to store out contracts: out(id){ ensure }
236 extern (C++) struct Ensure
238 Identifier id;
239 Statement ensure;
241 Ensure syntaxCopy()
243 return Ensure(id, ensure.syntaxCopy());
246 /*****************************************
247 * Do syntax copy of an array of Ensure's.
249 static Ensures* arraySyntaxCopy(Ensures* a)
251 Ensures* b = null;
252 if (a)
254 b = a.copy();
255 foreach (i, e; *a)
257 (*b)[i] = e.syntaxCopy();
260 return b;
265 /***********************************************************
266 * Most functions don't have contracts, so save memory by grouping
267 * this information into a separate struct
269 private struct ContractInfo
271 Statements* frequires; /// in contracts
272 Ensures* fensures; /// out contracts
273 Statement frequire; /// lowered in contract
274 Statement fensure; /// lowered out contract
275 FuncDeclaration fdrequire; /// function that does the in contract
276 FuncDeclaration fdensure; /// function that does the out contract
277 Expressions* fdrequireParams; /// argument list for __require
278 Expressions* fdensureParams; /// argument list for __ensure
281 /***********************************************************
283 extern (C++) class FuncDeclaration : Declaration
285 Statement fbody; /// function body
287 FuncDeclarations foverrides; /// functions this function overrides
289 private ContractInfo* contracts; /// contract information
291 const(char)* mangleString; /// mangled symbol created from mangleExact()
293 VarDeclaration vresult; /// result variable for out contracts
294 LabelDsymbol returnLabel; /// where the return goes
296 bool[size_t] isTypeIsolatedCache; /// cache for the potentially very expensive isTypeIsolated check
298 // used to prevent symbols in different
299 // scopes from having the same name
300 DsymbolTable localsymtab;
301 VarDeclaration vthis; /// 'this' parameter (member and nested)
302 VarDeclaration v_arguments; /// '_arguments' parameter
304 VarDeclaration v_argptr; /// '_argptr' variable
305 VarDeclarations* parameters; /// Array of VarDeclaration's for parameters
306 DsymbolTable labtab; /// statement label symbol table
307 Dsymbol overnext; /// next in overload list
308 FuncDeclaration overnext0; /// next in overload list (only used during IFTI)
309 Loc endloc; /// location of closing curly bracket
310 int vtblIndex = -1; /// for member functions, index into vtbl[]
312 ILS inlineStatusStmt = ILS.uninitialized;
313 ILS inlineStatusExp = ILS.uninitialized;
314 PINLINE inlining = PINLINE.default_;
316 int inlineNest; /// !=0 if nested inline
318 ForeachStatement fes; /// if foreach body, this is the foreach
319 BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[]
320 /** if !=NULL, then this is the type
321 of the 'introducing' function
322 this one is overriding
324 Type tintro;
326 StorageClass storage_class2; /// storage class for template onemember's
328 // Things that should really go into Scope
330 /// 1 if there's a return exp; statement
331 /// 2 if there's a throw statement
332 /// 4 if there's an assert(0)
333 /// 8 if there's inline asm
334 /// 16 if there are multiple return statements
335 int hasReturnExp;
337 VarDeclaration nrvo_var; /// variable to replace with shidden
338 Symbol* shidden; /// hidden pointer passed to function
340 ReturnStatements* returns;
342 GotoStatements* gotos; /// Gotos with forward references
344 version (MARS)
346 VarDeclarations* alignSectionVars; /// local variables with alignment needs larger than stackAlign
347 Symbol* salignSection; /// pointer to aligned section, if any
350 /// set if this is a known, builtin function we can evaluate at compile time
351 BUILTIN builtin = BUILTIN.unknown;
353 /// set if someone took the address of this function
354 int tookAddressOf;
356 bool requiresClosure; // this function needs a closure
358 /** local variables in this function which are referenced by nested functions
359 * (They'll get put into the "closure" for this function.)
361 VarDeclarations closureVars;
363 /** Outer variables which are referenced by this nested function
364 * (the inverse of closureVars)
366 VarDeclarations outerVars;
368 /// Sibling nested functions which called this one
369 FuncDeclarations siblingCallers;
371 FuncDeclarations *inlinedNestedCallees;
373 /// In case of failed `@safe` inference, store the error that made the function `@system` for
374 /// better diagnostics
375 AttributeViolation* safetyViolation;
376 AttributeViolation* nogcViolation;
377 AttributeViolation* pureViolation;
378 AttributeViolation* nothrowViolation;
380 /// See the `FUNCFLAG` struct
381 import dmd.common.bitfields;
382 mixin(generateBitFields!(FUNCFLAG, uint));
385 * Data for a function declaration that is needed for the Objective-C
386 * integration.
388 ObjcFuncDeclaration objc;
390 extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false)
392 super(loc, ident);
393 //.printf("FuncDeclaration(id = '%s', type = %s)\n", ident.toChars(), type.toChars());
394 //.printf("storage_class = x%llx\n", storage_class);
395 this.storage_class = storage_class;
396 this.type = type;
397 if (type)
399 // Normalize storage_class, because function-type related attributes
400 // are already set in the 'type' in parsing phase.
401 this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
403 this.endloc = endloc;
404 if (noreturn)
405 this.noreturn = true;
407 /* The type given for "infer the return type" is a TypeFunction with
408 * NULL for the return type.
410 if (type && type.nextOf() is null)
411 this.inferRetType = true;
414 static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
416 return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn);
419 final nothrow pure @safe
421 private ref ContractInfo getContracts()
423 if (!contracts)
424 contracts = new ContractInfo();
425 return *contracts;
428 // getters
429 inout(Statements*) frequires() inout { return contracts ? contracts.frequires : null; }
430 inout(Ensures*) fensures() inout { return contracts ? contracts.fensures : null; }
431 inout(Statement) frequire() inout { return contracts ? contracts.frequire: null; }
432 inout(Statement) fensure() inout { return contracts ? contracts.fensure : null; }
433 inout(FuncDeclaration) fdrequire() inout { return contracts ? contracts.fdrequire : null; }
434 inout(FuncDeclaration) fdensure() inout { return contracts ? contracts.fdensure: null; }
435 inout(Expressions*) fdrequireParams() inout { return contracts ? contracts.fdrequireParams: null; }
436 inout(Expressions*) fdensureParams() inout { return contracts ? contracts.fdensureParams: null; }
438 extern (D) private static string generateContractSetter(string field, string type)
440 return type ~ " " ~ field ~ "(" ~ type ~ " param)" ~
442 if (!param && !contracts) return null;
443 return getContracts()." ~ field ~ " = param;
447 mixin(generateContractSetter("frequires", "Statements*"));
448 mixin(generateContractSetter("fensures", "Ensures*"));
449 mixin(generateContractSetter("frequire", "Statement"));
450 mixin(generateContractSetter("fensure", "Statement"));
451 mixin(generateContractSetter("fdrequire", "FuncDeclaration"));
452 mixin(generateContractSetter("fdensure", "FuncDeclaration"));
453 mixin(generateContractSetter("fdrequireParams", "Expressions*"));
454 mixin(generateContractSetter("fdensureParams", "Expressions*"));
457 override FuncDeclaration syntaxCopy(Dsymbol s)
459 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
460 FuncDeclaration f = s ? cast(FuncDeclaration)s
461 : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), this.noreturn != 0);
462 f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
463 f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
464 f.fbody = fbody ? fbody.syntaxCopy() : null;
465 return f;
468 /****************************************************
469 * Resolve forward reference of function signature -
470 * parameter types, return type, and attributes.
471 * Returns:
472 * false if any errors exist in the signature.
474 final bool functionSemantic()
476 //printf("functionSemantic() %p %s\n", this, toChars());
477 if (!_scope)
478 return !errors;
480 this.cppnamespace = _scope.namespace;
482 if (!originalType) // semantic not yet run
484 TemplateInstance spec = isSpeculative();
485 uint olderrs = global.errors;
486 uint oldgag = global.gag;
487 if (global.gag && !spec)
488 global.gag = 0;
489 dsymbolSemantic(this, _scope);
490 global.gag = oldgag;
491 if (spec && global.errors != olderrs)
492 spec.errors = (global.errors - olderrs != 0);
493 if (olderrs != global.errors) // if errors compiling this function
494 return false;
497 // if inferring return type, sematic3 needs to be run
498 // - When the function body contains any errors, we cannot assume
499 // the inferred return type is valid.
500 // So, the body errors should become the function signature error.
501 if (inferRetType && type && !type.nextOf())
502 return functionSemantic3();
504 TemplateInstance ti;
505 if (isInstantiated() && !isVirtualMethod() &&
506 ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident))
508 AggregateDeclaration ad = isMemberLocal();
509 if (ad && ad.sizeok != Sizeok.done)
511 /* Currently dmd cannot resolve forward references per methods,
512 * then setting SIZOKfwd is too conservative and would break existing code.
513 * So, just stop method attributes inference until ad.dsymbolSemantic() done.
515 //ad.sizeok = Sizeok.fwd;
517 else
518 return functionSemantic3() || !errors;
521 if (storage_class & STC.inference)
522 return functionSemantic3() || !errors;
524 return !errors;
527 /****************************************************
528 * Resolve forward reference of function body.
529 * Returns false if any errors exist in the body.
531 final bool functionSemantic3()
533 if (semanticRun < PASS.semantic3 && _scope)
535 /* Forward reference - we need to run semantic3 on this function.
536 * If errors are gagged, and it's not part of a template instance,
537 * we need to temporarily ungag errors.
539 TemplateInstance spec = isSpeculative();
540 uint olderrs = global.errors;
541 uint oldgag = global.gag;
542 if (global.gag && !spec)
543 global.gag = 0;
544 semantic3(this, _scope);
545 global.gag = oldgag;
547 // If it is a speculatively-instantiated template, and errors occur,
548 // we need to mark the template as having errors.
549 if (spec && global.errors != olderrs)
550 spec.errors = (global.errors - olderrs != 0);
551 if (olderrs != global.errors) // if errors compiling this function
552 return false;
555 return !errors && !this.hasSemantic3Errors();
558 /****************************************************
559 * Check that this function type is properly resolved.
560 * If not, report "forward reference error" and return true.
562 extern (D) final bool checkForwardRef(const ref Loc loc)
564 if (!functionSemantic())
565 return true;
567 /* No deco means the functionSemantic() call could not resolve
568 * forward referenes in the type of this function.
570 if (!type.deco)
572 bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3);
573 .error(loc, "forward reference to %s`%s`",
574 (inSemantic3 ? "inferred return type of function " : "").ptr,
575 toChars());
576 return true;
578 return false;
581 // called from semantic3
583 * Creates and returns the hidden parameters for this function declaration.
585 * Hidden parameters include the `this` parameter of a class, struct or
586 * nested function and the selector parameter for Objective-C methods.
588 extern (D) final void declareThis(Scope* sc)
590 const bool dualCtx = (toParent2() != toParentLocal());
591 if (dualCtx)
592 this.hasDualContext = true;
593 auto ad = isThis();
594 if (!dualCtx && !ad && !isNested())
596 vthis = null;
597 objc.selectorParameter = null;
598 return;
601 Type addModStc(Type t)
603 return t.addMod(type.mod).addStorageClass(storage_class);
606 if (dualCtx || isNested())
608 /* The 'this' for a nested function is the link to the
609 * enclosing function's stack frame.
610 * Note that nested functions and member functions are disjoint.
612 Type tthis = addModStc(dualCtx ?
613 Type.tvoidptr.sarrayOf(2).pointerTo() :
614 Type.tvoid.pointerTo());
615 vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null);
616 vthis.storage_class |= STC.parameter | STC.nodtor;
618 else if (ad)
620 Type thandle = addModStc(ad.handleType());
621 vthis = new ThisDeclaration(loc, thandle);
622 vthis.storage_class |= STC.parameter;
623 if (thandle.ty == Tstruct)
625 vthis.storage_class |= STC.ref_;
629 if (auto tf = type.isTypeFunction())
631 if (tf.isreturn)
632 vthis.storage_class |= STC.return_;
633 if (tf.isScopeQual)
634 vthis.storage_class |= STC.scope_;
635 if (tf.isreturnscope)
636 vthis.storage_class |= STC.returnScope;
639 vthis.dsymbolSemantic(sc);
640 if (!sc.insert(vthis))
641 assert(0);
642 vthis.parent = this;
643 if (ad)
644 objc.selectorParameter = .objc.createSelectorParameter(this, sc);
647 override final bool equals(const RootObject o) const
649 if (this == o)
650 return true;
652 if (auto s = isDsymbol(o))
654 auto fd1 = this;
655 auto fd2 = s.isFuncDeclaration();
656 if (!fd2)
657 return false;
659 auto fa1 = fd1.isFuncAliasDeclaration();
660 auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
662 auto fa2 = fd2.isFuncAliasDeclaration();
663 auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
665 if (fa1 && fa2)
667 return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
670 bool b1 = fa1 !is null;
671 if (b1 && faf1.isUnique() && !fa1.hasOverloads)
672 b1 = false;
674 bool b2 = fa2 !is null;
675 if (b2 && faf2.isUnique() && !fa2.hasOverloads)
676 b2 = false;
678 if (b1 != b2)
679 return false;
681 return faf1.toParent().equals(faf2.toParent()) &&
682 faf1.ident.equals(faf2.ident) &&
683 faf1.type.equals(faf2.type);
685 return false;
688 /****************************************************
689 * Determine if 'this' overrides fd.
690 * Return !=0 if it does.
692 final int overrides(FuncDeclaration fd)
694 int result = 0;
695 if (fd.ident == ident)
697 const cov = type.covariant(fd.type);
698 if (cov != Covariant.distinct)
700 ClassDeclaration cd1 = toParent().isClassDeclaration();
701 ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
702 if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
703 result = 1;
706 return result;
709 /*************************************************
710 * Find index of function in vtbl[0..length] that
711 * this function overrides.
712 * Prefer an exact match to a covariant one.
713 * Params:
714 * vtbl = vtable to use
715 * dim = maximal vtable dimension
716 * Returns:
717 * -1 didn't find one
718 * -2 can't determine because of forward references
720 final int findVtblIndex(Dsymbols* vtbl, int dim)
722 //printf("findVtblIndex() %s\n", toChars());
723 FuncDeclaration mismatch = null;
724 StorageClass mismatchstc = 0;
725 int mismatchvi = -1;
726 int exactvi = -1;
727 int bestvi = -1;
728 for (int vi = 0; vi < dim; vi++)
730 FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration();
731 if (fdv && fdv.ident == ident)
733 if (type.equals(fdv.type)) // if exact match
735 if (fdv.parent.isClassDeclaration())
737 if (fdv.isFuture())
739 bestvi = vi;
740 continue; // keep looking
742 return vi; // no need to look further
745 if (exactvi >= 0)
747 .error(loc, "%s `%s` cannot determine overridden function", kind, toPrettyChars);
748 return exactvi;
750 exactvi = vi;
751 bestvi = vi;
752 continue;
755 StorageClass stc = 0;
756 const cov = type.covariant(fdv.type, &stc);
757 //printf("\tbaseclass cov = %d\n", cov);
758 final switch (cov)
760 case Covariant.distinct:
761 // types are distinct
762 break;
764 case Covariant.yes:
765 bestvi = vi; // covariant, but not identical
766 break;
767 // keep looking for an exact match
769 case Covariant.no:
770 mismatchvi = vi;
771 mismatchstc = stc;
772 mismatch = fdv; // overrides, but is not covariant
773 break;
774 // keep looking for an exact match
776 case Covariant.fwdref:
777 return -2; // forward references
781 if (_linkage == LINK.cpp && bestvi != -1)
783 StorageClass stc = 0;
784 FuncDeclaration fdv = (*vtbl)[bestvi].isFuncDeclaration();
785 assert(fdv && fdv.ident == ident);
786 if (type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no)
788 /* https://issues.dlang.org/show_bug.cgi?id=22351
789 * Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not.
790 * For now, continue to allow D covariant rules to apply when `override` has been used,
791 * but issue a deprecation warning that this behaviour will change in the future.
792 * Otherwise, follow the C++ covariant rules, which will create a new vtable entry.
794 if (isOverride())
796 /* @@@DEPRECATED_2.110@@@
797 * After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch,
798 * but also the `cppCovariant` parameter from Type.covariant, and update the function
799 * so that both `LINK.cpp` covariant conditions within are always checked.
801 .deprecation(loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated",
802 fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(),
803 toPrettyChars(), type.toTypeFunction().parameterList.parametersTypeToChars(), type.modToChars());
805 const char* where = type.isNaked() ? "parameters" : "type";
806 deprecationSupplemental(loc, "Either remove `override`, or adjust the `const` qualifiers of the "
807 ~ "overriding function %s", where);
809 else
811 // Treat as if Covariant.no
812 mismatchvi = bestvi;
813 mismatchstc = stc;
814 mismatch = fdv;
815 bestvi = -1;
819 if (bestvi == -1 && mismatch)
821 //type.print();
822 //mismatch.type.print();
823 //printf("%s %s\n", type.deco, mismatch.type.deco);
824 //printf("stc = %llx\n", mismatchstc);
825 if (mismatchstc)
827 // Fix it by modifying the type to add the storage classes
828 type = type.addStorageClass(mismatchstc);
829 bestvi = mismatchvi;
832 return bestvi;
835 /*********************************
836 * If function a function in a base class,
837 * return that base class.
838 * Returns:
839 * base class if overriding, null if not
841 final BaseClass* overrideInterface()
843 for (ClassDeclaration cd = toParent2().isClassDeclaration(); cd; cd = cd.baseClass)
845 foreach (b; cd.interfaces)
847 auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.length);
848 if (v >= 0)
849 return b;
852 return null;
855 /****************************************************
856 * Overload this FuncDeclaration with the new one f.
857 * Return true if successful; i.e. no conflict.
859 override bool overloadInsert(Dsymbol s)
861 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
862 assert(s != this);
863 AliasDeclaration ad = s.isAliasDeclaration();
864 if (ad)
866 if (overnext)
867 return overnext.overloadInsert(ad);
868 if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof)
870 //printf("\tad = '%s'\n", ad.type.toChars());
871 return false;
873 overnext = ad;
874 //printf("\ttrue: no conflict\n");
875 return true;
877 TemplateDeclaration td = s.isTemplateDeclaration();
878 if (td)
880 if (!td.funcroot)
881 td.funcroot = this;
882 if (overnext)
883 return overnext.overloadInsert(td);
884 overnext = td;
885 return true;
887 FuncDeclaration fd = s.isFuncDeclaration();
888 if (!fd)
889 return false;
891 version (none)
893 /* Disable this check because:
894 * const void foo();
895 * semantic() isn't run yet on foo(), so the const hasn't been
896 * applied yet.
898 if (type)
900 printf("type = %s\n", type.toChars());
901 printf("fd.type = %s\n", fd.type.toChars());
903 // fd.type can be NULL for overloaded constructors
904 if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
906 //printf("\tfalse: conflict %s\n", kind());
907 return false;
911 if (overnext)
913 td = overnext.isTemplateDeclaration();
914 if (td)
915 fd.overloadInsert(td);
916 else
917 return overnext.overloadInsert(fd);
919 overnext = fd;
920 //printf("\ttrue: no conflict\n");
921 return true;
924 /********************************************
925 * Find function in overload list that exactly matches t.
927 extern (D) final FuncDeclaration overloadExactMatch(Type t)
929 FuncDeclaration fd;
930 overloadApply(this, (Dsymbol s)
932 auto f = s.isFuncDeclaration();
933 if (!f)
934 return 0;
935 if (f.storage_class & STC.disable)
936 return 0;
937 if (t.equals(f.type))
939 fd = f;
940 return 1;
943 /* Allow covariant matches, as long as the return type
944 * is just a const conversion.
945 * This allows things like pure functions to match with an impure function type.
947 if (t.ty == Tfunction)
949 auto tf = cast(TypeFunction)f.type;
950 if (tf.covariant(t) == Covariant.yes &&
951 tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
953 fd = f;
954 return 1;
957 return 0;
959 return fd;
962 /********************************************
963 * Find function in overload list that matches to the 'this' modifier.
964 * There's four result types.
966 * 1. If the 'tthis' matches only one candidate, it's an "exact match".
967 * Returns the function and 'hasOverloads' is set to false.
968 * eg. If 'tthis" is mutable and there's only one mutable method.
969 * 2. If there's two or more match candidates, but a candidate function will be
970 * a "better match".
971 * Returns the better match function but 'hasOverloads' is set to true.
972 * eg. If 'tthis' is mutable, and there's both mutable and const methods,
973 * the mutable method will be a better match.
974 * 3. If there's two or more match candidates, but there's no better match,
975 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
976 * eg. If 'tthis' is mutable, and there's two or more mutable methods.
977 * 4. If there's no candidates, it's "no match" and returns null with error report.
978 * e.g. If 'tthis' is const but there's no const methods.
980 extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
982 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
983 MatchAccumulator m;
984 overloadApply(this, (Dsymbol s)
986 auto f = s.isFuncDeclaration();
987 if (!f || f == m.lastf) // skip duplicates
988 return 0;
990 auto tf = f.type.toTypeFunction();
991 //printf("tf = %s\n", tf.toChars());
993 MATCH match;
994 if (tthis) // non-static functions are preferred than static ones
996 if (f.needThis())
997 match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
998 else
999 match = MATCH.constant; // keep static function in overload candidates
1001 else // static functions are preferred than non-static ones
1003 if (f.needThis())
1004 match = MATCH.convert;
1005 else
1006 match = MATCH.exact;
1008 if (match == MATCH.nomatch)
1009 return 0;
1011 if (match > m.last) goto LcurrIsBetter;
1012 if (match < m.last) goto LlastIsBetter;
1014 // See if one of the matches overrides the other.
1015 if (m.lastf.overrides(f)) goto LlastIsBetter;
1016 if (f.overrides(m.lastf)) goto LcurrIsBetter;
1018 //printf("\tambiguous\n");
1019 m.nextf = f;
1020 m.count++;
1021 return 0;
1023 LlastIsBetter:
1024 //printf("\tlastbetter\n");
1025 m.count++; // count up
1026 return 0;
1028 LcurrIsBetter:
1029 //printf("\tisbetter\n");
1030 if (m.last <= MATCH.convert)
1032 // clear last secondary matching
1033 m.nextf = null;
1034 m.count = 0;
1036 m.last = match;
1037 m.lastf = f;
1038 m.count++; // count up
1039 return 0;
1042 if (m.count == 1) // exact match
1044 hasOverloads = false;
1046 else if (m.count > 1) // better or ambiguous match
1048 hasOverloads = true;
1050 else // no match
1052 hasOverloads = true;
1053 auto tf = this.type.toTypeFunction();
1054 assert(tthis);
1055 assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
1057 OutBuffer thisBuf, funcBuf;
1058 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
1059 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
1060 .error(loc, "%smethod %s is not callable using a %sobject", kind, toPrettyChars,
1061 funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
1064 return m.lastf;
1067 /********************************************
1068 * find function template root in overload list
1070 extern (D) final TemplateDeclaration findTemplateDeclRoot()
1072 FuncDeclaration f = this;
1073 while (f && f.overnext)
1075 //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
1076 TemplateDeclaration td = f.overnext.isTemplateDeclaration();
1077 if (td)
1078 return td;
1079 f = f.overnext.isFuncDeclaration();
1081 return null;
1084 /********************************************
1085 * Returns true if function was declared
1086 * directly or indirectly in a unittest block
1088 final bool inUnittest()
1090 Dsymbol f = this;
1093 if (f.isUnitTestDeclaration())
1094 return true;
1095 f = f.toParent();
1097 while (f);
1098 return false;
1101 /*************************************
1102 * Determine partial specialization order of 'this' vs g.
1103 * This is very similar to TemplateDeclaration::leastAsSpecialized().
1104 * Returns:
1105 * match 'this' is at least as specialized as g
1106 * 0 g is more specialized than 'this'
1108 final MATCH leastAsSpecialized(FuncDeclaration g, Identifiers* names)
1110 enum LOG_LEASTAS = 0;
1111 static if (LOG_LEASTAS)
1113 import core.stdc.stdio : printf;
1114 printf("%s.leastAsSpecialized(%s, %s)\n", toChars(), g.toChars(), names ? names.toChars() : "null");
1115 printf("%s, %s\n", type.toChars(), g.type.toChars());
1118 /* This works by calling g() with f()'s parameters, and
1119 * if that is possible, then f() is at least as specialized
1120 * as g() is.
1123 TypeFunction tf = type.toTypeFunction();
1124 TypeFunction tg = g.type.toTypeFunction();
1126 /* If both functions have a 'this' pointer, and the mods are not
1127 * the same and g's is not const, then this is less specialized.
1129 if (needThis() && g.needThis() && tf.mod != tg.mod)
1131 if (isCtorDeclaration())
1133 if (!MODimplicitConv(tg.mod, tf.mod))
1134 return MATCH.nomatch;
1136 else
1138 if (!MODimplicitConv(tf.mod, tg.mod))
1139 return MATCH.nomatch;
1143 /* Create a dummy array of arguments out of the parameters to f()
1145 Expressions args;
1146 foreach (u, p; tf.parameterList)
1148 Expression e;
1149 if (p.isReference())
1151 e = new IdentifierExp(Loc.initial, p.ident);
1152 e.type = p.type;
1154 else
1155 e = p.type.defaultInitLiteral(Loc.initial);
1156 args.push(e);
1159 MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
1160 if (m > MATCH.nomatch)
1162 /* A variadic parameter list is less specialized than a
1163 * non-variadic one.
1165 if (tf.parameterList.varargs && !tg.parameterList.varargs)
1166 goto L1; // less specialized
1168 static if (LOG_LEASTAS)
1170 printf(" matches %d, so is least as specialized\n", m);
1172 return m;
1175 static if (LOG_LEASTAS)
1177 printf(" doesn't match, so is not as specialized\n");
1179 return MATCH.nomatch;
1182 /********************************
1183 * Searches for a label with the given identifier. This function will insert a new
1184 * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
1186 * Params:
1187 * ident = identifier of the requested label
1188 * loc = location used when creating a new `LabelDsymbol`
1190 * Returns: the `LabelDsymbol` for `ident`
1192 final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial)
1194 Dsymbol s;
1195 if (!labtab)
1196 labtab = new DsymbolTable(); // guess we need one
1198 s = labtab.lookup(ident);
1199 if (!s)
1201 s = new LabelDsymbol(ident, loc);
1202 labtab.insert(s);
1204 return cast(LabelDsymbol)s;
1207 /*****************************************
1208 * Determine lexical level difference from `this` to nested function `fd`.
1209 * Params:
1210 * fd = target of call
1211 * intypeof = !=0 if inside typeof
1212 * Returns:
1213 * 0 same level
1214 * >0 decrease nesting by number
1215 * -1 increase nesting by 1 (`fd` is nested within `this`)
1216 * LevelError error, `this` cannot call `fd`
1218 final int getLevel(FuncDeclaration fd, int intypeof)
1220 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
1221 Dsymbol fdparent = fd.toParent2();
1222 if (fdparent == this)
1223 return -1;
1225 Dsymbol s = this;
1226 int level = 0;
1227 while (fd != s && fdparent != s.toParent2())
1229 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
1230 if (auto thisfd = s.isFuncDeclaration())
1232 if (!thisfd.isNested() && !thisfd.vthis && !intypeof)
1233 return LevelError;
1235 else
1237 if (auto thiscd = s.isAggregateDeclaration())
1239 /* AggregateDeclaration::isNested returns true only when
1240 * it has a hidden pointer.
1241 * But, calling the function belongs unrelated lexical scope
1242 * is still allowed inside typeof.
1244 * struct Map(alias fun) {
1245 * typeof({ return fun(); }) RetType;
1246 * // No member function makes Map struct 'not nested'.
1249 if (!thiscd.isNested() && !intypeof)
1250 return LevelError;
1252 else
1253 return LevelError;
1256 s = s.toParentP(fd);
1257 assert(s);
1258 level++;
1260 return level;
1263 /***********************************
1264 * Determine lexical level difference from `this` to nested function `fd`.
1265 * Issue error if `this` cannot call `fd`.
1267 * Params:
1268 * loc = location for error messages
1269 * sc = context
1270 * fd = target of call
1271 * decl = The `Declaration` that triggered this check.
1272 * Used to provide a better error message only.
1273 * Returns:
1274 * 0 same level
1275 * >0 decrease nesting by number
1276 * -1 increase nesting by 1 (`fd` is nested within 'this')
1277 * LevelError error
1279 final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd,
1280 Declaration decl)
1282 int level = getLevel(fd, sc.intypeof);
1283 if (level != LevelError)
1284 return level;
1286 // Don't give error if in template constraint
1287 if (!(sc.flags & SCOPE.constraint))
1289 const(char)* xstatic = isStatic() ? "`static` " : "";
1290 // better diagnostics for static functions
1291 .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
1292 xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(),
1293 fd.toPrettyChars());
1294 .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
1295 return LevelError;
1297 return 1;
1300 enum LevelError = -2;
1302 override const(char)* toPrettyChars(bool QualifyTypes = false)
1304 if (isMain())
1305 return "D main";
1306 else
1307 return Dsymbol.toPrettyChars(QualifyTypes);
1310 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
1311 final const(char)* toFullSignature()
1313 OutBuffer buf;
1314 functionToBufferWithIdent(type.toTypeFunction(), buf, toChars(), isStatic);
1315 return buf.extractChars();
1318 final bool isMain() const
1320 return ident == Id.main && resolvedLinkage() != LINK.c && !isMember() && !isNested();
1323 final bool isCMain() const
1325 return ident == Id.main && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1328 final bool isWinMain() const
1330 //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1331 version (none)
1333 bool x = ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1334 printf("%s\n", x ? "yes" : "no");
1335 return x;
1337 else
1339 return ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1343 final bool isDllMain() const
1345 return ident == Id.DllMain && resolvedLinkage() != LINK.c && !isMember();
1348 final bool isRtInit() const
1350 return ident == Id.rt_init && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1353 override final bool isExport() const
1355 return visibility.kind == Visibility.Kind.export_ || dllExport;
1358 override final bool isImportedSymbol() const
1360 //printf("isImportedSymbol()\n");
1361 //printf("protection = %d\n", visibility);
1362 return (visibility.kind == Visibility.Kind.export_ || dllImport) && !fbody;
1365 override final bool isCodeseg() const pure nothrow @nogc @safe
1367 return true; // functions are always in the code segment
1370 override final bool isOverloadable() const
1372 return true; // functions can be overloaded
1375 /***********************************
1376 * Override so it can work even if semantic() hasn't yet
1377 * been run.
1379 override final bool isAbstract()
1381 if (storage_class & STC.abstract_)
1382 return true;
1383 if (semanticRun >= PASS.semanticdone)
1384 return false;
1386 if (_scope)
1388 if (_scope.stc & STC.abstract_)
1389 return true;
1390 parent = _scope.parent;
1391 Dsymbol parent = toParent();
1392 if (parent.isInterfaceDeclaration())
1393 return true;
1395 return false;
1398 /**********************************
1399 * Decide if attributes for this function can be inferred from examining
1400 * the function body.
1401 * Returns:
1402 * true if can
1404 final bool canInferAttributes(Scope* sc)
1406 if (!fbody)
1407 return false;
1409 if (isVirtualMethod() &&
1411 * https://issues.dlang.org/show_bug.cgi?id=21719
1413 * If we have an auto virtual function we can infer
1414 * the attributes.
1416 !(inferRetType && !isCtorDeclaration()))
1417 return false; // since they may be overridden
1419 if (sc.func &&
1420 /********** this is for backwards compatibility for the moment ********/
1421 (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
1422 return true;
1424 if (isFuncLiteralDeclaration() || // externs are not possible with literals
1425 (storage_class & STC.inference) || // do attribute inference
1426 (inferRetType && !isCtorDeclaration()))
1427 return true;
1429 if (isInstantiated())
1431 auto ti = parent.isTemplateInstance();
1432 if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
1433 return true;
1436 return false;
1439 /*****************************************
1440 * Initialize for inferring the attributes of this function.
1442 final void initInferAttributes()
1444 //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1445 TypeFunction tf = type.toTypeFunction();
1446 if (tf.purity == PURE.impure) // purity not specified
1447 purityInprocess = true;
1449 if (tf.trust == TRUST.default_)
1450 safetyInprocess = true;
1452 if (!tf.isnothrow)
1453 nothrowInprocess = true;
1455 if (!tf.isnogc)
1456 nogcInprocess = true;
1458 if (!isVirtual() || this.isIntroducing())
1459 returnInprocess = true;
1461 // Initialize for inferring STC.scope_
1462 inferScope = true;
1465 final PURE isPure()
1467 //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1468 TypeFunction tf = type.toTypeFunction();
1469 if (purityInprocess)
1470 setImpure();
1471 if (tf.purity == PURE.fwdref)
1472 tf.purityLevel();
1473 PURE purity = tf.purity;
1474 if (purity > PURE.weak && isNested())
1475 purity = PURE.weak;
1476 if (purity > PURE.weak && needThis())
1478 // The attribute of the 'this' reference affects purity strength
1479 if (type.mod & MODFlags.immutable_)
1482 else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
1483 purity = PURE.const_;
1484 else
1485 purity = PURE.weak;
1487 tf.purity = purity;
1488 // ^ This rely on the current situation that every FuncDeclaration has a
1489 // unique TypeFunction.
1490 return purity;
1493 final PURE isPureBypassingInference()
1495 if (purityInprocess)
1496 return PURE.fwdref;
1497 else
1498 return isPure();
1501 /**************************************
1502 * The function is doing something impure, so mark it as impure.
1504 * Params:
1505 * loc = location of impure action
1506 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1507 * arg0 = (optional) argument to format string
1509 * Returns: `true` if there's a purity error
1511 extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
1513 if (purityInprocess)
1515 purityInprocess = false;
1516 if (fmt)
1517 pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action
1518 else if (arg0)
1519 pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
1521 if (fes)
1522 fes.func.setImpure(loc, fmt, arg0);
1524 else if (isPure())
1525 return true;
1526 return false;
1529 extern (D) final uint flags()
1531 return bitFields;
1534 extern (D) final uint flags(uint f)
1536 bitFields = f;
1537 return bitFields;
1540 final bool isSafe()
1542 if (safetyInprocess)
1543 setUnsafe();
1544 return type.toTypeFunction().trust == TRUST.safe;
1547 final bool isSafeBypassingInference()
1549 return !(safetyInprocess) && isSafe();
1552 final bool isTrusted()
1554 if (safetyInprocess)
1555 setUnsafe();
1556 return type.toTypeFunction().trust == TRUST.trusted;
1559 /**************************************
1560 * The function is doing something unsafe, so mark it as unsafe.
1562 * Params:
1563 * gag = surpress error message (used in escape.d)
1564 * loc = location of error
1565 * fmt = printf-style format string
1566 * arg0 = (optional) argument for first %s format specifier
1567 * arg1 = (optional) argument for second %s format specifier
1568 * arg2 = (optional) argument for third %s format specifier
1569 * Returns: whether there's a safe error
1571 extern (D) final bool setUnsafe(
1572 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
1573 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
1575 if (safetyInprocess)
1577 safetyInprocess = false;
1578 type.toTypeFunction().trust = TRUST.system;
1579 if (fmt || arg0)
1580 safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);
1582 if (fes)
1583 fes.func.setUnsafe();
1585 else if (isSafe())
1587 if (!gag && fmt)
1588 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
1590 return true;
1592 return false;
1595 /**************************************
1596 * The function is calling `@system` function `f`, so mark it as unsafe.
1598 * Params:
1599 * f = function being called (needed for diagnostic of inferred functions)
1600 * Returns: whether there's a safe error
1602 extern (D) final bool setUnsafeCall(FuncDeclaration f)
1604 return setUnsafe(false, f.loc, null, f, null);
1607 final bool isNogc()
1609 //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1610 if (nogcInprocess)
1611 setGC(loc, null);
1612 return type.toTypeFunction().isnogc;
1615 final bool isNogcBypassingInference()
1617 return !nogcInprocess && isNogc();
1620 /**************************************
1621 * The function is doing something that may allocate with the GC,
1622 * so mark it as not nogc (not no-how).
1624 * Params:
1625 * loc = location of impure action
1626 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1627 * arg0 = (optional) argument to format string
1629 * Returns:
1630 * true if function is marked as @nogc, meaning a user error occurred
1632 extern (D) final bool setGC(Loc loc, const(char)* fmt, RootObject arg0 = null)
1634 //printf("setGC() %s\n", toChars());
1635 if (nogcInprocess && semanticRun < PASS.semantic3 && _scope)
1637 this.semantic2(_scope);
1638 this.semantic3(_scope);
1641 if (nogcInprocess)
1643 nogcInprocess = false;
1644 if (fmt)
1645 nogcViolation = new AttributeViolation(loc, fmt, this, arg0); // action that requires GC
1646 else if (arg0)
1647 nogcViolation = new AttributeViolation(loc, fmt, arg0); // call to non-@nogc function
1649 type.toTypeFunction().isnogc = false;
1650 if (fes)
1651 fes.func.setGC(Loc.init, null, null);
1653 else if (isNogc())
1654 return true;
1655 return false;
1658 /**************************************
1659 * The function calls non-`@nogc` function f, mark it as not nogc.
1660 * Params:
1661 * f = function being called
1662 * Returns:
1663 * true if function is marked as @nogc, meaning a user error occurred
1665 extern (D) final bool setGCCall(FuncDeclaration f)
1667 return setGC(loc, null, f);
1670 /**************************************
1671 * The function is doing something that may throw an exception, register that in case nothrow is being inferred
1673 * Params:
1674 * loc = location of action
1675 * fmt = format string for error message
1676 * arg0 = (optional) argument to format string
1678 extern (D) final void setThrow(Loc loc, const(char)* fmt, RootObject arg0 = null)
1680 if (nothrowInprocess && !nothrowViolation)
1682 nothrowViolation = new AttributeViolation(loc, fmt, arg0); // action that requires GC
1686 /**************************************
1687 * The function calls non-`nothrow` function f, register that in case nothrow is being inferred
1688 * Params:
1689 * loc = location of call
1690 * f = function being called
1692 extern (D) final void setThrowCall(Loc loc, FuncDeclaration f)
1694 return setThrow(loc, null, f);
1697 extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
1699 if (!global.params.v.gc)
1700 return;
1702 Module m = getModule();
1703 if (m && m.isRoot() && !inUnittest())
1705 message(loc, "vgc: %s", warn);
1709 /********************************************
1710 * See if pointers from function parameters, mutable globals, or uplevel functions
1711 * could leak into return value.
1712 * Returns:
1713 * true if the function return value is isolated from
1714 * any inputs to the function
1716 extern (D) final bool isReturnIsolated()
1718 //printf("isReturnIsolated(this: %s)\n", this.toChars);
1719 TypeFunction tf = type.toTypeFunction();
1720 assert(tf.next);
1722 Type treti = tf.next;
1723 if (tf.isref)
1724 return isTypeIsolatedIndirect(treti); // check influence from parameters
1726 return isTypeIsolated(treti);
1729 /********************
1730 * See if pointers from function parameters, mutable globals, or uplevel functions
1731 * could leak into type `t`.
1732 * Params:
1733 * t = type to check if it is isolated
1734 * Returns:
1735 * true if `t` is isolated from
1736 * any inputs to the function
1738 extern (D) final bool isTypeIsolated(Type t)
1740 StringTable!Type parentTypes;
1741 const uniqueTypeID = t.getUniqueID();
1742 if (uniqueTypeID)
1744 const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
1745 if (cacheResultPtr !is null)
1746 return *cacheResultPtr;
1748 parentTypes._init();
1749 const isIsolated = isTypeIsolated(t, parentTypes);
1750 isTypeIsolatedCache[uniqueTypeID] = isIsolated;
1751 return isIsolated;
1753 else
1755 parentTypes._init();
1756 return isTypeIsolated(t, parentTypes);
1760 ///ditto
1761 extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
1763 //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
1765 t = t.baseElemOf();
1766 switch (t.ty)
1768 case Tarray:
1769 case Tpointer:
1770 return isTypeIsolatedIndirect(t.nextOf()); // go down one level
1772 case Taarray:
1773 case Tclass:
1774 return isTypeIsolatedIndirect(t);
1776 case Tstruct:
1777 /* Drill down and check the struct's fields
1779 auto sym = t.toDsymbol(null).isStructDeclaration();
1780 const tName = t.toChars.toDString;
1781 const entry = parentTypes.insert(tName, t);
1782 if (entry == null)
1784 //we've already seen this type in a parent, not isolated
1785 return false;
1787 foreach (v; sym.fields)
1789 Type tmi = v.type.addMod(t.mod);
1790 //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
1791 // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
1792 if (!isTypeIsolated(tmi, parentTypes))
1793 return false;
1795 return true;
1797 default:
1798 return true;
1802 /********************************************
1803 * Params:
1804 * t = type of object to test one level of indirection down
1805 * Returns:
1806 * true if an object typed `t` has no indirections
1807 * which could have come from the function's parameters, mutable
1808 * globals, or uplevel functions.
1810 private bool isTypeIsolatedIndirect(Type t)
1812 //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1813 assert(t);
1815 /* Since `t` is one level down from an indirection, it could pick
1816 * up a reference to a mutable global or an outer function, so
1817 * return false.
1819 if (!isPureBypassingInference() || isNested())
1820 return false;
1822 TypeFunction tf = type.toTypeFunction();
1824 //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1826 foreach (i, fparam; tf.parameterList)
1828 Type tp = fparam.type;
1829 if (!tp)
1830 continue;
1832 if (fparam.isLazy() || fparam.isReference())
1834 if (!traverseIndirections(tp, t))
1835 return false;
1836 continue;
1839 /* Goes down one level of indirection, then calls traverseIndirection() on
1840 * the result.
1841 * Returns:
1842 * true if t is isolated from tp
1844 static bool traverse(Type tp, Type t)
1846 tp = tp.baseElemOf();
1847 switch (tp.ty)
1849 case Tarray:
1850 case Tpointer:
1851 return traverseIndirections(tp.nextOf(), t);
1853 case Taarray:
1854 case Tclass:
1855 return traverseIndirections(tp, t);
1857 case Tstruct:
1858 /* Drill down and check the struct's fields
1860 auto sym = tp.toDsymbol(null).isStructDeclaration();
1861 foreach (v; sym.fields)
1863 Type tprmi = v.type.addMod(tp.mod);
1864 //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1865 if (!traverse(tprmi, t))
1866 return false;
1868 return true;
1870 default:
1871 return true;
1875 if (!traverse(tp, t))
1876 return false;
1878 // The 'this' reference is a parameter, too
1879 if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
1881 Type tthis = ad.getType().addMod(tf.mod);
1882 //printf("\ttthis = %s\n", tthis.toChars());
1883 if (!traverseIndirections(tthis, t))
1884 return false;
1887 return true;
1890 /****************************************
1891 * Determine if function needs a static frame pointer.
1892 * Returns:
1893 * `true` if function is really nested within other function.
1894 * Contracts:
1895 * If isNested() returns true, isThis() should return false,
1896 * unless the function needs a dual-context pointer.
1898 bool isNested() const
1900 auto f = toAliasFunc();
1901 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1902 return ((f.storage_class & STC.static_) == 0) &&
1903 (f._linkage == LINK.d) &&
1904 (f.toParent2().isFuncDeclaration() !is null ||
1905 f.toParent2() !is f.toParentLocal());
1908 /****************************************
1909 * Determine if function is a non-static member function
1910 * that has an implicit 'this' expression.
1911 * Returns:
1912 * The aggregate it is a member of, or null.
1913 * Contracts:
1914 * Both isThis() and isNested() should return true if function needs a dual-context pointer,
1915 * otherwise if isThis() returns true, isNested() should return false.
1917 override inout(AggregateDeclaration) isThis() inout
1919 //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1920 auto ad = (storage_class & STC.static_) ? .objc.isThis(this) : isMemberLocal();
1921 //printf("-FuncDeclaration::isThis() %p\n", ad);
1922 return ad;
1925 override final bool needThis()
1927 //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1928 return toAliasFunc().isThis() !is null;
1931 // Determine if a function is pedantically virtual
1932 final bool isVirtualMethod()
1934 if (toAliasFunc() != this)
1935 return toAliasFunc().isVirtualMethod();
1937 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1938 if (!isVirtual())
1939 return false;
1940 // If it's a final method, and does not override anything, then it is not virtual
1941 if (isFinalFunc() && foverrides.length == 0)
1943 return false;
1945 return true;
1948 // Determine if function goes into virtual function pointer table
1949 bool isVirtual() const
1951 if (toAliasFunc() != this)
1952 return toAliasFunc().isVirtual();
1954 auto p = toParent();
1956 if (!isMember || !p.isClassDeclaration)
1957 return false;
1959 if (p.isClassDeclaration.classKind == ClassKind.objc)
1960 return .objc.isVirtual(this);
1962 version (none)
1964 printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1965 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), visibility == Visibility.Kind.private_, isCtorDeclaration(), linkage != LINK.d);
1966 printf("result is %d\n", isMember() && !(isStatic() || visibility == Visibility.Kind.private_ || visibility == Visibility.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()));
1968 return !(isStatic() || visibility.kind == Visibility.Kind.private_ || visibility.kind == Visibility.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc());
1971 final bool isFinalFunc() const
1973 if (toAliasFunc() != this)
1974 return toAliasFunc().isFinalFunc();
1976 version (none)
1978 auto cd = toParent().isClassDeclaration();
1979 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal());
1980 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_));
1981 printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_)));
1982 if (cd)
1983 printf("\tmember of %s\n", cd.toChars());
1985 if (!isMember())
1986 return false;
1987 if (Declaration.isFinal())
1988 return true;
1989 auto cd = toParent().isClassDeclaration();
1990 return (cd !is null) && (cd.storage_class & STC.final_);
1993 bool addPreInvariant()
1995 auto ad = isThis();
1996 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1997 return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
2000 bool addPostInvariant()
2002 auto ad = isThis();
2003 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
2004 return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
2007 override const(char)* kind() const
2009 return this.isGenerated() ? "generated function" : "function";
2012 /********************************************
2013 * Returns:
2014 * true if there are no overloads of this function
2016 final bool isUnique() const
2018 bool result = false;
2019 overloadApply(cast() this, (Dsymbol s)
2021 auto f = s.isFuncDeclaration();
2022 auto td = s.isTemplateDeclaration();
2023 if (!f && !td)
2024 return 0;
2025 if (result)
2027 result = false;
2028 return 1; // ambiguous, done
2030 else
2032 result = true;
2033 return 0;
2036 return result;
2039 /*********************************************
2040 * In the current function, we are calling 'this' function.
2041 * 1. Check to see if the current function can call 'this' function, issue error if not.
2042 * 2. If the current function is not the parent of 'this' function, then add
2043 * the current function to the list of siblings of 'this' function.
2044 * 3. If the current function is a literal, and it's accessing an uplevel scope,
2045 * then mark it as a delegate.
2046 * Returns true if error occurs.
2048 extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
2050 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
2052 if (auto fld = this.isFuncLiteralDeclaration())
2054 if (fld.tok == TOK.reserved)
2056 fld.tok = TOK.function_;
2057 fld.vthis = null;
2061 if (!parent || parent == sc.parent)
2062 return false;
2063 if (ident == Id.require || ident == Id.ensure)
2064 return false;
2065 if (!isThis() && !isNested())
2066 return false;
2068 // The current function
2069 FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
2070 if (!fdthis)
2071 return false; // out of function scope
2073 Dsymbol p = toParentLocal();
2074 Dsymbol p2 = toParent2();
2076 // Function literals from fdthis to p must be delegates
2077 ensureStaticLinkTo(fdthis, p);
2078 if (p != p2)
2079 ensureStaticLinkTo(fdthis, p2);
2081 if (isNested())
2083 // The function that this function is in
2084 bool checkEnclosing(FuncDeclaration fdv)
2086 if (!fdv)
2087 return false;
2088 if (fdv == fdthis)
2089 return false;
2091 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
2092 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
2093 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
2095 // Add this function to the list of those which called us
2096 if (fdthis != this)
2098 bool found = false;
2099 for (size_t i = 0; i < siblingCallers.length; ++i)
2101 if (siblingCallers[i] == fdthis)
2102 found = true;
2104 if (!found)
2106 //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
2107 if (!sc.intypeof && !(sc.flags & SCOPE.compile))
2109 siblingCallers.push(fdthis);
2110 computedEscapingSiblings = false;
2115 const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this);
2116 if (lv == LevelError)
2117 return true; // error
2118 if (lv == -1)
2119 return false; // downlevel call
2120 if (lv == 0)
2121 return false; // same level call
2123 return false; // Uplevel call
2126 if (checkEnclosing(p.isFuncDeclaration()))
2127 return true;
2128 if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
2129 return true;
2131 return false;
2134 /*******************************
2135 * Look at all the variables in this function that are referenced
2136 * by nested functions, and determine if a closure needs to be
2137 * created for them.
2139 final bool needsClosure()
2141 /* Need a closure for all the closureVars[] if any of the
2142 * closureVars[] are accessed by a
2143 * function that escapes the scope of this function.
2144 * We take the conservative approach and decide that a function needs
2145 * a closure if it:
2146 * 1) is a virtual function
2147 * 2) has its address taken
2148 * 3) has a parent that escapes
2149 * 4) calls another nested function that needs a closure
2151 * Note that since a non-virtual function can be called by
2152 * a virtual one, if that non-virtual function accesses a closure
2153 * var, the closure still has to be taken. Hence, we check for isThis()
2154 * instead of isVirtual(). (thanks to David Friedman)
2156 * When the function returns a local struct or class, `requiresClosure`
2157 * is already set to `true` upon entering this function when the
2158 * struct/class refers to a local variable and a closure is needed.
2160 //printf("FuncDeclaration::needsClosure() %s\n", toPrettyChars());
2162 if (requiresClosure)
2163 goto Lyes;
2165 for (size_t i = 0; i < closureVars.length; i++)
2167 VarDeclaration v = closureVars[i];
2168 //printf("\tv = %s\n", v.toChars());
2170 for (size_t j = 0; j < v.nestedrefs.length; j++)
2172 FuncDeclaration f = v.nestedrefs[j];
2173 assert(f != this);
2175 /* __require and __ensure will always get called directly,
2176 * so they never make outer functions closure.
2178 if (f.ident == Id.require || f.ident == Id.ensure)
2179 continue;
2181 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
2183 /* Look to see if f escapes. We consider all parents of f within
2184 * this, and also all siblings which call f; if any of them escape,
2185 * so does f.
2186 * Mark all affected functions as requiring closures.
2188 for (Dsymbol s = f; s && s != this; s = s.toParentP(this))
2190 FuncDeclaration fx = s.isFuncDeclaration();
2191 if (!fx)
2192 continue;
2193 if (fx.isThis() || fx.tookAddressOf)
2195 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
2197 /* Mark as needing closure any functions between this and f
2199 markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this);
2201 requiresClosure = true;
2204 /* We also need to check if any sibling functions that
2205 * called us, have escaped. This is recursive: we need
2206 * to check the callers of our siblings.
2208 if (checkEscapingSiblings(fx, this))
2209 requiresClosure = true;
2211 /* https://issues.dlang.org/show_bug.cgi?id=12406
2212 * Iterate all closureVars to mark all descendant
2213 * nested functions that access to the closing context of this function.
2218 if (requiresClosure)
2219 goto Lyes;
2221 return false;
2223 Lyes:
2224 return true;
2227 /***********************************************
2228 * Check that the function contains any closure.
2229 * If it's @nogc, report suitable errors.
2230 * This is mostly consistent with FuncDeclaration::needsClosure().
2232 * Returns:
2233 * true if any errors occur.
2235 extern (C++) final bool checkClosure()
2237 //printf("checkClosure() %s\n", toPrettyChars());
2238 if (!needsClosure())
2239 return false;
2241 if (setGC(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", this))
2243 .error(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", kind, toPrettyChars, toChars());
2244 if (global.gag) // need not report supplemental errors
2245 return true;
2247 else if (!global.params.useGC)
2249 .error(loc, "%s `%s` is `-betterC` 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
2255 printGCUsage(loc, "using closure causes GC allocation");
2256 return false;
2259 FuncDeclarations a;
2260 foreach (v; closureVars)
2262 foreach (f; v.nestedrefs)
2264 assert(f !is this);
2266 LcheckAncestorsOfANestedRef:
2267 for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
2269 auto fx = s.isFuncDeclaration();
2270 if (!fx)
2271 continue;
2272 if (fx.isThis() ||
2273 fx.tookAddressOf ||
2274 checkEscapingSiblings(fx, this))
2276 foreach (f2; a)
2278 if (f2 == f)
2279 break LcheckAncestorsOfANestedRef;
2281 a.push(f);
2282 .errorSupplemental(f.loc, "%s `%s` closes over variable `%s`",
2283 f.kind, f.toPrettyChars(), v.toChars());
2284 if (v.ident != Id.This)
2285 .errorSupplemental(v.loc, "`%s` declared here", v.toChars());
2287 break LcheckAncestorsOfANestedRef;
2293 return true;
2296 /***********************************************
2297 * Determine if function's variables are referenced by a function
2298 * nested within it.
2300 final bool hasNestedFrameRefs()
2302 if (closureVars.length)
2303 return true;
2305 /* If a virtual function has contracts, assume its variables are referenced
2306 * by those contracts, even if they aren't. Because they might be referenced
2307 * by the overridden or overriding function's contracts.
2308 * This can happen because frequire and fensure are implemented as nested functions,
2309 * and they can be called directly by an overriding function and the overriding function's
2310 * context had better match, or
2311 * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
2313 if (fdrequire || fdensure)
2314 return true;
2316 if (foverrides.length && isVirtualMethod())
2318 for (size_t i = 0; i < foverrides.length; i++)
2320 FuncDeclaration fdv = foverrides[i];
2321 if (fdv.hasNestedFrameRefs())
2322 return true;
2325 return false;
2328 /****************************************************
2329 * Check whether result variable can be built.
2330 * Returns:
2331 * `true` if the function has a return type that
2332 * is different from `void`.
2334 extern (D) private bool canBuildResultVar()
2336 auto f = cast(TypeFunction)type;
2337 return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
2340 /****************************************************
2341 * Declare result variable lazily.
2343 extern (D) final void buildResultVar(Scope* sc, Type tret)
2345 if (!vresult)
2347 Loc loc = fensure ? fensure.loc : this.loc;
2349 /* If inferRetType is true, tret may not be a correct return type yet.
2350 * So, in here it may be a temporary type for vresult, and after
2351 * fbody.dsymbolSemantic() running, vresult.type might be modified.
2353 vresult = new VarDeclaration(loc, tret, Id.result, null);
2354 vresult.storage_class |= STC.nodtor | STC.temp;
2355 if (!isVirtual())
2356 vresult.storage_class |= STC.const_;
2357 vresult.storage_class |= STC.result;
2359 // set before the semantic() for checkNestedReference()
2360 vresult.parent = this;
2363 if (sc && vresult.semanticRun == PASS.initial)
2365 TypeFunction tf = type.toTypeFunction();
2366 if (tf.isref)
2367 vresult.storage_class |= STC.ref_;
2368 vresult.type = tret;
2370 vresult.dsymbolSemantic(sc);
2372 if (!sc.insert(vresult))
2373 .error(loc, "%s `%s` out result %s is already defined", kind, toPrettyChars, vresult.toChars());
2374 assert(vresult.parent == this);
2378 /****************************************************
2379 * Merge into this function the 'in' contracts of all it overrides.
2380 * 'in's are OR'd together, i.e. only one of them needs to pass.
2382 extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
2384 /* If a base function and its override both have an IN contract, then
2385 * only one of them needs to succeed. This is done by generating:
2387 * void derived.in() {
2388 * try {
2389 * base.in();
2391 * catch () {
2392 * ... body of derived.in() ...
2396 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2397 * If base.in() throws, then derived.in()'s body is executed.
2400 foreach (fdv; foverrides)
2402 /* The semantic pass on the contracts of the overridden functions must
2403 * be completed before code generation occurs.
2404 * https://issues.dlang.org/show_bug.cgi?id=3602
2406 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2408 assert(fdv._scope);
2409 Scope* sc = fdv._scope.push();
2410 sc.stc &= ~STC.override_;
2411 fdv.semantic3(sc);
2412 sc.pop();
2415 sf = fdv.mergeFrequire(sf, params);
2416 if (!sf || !fdv.fdrequire)
2417 return null;
2418 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2419 /* Make the call:
2420 * try { __require(params); }
2421 * catch (Throwable) { frequire; }
2423 params = Expression.arraySyntaxCopy(params);
2424 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2425 Statement s2 = new ExpStatement(loc, e);
2427 auto c = new Catch(loc, getThrowable(), null, sf);
2428 c.internalCatch = true;
2429 auto catches = new Catches();
2430 catches.push(c);
2431 sf = new TryCatchStatement(loc, s2, catches);
2433 return sf;
2436 /****************************************************
2437 * Merge into this function the 'in' contracts of all it overrides.
2439 extern (D) final Statement mergeFrequireInclusivePreview(Statement sf, Expressions* params)
2441 /* If a base function and its override both have an IN contract, then
2442 * the override in contract must widen the guarantee of the base contract.
2443 * This is checked by generating:
2445 * void derived.in() {
2446 * try {
2447 * ... body of derived.in() ...
2449 * catch () {
2450 * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
2451 * base.in();
2452 * assert(false, "Logic error: " ~ thr.msg);
2457 foreach (fdv; foverrides)
2459 /* The semantic pass on the contracts of the overridden functions must
2460 * be completed before code generation occurs.
2461 * https://issues.dlang.org/show_bug.cgi?id=3602
2463 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2465 assert(fdv._scope);
2466 Scope* sc = fdv._scope.push();
2467 sc.stc &= ~STC.override_;
2468 fdv.semantic3(sc);
2469 sc.pop();
2472 sf = fdv.mergeFrequireInclusivePreview(sf, params);
2473 if (sf && fdv.fdrequire)
2475 const loc = this.fdrequire.loc;
2477 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2478 /* Make the call:
2479 * try { frequire; }
2480 * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
2482 Identifier id = Identifier.generateId("thr");
2483 params = Expression.arraySyntaxCopy(params);
2484 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2485 Statement s2 = new ExpStatement(loc, e);
2486 // assert(false, ...)
2487 // TODO make this a runtime helper to allow:
2488 // - chaining the original expression
2489 // - nogc concatenation
2490 Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
2491 Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
2493 Statement s3 = new CompoundStatement(loc, s2, fail);
2495 auto c = new Catch(loc, getThrowable(), id, s3);
2496 c.internalCatch = true;
2497 auto catches = new Catches();
2498 catches.push(c);
2499 sf = new TryCatchStatement(loc, sf, catches);
2501 else
2502 return null;
2504 return sf;
2507 /****************************************************
2508 * Determine whether an 'out' contract is declared inside
2509 * the given function or any of its overrides.
2510 * Params:
2511 * fd = the function to search
2512 * Returns:
2513 * true found an 'out' contract
2515 static bool needsFensure(FuncDeclaration fd) @safe
2517 if (fd.fensures)
2518 return true;
2520 foreach (fdv; fd.foverrides)
2522 if (needsFensure(fdv))
2523 return true;
2525 return false;
2528 /****************************************************
2529 * Rewrite contracts as statements.
2531 final void buildEnsureRequire()
2534 if (frequires)
2536 /* in { statements1... }
2537 * in { statements2... }
2538 * ...
2539 * becomes:
2540 * in { { statements1... } { statements2... } ... }
2542 assert(frequires.length);
2543 auto loc = (*frequires)[0].loc;
2544 auto s = new Statements;
2545 foreach (r; *frequires)
2547 s.push(new ScopeStatement(r.loc, r, r.loc));
2549 frequire = new CompoundStatement(loc, s);
2552 if (fensures)
2554 /* out(id1) { statements1... }
2555 * out(id2) { statements2... }
2556 * ...
2557 * becomes:
2558 * out(__result) { { ref id1 = __result; { statements1... } }
2559 * { ref id2 = __result; { statements2... } } ... }
2561 assert(fensures.length);
2562 auto loc = (*fensures)[0].ensure.loc;
2563 auto s = new Statements;
2564 foreach (r; *fensures)
2566 if (r.id && canBuildResultVar())
2568 auto rloc = r.ensure.loc;
2569 auto resultId = new IdentifierExp(rloc, Id.result);
2570 auto init = new ExpInitializer(rloc, resultId);
2571 auto stc = STC.ref_ | STC.temp | STC.result;
2572 auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
2573 auto sdecl = new ExpStatement(rloc, decl);
2574 s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
2576 else
2578 s.push(r.ensure);
2581 fensure = new CompoundStatement(loc, s);
2584 if (!isVirtual())
2585 return;
2587 /* Rewrite contracts as nested functions, then call them. Doing it as nested
2588 * functions means that overriding functions can call them.
2590 TypeFunction f = cast(TypeFunction) type;
2592 /* Make a copy of the parameters and make them all ref */
2593 static Parameters* toRefCopy(ParameterList parameterList)
2595 auto result = new Parameters();
2597 foreach (n, p; parameterList)
2599 p = p.syntaxCopy();
2600 if (!p.isLazy())
2601 p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
2602 p.defaultArg = null; // won't be the same with ref
2603 result.push(p);
2606 return result;
2609 if (frequire)
2611 /* in { ... }
2612 * becomes:
2613 * void __require(ref params) { ... }
2614 * __require(params);
2616 Loc loc = frequire.loc;
2617 fdrequireParams = new Expressions();
2618 if (parameters)
2620 foreach (vd; *parameters)
2621 fdrequireParams.push(new VarExp(loc, vd));
2623 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2624 auto fparams = toRefCopy(fo.parameterList);
2625 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2626 tf.isnothrow = f.isnothrow;
2627 tf.isnogc = f.isnogc;
2628 tf.purity = f.purity;
2629 tf.trust = f.trust;
2630 auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
2631 fd.fbody = frequire;
2632 Statement s1 = new ExpStatement(loc, fd);
2633 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
2634 Statement s2 = new ExpStatement(loc, e);
2635 frequire = new CompoundStatement(loc, s1, s2);
2636 fdrequire = fd;
2639 /* We need to set fdensureParams here and not in the block below to
2640 * have the parameters available when calling a base class ensure(),
2641 * even if this function doesn't have an out contract.
2643 fdensureParams = new Expressions();
2644 if (canBuildResultVar())
2645 fdensureParams.push(new IdentifierExp(loc, Id.result));
2646 if (parameters)
2648 foreach (vd; *parameters)
2649 fdensureParams.push(new VarExp(loc, vd));
2652 if (fensure)
2654 /* out (result) { ... }
2655 * becomes:
2656 * void __ensure(ref tret result, ref params) { ... }
2657 * __ensure(result, params);
2659 Loc loc = fensure.loc;
2660 auto fparams = new Parameters();
2661 if (canBuildResultVar())
2663 Parameter p = new Parameter(loc, STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
2664 fparams.push(p);
2666 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2667 fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
2668 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2669 tf.isnothrow = f.isnothrow;
2670 tf.isnogc = f.isnogc;
2671 tf.purity = f.purity;
2672 tf.trust = f.trust;
2673 auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
2674 fd.fbody = fensure;
2675 Statement s1 = new ExpStatement(loc, fd);
2676 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
2677 Statement s2 = new ExpStatement(loc, e);
2678 fensure = new CompoundStatement(loc, s1, s2);
2679 fdensure = fd;
2683 /****************************************************
2684 * Merge into this function the 'out' contracts of all it overrides.
2685 * 'out's are AND'd together, i.e. all of them need to pass.
2687 extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
2689 /* Same comments as for mergeFrequire(), except that we take care
2690 * of generating a consistent reference to the 'result' local by
2691 * explicitly passing 'result' to the nested function as a reference
2692 * argument.
2693 * This won't work for the 'this' parameter as it would require changing
2694 * the semantic code for the nested function so that it looks on the parameter
2695 * list for the 'this' pointer, something that would need an unknown amount
2696 * of tweaking of various parts of the compiler that I'd rather leave alone.
2698 foreach (fdv; foverrides)
2700 /* The semantic pass on the contracts of the overridden functions must
2701 * be completed before code generation occurs.
2702 * https://issues.dlang.org/show_bug.cgi?id=3602 and
2703 * https://issues.dlang.org/show_bug.cgi?id=5230
2705 if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
2707 assert(fdv._scope);
2708 Scope* sc = fdv._scope.push();
2709 sc.stc &= ~STC.override_;
2710 fdv.semantic3(sc);
2711 sc.pop();
2714 sf = fdv.mergeFensure(sf, oid, params);
2715 if (fdv.fdensure)
2717 //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2718 // Make the call: __ensure(result, params)
2719 params = Expression.arraySyntaxCopy(params);
2720 if (canBuildResultVar())
2722 Type t1 = fdv.type.nextOf().toBasetype();
2723 Type t2 = this.type.nextOf().toBasetype();
2724 if (t1.isBaseOf(t2, null))
2726 /* Making temporary reference variable is necessary
2727 * in covariant return.
2728 * https://issues.dlang.org/show_bug.cgi?id=5204
2729 * https://issues.dlang.org/show_bug.cgi?id=10479
2731 Expression* eresult = &(*params)[0];
2732 auto ei = new ExpInitializer(Loc.initial, *eresult);
2733 auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
2734 v.storage_class |= STC.temp;
2735 auto de = new DeclarationExp(Loc.initial, v);
2736 auto ve = new VarExp(Loc.initial, v);
2737 *eresult = new CommaExp(Loc.initial, de, ve);
2740 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
2741 Statement s2 = new ExpStatement(loc, e);
2743 if (sf)
2745 sf = new CompoundStatement(sf.loc, s2, sf);
2747 else
2748 sf = s2;
2751 return sf;
2754 /*********************************************
2755 * Returns: the function's parameter list, and whether
2756 * it is variadic or not.
2758 final ParameterList getParameterList()
2760 if (type)
2762 TypeFunction fdtype = type.isTypeFunction();
2763 if (fdtype) // Could also be TypeError
2764 return fdtype.parameterList;
2767 return ParameterList(null, VarArg.none);
2770 /**********************************
2771 * Generate a FuncDeclaration for a runtime library function.
2773 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
2775 return genCfunc(fparams, treturn, Identifier.idPool(name[0 .. strlen(name)]), stc);
2778 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
2780 FuncDeclaration fd;
2781 TypeFunction tf;
2782 Dsymbol s;
2783 __gshared DsymbolTable st = null;
2785 //printf("genCfunc(name = '%s')\n", id.toChars());
2786 //printf("treturn\n\t"); treturn.print();
2788 // See if already in table
2789 if (!st)
2790 st = new DsymbolTable();
2791 s = st.lookup(id);
2792 if (s)
2794 fd = s.isFuncDeclaration();
2795 assert(fd);
2796 assert(fd.type.nextOf().equals(treturn));
2798 else
2800 tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc);
2801 fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf);
2802 fd.visibility = Visibility(Visibility.Kind.public_);
2803 fd._linkage = LINK.c;
2805 st.insert(fd);
2807 return fd;
2811 + Checks the parameter and return types iff this is a `main` function.
2813 + The following signatures are allowed for a `D main`:
2814 + - Either no or a single parameter of type `string[]`
2815 + - Return type is either `void`, `int` or `noreturn`
2817 + The following signatures are standard C:
2818 + - `int main()`
2819 + - `int main(int, char**)`
2821 + This function accepts the following non-standard extensions:
2822 + - `char** envp` as a third parameter
2823 + - `void` / `noreturn` as return type
2825 + This function will issue errors for unexpected arguments / return types.
2827 extern (D) final void checkMain()
2829 if (ident != Id.main || isMember() || isNested())
2830 return; // Not a main function
2832 TypeFunction tf = type.toTypeFunction();
2834 Type retType = tf.nextOf();
2835 if (!retType)
2837 // auto main(), check after semantic
2838 assert(this.inferRetType);
2839 return;
2842 /// Checks whether `t` is equivalent to `char**`
2843 /// Ignores qualifiers and treats enums according to their base type
2844 static bool isCharPtrPtr(Type t)
2846 auto tp = t.toBasetype().isTypePointer();
2847 if (!tp)
2848 return false;
2850 tp = tp.next.toBasetype().isTypePointer();
2851 if (!tp)
2852 return false;
2854 return tp.next.toBasetype().ty == Tchar;
2857 // Neither of these qualifiers is allowed because they affect the ABI
2858 enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
2860 const nparams = tf.parameterList.length;
2861 bool argerr;
2863 const linkage = resolvedLinkage();
2864 if (linkage == LINK.d)
2866 if (nparams == 1)
2868 auto fparam0 = tf.parameterList[0];
2869 auto t = fparam0.type.toBasetype();
2870 if (t.ty != Tarray ||
2871 t.nextOf().ty != Tarray ||
2872 t.nextOf().nextOf().ty != Tchar ||
2873 fparam0.storageClass & invalidSTC)
2875 argerr = true;
2879 if (tf.parameterList.varargs || nparams >= 2 || argerr)
2880 .error(loc, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", kind, toPrettyChars);
2883 else if (linkage == LINK.c)
2885 if (nparams == 2 || nparams == 3)
2887 // Argument count must be int
2888 auto argCount = tf.parameterList[0];
2889 argerr |= !!(argCount.storageClass & invalidSTC);
2890 argerr |= argCount.type.toBasetype().ty != Tint32;
2892 // Argument pointer must be char**
2893 auto argPtr = tf.parameterList[1];
2894 argerr |= !!(argPtr.storageClass & invalidSTC);
2895 argerr |= !isCharPtrPtr(argPtr.type);
2897 // `char** environ` is a common extension, see J.5.1 of the C standard
2898 if (nparams == 3)
2900 auto envPtr = tf.parameterList[2];
2901 argerr |= !!(envPtr.storageClass & invalidSTC);
2902 argerr |= !isCharPtrPtr(envPtr.type);
2905 else
2906 argerr = nparams != 0;
2908 // Disallow variadic main() - except for K&R declarations in C files.
2909 // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
2910 if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
2911 argerr |= true;
2913 if (argerr)
2915 .error(loc, "%s `%s` parameters must match one of the following signatures", kind, toPrettyChars);
2916 loc.errorSupplemental("`main()`");
2917 loc.errorSupplemental("`main(int argc, char** argv)`");
2918 loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
2921 else
2922 return; // Neither C nor D main, ignore (should probably be an error)
2924 // Allow enums with appropriate base types (same ABI)
2925 retType = retType.toBasetype();
2927 if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
2928 .error(loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", kind, toPrettyChars, tf.nextOf().toChars());
2931 /***********************************************
2932 * Check all return statements for a function to verify that returning
2933 * using NRVO is possible.
2935 * Returns:
2936 * `false` if the result cannot be returned by hidden reference.
2938 final bool checkNRVO()
2940 if (!isNRVO() || returns is null)
2941 return false;
2943 auto tf = type.toTypeFunction();
2944 if (tf.isref)
2945 return false;
2947 foreach (rs; *returns)
2949 if (auto ve = rs.exp.isVarExp())
2951 auto v = ve.var.isVarDeclaration();
2952 if (!v || v.isReference())
2953 return false;
2954 else if (nrvo_var is null)
2956 // Variables in the data segment (e.g. globals, TLS or not),
2957 // parameters and closure variables cannot be NRVOed.
2958 if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
2959 return false;
2960 if (v.nestedrefs.length && needsClosure())
2961 return false;
2962 // don't know if the return storage is aligned
2963 version (MARS)
2965 if (alignSectionVars && (*alignSectionVars).contains(v))
2966 return false;
2968 // The variable type needs to be equivalent to the return type.
2969 if (!v.type.equivalent(tf.next))
2970 return false;
2971 //printf("Setting nrvo to %s\n", v.toChars());
2972 nrvo_var = v;
2974 else if (nrvo_var != v)
2975 return false;
2977 else //if (!exp.isLvalue()) // keep NRVO-ability
2978 return false;
2980 return true;
2983 override final inout(FuncDeclaration) isFuncDeclaration() inout
2985 return this;
2988 inout(FuncDeclaration) toAliasFunc() inout
2990 return this;
2993 override void accept(Visitor v)
2995 v.visit(this);
2999 /********************************************************
3000 * Generate Expression to call the invariant.
3001 * Input:
3002 * ad aggregate with the invariant
3003 * vthis variable with 'this'
3004 * Returns:
3005 * void expression that calls the invariant
3007 Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
3009 Expression e = null;
3010 // Call invariant directly only if it exists
3011 FuncDeclaration inv = ad.inv;
3012 ClassDeclaration cd = ad.isClassDeclaration();
3014 while (!inv && cd)
3016 cd = cd.baseClass;
3017 if (!cd)
3018 break;
3019 inv = cd.inv;
3021 if (inv)
3023 version (all)
3025 // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
3026 // For the correct mangling,
3027 // run attribute inference on inv if needed.
3028 inv.functionSemantic();
3031 //e = new DsymbolExp(Loc.initial, inv);
3032 //e = new CallExp(Loc.initial, e);
3033 //e = e.semantic(sc2);
3035 /* https://issues.dlang.org/show_bug.cgi?id=13113
3036 * Currently virtual invariant calls completely
3037 * bypass attribute enforcement.
3038 * Change the behavior of pre-invariant call by following it.
3040 e = new ThisExp(Loc.initial);
3041 e.type = ad.type.addMod(vthis.type.mod);
3042 e = new DotVarExp(Loc.initial, e, inv, false);
3043 e.type = inv.type;
3044 e = new CallExp(Loc.initial, e);
3045 e.type = Type.tvoid;
3047 return e;
3050 /***************************************************
3051 * Visit each overloaded function/template in turn, and call dg(s) on it.
3052 * Exit when no more, or dg(s) returns nonzero.
3054 * Params:
3055 * fstart = symbol to start from
3056 * dg = the delegate to be called on the overload
3057 * sc = context used to check if symbol is accessible (and therefore visible),
3058 * can be null
3060 * Returns:
3061 * ==0 continue
3062 * !=0 done (and the return value from the last dg() call)
3064 extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
3066 Dsymbols visited;
3068 int overloadApplyRecurse(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc)
3070 // Detect cyclic calls.
3071 if (visited.contains(fstart))
3072 return 0;
3073 visited.push(fstart);
3075 Dsymbol next;
3076 for (auto d = fstart; d; d = next)
3078 import dmd.access : checkSymbolAccess;
3079 if (auto od = d.isOverDeclaration())
3081 /* The scope is needed here to check whether a function in
3082 an overload set was added by means of a private alias (or a
3083 selective import). If the scope where the alias is created
3084 is imported somewhere, the overload set is visible, but the private
3085 alias is not.
3087 if (sc)
3089 if (checkSymbolAccess(sc, od))
3091 if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
3092 return r;
3095 else if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
3096 return r;
3097 next = od.overnext;
3099 else if (auto fa = d.isFuncAliasDeclaration())
3101 if (fa.hasOverloads)
3103 if (int r = overloadApplyRecurse(fa.funcalias, dg, sc))
3104 return r;
3106 else if (auto fd = fa.toAliasFunc())
3108 if (int r = dg(fd))
3109 return r;
3111 else
3113 .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
3114 break;
3116 next = fa.overnext;
3118 else if (auto ad = d.isAliasDeclaration())
3120 if (sc)
3122 if (checkSymbolAccess(sc, ad))
3123 next = ad.toAlias();
3125 else
3126 next = ad.toAlias();
3127 if (next == ad)
3128 break;
3129 if (next == fstart)
3130 break;
3132 else if (auto td = d.isTemplateDeclaration())
3134 if (int r = dg(td))
3135 return r;
3136 next = td.overnext;
3138 else if (auto fd = d.isFuncDeclaration())
3140 if (int r = dg(fd))
3141 return r;
3142 next = fd.overnext;
3144 else if (auto os = d.isOverloadSet())
3146 foreach (ds; os.a)
3147 if (int r = dg(ds))
3148 return r;
3150 else
3152 .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
3153 break;
3154 // BUG: should print error message?
3157 return 0;
3159 return overloadApplyRecurse(fstart, dg, sc);
3163 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
3164 mismatching modifiers to `buf`.
3166 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
3167 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
3169 Params:
3170 buf = output buffer to write to
3171 lhsMod = modifier on the left-hand side
3172 lhsMod = modifier on the right-hand side
3174 Returns:
3176 A tuple with `isMutable` and `isNotShared` set
3177 if the `lhsMod` is missing those modifiers (compared to rhs).
3179 auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod)
3181 static struct Mismatches
3183 bool isNotShared;
3184 bool isMutable;
3187 Mismatches mismatches;
3189 bool bothMutable = ((lhsMod & rhsMod) == 0);
3190 bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0;
3191 bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_);
3193 if (lhsMod & MODFlags.shared_)
3194 buf.writestring("`shared` ");
3195 else if (sharedMismatch && !(lhsMod & MODFlags.immutable_))
3197 buf.writestring("non-shared ");
3198 mismatches.isNotShared = true;
3201 if (bothMutable && sharedMismatchOnly)
3204 else if (lhsMod & MODFlags.immutable_)
3205 buf.writestring("`immutable` ");
3206 else if (lhsMod & MODFlags.const_)
3207 buf.writestring("`const` ");
3208 else if (lhsMod & MODFlags.wild)
3209 buf.writestring("`inout` ");
3210 else
3212 buf.writestring("mutable ");
3213 mismatches.isMutable = true;
3216 return mismatches;
3220 unittest
3222 OutBuffer buf;
3223 auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0);
3224 assert(buf[] == "`shared` ");
3225 assert(!mismatches.isNotShared);
3227 buf.setsize(0);
3228 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_);
3229 assert(buf[] == "non-shared ");
3230 assert(mismatches.isNotShared);
3232 buf.setsize(0);
3233 mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0);
3234 assert(buf[] == "`const` ");
3235 assert(!mismatches.isMutable);
3237 buf.setsize(0);
3238 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_);
3239 assert(buf[] == "mutable ");
3240 assert(mismatches.isMutable);
3243 private const(char)* prependSpace(const(char)* str)
3245 if (!str || !*str) return "";
3247 return (" " ~ str.toDString() ~ "\0").ptr;
3250 /// Flag used by $(LREF resolveFuncCall).
3251 enum FuncResolveFlag : ubyte
3253 standard = 0, /// issue error messages, solve the call.
3254 quiet = 1, /// do not issue error message on no match, just return `null`.
3255 overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous
3256 /// matches and need explicit this.
3257 ufcs = 4, /// trying to resolve UFCS call
3260 /*******************************************
3261 * Given a symbol that could be either a FuncDeclaration or
3262 * a function template, resolve it to a function symbol.
3263 * Params:
3264 * loc = instantiation location
3265 * sc = instantiation scope
3266 * s = instantiation symbol
3267 * tiargs = initial list of template arguments
3268 * tthis = if !NULL, the `this` argument type
3269 * argumentList = arguments to function
3270 * flags = see $(LREF FuncResolveFlag).
3271 * Returns:
3272 * if match is found, then function symbol, else null
3274 FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
3275 Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
3277 auto fargs = argumentList.arguments;
3278 if (!s)
3279 return null; // no match
3281 version (none)
3283 printf("resolveFuncCall('%s')\n", s.toChars());
3284 if (tthis)
3285 printf("\tthis: %s\n", tthis.toChars());
3286 if (fargs)
3288 for (size_t i = 0; i < fargs.length; i++)
3290 Expression arg = (*fargs)[i];
3291 assert(arg.type);
3292 printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
3295 printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
3298 if (tiargs && arrayObjectIsError(tiargs))
3299 return null;
3300 if (fargs !is null)
3301 foreach (arg; *fargs)
3302 if (isError(arg))
3303 return null;
3305 MatchAccumulator m;
3306 functionResolve(m, s, loc, sc, tiargs, tthis, argumentList);
3307 auto orig_s = s;
3309 if (m.last > MATCH.nomatch && m.lastf)
3311 if (m.count == 1) // exactly one match
3313 if (!(flags & FuncResolveFlag.quiet))
3314 m.lastf.functionSemantic();
3315 return m.lastf;
3317 if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
3319 return m.lastf;
3323 /* Failed to find a best match.
3324 * Do nothing or print error.
3326 if (m.last == MATCH.nomatch)
3328 // error was caused on matched function, not on the matching itself,
3329 // so return the function to produce a better diagnostic
3330 if (m.count == 1)
3331 return m.lastf;
3334 // We are done at this point, as the rest of this function generate
3335 // a diagnostic on invalid match
3336 if (flags & FuncResolveFlag.quiet)
3337 return null;
3339 auto fd = s.isFuncDeclaration();
3340 auto od = s.isOverDeclaration();
3341 auto td = s.isTemplateDeclaration();
3342 if (td && td.funcroot)
3343 s = fd = td.funcroot;
3345 OutBuffer tiargsBuf;
3346 arrayObjectsToBuffer(tiargsBuf, tiargs);
3348 OutBuffer fargsBuf;
3349 fargsBuf.writeByte('(');
3350 argExpTypesToCBuffer(fargsBuf, fargs);
3351 fargsBuf.writeByte(')');
3352 if (tthis)
3353 tthis.modToBuffer(fargsBuf);
3355 // The call is ambiguous
3356 if (m.lastf && m.nextf)
3358 TypeFunction tf1 = m.lastf.type.toTypeFunction();
3359 TypeFunction tf2 = m.nextf.type.toTypeFunction();
3360 const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
3361 const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
3363 const(char)* mod1 = prependSpace(MODtoChars(tf1.mod));
3364 const(char)* mod2 = prependSpace(MODtoChars(tf2.mod));
3366 .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
3367 s.parent.toPrettyChars(), s.ident.toChars(),
3368 fargsBuf.peekChars(),
3369 m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1,
3370 m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2);
3371 return null;
3374 // no match, generate an error messages
3375 if (flags & FuncResolveFlag.ufcs)
3377 auto arg = (*fargs)[0];
3378 .error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars());
3379 .errorSupplemental(loc, "the following error occured while looking for a UFCS match");
3382 if (!fd)
3384 // all of overloads are templates
3385 if (td)
3387 const(char)* msg = "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`";
3388 if (!od && !td.overnext)
3389 msg = "%s `%s.%s` is not callable using argument types `!(%s)%s`";
3390 .error(loc, msg,
3391 td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
3392 tiargsBuf.peekChars(), fargsBuf.peekChars());
3394 if (!global.gag || global.params.v.showGaggedErrors)
3395 printCandidates(loc, td, sc.isDeprecated());
3396 return null;
3398 /* This case used to happen when several ctors are mixed in an agregate.
3399 A (bad) error message is already generated in overloadApply().
3400 see https://issues.dlang.org/show_bug.cgi?id=19729
3401 and https://issues.dlang.org/show_bug.cgi?id=17259
3403 if (!od)
3404 return null;
3407 if (od)
3409 .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
3410 od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
3411 return null;
3414 // remove when deprecation period of class allocators and deallocators is over
3415 if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
3416 return null;
3418 bool hasOverloads = fd.overnext !is null;
3419 auto tf = fd.type.isTypeFunction();
3420 // if type is an error, the original type should be there for better diagnostics
3421 if (!tf)
3422 tf = fd.originalType.toTypeFunction();
3424 if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch
3426 OutBuffer thisBuf, funcBuf;
3427 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
3428 auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
3429 if (hasOverloads)
3431 .error(loc, "none of the overloads of `%s` are callable using a %sobject",
3432 fd.ident.toChars(), thisBuf.peekChars());
3433 if (!global.gag || global.params.v.showGaggedErrors)
3434 printCandidates(loc, fd, sc.isDeprecated());
3435 return null;
3438 const(char)* failMessage;
3439 functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
3440 if (failMessage)
3442 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3443 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3444 tf.modToChars(), fargsBuf.peekChars());
3445 errorSupplemental(loc, failMessage);
3446 return null;
3449 .error(loc, "%smethod `%s` is not callable using a %sobject",
3450 funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
3452 if (mismatches.isNotShared)
3453 .errorSupplemental(fd.loc, "Consider adding `shared` here");
3454 else if (mismatches.isMutable)
3455 .errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
3456 return null;
3459 //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
3460 if (hasOverloads)
3462 .error(loc, "none of the overloads of `%s` are callable using argument types `%s`",
3463 fd.toChars(), fargsBuf.peekChars());
3464 if (!global.gag || global.params.v.showGaggedErrors)
3465 printCandidates(loc, fd, sc.isDeprecated());
3466 return null;
3469 .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
3470 fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
3471 tf.modToChars(), fargsBuf.peekChars());
3473 // re-resolve to check for supplemental message
3474 if (!global.gag || global.params.v.showGaggedErrors)
3476 if (tthis)
3478 if (auto classType = tthis.isTypeClass())
3480 if (auto baseClass = classType.sym.baseClass)
3482 if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
3484 MatchAccumulator mErr;
3485 functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
3486 if (mErr.last > MATCH.nomatch && mErr.lastf)
3488 errorSupplemental(loc, "%s `%s` hides base class function `%s`",
3489 fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
3490 errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
3491 fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
3492 return null;
3498 const(char)* failMessage;
3499 functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
3500 if (failMessage)
3501 errorSupplemental(loc, failMessage);
3503 return null;
3506 /*******************************************
3507 * Prints template and function overload candidates as supplemental errors.
3508 * Params:
3509 * loc = instantiation location
3510 * declaration = the declaration to print overload candidates for
3511 * showDeprecated = If `false`, `deprecated` function won't be shown
3513 private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
3514 if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
3516 // max num of overloads to print (-v or -verror-supplements overrides this).
3517 const uint DisplayLimit = global.params.v.errorSupplementCount();
3518 const(char)* constraintsTip;
3519 // determine if the first candidate was printed
3520 int printed;
3522 bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false)
3524 if (auto fd = s.isFuncDeclaration())
3526 // Don't print overloads which have errors.
3527 // Not that if the whole overload set has errors, we'll never reach
3528 // this point so there's no risk of printing no candidate
3529 if (fd.errors || fd.type.ty == Terror)
3530 return false;
3531 // Don't print disabled functions, or `deprecated` outside of deprecated scope
3532 if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
3533 return false;
3534 if (!print)
3535 return true;
3536 auto tf = cast(TypeFunction) fd.type;
3537 .errorSupplemental(fd.loc,
3538 printed ? " `%s%s`" :
3539 single_candidate ? "Candidate is: `%s%s`" : "Candidates are: `%s%s`",
3540 fd.toPrettyChars(),
3541 parametersTypeToChars(tf.parameterList));
3543 else if (auto td = s.isTemplateDeclaration())
3545 import dmd.staticcond;
3547 if (!print)
3548 return true;
3549 const tmsg = td.toCharsNoConstraints();
3550 const cmsg = td.getConstraintEvalError(constraintsTip);
3552 // add blank space if there are multiple candidates
3553 // the length of the blank space is `strlen("Candidates are: ")`
3555 if (cmsg)
3557 .errorSupplemental(td.loc,
3558 printed ? " `%s`\n%s" :
3559 single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
3560 tmsg, cmsg);
3562 else
3564 .errorSupplemental(td.loc,
3565 printed ? " `%s`" :
3566 single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
3567 tmsg);
3570 return true;
3572 // determine if there's > 1 candidate
3573 int count = 0;
3574 overloadApply(declaration, (s) {
3575 if (matchSymbol(s, false))
3576 count++;
3577 return count > 1;
3579 int skipped = 0;
3580 overloadApply(declaration, (s) {
3581 if (global.params.v.verbose || printed < DisplayLimit)
3583 if (matchSymbol(s, true, count == 1))
3584 printed++;
3586 else
3588 // Too many overloads to sensibly display.
3589 // Just show count of remaining overloads.
3590 if (matchSymbol(s, false))
3591 skipped++;
3593 return 0;
3595 if (skipped > 0)
3596 .errorSupplemental(loc, "... (%d more, -v to show) ...", skipped);
3598 // Nothing was displayed, all overloads are either disabled or deprecated
3599 if (!printed)
3600 .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
3601 // should be only in verbose mode
3602 if (constraintsTip)
3603 .tip(constraintsTip);
3606 /**************************************
3607 * Returns an indirect type one step from t.
3609 Type getIndirection(Type t)
3611 t = t.baseElemOf();
3612 if (t.ty == Tarray || t.ty == Tpointer)
3613 return t.nextOf().toBasetype();
3614 if (t.ty == Taarray || t.ty == Tclass)
3615 return t;
3616 if (t.ty == Tstruct)
3617 return t.hasPointers() ? t : null; // TODO
3619 // should consider TypeDelegate?
3620 return null;
3623 /**************************************
3624 * Performs type-based alias analysis between a newly created value and a pre-
3625 * existing memory reference:
3627 * Assuming that a reference A to a value of type `ta` was available to the code
3628 * that created a reference B to a value of type `tb`, it returns whether B
3629 * might alias memory reachable from A based on the types involved (either
3630 * directly or via any number of indirections in either A or B).
3632 * This relation is not symmetric in the two arguments. For example, a
3633 * a `const(int)` reference can point to a pre-existing `int`, but not the other
3634 * way round.
3636 * Examples:
3638 * ta, tb, result
3639 * `const(int)`, `int`, `false`
3640 * `int`, `const(int)`, `true`
3641 * `int`, `immutable(int)`, `false`
3642 * const(immutable(int)*), immutable(int)*, false // BUG: returns true
3644 * Params:
3645 * ta = value type being referred to
3646 * tb = referred to value type that could be constructed from ta
3648 * Returns:
3649 * true if reference to `tb` is isolated from reference to `ta`
3651 private bool traverseIndirections(Type ta, Type tb)
3653 //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
3655 static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
3657 //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
3658 ta = ta.baseElemOf();
3659 tb = tb.baseElemOf();
3661 // First, check if the pointed-to types are convertible to each other such
3662 // that they might alias directly.
3663 static bool mayAliasDirect(Type source, Type target)
3665 return
3666 // if source is the same as target or can be const-converted to target
3667 source.constConv(target) != MATCH.nomatch ||
3668 // if target is void and source can be const-converted to target
3669 (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
3672 if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
3674 //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3675 return false;
3677 if (ta.nextOf() && ta.nextOf() == tb.nextOf())
3679 //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3680 return true;
3683 if (tb.ty == Tclass || tb.ty == Tstruct)
3685 /* Traverse the type of each field of the aggregate
3687 bool* found = table.getLvalue(tb.deco);
3688 if (*found == true)
3689 return true; // We have already seen this symbol, break the cycle
3690 else
3691 *found = true;
3693 AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
3694 foreach (v; sym.fields)
3696 Type tprmi = v.type.addMod(tb.mod);
3697 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
3698 if (!traverse(ta, tprmi, table, reversePass))
3699 return false;
3702 else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
3704 Type tind = tb.nextOf();
3705 if (!traverse(ta, tind, table, reversePass))
3706 return false;
3708 else if (tb.hasPointers())
3710 // BUG: consider the context pointer of delegate types
3711 return false;
3714 // Still no match, so try breaking up ta if we have not done so yet.
3715 if (!reversePass)
3717 scope newTable = AssocArray!(const(char)*, bool)();
3718 return traverse(tb, ta, newTable, true);
3721 return true;
3724 // To handle arbitrary levels of indirections in both parameters, we
3725 // recursively descend into aggregate members/levels of indirection in both
3726 // `ta` and `tb` while avoiding cycles. Start with the original types.
3727 scope table = AssocArray!(const(char)*, bool)();
3728 const result = traverse(ta, tb, table, false);
3729 //printf(" returns %d\n", result);
3730 return result;
3733 /* For all functions between outerFunc and f, mark them as needing
3734 * a closure.
3736 private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc)
3738 for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc))
3740 FuncDeclaration fy = sx.isFuncDeclaration();
3741 if (fy && fy.closureVars.length)
3743 /* fy needs a closure if it has closureVars[],
3744 * because the frame pointer in the closure will be accessed.
3746 fy.requiresClosure = true;
3751 /********
3752 * Given a nested function f inside a function outerFunc, check
3753 * if any sibling callers of f have escaped. If so, mark
3754 * all the enclosing functions as needing closures.
3755 * This is recursive: we need to check the callers of our siblings.
3756 * Note that nested functions can only call lexically earlier nested
3757 * functions, so loops are impossible.
3758 * Params:
3759 * f = inner function (nested within outerFunc)
3760 * outerFunc = outer function
3761 * p = for internal recursion use
3762 * Returns:
3763 * true if any closures were needed
3765 private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
3767 static struct PrevSibling
3769 PrevSibling* p;
3770 FuncDeclaration f;
3773 if (f.computedEscapingSiblings)
3774 return f.hasEscapingSiblings;
3776 PrevSibling ps;
3777 ps.p = cast(PrevSibling*)p;
3778 ps.f = f;
3780 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
3781 bool bAnyClosures = false;
3782 for (size_t i = 0; i < f.siblingCallers.length; ++i)
3784 FuncDeclaration g = f.siblingCallers[i];
3785 if (g.isThis() || g.tookAddressOf)
3787 markAsNeedingClosure(g, outerFunc);
3788 bAnyClosures = true;
3791 for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc))
3793 // A parent of the sibling had its address taken.
3794 // Assume escaping of parent affects its children, so needs propagating.
3795 // see https://issues.dlang.org/show_bug.cgi?id=19679
3796 FuncDeclaration parentFunc = parent.isFuncDeclaration;
3797 if (parentFunc && parentFunc.tookAddressOf)
3799 markAsNeedingClosure(parentFunc, outerFunc);
3800 bAnyClosures = true;
3804 PrevSibling* prev = cast(PrevSibling*)p;
3805 while (1)
3807 if (!prev)
3809 bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
3810 break;
3812 if (prev.f == g)
3813 break;
3814 prev = prev.p;
3817 f.hasEscapingSiblings = bAnyClosures;
3818 f.computedEscapingSiblings = true;
3819 //printf("\t%d\n", bAnyClosures);
3820 return bAnyClosures;
3823 /***********************************************************
3824 * Used as a way to import a set of functions from another scope into this one.
3826 extern (C++) final class FuncAliasDeclaration : FuncDeclaration
3828 FuncDeclaration funcalias;
3829 bool hasOverloads;
3831 extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true)
3833 super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type);
3834 assert(funcalias != this);
3835 this.funcalias = funcalias;
3837 this.hasOverloads = hasOverloads;
3838 if (hasOverloads)
3840 if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration())
3841 this.hasOverloads = fad.hasOverloads;
3843 else
3845 // for internal use
3846 assert(!funcalias.isFuncAliasDeclaration());
3847 this.hasOverloads = false;
3849 userAttribDecl = funcalias.userAttribDecl;
3852 override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
3854 return this;
3857 override const(char)* kind() const
3859 return "function alias";
3862 override inout(FuncDeclaration) toAliasFunc() inout
3864 return funcalias.toAliasFunc();
3867 override void accept(Visitor v)
3869 v.visit(this);
3873 /***********************************************************
3875 extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
3877 TOK tok; // TOK.function_ or TOK.delegate_
3878 Type treq; // target of return type inference
3880 // backend
3881 bool deferToObj;
3883 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_)
3885 super(loc, endloc, null, storage_class, type);
3886 this.ident = id ? id : Id.empty;
3887 this.tok = tok;
3888 this.fes = fes;
3889 // Always infer scope for function literals
3890 // See https://issues.dlang.org/show_bug.cgi?id=20362
3891 this.inferScope = true;
3892 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
3895 override FuncLiteralDeclaration syntaxCopy(Dsymbol s)
3897 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
3898 assert(!s);
3899 auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident, storage_class & STC.auto_);
3900 f.treq = treq; // don't need to copy
3901 FuncDeclaration.syntaxCopy(f);
3902 return f;
3905 override bool isNested() const
3907 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
3908 return (tok != TOK.function_) && !isThis();
3911 override inout(AggregateDeclaration) isThis() inout
3913 return tok == TOK.delegate_ ? super.isThis() : null;
3916 override bool isVirtual() const
3918 return false;
3921 override bool addPreInvariant()
3923 return false;
3926 override bool addPostInvariant()
3928 return false;
3931 /*******************************
3932 * Modify all expression type of return statements to tret.
3934 * On function literals, return type may be modified based on the context type
3935 * after its semantic3 is done, in FuncExp::implicitCastTo.
3937 * A function() dg = (){ return new B(); } // OK if is(B : A) == true
3939 * If B to A conversion is convariant that requires offseet adjusting,
3940 * all return statements should be adjusted to return expressions typed A.
3942 void modifyReturns(Scope* sc, Type tret)
3944 import dmd.statement_rewrite_walker;
3946 extern (C++) final class RetWalker : StatementRewriteWalker
3948 alias visit = typeof(super).visit;
3949 public:
3950 Scope* sc;
3951 Type tret;
3952 FuncLiteralDeclaration fld;
3954 override void visit(ReturnStatement s)
3956 Expression exp = s.exp;
3957 if (exp && !exp.type.equals(tret))
3958 s.exp = exp.implicitCastTo(sc, tret);
3962 if (semanticRun < PASS.semantic3done)
3963 return;
3965 if (fes)
3966 return;
3968 scope RetWalker w = new RetWalker();
3969 w.sc = sc;
3970 w.tret = tret;
3971 w.fld = this;
3972 fbody.accept(w);
3974 // Also update the inferred function type to match the new return type.
3975 // This is required so the code generator does not try to cast the
3976 // modified returns back to the original type.
3977 if (inferRetType && type.nextOf() != tret)
3978 type.toTypeFunction().next = tret;
3981 override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
3983 return this;
3986 override const(char)* kind() const
3988 // GCC requires the (char*) casts
3989 return (tok != TOK.function_) ? "delegate" : "function";
3992 override const(char)* toPrettyChars(bool QualifyTypes = false)
3994 if (parent)
3996 TemplateInstance ti = parent.isTemplateInstance();
3997 if (ti)
3998 return ti.tempdecl.toPrettyChars(QualifyTypes);
4000 return Dsymbol.toPrettyChars(QualifyTypes);
4003 override void accept(Visitor v)
4005 v.visit(this);
4009 /***********************************************************
4011 extern (C++) final class CtorDeclaration : FuncDeclaration
4013 bool isCpCtor;
4014 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
4016 super(loc, endloc, Id.ctor, stc, type);
4017 this.isCpCtor = isCpCtor;
4018 //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
4021 override CtorDeclaration syntaxCopy(Dsymbol s)
4023 assert(!s);
4024 auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy());
4025 FuncDeclaration.syntaxCopy(f);
4026 return f;
4029 override const(char)* kind() const
4031 return isCpCtor ? "copy constructor" : "constructor";
4034 override const(char)* toChars() const
4036 return "this";
4039 override bool isVirtual() const
4041 return false;
4044 override bool addPreInvariant()
4046 return false;
4049 override bool addPostInvariant()
4051 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
4054 override inout(CtorDeclaration) isCtorDeclaration() inout
4056 return this;
4059 override void accept(Visitor v)
4061 v.visit(this);
4065 /***********************************************************
4067 extern (C++) final class PostBlitDeclaration : FuncDeclaration
4069 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
4071 super(loc, endloc, id, stc, null);
4074 override PostBlitDeclaration syntaxCopy(Dsymbol s)
4076 assert(!s);
4077 auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
4078 FuncDeclaration.syntaxCopy(dd);
4079 return dd;
4082 override bool isVirtual() const
4084 return false;
4087 override bool addPreInvariant()
4089 return false;
4092 override bool addPostInvariant()
4094 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
4097 override bool overloadInsert(Dsymbol s)
4099 return false; // cannot overload postblits
4102 override inout(PostBlitDeclaration) isPostBlitDeclaration() inout
4104 return this;
4107 override void accept(Visitor v)
4109 v.visit(this);
4113 /***********************************************************
4115 extern (C++) final class DtorDeclaration : FuncDeclaration
4117 extern (D) this(const ref Loc loc, const ref Loc endloc)
4119 super(loc, endloc, Id.dtor, STC.undefined_, null);
4122 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
4124 super(loc, endloc, id, stc, null);
4127 override DtorDeclaration syntaxCopy(Dsymbol s)
4129 assert(!s);
4130 auto dd = new DtorDeclaration(loc, endloc, storage_class, ident);
4131 FuncDeclaration.syntaxCopy(dd);
4132 return dd;
4135 override const(char)* kind() const
4137 return "destructor";
4140 override const(char)* toChars() const
4142 return "~this";
4145 override bool isVirtual() const
4147 // D dtor's don't get put into the vtbl[]
4148 // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
4149 return vtblIndex != -1;
4152 override bool addPreInvariant()
4154 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
4157 override bool addPostInvariant()
4159 return false;
4162 override bool overloadInsert(Dsymbol s)
4164 return false; // cannot overload destructors
4167 override inout(DtorDeclaration) isDtorDeclaration() inout
4169 return this;
4172 override void accept(Visitor v)
4174 v.visit(this);
4178 /***********************************************************
4180 extern (C++) class StaticCtorDeclaration : FuncDeclaration
4182 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4184 super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null);
4187 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
4189 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
4192 override StaticCtorDeclaration syntaxCopy(Dsymbol s)
4194 assert(!s);
4195 auto scd = new StaticCtorDeclaration(loc, endloc, storage_class);
4196 FuncDeclaration.syntaxCopy(scd);
4197 return scd;
4200 override final inout(AggregateDeclaration) isThis() inout @nogc nothrow pure @safe
4202 return null;
4205 override final bool isVirtual() const @nogc nothrow pure @safe
4207 return false;
4210 override final bool addPreInvariant() @nogc nothrow pure @safe
4212 return false;
4215 override final bool addPostInvariant() @nogc nothrow pure @safe
4217 return false;
4220 override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
4222 return true;
4225 override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
4227 return this;
4230 override void accept(Visitor v)
4232 v.visit(this);
4236 /***********************************************************
4238 extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
4240 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4242 super(loc, endloc, "_sharedStaticCtor", stc);
4245 override SharedStaticCtorDeclaration syntaxCopy(Dsymbol s)
4247 assert(!s);
4248 auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
4249 FuncDeclaration.syntaxCopy(scd);
4250 return scd;
4253 override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
4255 return this;
4258 override void accept(Visitor v)
4260 v.visit(this);
4264 /***********************************************************
4266 extern (C++) class StaticDtorDeclaration : FuncDeclaration
4268 VarDeclaration vgate; // 'gate' variable
4270 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4272 super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null);
4275 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
4277 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
4280 override StaticDtorDeclaration syntaxCopy(Dsymbol s)
4282 assert(!s);
4283 auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
4284 FuncDeclaration.syntaxCopy(sdd);
4285 return sdd;
4288 override final inout(AggregateDeclaration) isThis() inout
4290 return null;
4293 override final bool isVirtual() const
4295 return false;
4298 override final bool hasStaticCtorOrDtor()
4300 return true;
4303 override final bool addPreInvariant()
4305 return false;
4308 override final bool addPostInvariant()
4310 return false;
4313 override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
4315 return this;
4318 override void accept(Visitor v)
4320 v.visit(this);
4324 /***********************************************************
4326 extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
4328 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
4330 super(loc, endloc, "_sharedStaticDtor", stc);
4333 override SharedStaticDtorDeclaration syntaxCopy(Dsymbol s)
4335 assert(!s);
4336 auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
4337 FuncDeclaration.syntaxCopy(sdd);
4338 return sdd;
4341 override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
4343 return this;
4346 override void accept(Visitor v)
4348 v.visit(this);
4352 /***********************************************************
4354 extern (C++) final class InvariantDeclaration : FuncDeclaration
4356 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
4358 // Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list.
4359 super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
4360 this.fbody = fbody;
4363 override InvariantDeclaration syntaxCopy(Dsymbol s)
4365 assert(!s);
4366 auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null);
4367 FuncDeclaration.syntaxCopy(id);
4368 return id;
4371 override bool isVirtual() const
4373 return false;
4376 override bool addPreInvariant()
4378 return false;
4381 override bool addPostInvariant()
4383 return false;
4386 override inout(InvariantDeclaration) isInvariantDeclaration() inout
4388 return this;
4391 override void accept(Visitor v)
4393 v.visit(this);
4396 extern (D) void fixupInvariantIdent(size_t offset)
4398 OutBuffer idBuf;
4399 idBuf.writestring("__invariant");
4400 idBuf.print(offset);
4402 ident = Identifier.idPool(idBuf[]);
4407 /***********************************************************
4409 extern (C++) final class UnitTestDeclaration : FuncDeclaration
4411 char* codedoc; // for documented unittest
4413 // toObjFile() these nested functions after this one
4414 FuncDeclarations deferredNested;
4416 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
4418 super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null);
4419 this.codedoc = codedoc;
4422 override UnitTestDeclaration syntaxCopy(Dsymbol s)
4424 assert(!s);
4425 auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
4426 FuncDeclaration.syntaxCopy(utd);
4427 return utd;
4430 override inout(AggregateDeclaration) isThis() inout
4432 return null;
4435 override bool isVirtual() const
4437 return false;
4440 override bool addPreInvariant()
4442 return false;
4445 override bool addPostInvariant()
4447 return false;
4450 override inout(UnitTestDeclaration) isUnitTestDeclaration() inout
4452 return this;
4455 override void accept(Visitor v)
4457 v.visit(this);
4461 /***********************************************************
4463 extern (C++) final class NewDeclaration : FuncDeclaration
4465 extern (D) this(const ref Loc loc, StorageClass stc)
4467 super(loc, Loc.initial, Id.classNew, STC.static_ | stc, null);
4470 override NewDeclaration syntaxCopy(Dsymbol s)
4472 assert(!s);
4473 auto f = new NewDeclaration(loc, storage_class);
4474 FuncDeclaration.syntaxCopy(f);
4475 return f;
4478 override const(char)* kind() const
4480 return "allocator";
4483 override bool isVirtual() const
4485 return false;
4488 override bool addPreInvariant()
4490 return false;
4493 override bool addPostInvariant()
4495 return false;
4498 override inout(NewDeclaration) isNewDeclaration() inout
4500 return this;
4503 override void accept(Visitor v)
4505 v.visit(this);
4509 /**************************************
4510 * When a traits(compiles) is used on a function literal call
4511 * we need to take into account if the body of the function
4512 * violates any attributes, however, we must not affect the
4513 * attribute inference on the outer function. The attributes
4514 * of the function literal still need to be inferred, therefore
4515 * we need a way to check for the scope that the traits compiles
4516 * introduces.
4518 * Params:
4519 * sc = scope to be checked for
4521 * Returns: `true` if the provided scope is the root
4522 * of the traits compiles list of scopes.
4524 bool isRootTraitsCompilesScope(Scope* sc)
4526 return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
4529 /**************************************
4530 * A statement / expression in this scope is not `@safe`,
4531 * so mark the enclosing function as `@system`
4533 * Params:
4534 * sc = scope that the unsafe statement / expression is in
4535 * gag = surpress error message (used in escape.d)
4536 * loc = location of error
4537 * fmt = printf-style format string
4538 * arg0 = (optional) argument for first %s format specifier
4539 * arg1 = (optional) argument for second %s format specifier
4540 * arg2 = (optional) argument for third %s format specifier
4541 * Returns: whether there's a safe error
4543 bool setUnsafe(Scope* sc,
4544 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
4545 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
4547 if (sc.intypeof)
4548 return false; // typeof(cast(int*)0) is safe
4550 if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
4551 return false;
4553 if (!sc.func)
4555 if (sc.varDecl)
4557 if (sc.varDecl.storage_class & STC.safe)
4559 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4560 return true;
4562 else if (!(sc.varDecl.storage_class & STC.trusted))
4564 sc.varDecl.storage_class |= STC.system;
4565 sc.varDecl.systemInferred = true;
4568 return false;
4572 if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
4574 if (sc.func.isSafeBypassingInference())
4576 // Message wil be gagged, but still call error() to update global.errors and for
4577 // -verrors=spec
4578 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4579 return true;
4581 return false;
4584 return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
4587 /***************************************
4588 * Like `setUnsafe`, but for safety errors still behind preview switches
4590 * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
4591 * the behavior changes based on the setting:
4593 * - In case of `-revert=fs`, it does nothing.
4594 * - In case of `-preview=fs`, it's the same as `setUnsafe`
4595 * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
4597 * Params:
4598 * sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
4599 * fs = feature state from the preview flag
4600 * gag = surpress error message
4601 * loc = location of error
4602 * msg = printf-style format string
4603 * arg0 = (optional) argument for first %s format specifier
4604 * arg1 = (optional) argument for second %s format specifier
4605 * arg2 = (optional) argument for third %s format specifier
4606 * Returns: whether an actual safe error (not deprecation) occured
4608 bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
4609 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
4611 //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
4612 with (FeatureState) final switch (fs)
4614 case disabled:
4615 return false;
4617 case enabled:
4618 return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
4620 case default_:
4621 if (!sc.func)
4622 return false;
4623 if (sc.func.isSafeBypassingInference())
4625 if (!gag)
4627 version (none) // disable obsolete warning
4628 warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
4631 else if (!sc.func.safetyViolation)
4633 import dmd.func : AttributeViolation;
4634 sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
4636 return false;
4640 /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
4642 /// Has two modes:
4643 /// - a regular safety error, stored in (fmtStr, arg0, arg1)
4644 /// - a call to a function without the attribute, which is a special case, because in that case,
4645 /// that function might recursively also have a `AttributeViolation`. This way, in case
4646 /// of a big call stack, the error can go down all the way to the root cause.
4647 /// The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`.
4648 struct AttributeViolation
4650 /// location of error
4651 Loc loc = Loc.init;
4652 /// printf-style format string
4653 const(char)* fmtStr = null;
4654 /// Arguments for up to two `%s` format specifiers in format string
4655 RootObject arg0 = null;
4656 /// ditto
4657 RootObject arg1 = null;
4658 /// ditto
4659 RootObject arg2 = null;
4662 /// Print the reason why `fd` was inferred `@system` as a supplemental error
4663 /// Params:
4664 /// fd = function to check
4665 /// maxDepth = up to how many functions deep to report errors
4666 /// deprecation = print deprecations instead of errors
4667 /// stc = storage class of attribute to check
4668 void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc)
4670 auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
4672 AttributeViolation* s;
4673 const(char)* attr;
4674 if (stc & STC.safe)
4676 s = fd.safetyViolation;
4677 attr = "@safe";
4679 else if (stc & STC.pure_)
4681 s = fd.pureViolation;
4682 attr = "pure";
4684 else if (stc & STC.nothrow_)
4686 s = fd.nothrowViolation;
4687 attr = "nothrow";
4689 else if (stc & STC.nogc)
4691 s = fd.nogcViolation;
4692 attr = "@nogc";
4695 if (s)
4697 if (s.fmtStr)
4699 errorFunc(s.loc, deprecation ?
4700 "which wouldn't be `%s` because of:" :
4701 "which wasn't inferred `%s` because of:", attr);
4702 if (stc == STC.nogc || stc == STC.pure_)
4704 auto f = (cast(Dsymbol) s.arg0).isFuncDeclaration();
4705 errorFunc(s.loc, s.fmtStr, f.kind(), f.toPrettyChars(), s.arg1 ? s.arg1.toChars() : "");
4707 else
4709 errorFunc(s.loc, s.fmtStr,
4710 s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
4713 else if (auto sa = s.arg0.isDsymbol())
4715 if (FuncDeclaration fd2 = sa.isFuncDeclaration())
4717 if (maxDepth > 0)
4719 errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
4720 errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc);