2 * Defines a function declaration.
5 * - function/delegate literals
7 * - (static/shared) constructors/destructors/post-blits
11 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
12 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
13 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
14 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d)
15 * Documentation: https://dlang.org/phobos/dmd_func.html
16 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d
21 import core.stdc.stdio;
22 import core.stdc.string;
24 import dmd.arraytypes;
30 import dmd.declaration;
31 import dmd.delegatize;
32 import dmd.dinterpret;
37 import dmd.dsymbolsem;
41 import dmd.expression;
46 import dmd.identifier;
52 import dmd.common.outbuffer;
53 import dmd.rootobject;
54 import dmd.root.string;
55 import dmd.root.stringtable;
58 import dmd.statement_rewrite_walker;
60 import dmd.statementsem;
66 else version (IN_LLVM) {}
72 uninitialized, /// not computed yet
79 unknown = 255, /// not known if this is a builtin
80 unimp = 0, /// this is not a builtin
81 gcc, /// this is a GCC builtin
82 llvm, /// this is an LLVM builtin
118 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
120 extern (C++) final class NrvoWalker : StatementRewriteWalker
122 alias visit = typeof(super).visit;
127 override void visit(ReturnStatement s)
129 // See if all returns are instead to be replaced with a goto returnLabel;
135 * vresult = exp; goto Lresult;
137 auto gs = new GotoStatement(s.loc, Id.returnLabel);
138 gs.label = fd.returnLabel;
142 s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
148 override void visit(TryFinallyStatement s)
150 DtorExpStatement des;
151 if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
152 fd.nrvo_var == des.var)
154 if (!(global.params.useExceptions && ClassDeclaration.throwable))
156 /* Don't need to call destructor at all, since it is nrvo
158 replaceCurrent(s._body);
159 s._body.accept(this);
163 /* Normally local variable dtors are called regardless exceptions.
164 * But for nrvo_var, its dtor should be called only when exception is thrown.
167 * try { s.body; } finally { nrvo_var.edtor; }
168 * // equivalent with:
169 * // s.body; scope(exit) nrvo_var.edtor;
171 * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
172 * // equivalent with:
173 * // s.body; scope(failure) nrvo_var.edtor;
175 Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
176 Identifier id = Identifier.generateId("__o");
178 Statement handler = new PeelStatement(sexception);
179 if (sexception.blockExit(fd, null) & BE.fallthru)
181 auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
182 ts.internalThrow = true;
183 handler = new CompoundStatement(Loc.initial, handler, ts);
186 auto catches = new Catches();
187 auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
188 ctch.internalCatch = true;
189 ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
192 Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
198 StatementRewriteWalker.visit(s);
202 private struct FUNCFLAG
204 bool purityInprocess; /// working on determining purity
205 bool safetyInprocess; /// working on determining safety
206 bool nothrowInprocess; /// working on determining nothrow
207 bool nogcInprocess; /// working on determining @nogc
208 bool returnInprocess; /// working on inferring 'return' for parameters
209 bool inlineScanned; /// function has been scanned for inline possibilities
210 bool inferScope; /// infer 'scope' for parameters
211 bool hasCatches; /// function has try-catch statements
212 bool skipCodegen; /// do not generate code for this function.
213 bool printf; /// is a printf-like function
215 bool scanf; /// is a scanf-like function
216 bool noreturn; /// the function does not return
217 bool isNRVO = true; /// Support for named return value optimization
218 bool isNaked; /// The function is 'naked' (see inline ASM)
219 bool isGenerated; /// The function is compiler generated (e.g. `opCmp`)
220 bool isIntroducing; /// If this function introduces the overload set
221 bool hasSemantic3Errors; /// If errors in semantic3 this function's frame ptr
222 bool hasNoEH; /// No exception unwinding is needed
223 bool inferRetType; /// Return type is to be inferred
224 bool hasDualContext; /// has a dual-context 'this' parameter
226 bool hasAlwaysInlines; /// Contains references to functions that must be inlined
227 bool isCrtCtor; /// Has attribute pragma(crt_constructor)
228 bool isCrtDtor; /// Has attribute pragma(crt_destructor)
229 bool hasEscapingSiblings;/// Has sibling functions that escape
230 bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed
231 bool dllImport; /// __declspec(dllimport)
232 bool dllExport; /// __declspec(dllexport)
235 /***********************************************************
236 * Tuple of result identifier (possibly null) and statement.
237 * This is used to store out contracts: out(id){ ensure }
239 extern (C++) struct Ensure
246 return Ensure(id, ensure.syntaxCopy());
249 /*****************************************
250 * Do syntax copy of an array of Ensure's.
252 static Ensures* arraySyntaxCopy(Ensures* a)
260 (*b)[i] = e.syntaxCopy();
268 /***********************************************************
269 * Most functions don't have contracts, so save memory by grouping
270 * this information into a separate struct
272 private struct ContractInfo
274 Statements* frequires; /// in contracts
275 Ensures* fensures; /// out contracts
276 Statement frequire; /// lowered in contract
277 Statement fensure; /// lowered out contract
278 FuncDeclaration fdrequire; /// function that does the in contract
279 FuncDeclaration fdensure; /// function that does the out contract
280 Expressions* fdrequireParams; /// argument list for __require
281 Expressions* fdensureParams; /// argument list for __ensure
284 /***********************************************************
286 extern (C++) class FuncDeclaration : Declaration
288 Statement fbody; /// function body
290 FuncDeclarations foverrides; /// functions this function overrides
292 private ContractInfo* contracts; /// contract information
294 const(char)* mangleString; /// mangled symbol created from mangleExact()
296 VarDeclaration vresult; /// result variable for out contracts
297 LabelDsymbol returnLabel; /// where the return goes
299 bool[size_t] isTypeIsolatedCache; /// cache for the potentially very expensive isTypeIsolated check
301 // used to prevent symbols in different
302 // scopes from having the same name
303 DsymbolTable localsymtab;
304 VarDeclaration vthis; /// 'this' parameter (member and nested)
305 VarDeclaration v_arguments; /// '_arguments' parameter
307 VarDeclaration v_argptr; /// '_argptr' variable
308 VarDeclarations* parameters; /// Array of VarDeclaration's for parameters
309 DsymbolTable labtab; /// statement label symbol table
310 Dsymbol overnext; /// next in overload list
311 FuncDeclaration overnext0; /// next in overload list (only used during IFTI)
312 Loc endloc; /// location of closing curly bracket
313 int vtblIndex = -1; /// for member functions, index into vtbl[]
315 ILS inlineStatusStmt = ILS.uninitialized;
316 ILS inlineStatusExp = ILS.uninitialized;
317 PINLINE inlining = PINLINE.default_;
319 int inlineNest; /// !=0 if nested inline
321 ForeachStatement fes; /// if foreach body, this is the foreach
322 BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[]
323 /** if !=NULL, then this is the type
324 of the 'introducing' function
325 this one is overriding
329 StorageClass storage_class2; /// storage class for template onemember's
331 // Things that should really go into Scope
333 /// 1 if there's a return exp; statement
334 /// 2 if there's a throw statement
335 /// 4 if there's an assert(0)
336 /// 8 if there's inline asm
337 /// 16 if there are multiple return statements
340 VarDeclaration nrvo_var; /// variable to replace with shidden
341 Symbol* shidden; /// hidden pointer passed to function
343 ReturnStatements* returns;
345 GotoStatements* gotos; /// Gotos with forward references
349 VarDeclarations* alignSectionVars; /// local variables with alignment needs larger than stackAlign
350 Symbol* salignSection; /// pointer to aligned section, if any
353 /// set if this is a known, builtin function we can evaluate at compile time
354 BUILTIN builtin = BUILTIN.unknown;
356 /// set if someone took the address of this function
359 bool requiresClosure; // this function needs a closure
361 /** local variables in this function which are referenced by nested functions
362 * (They'll get put into the "closure" for this function.)
364 VarDeclarations closureVars;
366 /** Outer variables which are referenced by this nested function
367 * (the inverse of closureVars)
369 VarDeclarations outerVars;
371 /// Sibling nested functions which called this one
372 FuncDeclarations siblingCallers;
374 FuncDeclarations *inlinedNestedCallees;
376 /// In case of failed `@safe` inference, store the error that made the function `@system` for
377 /// better diagnostics
378 AttributeViolation* safetyViolation;
379 AttributeViolation* nogcViolation;
380 AttributeViolation* pureViolation;
381 AttributeViolation* nothrowViolation;
383 /// See the `FUNCFLAG` struct
384 import dmd.common.bitfields;
385 mixin(generateBitFields!(FUNCFLAG, uint));
388 * Data for a function declaration that is needed for the Objective-C
391 ObjcFuncDeclaration objc;
393 extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false)
396 //.printf("FuncDeclaration(id = '%s', type = %s)\n", ident.toChars(), type.toChars());
397 //.printf("storage_class = x%llx\n", storage_class);
398 this.storage_class = storage_class;
402 // Normalize storage_class, because function-type related attributes
403 // are already set in the 'type' in parsing phase.
404 this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
406 this.endloc = endloc;
408 this.noreturn = true;
410 /* The type given for "infer the return type" is a TypeFunction with
411 * NULL for the return type.
413 if (type && type.nextOf() is null)
414 this.inferRetType = true;
417 static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
419 return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn);
422 final nothrow pure @safe
424 private ref ContractInfo getContracts()
427 contracts = new ContractInfo();
432 inout(Statements*) frequires() inout { return contracts ? contracts.frequires : null; }
433 inout(Ensures*) fensures() inout { return contracts ? contracts.fensures : null; }
434 inout(Statement) frequire() inout { return contracts ? contracts.frequire: null; }
435 inout(Statement) fensure() inout { return contracts ? contracts.fensure : null; }
436 inout(FuncDeclaration) fdrequire() inout { return contracts ? contracts.fdrequire : null; }
437 inout(FuncDeclaration) fdensure() inout { return contracts ? contracts.fdensure: null; }
438 inout(Expressions*) fdrequireParams() inout { return contracts ? contracts.fdrequireParams: null; }
439 inout(Expressions*) fdensureParams() inout { return contracts ? contracts.fdensureParams: null; }
441 extern (D) private static string generateContractSetter(string field, string type)
443 return type ~ " " ~ field ~ "(" ~ type ~ " param)" ~
445 if (!param && !contracts) return null;
446 return getContracts()." ~ field ~ " = param;
450 mixin(generateContractSetter("frequires", "Statements*"));
451 mixin(generateContractSetter("fensures", "Ensures*"));
452 mixin(generateContractSetter("frequire", "Statement"));
453 mixin(generateContractSetter("fensure", "Statement"));
454 mixin(generateContractSetter("fdrequire", "FuncDeclaration"));
455 mixin(generateContractSetter("fdensure", "FuncDeclaration"));
456 mixin(generateContractSetter("fdrequireParams", "Expressions*"));
457 mixin(generateContractSetter("fdensureParams", "Expressions*"));
460 override FuncDeclaration syntaxCopy(Dsymbol s)
462 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
463 FuncDeclaration f = s ? cast(FuncDeclaration)s
464 : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), this.noreturn != 0);
465 f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
466 f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
467 f.fbody = fbody ? fbody.syntaxCopy() : null;
471 override final bool equals(const RootObject o) const
476 if (auto s = isDsymbol(o))
479 auto fd2 = s.isFuncDeclaration();
483 auto fa1 = fd1.isFuncAliasDeclaration();
484 auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
486 auto fa2 = fd2.isFuncAliasDeclaration();
487 auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
491 return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
494 bool b1 = fa1 !is null;
495 if (b1 && faf1.isUnique() && !fa1.hasOverloads)
498 bool b2 = fa2 !is null;
499 if (b2 && faf2.isUnique() && !fa2.hasOverloads)
505 return faf1.toParent().equals(faf2.toParent()) &&
506 faf1.ident.equals(faf2.ident) &&
507 faf1.type.equals(faf2.type);
512 /****************************************************
513 * Determine if 'this' overrides fd.
514 * Return !=0 if it does.
516 extern (D) final int overrides(FuncDeclaration fd)
519 if (fd.ident == ident)
521 const cov = type.covariant(fd.type);
522 if (cov != Covariant.distinct)
524 ClassDeclaration cd1 = toParent().isClassDeclaration();
525 ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
526 if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
533 /****************************************************
534 * Overload this FuncDeclaration with the new one f.
535 * Return true if successful; i.e. no conflict.
537 override bool overloadInsert(Dsymbol s)
539 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
541 AliasDeclaration ad = s.isAliasDeclaration();
545 return overnext.overloadInsert(ad);
546 if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof)
548 //printf("\tad = '%s'\n", ad.type.toChars());
552 //printf("\ttrue: no conflict\n");
555 TemplateDeclaration td = s.isTemplateDeclaration();
561 return overnext.overloadInsert(td);
565 FuncDeclaration fd = s.isFuncDeclaration();
571 /* Disable this check because:
573 * semantic() isn't run yet on foo(), so the const hasn't been
578 printf("type = %s\n", type.toChars());
579 printf("fd.type = %s\n", fd.type.toChars());
581 // fd.type can be NULL for overloaded constructors
582 if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
584 //printf("\tfalse: conflict %s\n", kind());
591 td = overnext.isTemplateDeclaration();
593 fd.overloadInsert(td);
595 return overnext.overloadInsert(fd);
598 //printf("\ttrue: no conflict\n");
602 /********************************************
603 * Find function in overload list that exactly matches t.
605 extern (D) final FuncDeclaration overloadExactMatch(Type t)
608 overloadApply(this, (Dsymbol s)
610 auto f = s.isFuncDeclaration();
613 if (f.storage_class & STC.disable)
615 if (t.equals(f.type))
621 /* Allow covariant matches, as long as the return type
622 * is just a const conversion.
623 * This allows things like pure functions to match with an impure function type.
625 if (t.ty == Tfunction)
627 auto tf = cast(TypeFunction)f.type;
628 if (tf.covariant(t) == Covariant.yes &&
629 tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
640 /********************************************
641 * Find function in overload list that matches to the 'this' modifier.
642 * There's four result types.
644 * 1. If the 'tthis' matches only one candidate, it's an "exact match".
645 * Returns the function and 'hasOverloads' is set to false.
646 * eg. If 'tthis" is mutable and there's only one mutable method.
647 * 2. If there's two or more match candidates, but a candidate function will be
649 * Returns the better match function but 'hasOverloads' is set to true.
650 * eg. If 'tthis' is mutable, and there's both mutable and const methods,
651 * the mutable method will be a better match.
652 * 3. If there's two or more match candidates, but there's no better match,
653 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
654 * eg. If 'tthis' is mutable, and there's two or more mutable methods.
655 * 4. If there's no candidates, it's "no match" and returns null with error report.
656 * e.g. If 'tthis' is const but there's no const methods.
658 extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
660 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
662 overloadApply(this, (Dsymbol s)
664 auto f = s.isFuncDeclaration();
665 if (!f || f == m.lastf) // skip duplicates
668 auto tf = f.type.toTypeFunction();
669 //printf("tf = %s\n", tf.toChars());
672 if (tthis) // non-static functions are preferred than static ones
675 match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
677 match = MATCH.constant; // keep static function in overload candidates
679 else // static functions are preferred than non-static ones
682 match = MATCH.convert;
686 if (match == MATCH.nomatch)
689 if (match > m.last) goto LcurrIsBetter;
690 if (match < m.last) goto LlastIsBetter;
692 // See if one of the matches overrides the other.
693 if (m.lastf.overrides(f)) goto LlastIsBetter;
694 if (f.overrides(m.lastf)) goto LcurrIsBetter;
696 //printf("\tambiguous\n");
702 //printf("\tlastbetter\n");
703 m.count++; // count up
707 //printf("\tisbetter\n");
708 if (m.last <= MATCH.convert)
710 // clear last secondary matching
716 m.count++; // count up
720 if (m.count == 1) // exact match
722 hasOverloads = false;
724 else if (m.count > 1) // better or ambiguous match
731 auto tf = this.type.toTypeFunction();
733 assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
735 OutBuffer thisBuf, funcBuf;
736 MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
737 MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
738 .error(loc, "%smethod %s is not callable using a %sobject", kind, toPrettyChars,
739 funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
745 /********************************************
746 * find function template root in overload list
748 extern (D) final TemplateDeclaration findTemplateDeclRoot()
750 FuncDeclaration f = this;
751 while (f && f.overnext)
753 //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
754 TemplateDeclaration td = f.overnext.isTemplateDeclaration();
757 f = f.overnext.isFuncDeclaration();
762 /********************************************
763 * Returns true if function was declared
764 * directly or indirectly in a unittest block
766 final bool inUnittest()
771 if (f.isUnitTestDeclaration())
779 /*************************************
780 * Determine partial specialization order of functions `f` vs `g`.
781 * This is very similar to TemplateDeclaration::leastAsSpecialized().
784 * g = second function
785 * names = names of parameters
787 * match 'this' is at least as specialized as g
788 * 0 g is more specialized than 'this'
790 static MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names)
792 enum LOG_LEASTAS = 0;
793 static if (LOG_LEASTAS)
795 import core.stdc.stdio : printf;
796 printf("leastAsSpecialized(%s, %s, %s)\n", f.toChars(), g.toChars(), names ? names.toChars() : "null");
797 printf("%s, %s\n", f.type.toChars(), g.type.toChars());
800 /* This works by calling g() with f()'s parameters, and
801 * if that is possible, then f() is at least as specialized
805 TypeFunction tf = f.type.toTypeFunction();
806 TypeFunction tg = g.type.toTypeFunction();
808 /* If both functions have a 'this' pointer, and the mods are not
809 * the same and g's is not const, then this is less specialized.
811 if (f.needThis() && g.needThis() && tf.mod != tg.mod)
813 if (f.isCtorDeclaration())
815 if (!MODimplicitConv(tg.mod, tf.mod))
816 return MATCH.nomatch;
820 if (!MODimplicitConv(tf.mod, tg.mod))
821 return MATCH.nomatch;
825 /* Create a dummy array of arguments out of the parameters to f()
828 foreach (u, p; tf.parameterList)
833 e = new IdentifierExp(Loc.initial, p.ident);
837 e = p.type.defaultInitLiteral(Loc.initial);
841 MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
842 if (m > MATCH.nomatch)
844 /* A variadic parameter list is less specialized than a
847 if (tf.parameterList.varargs && !tg.parameterList.varargs)
848 goto L1; // less specialized
850 static if (LOG_LEASTAS)
852 printf(" matches %d, so is least as specialized\n", m);
857 static if (LOG_LEASTAS)
859 printf(" doesn't match, so is not as specialized\n");
861 return MATCH.nomatch;
864 /********************************
865 * Searches for a label with the given identifier. This function will insert a new
866 * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
869 * ident = identifier of the requested label
870 * loc = location used when creating a new `LabelDsymbol`
872 * Returns: the `LabelDsymbol` for `ident`
874 final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc)
878 labtab = new DsymbolTable(); // guess we need one
880 s = labtab.lookup(ident);
883 s = new LabelDsymbol(ident, loc);
886 return cast(LabelDsymbol)s;
889 /*****************************************
890 * Determine lexical level difference from `this` to nested function `fd`.
892 * fd = target of call
893 * intypeof = !=0 if inside typeof
896 * >0 decrease nesting by number
897 * -1 increase nesting by 1 (`fd` is nested within `this`)
898 * LevelError error, `this` cannot call `fd`
900 extern (D) final int getLevel(FuncDeclaration fd, int intypeof)
902 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
903 Dsymbol fdparent = fd.toParent2();
904 if (fdparent == this)
909 while (fd != s && fdparent != s.toParent2())
911 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
912 if (auto thisfd = s.isFuncDeclaration())
914 if (!thisfd.isNested() && !thisfd.vthis && !intypeof)
919 if (auto thiscd = s.isAggregateDeclaration())
921 /* AggregateDeclaration::isNested returns true only when
922 * it has a hidden pointer.
923 * But, calling the function belongs unrelated lexical scope
924 * is still allowed inside typeof.
926 * struct Map(alias fun) {
927 * typeof({ return fun(); }) RetType;
928 * // No member function makes Map struct 'not nested'.
931 if (!thiscd.isNested() && !intypeof)
945 /***********************************
946 * Determine lexical level difference from `this` to nested function `fd`.
947 * Issue error if `this` cannot call `fd`.
950 * loc = location for error messages
952 * fd = target of call
953 * decl = The `Declaration` that triggered this check.
954 * Used to provide a better error message only.
957 * >0 decrease nesting by number
958 * -1 increase nesting by 1 (`fd` is nested within 'this')
961 extern (D) final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd,
964 int level = getLevel(fd, sc.intypeof);
965 if (level != LevelError)
968 // Don't give error if in template constraint
969 if (!(sc.flags & SCOPE.constraint))
971 const(char)* xstatic = isStatic() ? "`static` " : "";
972 // better diagnostics for static functions
973 .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
974 xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(),
976 .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
982 enum LevelError = -2;
984 override const(char)* toPrettyChars(bool QualifyTypes = false)
989 return Dsymbol.toPrettyChars(QualifyTypes);
992 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
993 final const(char)* toFullSignature()
996 functionToBufferWithIdent(type.toTypeFunction(), buf, toChars(), isStatic);
997 return buf.extractChars();
1000 final bool isMain() const
1002 return ident == Id.main && resolvedLinkage() != LINK.c && !isMember() && !isNested();
1005 final bool isCMain() const
1007 return ident == Id.main && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1010 final bool isWinMain() const
1012 //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1015 bool x = ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1016 printf("%s\n", x ? "yes" : "no");
1021 return ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember();
1025 final bool isDllMain() const
1027 return ident == Id.DllMain && resolvedLinkage() != LINK.c && !isMember();
1030 final bool isRtInit() const
1032 return ident == Id.rt_init && resolvedLinkage() == LINK.c && !isMember() && !isNested();
1035 override final bool isExport() const
1037 return visibility.kind == Visibility.Kind.export_ || dllExport;
1040 override final bool isImportedSymbol() const
1042 //printf("isImportedSymbol()\n");
1043 //printf("protection = %d\n", visibility);
1044 return (visibility.kind == Visibility.Kind.export_ || dllImport) && !fbody;
1047 override final bool isCodeseg() const pure nothrow @nogc @safe
1049 return true; // functions are always in the code segment
1052 override final bool isOverloadable() const
1054 return true; // functions can be overloaded
1057 /***********************************
1058 * Override so it can work even if semantic() hasn't yet
1061 override final bool isAbstract()
1063 if (storage_class & STC.abstract_)
1065 if (semanticRun >= PASS.semanticdone)
1070 if (_scope.stc & STC.abstract_)
1072 parent = _scope.parent;
1073 Dsymbol parent = toParent();
1074 if (parent.isInterfaceDeclaration())
1080 /**********************************
1081 * Decide if attributes for this function can be inferred from examining
1082 * the function body.
1086 final bool canInferAttributes(Scope* sc)
1091 if (isVirtualMethod() &&
1093 * https://issues.dlang.org/show_bug.cgi?id=21719
1095 * If we have an auto virtual function we can infer
1098 !(inferRetType && !isCtorDeclaration()))
1099 return false; // since they may be overridden
1102 /********** this is for backwards compatibility for the moment ********/
1103 (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
1106 if (isFuncLiteralDeclaration() || // externs are not possible with literals
1107 (storage_class & STC.inference) || // do attribute inference
1108 (inferRetType && !isCtorDeclaration()))
1111 if (isInstantiated())
1113 auto ti = parent.isTemplateInstance();
1114 if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
1121 /*****************************************
1122 * Initialize for inferring the attributes of this function.
1124 final void initInferAttributes()
1126 //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1127 TypeFunction tf = type.toTypeFunction();
1128 if (tf.purity == PURE.impure) // purity not specified
1129 purityInprocess = true;
1131 if (tf.trust == TRUST.default_)
1132 safetyInprocess = true;
1135 nothrowInprocess = true;
1138 nogcInprocess = true;
1140 if (!isVirtual() || this.isIntroducing())
1141 returnInprocess = true;
1143 // Initialize for inferring STC.scope_
1149 //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1152 TypeFunction tf = type.toTypeFunction();
1153 if (purityInprocess)
1155 if (tf.purity == PURE.fwdref)
1157 PURE purity = tf.purity;
1158 if (purity > PURE.weak && isNested())
1160 if (purity > PURE.weak && needThis())
1162 // The attribute of the 'this' reference affects purity strength
1163 if (type.mod & MODFlags.immutable_)
1166 else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
1167 purity = PURE.const_;
1172 // ^ This rely on the current situation that every FuncDeclaration has a
1173 // unique TypeFunction.
1177 extern (D) final PURE isPureBypassingInference()
1179 if (purityInprocess)
1185 /**************************************
1186 * The function is doing something impure, so mark it as impure.
1189 * loc = location of impure action
1190 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1191 * arg0 = (optional) argument to format string
1193 * Returns: `true` if there's a purity error
1195 extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
1197 if (purityInprocess)
1199 purityInprocess = false;
1201 pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action
1203 pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
1206 fes.func.setImpure(loc, fmt, arg0);
1213 extern (D) final uint flags()
1218 extern (D) final uint flags(uint f)
1226 if (safetyInprocess)
1228 return type.toTypeFunction().trust == TRUST.safe;
1231 extern (D) final bool isSafeBypassingInference()
1233 return !(safetyInprocess) && isSafe();
1236 final bool isTrusted()
1238 if (safetyInprocess)
1240 return type.toTypeFunction().trust == TRUST.trusted;
1243 /**************************************
1244 * The function is doing something unsafe, so mark it as unsafe.
1247 * gag = surpress error message (used in escape.d)
1248 * loc = location of error
1249 * fmt = printf-style format string
1250 * arg0 = (optional) argument for first %s format specifier
1251 * arg1 = (optional) argument for second %s format specifier
1252 * arg2 = (optional) argument for third %s format specifier
1253 * Returns: whether there's a safe error
1255 extern (D) final bool setUnsafe(
1256 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
1257 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
1259 if (safetyInprocess)
1261 safetyInprocess = false;
1262 type.toTypeFunction().trust = TRUST.system;
1264 safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);
1267 fes.func.setUnsafe();
1272 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
1279 /**************************************
1280 * The function is calling `@system` function `f`, so mark it as unsafe.
1283 * f = function being called (needed for diagnostic of inferred functions)
1284 * Returns: whether there's a safe error
1286 extern (D) final bool setUnsafeCall(FuncDeclaration f)
1288 return setUnsafe(false, f.loc, null, f, null);
1293 //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1296 return type.toTypeFunction().isnogc;
1299 extern (D) final bool isNogcBypassingInference()
1301 return !nogcInprocess && isNogc();
1304 /**************************************
1305 * The function is doing something that may allocate with the GC,
1306 * so mark it as not nogc (not no-how).
1309 * loc = location of impure action
1310 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1311 * arg0 = (optional) argument to format string
1314 * true if function is marked as @nogc, meaning a user error occurred
1316 extern (D) final bool setGC(Loc loc, const(char)* fmt, RootObject arg0 = null)
1318 //printf("setGC() %s\n", toChars());
1319 if (nogcInprocess && semanticRun < PASS.semantic3 && _scope)
1321 this.semantic2(_scope);
1322 this.semantic3(_scope);
1327 nogcInprocess = false;
1329 nogcViolation = new AttributeViolation(loc, fmt, this, arg0); // action that requires GC
1331 nogcViolation = new AttributeViolation(loc, fmt, arg0); // call to non-@nogc function
1333 type.toTypeFunction().isnogc = false;
1335 fes.func.setGC(Loc.init, null, null);
1342 /**************************************
1343 * The function calls non-`@nogc` function f, mark it as not nogc.
1345 * f = function being called
1347 * true if function is marked as @nogc, meaning a user error occurred
1349 extern (D) final bool setGCCall(FuncDeclaration f)
1351 return setGC(loc, null, f);
1354 /**************************************
1355 * The function is doing something that may throw an exception, register that in case nothrow is being inferred
1358 * loc = location of action
1359 * fmt = format string for error message
1360 * arg0 = (optional) argument to format string
1362 extern (D) final void setThrow(Loc loc, const(char)* fmt, RootObject arg0 = null)
1364 if (nothrowInprocess && !nothrowViolation)
1366 nothrowViolation = new AttributeViolation(loc, fmt, arg0); // action that requires GC
1370 /**************************************
1371 * The function calls non-`nothrow` function f, register that in case nothrow is being inferred
1373 * loc = location of call
1374 * f = function being called
1376 extern (D) final void setThrowCall(Loc loc, FuncDeclaration f)
1378 return setThrow(loc, null, f);
1381 extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
1383 if (!global.params.v.gc)
1386 Module m = getModule();
1387 if (m && m.isRoot() && !inUnittest())
1389 message(loc, "vgc: %s", warn);
1393 /********************************************
1394 * See if pointers from function parameters, mutable globals, or uplevel functions
1395 * could leak into return value.
1397 * true if the function return value is isolated from
1398 * any inputs to the function
1400 extern (D) final bool isReturnIsolated()
1402 //printf("isReturnIsolated(this: %s)\n", this.toChars);
1403 TypeFunction tf = type.toTypeFunction();
1406 Type treti = tf.next;
1408 return isTypeIsolatedIndirect(treti); // check influence from parameters
1410 return isTypeIsolated(treti);
1413 /********************
1414 * See if pointers from function parameters, mutable globals, or uplevel functions
1415 * could leak into type `t`.
1417 * t = type to check if it is isolated
1419 * true if `t` is isolated from
1420 * any inputs to the function
1422 extern (D) final bool isTypeIsolated(Type t)
1424 StringTable!Type parentTypes;
1425 const uniqueTypeID = t.getUniqueID();
1428 const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
1429 if (cacheResultPtr !is null)
1430 return *cacheResultPtr;
1432 parentTypes._init();
1433 const isIsolated = isTypeIsolated(t, parentTypes);
1434 isTypeIsolatedCache[uniqueTypeID] = isIsolated;
1439 parentTypes._init();
1440 return isTypeIsolated(t, parentTypes);
1445 extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
1447 //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
1454 return isTypeIsolatedIndirect(t.nextOf()); // go down one level
1458 return isTypeIsolatedIndirect(t);
1461 /* Drill down and check the struct's fields
1463 auto sym = t.toDsymbol(null).isStructDeclaration();
1464 const tName = t.toChars.toDString;
1465 const entry = parentTypes.insert(tName, t);
1468 //we've already seen this type in a parent, not isolated
1471 foreach (v; sym.fields)
1473 Type tmi = v.type.addMod(t.mod);
1474 //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
1475 // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
1476 if (!isTypeIsolated(tmi, parentTypes))
1486 /********************************************
1488 * t = type of object to test one level of indirection down
1490 * true if an object typed `t` has no indirections
1491 * which could have come from the function's parameters, mutable
1492 * globals, or uplevel functions.
1494 private bool isTypeIsolatedIndirect(Type t)
1496 //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1499 /* Since `t` is one level down from an indirection, it could pick
1500 * up a reference to a mutable global or an outer function, so
1503 if (!isPureBypassingInference() || isNested())
1506 TypeFunction tf = type.toTypeFunction();
1508 //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1510 foreach (i, fparam; tf.parameterList)
1512 Type tp = fparam.type;
1516 if (fparam.isLazy() || fparam.isReference())
1518 if (!traverseIndirections(tp, t))
1523 /* Goes down one level of indirection, then calls traverseIndirection() on
1526 * true if t is isolated from tp
1528 static bool traverse(Type tp, Type t)
1530 tp = tp.baseElemOf();
1535 return traverseIndirections(tp.nextOf(), t);
1539 return traverseIndirections(tp, t);
1542 /* Drill down and check the struct's fields
1544 auto sym = tp.toDsymbol(null).isStructDeclaration();
1545 foreach (v; sym.fields)
1547 Type tprmi = v.type.addMod(tp.mod);
1548 //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1549 if (!traverse(tprmi, t))
1559 if (!traverse(tp, t))
1562 // The 'this' reference is a parameter, too
1563 if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
1565 Type tthis = ad.getType().addMod(tf.mod);
1566 //printf("\ttthis = %s\n", tthis.toChars());
1567 if (!traverseIndirections(tthis, t))
1574 /****************************************
1575 * Determine if function needs a static frame pointer.
1577 * `true` if function is really nested within other function.
1579 * If isNested() returns true, isThis() should return false,
1580 * unless the function needs a dual-context pointer.
1582 bool isNested() const
1584 auto f = toAliasFunc();
1585 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1586 return ((f.storage_class & STC.static_) == 0) &&
1587 (f._linkage == LINK.d) &&
1588 (f.toParent2().isFuncDeclaration() !is null ||
1589 f.toParent2() !is f.toParentLocal());
1592 /****************************************
1593 * Determine if function is a non-static member function
1594 * that has an implicit 'this' expression.
1596 * The aggregate it is a member of, or null.
1598 * Both isThis() and isNested() should return true if function needs a dual-context pointer,
1599 * otherwise if isThis() returns true, isNested() should return false.
1601 override inout(AggregateDeclaration) isThis() inout
1603 //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1604 auto ad = (storage_class & STC.static_) ? .objc.isThis(this) : isMemberLocal();
1605 //printf("-FuncDeclaration::isThis() %p\n", ad);
1609 override final bool needThis()
1611 //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1612 return toAliasFunc().isThis() !is null;
1615 // Determine if a function is pedantically virtual
1616 final bool isVirtualMethod()
1618 if (toAliasFunc() != this)
1619 return toAliasFunc().isVirtualMethod();
1621 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1624 // If it's a final method, and does not override anything, then it is not virtual
1625 if (isFinalFunc() && foverrides.length == 0)
1632 // Determine if function goes into virtual function pointer table
1633 bool isVirtual() const
1635 if (toAliasFunc() != this)
1636 return toAliasFunc().isVirtual();
1638 auto p = toParent();
1640 if (!isMember || !p.isClassDeclaration)
1643 if (p.isClassDeclaration.classKind == ClassKind.objc)
1644 return .objc.isVirtual(this);
1648 printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1649 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), visibility == Visibility.Kind.private_, isCtorDeclaration(), linkage != LINK.d);
1650 printf("result is %d\n", isMember() && !(isStatic() || visibility == Visibility.Kind.private_ || visibility == Visibility.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()));
1652 return !(isStatic() || visibility.kind == Visibility.Kind.private_ || visibility.kind == Visibility.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc());
1655 final bool isFinalFunc() const
1657 if (toAliasFunc() != this)
1658 return toAliasFunc().isFinalFunc();
1662 auto cd = toParent().isClassDeclaration();
1663 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal());
1664 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_));
1665 printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_)));
1667 printf("\tmember of %s\n", cd.toChars());
1671 if (Declaration.isFinal())
1673 auto cd = toParent().isClassDeclaration();
1674 return (cd !is null) && (cd.storage_class & STC.final_);
1677 bool addPreInvariant()
1680 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1681 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());
1684 bool addPostInvariant()
1687 ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
1688 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());
1691 override const(char)* kind() const
1693 return this.isGenerated() ? "generated function" : "function";
1696 /********************************************
1698 * true if there are no overloads of this function
1700 final bool isUnique() const
1702 bool result = false;
1703 overloadApply(cast() this, (Dsymbol s)
1705 auto f = s.isFuncDeclaration();
1706 auto td = s.isTemplateDeclaration();
1712 return 1; // ambiguous, done
1723 /*********************************************
1724 * In the current function, we are calling 'this' function.
1725 * 1. Check to see if the current function can call 'this' function, issue error if not.
1726 * 2. If the current function is not the parent of 'this' function, then add
1727 * the current function to the list of siblings of 'this' function.
1728 * 3. If the current function is a literal, and it's accessing an uplevel scope,
1729 * then mark it as a delegate.
1730 * Returns true if error occurs.
1732 extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
1734 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
1736 if (auto fld = this.isFuncLiteralDeclaration())
1738 if (fld.tok == TOK.reserved)
1740 fld.tok = TOK.function_;
1745 if (!parent || parent == sc.parent)
1747 if (ident == Id.require || ident == Id.ensure)
1749 if (!isThis() && !isNested())
1752 // The current function
1753 FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
1755 return false; // out of function scope
1757 Dsymbol p = toParentLocal();
1758 Dsymbol p2 = toParent2();
1760 // Function literals from fdthis to p must be delegates
1761 ensureStaticLinkTo(fdthis, p);
1763 ensureStaticLinkTo(fdthis, p2);
1767 // The function that this function is in
1768 bool checkEnclosing(FuncDeclaration fdv)
1775 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
1776 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
1777 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
1779 // Add this function to the list of those which called us
1783 for (size_t i = 0; i < siblingCallers.length; ++i)
1785 if (siblingCallers[i] == fdthis)
1790 //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
1791 if (!sc.intypeof && !(sc.flags & SCOPE.compile))
1793 siblingCallers.push(fdthis);
1794 computedEscapingSiblings = false;
1799 const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this);
1800 if (lv == LevelError)
1801 return true; // error
1803 return false; // downlevel call
1805 return false; // same level call
1807 return false; // Uplevel call
1810 if (checkEnclosing(p.isFuncDeclaration()))
1812 if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
1818 /*******************************
1819 * Look at all the variables in this function that are referenced
1820 * by nested functions, and determine if a closure needs to be
1823 final bool needsClosure()
1825 /* Need a closure for all the closureVars[] if any of the
1826 * closureVars[] are accessed by a
1827 * function that escapes the scope of this function.
1828 * We take the conservative approach and decide that a function needs
1830 * 1) is a virtual function
1831 * 2) has its address taken
1832 * 3) has a parent that escapes
1833 * 4) calls another nested function that needs a closure
1835 * Note that since a non-virtual function can be called by
1836 * a virtual one, if that non-virtual function accesses a closure
1837 * var, the closure still has to be taken. Hence, we check for isThis()
1838 * instead of isVirtual(). (thanks to David Friedman)
1840 * When the function returns a local struct or class, `requiresClosure`
1841 * is already set to `true` upon entering this function when the
1842 * struct/class refers to a local variable and a closure is needed.
1844 //printf("FuncDeclaration::needsClosure() %s\n", toPrettyChars());
1846 if (requiresClosure)
1849 for (size_t i = 0; i < closureVars.length; i++)
1851 VarDeclaration v = closureVars[i];
1852 //printf("\tv = %s\n", v.toChars());
1854 for (size_t j = 0; j < v.nestedrefs.length; j++)
1856 FuncDeclaration f = v.nestedrefs[j];
1859 /* __require and __ensure will always get called directly,
1860 * so they never make outer functions closure.
1862 if (f.ident == Id.require || f.ident == Id.ensure)
1865 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
1867 /* Look to see if f escapes. We consider all parents of f within
1868 * this, and also all siblings which call f; if any of them escape,
1870 * Mark all affected functions as requiring closures.
1872 for (Dsymbol s = f; s && s != this; s = s.toParentP(this))
1874 FuncDeclaration fx = s.isFuncDeclaration();
1877 if (fx.isThis() || fx.tookAddressOf)
1879 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
1881 /* Mark as needing closure any functions between this and f
1883 markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this);
1885 requiresClosure = true;
1888 /* We also need to check if any sibling functions that
1889 * called us, have escaped. This is recursive: we need
1890 * to check the callers of our siblings.
1892 if (checkEscapingSiblings(fx, this))
1893 requiresClosure = true;
1895 /* https://issues.dlang.org/show_bug.cgi?id=12406
1896 * Iterate all closureVars to mark all descendant
1897 * nested functions that access to the closing context of this function.
1902 if (requiresClosure)
1911 /***********************************************
1912 * Check that the function contains any closure.
1913 * If it's @nogc, report suitable errors.
1914 * This is mostly consistent with FuncDeclaration::needsClosure().
1917 * true if any errors occur.
1919 extern (C++) final bool checkClosure()
1921 //printf("checkClosure() %s\n", toPrettyChars());
1922 if (!needsClosure())
1925 if (setGC(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", this))
1927 .error(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", kind, toPrettyChars, toChars());
1928 if (global.gag) // need not report supplemental errors
1931 else if (!global.params.useGC)
1933 .error(loc, "%s `%s` is `-betterC` yet allocates closure for `%s()` with the GC", kind, toPrettyChars, toChars());
1934 if (global.gag) // need not report supplemental errors
1939 printGCUsage(loc, "using closure causes GC allocation");
1944 foreach (v; closureVars)
1946 foreach (f; v.nestedrefs)
1950 LcheckAncestorsOfANestedRef:
1951 for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
1953 auto fx = s.isFuncDeclaration();
1958 checkEscapingSiblings(fx, this))
1963 break LcheckAncestorsOfANestedRef;
1966 .errorSupplemental(f.loc, "%s `%s` closes over variable `%s`",
1967 f.kind, f.toPrettyChars(), v.toChars());
1968 if (v.ident != Id.This)
1969 .errorSupplemental(v.loc, "`%s` declared here", v.toChars());
1971 break LcheckAncestorsOfANestedRef;
1980 /***********************************************
1981 * Determine if function's variables are referenced by a function
1984 final bool hasNestedFrameRefs()
1986 if (closureVars.length)
1989 /* If a virtual function has contracts, assume its variables are referenced
1990 * by those contracts, even if they aren't. Because they might be referenced
1991 * by the overridden or overriding function's contracts.
1992 * This can happen because frequire and fensure are implemented as nested functions,
1993 * and they can be called directly by an overriding function and the overriding function's
1994 * context had better match, or
1995 * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
1997 if (fdrequire || fdensure)
2000 if (foverrides.length && isVirtualMethod())
2002 for (size_t i = 0; i < foverrides.length; i++)
2004 FuncDeclaration fdv = foverrides[i];
2005 if (fdv.hasNestedFrameRefs())
2012 /****************************************************
2013 * Check whether result variable can be built.
2015 * `true` if the function has a return type that
2016 * is different from `void`.
2018 extern (D) private bool canBuildResultVar()
2020 auto f = cast(TypeFunction)type;
2021 return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
2024 /****************************************************
2025 * Declare result variable lazily.
2027 extern (D) final void buildResultVar(Scope* sc, Type tret)
2031 Loc loc = fensure ? fensure.loc : this.loc;
2033 /* If inferRetType is true, tret may not be a correct return type yet.
2034 * So, in here it may be a temporary type for vresult, and after
2035 * fbody.dsymbolSemantic() running, vresult.type might be modified.
2037 vresult = new VarDeclaration(loc, tret, Id.result, null);
2038 vresult.storage_class |= STC.nodtor | STC.temp;
2040 vresult.storage_class |= STC.const_;
2041 vresult.storage_class |= STC.result;
2043 // set before the semantic() for checkNestedReference()
2044 vresult.parent = this;
2047 if (sc && vresult.semanticRun == PASS.initial)
2049 TypeFunction tf = type.toTypeFunction();
2051 vresult.storage_class |= STC.ref_;
2052 vresult.type = tret;
2054 vresult.dsymbolSemantic(sc);
2056 if (!sc.insert(vresult))
2057 .error(loc, "%s `%s` out result %s is already defined", kind, toPrettyChars, vresult.toChars());
2058 assert(vresult.parent == this);
2062 /****************************************************
2063 * Merge into this function the 'in' contracts of all it overrides.
2064 * 'in's are OR'd together, i.e. only one of them needs to pass.
2066 extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
2068 /* If a base function and its override both have an IN contract, then
2069 * only one of them needs to succeed. This is done by generating:
2071 * void derived.in() {
2076 * ... body of derived.in() ...
2080 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2081 * If base.in() throws, then derived.in()'s body is executed.
2084 foreach (fdv; foverrides)
2086 /* The semantic pass on the contracts of the overridden functions must
2087 * be completed before code generation occurs.
2088 * https://issues.dlang.org/show_bug.cgi?id=3602
2090 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2093 Scope* sc = fdv._scope.push();
2094 sc.stc &= ~STC.override_;
2099 sf = fdv.mergeFrequire(sf, params);
2100 if (!sf || !fdv.fdrequire)
2102 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2104 * try { __require(params); }
2105 * catch (Throwable) { frequire; }
2107 params = Expression.arraySyntaxCopy(params);
2108 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2109 Statement s2 = new ExpStatement(loc, e);
2111 auto c = new Catch(loc, getThrowable(), null, sf);
2112 c.internalCatch = true;
2113 auto catches = new Catches();
2115 sf = new TryCatchStatement(loc, s2, catches);
2120 /****************************************************
2121 * Merge into this function the 'in' contracts of all it overrides.
2123 extern (D) final Statement mergeFrequireInclusivePreview(Statement sf, Expressions* params)
2125 /* If a base function and its override both have an IN contract, then
2126 * the override in contract must widen the guarantee of the base contract.
2127 * This is checked by generating:
2129 * void derived.in() {
2131 * ... body of derived.in() ...
2134 * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
2136 * assert(false, "Logic error: " ~ thr.msg);
2141 foreach (fdv; foverrides)
2143 /* The semantic pass on the contracts of the overridden functions must
2144 * be completed before code generation occurs.
2145 * https://issues.dlang.org/show_bug.cgi?id=3602
2147 if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
2150 Scope* sc = fdv._scope.push();
2151 sc.stc &= ~STC.override_;
2156 sf = fdv.mergeFrequireInclusivePreview(sf, params);
2157 if (sf && fdv.fdrequire)
2159 const loc = this.fdrequire.loc;
2161 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2164 * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
2166 Identifier id = Identifier.generateId("thr");
2167 params = Expression.arraySyntaxCopy(params);
2168 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
2169 Statement s2 = new ExpStatement(loc, e);
2170 // assert(false, ...)
2171 // TODO make this a runtime helper to allow:
2172 // - chaining the original expression
2173 // - nogc concatenation
2174 Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
2175 Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
2177 Statement s3 = new CompoundStatement(loc, s2, fail);
2179 auto c = new Catch(loc, getThrowable(), id, s3);
2180 c.internalCatch = true;
2181 auto catches = new Catches();
2183 sf = new TryCatchStatement(loc, sf, catches);
2191 /****************************************************
2192 * Determine whether an 'out' contract is declared inside
2193 * the given function or any of its overrides.
2195 * fd = the function to search
2197 * true found an 'out' contract
2199 static bool needsFensure(FuncDeclaration fd) @safe
2204 foreach (fdv; fd.foverrides)
2206 if (needsFensure(fdv))
2212 /****************************************************
2213 * Rewrite contracts as statements.
2215 final void buildEnsureRequire()
2220 /* in { statements1... }
2221 * in { statements2... }
2224 * in { { statements1... } { statements2... } ... }
2226 assert(frequires.length);
2227 auto loc = (*frequires)[0].loc;
2228 auto s = new Statements;
2229 foreach (r; *frequires)
2231 s.push(new ScopeStatement(r.loc, r, r.loc));
2233 frequire = new CompoundStatement(loc, s);
2238 /* out(id1) { statements1... }
2239 * out(id2) { statements2... }
2242 * out(__result) { { ref id1 = __result; { statements1... } }
2243 * { ref id2 = __result; { statements2... } } ... }
2245 assert(fensures.length);
2246 auto loc = (*fensures)[0].ensure.loc;
2247 auto s = new Statements;
2248 foreach (r; *fensures)
2250 if (r.id && canBuildResultVar())
2252 auto rloc = r.ensure.loc;
2253 auto resultId = new IdentifierExp(rloc, Id.result);
2254 auto init = new ExpInitializer(rloc, resultId);
2255 auto stc = STC.ref_ | STC.temp | STC.result;
2256 auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
2257 auto sdecl = new ExpStatement(rloc, decl);
2258 s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
2265 fensure = new CompoundStatement(loc, s);
2271 /* Rewrite contracts as nested functions, then call them. Doing it as nested
2272 * functions means that overriding functions can call them.
2274 TypeFunction f = cast(TypeFunction) type;
2276 /* Make a copy of the parameters and make them all ref */
2277 static Parameters* toRefCopy(ParameterList parameterList)
2279 auto result = new Parameters();
2281 foreach (n, p; parameterList)
2285 p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
2286 p.defaultArg = null; // won't be the same with ref
2297 * void __require(ref params) { ... }
2298 * __require(params);
2300 Loc loc = frequire.loc;
2301 fdrequireParams = new Expressions();
2304 foreach (vd; *parameters)
2305 fdrequireParams.push(new VarExp(loc, vd));
2307 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2308 auto fparams = toRefCopy(fo.parameterList);
2309 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2310 tf.isnothrow = f.isnothrow;
2311 tf.isnogc = f.isnogc;
2312 tf.purity = f.purity;
2314 auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
2315 fd.fbody = frequire;
2316 Statement s1 = new ExpStatement(loc, fd);
2317 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
2318 Statement s2 = new ExpStatement(loc, e);
2319 frequire = new CompoundStatement(loc, s1, s2);
2323 /* We need to set fdensureParams here and not in the block below to
2324 * have the parameters available when calling a base class ensure(),
2325 * even if this function doesn't have an out contract.
2327 fdensureParams = new Expressions();
2328 if (canBuildResultVar())
2329 fdensureParams.push(new IdentifierExp(loc, Id.result));
2332 foreach (vd; *parameters)
2333 fdensureParams.push(new VarExp(loc, vd));
2338 /* out (result) { ... }
2340 * void __ensure(ref tret result, ref params) { ... }
2341 * __ensure(result, params);
2343 Loc loc = fensure.loc;
2344 auto fparams = new Parameters();
2345 if (canBuildResultVar())
2347 Parameter p = new Parameter(loc, STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
2350 auto fo = cast(TypeFunction)(originalType ? originalType : f);
2351 fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
2352 auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
2353 tf.isnothrow = f.isnothrow;
2354 tf.isnogc = f.isnogc;
2355 tf.purity = f.purity;
2357 auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
2359 Statement s1 = new ExpStatement(loc, fd);
2360 Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
2361 Statement s2 = new ExpStatement(loc, e);
2362 fensure = new CompoundStatement(loc, s1, s2);
2367 /****************************************************
2368 * Merge into this function the 'out' contracts of all it overrides.
2369 * 'out's are AND'd together, i.e. all of them need to pass.
2371 extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
2373 /* Same comments as for mergeFrequire(), except that we take care
2374 * of generating a consistent reference to the 'result' local by
2375 * explicitly passing 'result' to the nested function as a reference
2377 * This won't work for the 'this' parameter as it would require changing
2378 * the semantic code for the nested function so that it looks on the parameter
2379 * list for the 'this' pointer, something that would need an unknown amount
2380 * of tweaking of various parts of the compiler that I'd rather leave alone.
2382 foreach (fdv; foverrides)
2384 /* The semantic pass on the contracts of the overridden functions must
2385 * be completed before code generation occurs.
2386 * https://issues.dlang.org/show_bug.cgi?id=3602 and
2387 * https://issues.dlang.org/show_bug.cgi?id=5230
2389 if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
2392 Scope* sc = fdv._scope.push();
2393 sc.stc &= ~STC.override_;
2398 sf = fdv.mergeFensure(sf, oid, params);
2401 //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2402 // Make the call: __ensure(result, params)
2403 params = Expression.arraySyntaxCopy(params);
2404 if (canBuildResultVar())
2406 Type t1 = fdv.type.nextOf().toBasetype();
2407 Type t2 = this.type.nextOf().toBasetype();
2408 if (t1.isBaseOf(t2, null))
2410 /* Making temporary reference variable is necessary
2411 * in covariant return.
2412 * https://issues.dlang.org/show_bug.cgi?id=5204
2413 * https://issues.dlang.org/show_bug.cgi?id=10479
2415 Expression* eresult = &(*params)[0];
2416 auto ei = new ExpInitializer(Loc.initial, *eresult);
2417 auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
2418 v.storage_class |= STC.temp;
2419 auto de = new DeclarationExp(Loc.initial, v);
2420 auto ve = new VarExp(Loc.initial, v);
2421 *eresult = new CommaExp(Loc.initial, de, ve);
2424 Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
2425 Statement s2 = new ExpStatement(loc, e);
2429 sf = new CompoundStatement(sf.loc, s2, sf);
2438 /*********************************************
2439 * Returns: the function's parameter list, and whether
2440 * it is variadic or not.
2442 final ParameterList getParameterList()
2446 TypeFunction fdtype = type.isTypeFunction();
2447 if (fdtype) // Could also be TypeError
2448 return fdtype.parameterList;
2451 return ParameterList(null, VarArg.none);
2454 /**********************************
2455 * Generate a FuncDeclaration for a runtime library function.
2457 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
2459 return genCfunc(fparams, treturn, Identifier.idPool(name[0 .. strlen(name)]), stc);
2462 static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
2467 __gshared DsymbolTable st = null;
2469 //printf("genCfunc(name = '%s')\n", id.toChars());
2470 //printf("treturn\n\t"); treturn.print();
2472 // See if already in table
2474 st = new DsymbolTable();
2478 fd = s.isFuncDeclaration();
2480 assert(fd.type.nextOf().equals(treturn));
2484 tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc);
2485 fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf);
2486 fd.visibility = Visibility(Visibility.Kind.public_);
2487 fd._linkage = LINK.c;
2495 + Checks the parameter and return types iff this is a `main` function.
2497 + The following signatures are allowed for a `D main`:
2498 + - Either no or a single parameter of type `string[]`
2499 + - Return type is either `void`, `int` or `noreturn`
2501 + The following signatures are standard C:
2503 + - `int main(int, char**)`
2505 + This function accepts the following non-standard extensions:
2506 + - `char** envp` as a third parameter
2507 + - `void` / `noreturn` as return type
2509 + This function will issue errors for unexpected arguments / return types.
2511 extern (D) final void checkMain()
2513 if (ident != Id.main || isMember() || isNested())
2514 return; // Not a main function
2516 TypeFunction tf = type.toTypeFunction();
2518 Type retType = tf.nextOf();
2521 // auto main(), check after semantic
2522 assert(this.inferRetType);
2526 /// Checks whether `t` is equivalent to `char**`
2527 /// Ignores qualifiers and treats enums according to their base type
2528 static bool isCharPtrPtr(Type t)
2530 auto tp = t.toBasetype().isTypePointer();
2534 tp = tp.next.toBasetype().isTypePointer();
2538 return tp.next.toBasetype().ty == Tchar;
2541 // Neither of these qualifiers is allowed because they affect the ABI
2542 enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
2544 const nparams = tf.parameterList.length;
2547 const linkage = resolvedLinkage();
2548 if (linkage == LINK.d)
2552 auto fparam0 = tf.parameterList[0];
2553 auto t = fparam0.type.toBasetype();
2554 if (t.ty != Tarray ||
2555 t.nextOf().ty != Tarray ||
2556 t.nextOf().nextOf().ty != Tchar ||
2557 fparam0.storageClass & invalidSTC)
2563 if (tf.parameterList.varargs || nparams >= 2 || argerr)
2564 .error(loc, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", kind, toPrettyChars);
2567 else if (linkage == LINK.c)
2569 if (nparams == 2 || nparams == 3)
2571 // Argument count must be int
2572 auto argCount = tf.parameterList[0];
2573 argerr |= !!(argCount.storageClass & invalidSTC);
2574 argerr |= argCount.type.toBasetype().ty != Tint32;
2576 // Argument pointer must be char**
2577 auto argPtr = tf.parameterList[1];
2578 argerr |= !!(argPtr.storageClass & invalidSTC);
2579 argerr |= !isCharPtrPtr(argPtr.type);
2581 // `char** environ` is a common extension, see J.5.1 of the C standard
2584 auto envPtr = tf.parameterList[2];
2585 argerr |= !!(envPtr.storageClass & invalidSTC);
2586 argerr |= !isCharPtrPtr(envPtr.type);
2590 argerr = nparams != 0;
2592 // Disallow variadic main() - except for K&R declarations in C files.
2593 // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
2594 if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
2599 .error(loc, "%s `%s` parameters must match one of the following signatures", kind, toPrettyChars);
2600 loc.errorSupplemental("`main()`");
2601 loc.errorSupplemental("`main(int argc, char** argv)`");
2602 loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
2606 return; // Neither C nor D main, ignore (should probably be an error)
2608 // Allow enums with appropriate base types (same ABI)
2609 retType = retType.toBasetype();
2611 if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
2612 .error(loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", kind, toPrettyChars, tf.nextOf().toChars());
2615 /***********************************************
2616 * Check all return statements for a function to verify that returning
2617 * using NRVO is possible.
2620 * `false` if the result cannot be returned by hidden reference.
2622 extern (D) final bool checkNRVO()
2624 if (!isNRVO() || returns is null)
2627 auto tf = type.toTypeFunction();
2631 foreach (rs; *returns)
2633 if (auto ve = rs.exp.isVarExp())
2635 auto v = ve.var.isVarDeclaration();
2636 if (!v || v.isReference())
2638 else if (nrvo_var is null)
2640 // Variables in the data segment (e.g. globals, TLS or not),
2641 // parameters and closure variables cannot be NRVOed.
2642 if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
2644 if (v.nestedrefs.length && needsClosure())
2646 // don't know if the return storage is aligned
2649 if (alignSectionVars && (*alignSectionVars).contains(v))
2652 // The variable type needs to be equivalent to the return type.
2653 if (!v.type.equivalent(tf.next))
2655 //printf("Setting nrvo to %s\n", v.toChars());
2658 else if (nrvo_var != v)
2661 else //if (!exp.isLvalue()) // keep NRVO-ability
2667 override final inout(FuncDeclaration) isFuncDeclaration() inout
2672 inout(FuncDeclaration) toAliasFunc() inout
2677 override void accept(Visitor v)
2683 /********************************************************
2684 * Generate Expression to call the invariant.
2686 * ad aggregate with the invariant
2687 * vthis variable with 'this'
2689 * void expression that calls the invariant
2691 Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
2693 Expression e = null;
2694 // Call invariant directly only if it exists
2695 FuncDeclaration inv = ad.inv;
2696 ClassDeclaration cd = ad.isClassDeclaration();
2709 // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
2710 // For the correct mangling,
2711 // run attribute inference on inv if needed.
2712 functionSemantic(inv);
2715 //e = new DsymbolExp(Loc.initial, inv);
2716 //e = new CallExp(Loc.initial, e);
2717 //e = e.semantic(sc2);
2719 /* https://issues.dlang.org/show_bug.cgi?id=13113
2720 * Currently virtual invariant calls completely
2721 * bypass attribute enforcement.
2722 * Change the behavior of pre-invariant call by following it.
2724 e = new ThisExp(Loc.initial);
2725 e.type = ad.type.addMod(vthis.type.mod);
2726 e = new DotVarExp(Loc.initial, e, inv, false);
2728 e = new CallExp(Loc.initial, e);
2729 e.type = Type.tvoid;
2734 /***************************************************
2735 * Visit each overloaded function/template in turn, and call dg(s) on it.
2736 * Exit when no more, or dg(s) returns nonzero.
2739 * fstart = symbol to start from
2740 * dg = the delegate to be called on the overload
2741 * sc = context used to check if symbol is accessible (and therefore visible),
2746 * !=0 done (and the return value from the last dg() call)
2748 extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
2752 int overloadApplyRecurse(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc)
2754 // Detect cyclic calls.
2755 if (visited.contains(fstart))
2757 visited.push(fstart);
2760 for (auto d = fstart; d; d = next)
2762 import dmd.access : checkSymbolAccess;
2763 if (auto od = d.isOverDeclaration())
2765 /* The scope is needed here to check whether a function in
2766 an overload set was added by means of a private alias (or a
2767 selective import). If the scope where the alias is created
2768 is imported somewhere, the overload set is visible, but the private
2773 if (checkSymbolAccess(sc, od))
2775 if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
2779 else if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
2783 else if (auto fa = d.isFuncAliasDeclaration())
2785 if (fa.hasOverloads)
2787 if (int r = overloadApplyRecurse(fa.funcalias, dg, sc))
2790 else if (auto fd = fa.toAliasFunc())
2797 .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
2802 else if (auto ad = d.isAliasDeclaration())
2806 if (checkSymbolAccess(sc, ad))
2807 next = ad.toAlias();
2810 next = ad.toAlias();
2816 else if (auto td = d.isTemplateDeclaration())
2822 else if (auto fd = d.isFuncDeclaration())
2828 else if (auto os = d.isOverloadSet())
2836 .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
2838 // BUG: should print error message?
2843 return overloadApplyRecurse(fstart, dg, sc);
2847 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
2848 mismatching modifiers to `buf`.
2850 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
2851 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
2854 buf = output buffer to write to
2855 lhsMod = modifier on the left-hand side
2856 lhsMod = modifier on the right-hand side
2860 A tuple with `isMutable` and `isNotShared` set
2861 if the `lhsMod` is missing those modifiers (compared to rhs).
2863 auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod)
2865 static struct Mismatches
2871 Mismatches mismatches;
2873 bool bothMutable = ((lhsMod & rhsMod) == 0);
2874 bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0;
2875 bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_);
2877 if (lhsMod & MODFlags.shared_)
2878 buf.writestring("`shared` ");
2879 else if (sharedMismatch && !(lhsMod & MODFlags.immutable_))
2881 buf.writestring("non-shared ");
2882 mismatches.isNotShared = true;
2885 if (bothMutable && sharedMismatchOnly)
2888 else if (lhsMod & MODFlags.immutable_)
2889 buf.writestring("`immutable` ");
2890 else if (lhsMod & MODFlags.const_)
2891 buf.writestring("`const` ");
2892 else if (lhsMod & MODFlags.wild)
2893 buf.writestring("`inout` ");
2896 buf.writestring("mutable ");
2897 mismatches.isMutable = true;
2907 auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0);
2908 assert(buf[] == "`shared` ");
2909 assert(!mismatches.isNotShared);
2912 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_);
2913 assert(buf[] == "non-shared ");
2914 assert(mismatches.isNotShared);
2917 mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0);
2918 assert(buf[] == "`const` ");
2919 assert(!mismatches.isMutable);
2922 mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_);
2923 assert(buf[] == "mutable ");
2924 assert(mismatches.isMutable);
2927 /**************************************
2928 * Returns an indirect type one step from t.
2930 Type getIndirection(Type t)
2933 if (t.ty == Tarray || t.ty == Tpointer)
2934 return t.nextOf().toBasetype();
2935 if (t.ty == Taarray || t.ty == Tclass)
2937 if (t.ty == Tstruct)
2938 return t.hasPointers() ? t : null; // TODO
2940 // should consider TypeDelegate?
2944 /**************************************
2945 * Performs type-based alias analysis between a newly created value and a pre-
2946 * existing memory reference:
2948 * Assuming that a reference A to a value of type `ta` was available to the code
2949 * that created a reference B to a value of type `tb`, it returns whether B
2950 * might alias memory reachable from A based on the types involved (either
2951 * directly or via any number of indirections in either A or B).
2953 * This relation is not symmetric in the two arguments. For example, a
2954 * a `const(int)` reference can point to a pre-existing `int`, but not the other
2960 * `const(int)`, `int`, `false`
2961 * `int`, `const(int)`, `true`
2962 * `int`, `immutable(int)`, `false`
2963 * const(immutable(int)*), immutable(int)*, false // BUG: returns true
2966 * ta = value type being referred to
2967 * tb = referred to value type that could be constructed from ta
2970 * true if reference to `tb` is isolated from reference to `ta`
2972 private bool traverseIndirections(Type ta, Type tb)
2974 //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
2976 static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
2978 //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
2979 ta = ta.baseElemOf();
2980 tb = tb.baseElemOf();
2982 // First, check if the pointed-to types are convertible to each other such
2983 // that they might alias directly.
2984 static bool mayAliasDirect(Type source, Type target)
2987 // if source is the same as target or can be const-converted to target
2988 source.constConv(target) != MATCH.nomatch ||
2989 // if target is void and source can be const-converted to target
2990 (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
2993 if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
2995 //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
2998 if (ta.nextOf() && ta.nextOf() == tb.nextOf())
3000 //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3004 if (tb.ty == Tclass || tb.ty == Tstruct)
3006 /* Traverse the type of each field of the aggregate
3008 bool* found = table.getLvalue(tb.deco);
3010 return true; // We have already seen this symbol, break the cycle
3014 AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
3015 foreach (v; sym.fields)
3017 Type tprmi = v.type.addMod(tb.mod);
3018 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
3019 if (!traverse(ta, tprmi, table, reversePass))
3023 else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
3025 Type tind = tb.nextOf();
3026 if (!traverse(ta, tind, table, reversePass))
3029 else if (tb.hasPointers())
3031 // BUG: consider the context pointer of delegate types
3035 // Still no match, so try breaking up ta if we have not done so yet.
3038 scope newTable = AssocArray!(const(char)*, bool)();
3039 return traverse(tb, ta, newTable, true);
3045 // To handle arbitrary levels of indirections in both parameters, we
3046 // recursively descend into aggregate members/levels of indirection in both
3047 // `ta` and `tb` while avoiding cycles. Start with the original types.
3048 scope table = AssocArray!(const(char)*, bool)();
3049 const result = traverse(ta, tb, table, false);
3050 //printf(" returns %d\n", result);
3054 /* For all functions between outerFunc and f, mark them as needing
3057 private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc)
3059 for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc))
3061 FuncDeclaration fy = sx.isFuncDeclaration();
3062 if (fy && fy.closureVars.length)
3064 /* fy needs a closure if it has closureVars[],
3065 * because the frame pointer in the closure will be accessed.
3067 fy.requiresClosure = true;
3073 * Given a nested function f inside a function outerFunc, check
3074 * if any sibling callers of f have escaped. If so, mark
3075 * all the enclosing functions as needing closures.
3076 * This is recursive: we need to check the callers of our siblings.
3077 * Note that nested functions can only call lexically earlier nested
3078 * functions, so loops are impossible.
3080 * f = inner function (nested within outerFunc)
3081 * outerFunc = outer function
3082 * p = for internal recursion use
3084 * true if any closures were needed
3086 private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
3088 static struct PrevSibling
3094 if (f.computedEscapingSiblings)
3095 return f.hasEscapingSiblings;
3098 ps.p = cast(PrevSibling*)p;
3101 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
3102 bool bAnyClosures = false;
3103 for (size_t i = 0; i < f.siblingCallers.length; ++i)
3105 FuncDeclaration g = f.siblingCallers[i];
3106 if (g.isThis() || g.tookAddressOf)
3108 markAsNeedingClosure(g, outerFunc);
3109 bAnyClosures = true;
3112 for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc))
3114 // A parent of the sibling had its address taken.
3115 // Assume escaping of parent affects its children, so needs propagating.
3116 // see https://issues.dlang.org/show_bug.cgi?id=19679
3117 FuncDeclaration parentFunc = parent.isFuncDeclaration;
3118 if (parentFunc && parentFunc.tookAddressOf)
3120 markAsNeedingClosure(parentFunc, outerFunc);
3121 bAnyClosures = true;
3125 PrevSibling* prev = cast(PrevSibling*)p;
3130 bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
3138 f.hasEscapingSiblings = bAnyClosures;
3139 f.computedEscapingSiblings = true;
3140 //printf("\t%d\n", bAnyClosures);
3141 return bAnyClosures;
3144 /***********************************************************
3145 * Used as a way to import a set of functions from another scope into this one.
3147 extern (C++) final class FuncAliasDeclaration : FuncDeclaration
3149 FuncDeclaration funcalias;
3152 extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true)
3154 super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type);
3155 assert(funcalias != this);
3156 this.funcalias = funcalias;
3158 this.hasOverloads = hasOverloads;
3161 if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration())
3162 this.hasOverloads = fad.hasOverloads;
3167 assert(!funcalias.isFuncAliasDeclaration());
3168 this.hasOverloads = false;
3170 userAttribDecl = funcalias.userAttribDecl;
3173 override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
3178 override const(char)* kind() const
3180 return "function alias";
3183 override inout(FuncDeclaration) toAliasFunc() inout
3185 return funcalias.toAliasFunc();
3188 override void accept(Visitor v)
3194 /***********************************************************
3196 extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
3198 TOK tok; // TOK.function_ or TOK.delegate_
3199 Type treq; // target of return type inference
3204 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_)
3206 super(loc, endloc, null, storage_class, type);
3207 this.ident = id ? id : Id.empty;
3210 // Always infer scope for function literals
3211 // See https://issues.dlang.org/show_bug.cgi?id=20362
3212 this.inferScope = true;
3213 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
3216 override FuncLiteralDeclaration syntaxCopy(Dsymbol s)
3218 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
3220 auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident, storage_class & STC.auto_);
3221 f.treq = treq; // don't need to copy
3222 FuncDeclaration.syntaxCopy(f);
3226 override bool isNested() const
3228 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
3229 return (tok != TOK.function_) && !isThis();
3232 override inout(AggregateDeclaration) isThis() inout
3234 return tok == TOK.delegate_ ? super.isThis() : null;
3237 override bool isVirtual() const
3242 override bool addPreInvariant()
3247 override bool addPostInvariant()
3252 /*******************************
3253 * Modify all expression type of return statements to tret.
3255 * On function literals, return type may be modified based on the context type
3256 * after its semantic3 is done, in FuncExp::implicitCastTo.
3258 * A function() dg = (){ return new B(); } // OK if is(B : A) == true
3260 * If B to A conversion is convariant that requires offseet adjusting,
3261 * all return statements should be adjusted to return expressions typed A.
3263 extern (D) void modifyReturns(Scope* sc, Type tret)
3265 import dmd.statement_rewrite_walker;
3267 extern (C++) final class RetWalker : StatementRewriteWalker
3269 alias visit = typeof(super).visit;
3273 FuncLiteralDeclaration fld;
3275 override void visit(ReturnStatement s)
3277 Expression exp = s.exp;
3278 if (exp && !exp.type.equals(tret))
3279 s.exp = exp.implicitCastTo(sc, tret);
3283 if (semanticRun < PASS.semantic3done)
3289 scope RetWalker w = new RetWalker();
3295 // Also update the inferred function type to match the new return type.
3296 // This is required so the code generator does not try to cast the
3297 // modified returns back to the original type.
3298 if (inferRetType && type.nextOf() != tret)
3299 type.toTypeFunction().next = tret;
3302 override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
3307 override const(char)* kind() const
3309 // GCC requires the (char*) casts
3310 return (tok != TOK.function_) ? "delegate" : "function";
3313 override const(char)* toPrettyChars(bool QualifyTypes = false)
3317 TemplateInstance ti = parent.isTemplateInstance();
3319 return ti.tempdecl.toPrettyChars(QualifyTypes);
3321 return Dsymbol.toPrettyChars(QualifyTypes);
3324 override void accept(Visitor v)
3330 /***********************************************************
3332 extern (C++) final class CtorDeclaration : FuncDeclaration
3335 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
3337 super(loc, endloc, Id.ctor, stc, type);
3338 this.isCpCtor = isCpCtor;
3339 //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
3342 override CtorDeclaration syntaxCopy(Dsymbol s)
3345 auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy());
3346 FuncDeclaration.syntaxCopy(f);
3350 override const(char)* kind() const
3352 return isCpCtor ? "copy constructor" : "constructor";
3355 override const(char)* toChars() const
3360 override bool isVirtual() const
3365 override bool addPreInvariant()
3370 override bool addPostInvariant()
3372 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3375 override inout(CtorDeclaration) isCtorDeclaration() inout
3380 override void accept(Visitor v)
3386 /***********************************************************
3388 extern (C++) final class PostBlitDeclaration : FuncDeclaration
3390 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
3392 super(loc, endloc, id, stc, null);
3395 override PostBlitDeclaration syntaxCopy(Dsymbol s)
3398 auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
3399 FuncDeclaration.syntaxCopy(dd);
3403 override bool isVirtual() const
3408 override bool addPreInvariant()
3413 override bool addPostInvariant()
3415 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3418 override bool overloadInsert(Dsymbol s)
3420 return false; // cannot overload postblits
3423 override inout(PostBlitDeclaration) isPostBlitDeclaration() inout
3428 override void accept(Visitor v)
3434 /***********************************************************
3436 extern (C++) final class DtorDeclaration : FuncDeclaration
3438 extern (D) this(const ref Loc loc, const ref Loc endloc)
3440 super(loc, endloc, Id.dtor, STC.undefined_, null);
3443 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
3445 super(loc, endloc, id, stc, null);
3448 override DtorDeclaration syntaxCopy(Dsymbol s)
3451 auto dd = new DtorDeclaration(loc, endloc, storage_class, ident);
3452 FuncDeclaration.syntaxCopy(dd);
3456 override const(char)* kind() const
3458 return "destructor";
3461 override const(char)* toChars() const
3466 override bool isVirtual() const
3468 // D dtor's don't get put into the vtbl[]
3469 // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
3470 return vtblIndex != -1;
3473 override bool addPreInvariant()
3475 return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
3478 override bool addPostInvariant()
3483 override bool overloadInsert(Dsymbol s)
3485 return false; // cannot overload destructors
3488 override inout(DtorDeclaration) isDtorDeclaration() inout
3493 override void accept(Visitor v)
3499 /***********************************************************
3501 extern (C++) class StaticCtorDeclaration : FuncDeclaration
3503 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3505 super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null);
3508 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
3510 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
3513 override StaticCtorDeclaration syntaxCopy(Dsymbol s)
3516 auto scd = new StaticCtorDeclaration(loc, endloc, storage_class);
3517 FuncDeclaration.syntaxCopy(scd);
3521 override final inout(AggregateDeclaration) isThis() inout @nogc nothrow pure @safe
3526 override final bool isVirtual() const @nogc nothrow pure @safe
3531 override final bool addPreInvariant() @nogc nothrow pure @safe
3536 override final bool addPostInvariant() @nogc nothrow pure @safe
3541 override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
3546 override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
3551 override void accept(Visitor v)
3557 /***********************************************************
3559 extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
3561 /// Exclude this constructor from cyclic dependency check
3564 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3566 super(loc, endloc, "_sharedStaticCtor", stc);
3569 override SharedStaticCtorDeclaration syntaxCopy(Dsymbol s)
3572 auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
3573 FuncDeclaration.syntaxCopy(scd);
3577 override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
3582 override void accept(Visitor v)
3588 /***********************************************************
3590 extern (C++) class StaticDtorDeclaration : FuncDeclaration
3592 VarDeclaration vgate; // 'gate' variable
3594 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3596 super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null);
3599 extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
3601 super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
3604 override StaticDtorDeclaration syntaxCopy(Dsymbol s)
3607 auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
3608 FuncDeclaration.syntaxCopy(sdd);
3612 override final inout(AggregateDeclaration) isThis() inout
3617 override final bool isVirtual() const
3622 override final bool hasStaticCtorOrDtor()
3627 override final bool addPreInvariant()
3632 override final bool addPostInvariant()
3637 override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
3642 override void accept(Visitor v)
3648 /***********************************************************
3650 extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
3652 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
3654 super(loc, endloc, "_sharedStaticDtor", stc);
3657 override SharedStaticDtorDeclaration syntaxCopy(Dsymbol s)
3660 auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
3661 FuncDeclaration.syntaxCopy(sdd);
3665 override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
3670 override void accept(Visitor v)
3676 /***********************************************************
3678 extern (C++) final class InvariantDeclaration : FuncDeclaration
3680 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
3682 // Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list.
3683 super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
3687 override InvariantDeclaration syntaxCopy(Dsymbol s)
3690 auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null);
3691 FuncDeclaration.syntaxCopy(id);
3695 override bool isVirtual() const
3700 override bool addPreInvariant()
3705 override bool addPostInvariant()
3710 override inout(InvariantDeclaration) isInvariantDeclaration() inout
3715 override void accept(Visitor v)
3720 extern (D) void fixupInvariantIdent(size_t offset)
3723 idBuf.writestring("__invariant");
3724 idBuf.print(offset);
3726 ident = Identifier.idPool(idBuf[]);
3731 /***********************************************************
3733 extern (C++) final class UnitTestDeclaration : FuncDeclaration
3735 char* codedoc; // for documented unittest
3737 // toObjFile() these nested functions after this one
3738 FuncDeclarations deferredNested;
3740 extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
3742 super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null);
3743 this.codedoc = codedoc;
3746 override UnitTestDeclaration syntaxCopy(Dsymbol s)
3749 auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
3750 FuncDeclaration.syntaxCopy(utd);
3754 override inout(AggregateDeclaration) isThis() inout
3759 override bool isVirtual() const
3764 override bool addPreInvariant()
3769 override bool addPostInvariant()
3774 override inout(UnitTestDeclaration) isUnitTestDeclaration() inout
3779 override void accept(Visitor v)
3785 /***********************************************************
3787 extern (C++) final class NewDeclaration : FuncDeclaration
3789 extern (D) this(const ref Loc loc, StorageClass stc)
3791 super(loc, Loc.initial, Id.classNew, STC.static_ | stc, null);
3794 override NewDeclaration syntaxCopy(Dsymbol s)
3797 auto f = new NewDeclaration(loc, storage_class);
3798 FuncDeclaration.syntaxCopy(f);
3802 override const(char)* kind() const
3807 override bool isVirtual() const
3812 override bool addPreInvariant()
3817 override bool addPostInvariant()
3822 override inout(NewDeclaration) isNewDeclaration() inout
3827 override void accept(Visitor v)
3833 /**************************************
3834 * When a traits(compiles) is used on a function literal call
3835 * we need to take into account if the body of the function
3836 * violates any attributes, however, we must not affect the
3837 * attribute inference on the outer function. The attributes
3838 * of the function literal still need to be inferred, therefore
3839 * we need a way to check for the scope that the traits compiles
3843 * sc = scope to be checked for
3845 * Returns: `true` if the provided scope is the root
3846 * of the traits compiles list of scopes.
3848 bool isRootTraitsCompilesScope(Scope* sc)
3850 return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
3853 /**************************************
3854 * A statement / expression in this scope is not `@safe`,
3855 * so mark the enclosing function as `@system`
3858 * sc = scope that the unsafe statement / expression is in
3859 * gag = surpress error message (used in escape.d)
3860 * loc = location of error
3861 * fmt = printf-style format string
3862 * arg0 = (optional) argument for first %s format specifier
3863 * arg1 = (optional) argument for second %s format specifier
3864 * arg2 = (optional) argument for third %s format specifier
3865 * Returns: whether there's a safe error
3867 bool setUnsafe(Scope* sc,
3868 bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
3869 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
3872 return false; // typeof(cast(int*)0) is safe
3874 if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
3881 if (sc.varDecl.storage_class & STC.safe)
3883 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
3886 else if (!(sc.varDecl.storage_class & STC.trusted))
3888 sc.varDecl.storage_class |= STC.system;
3889 sc.varDecl.systemInferred = true;
3896 if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
3898 if (sc.func.isSafeBypassingInference())
3900 // Message wil be gagged, but still call error() to update global.errors and for
3902 .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
3908 return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
3911 /***************************************
3912 * Like `setUnsafe`, but for safety errors still behind preview switches
3914 * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
3915 * the behavior changes based on the setting:
3917 * - In case of `-revert=fs`, it does nothing.
3918 * - In case of `-preview=fs`, it's the same as `setUnsafe`
3919 * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
3922 * sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
3923 * fs = feature state from the preview flag
3924 * gag = surpress error message
3925 * loc = location of error
3926 * msg = printf-style format string
3927 * arg0 = (optional) argument for first %s format specifier
3928 * arg1 = (optional) argument for second %s format specifier
3929 * arg2 = (optional) argument for third %s format specifier
3930 * Returns: whether an actual safe error (not deprecation) occured
3932 bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
3933 RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
3935 //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
3936 with (FeatureState) final switch (fs)
3942 return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
3947 if (sc.func.isSafeBypassingInference())
3949 if (!gag && !sc.isDeprecated())
3951 deprecation(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
3954 else if (!sc.func.safetyViolation)
3956 import dmd.func : AttributeViolation;
3957 sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
3963 /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
3966 /// - a regular safety error, stored in (fmtStr, arg0, arg1)
3967 /// - a call to a function without the attribute, which is a special case, because in that case,
3968 /// that function might recursively also have a `AttributeViolation`. This way, in case
3969 /// of a big call stack, the error can go down all the way to the root cause.
3970 /// The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`.
3971 struct AttributeViolation
3973 /// location of error
3975 /// printf-style format string
3976 const(char)* fmtStr = null;
3977 /// Arguments for up to two `%s` format specifiers in format string
3978 RootObject arg0 = null;
3980 RootObject arg1 = null;
3982 RootObject arg2 = null;
3985 /// Print the reason why `fd` was inferred `@system` as a supplemental error
3987 /// fd = function to check
3988 /// maxDepth = up to how many functions deep to report errors
3989 /// deprecation = print deprecations instead of errors
3990 /// stc = storage class of attribute to check
3991 void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc)
3993 auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
3995 AttributeViolation* s;
3999 s = fd.safetyViolation;
4002 else if (stc & STC.pure_)
4004 s = fd.pureViolation;
4007 else if (stc & STC.nothrow_)
4009 s = fd.nothrowViolation;
4012 else if (stc & STC.nogc)
4014 s = fd.nogcViolation;
4022 errorFunc(s.loc, deprecation ?
4023 "which wouldn't be `%s` because of:" :
4024 "which wasn't inferred `%s` because of:", attr);
4025 if (stc == STC.nogc || stc == STC.pure_)
4027 auto f = (cast(Dsymbol) s.arg0).isFuncDeclaration();
4028 errorFunc(s.loc, s.fmtStr, f.kind(), f.toPrettyChars(), s.arg1 ? s.arg1.toChars() : "");
4032 errorFunc(s.loc, s.fmtStr,
4033 s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
4036 else if (auto sa = s.arg0.isDsymbol())
4038 if (FuncDeclaration fd2 = sa.isFuncDeclaration())
4042 errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
4043 errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc);