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
;
65 else version (IN_LLVM
) {}
71 uninitialized
, /// not computed yet
78 unknown
= 255, /// not known if this is a builtin
79 unimp
= 0, /// this is not a builtin
80 gcc
, /// this is a GCC builtin
81 llvm
, /// this is an LLVM builtin
117 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
119 extern (C
++) final class NrvoWalker
: StatementRewriteWalker
121 alias visit
= typeof(super).visit
;
126 override void visit(ReturnStatement s
)
128 // See if all returns are instead to be replaced with a goto returnLabel;
134 * vresult = exp; goto Lresult;
136 auto gs
= new GotoStatement(s
.loc
, Id
.returnLabel
);
137 gs
.label
= fd
.returnLabel
;
141 s1
= new CompoundStatement(s
.loc
, new ExpStatement(s
.loc
, s
.exp
), gs
);
147 override void visit(TryFinallyStatement s
)
149 DtorExpStatement des
;
150 if (fd
.isNRVO() && s
.finalbody
&& (des
= s
.finalbody
.isDtorExpStatement()) !is null &&
151 fd
.nrvo_var
== des
.var
)
153 if (!(global
.params
.useExceptions
&& ClassDeclaration
.throwable
))
155 /* Don't need to call destructor at all, since it is nrvo
157 replaceCurrent(s
._body
);
158 s
._body
.accept(this);
162 /* Normally local variable dtors are called regardless exceptions.
163 * But for nrvo_var, its dtor should be called only when exception is thrown.
166 * try { s.body; } finally { nrvo_var.edtor; }
167 * // equivalent with:
168 * // s.body; scope(exit) nrvo_var.edtor;
170 * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
171 * // equivalent with:
172 * // s.body; scope(failure) nrvo_var.edtor;
174 Statement sexception
= new DtorExpStatement(Loc
.initial
, fd
.nrvo_var
.edtor
, fd
.nrvo_var
);
175 Identifier id
= Identifier
.generateId("__o");
177 Statement handler
= new PeelStatement(sexception
);
178 if (sexception
.blockExit(fd
, null) & BE
.fallthru
)
180 auto ts
= new ThrowStatement(Loc
.initial
, new IdentifierExp(Loc
.initial
, id
));
181 ts
.internalThrow
= true;
182 handler
= new CompoundStatement(Loc
.initial
, handler
, ts
);
185 auto catches
= new Catches();
186 auto ctch
= new Catch(Loc
.initial
, getThrowable(), id
, handler
);
187 ctch
.internalCatch
= true;
188 ctch
.catchSemantic(sc
); // Run semantic to resolve identifier '__o'
191 Statement s2
= new TryCatchStatement(Loc
.initial
, s
._body
, catches
);
197 StatementRewriteWalker
.visit(s
);
201 private struct FUNCFLAG
203 bool purityInprocess
; /// working on determining purity
204 bool safetyInprocess
; /// working on determining safety
205 bool nothrowInprocess
; /// working on determining nothrow
206 bool nogcInprocess
; /// working on determining @nogc
207 bool returnInprocess
; /// working on inferring 'return' for parameters
208 bool inlineScanned
; /// function has been scanned for inline possibilities
209 bool inferScope
; /// infer 'scope' for parameters
210 bool hasCatches
; /// function has try-catch statements
211 bool skipCodegen
; /// do not generate code for this function.
212 bool printf
; /// is a printf-like function
214 bool scanf
; /// is a scanf-like function
215 bool noreturn
; /// the function does not return
216 bool isNRVO
= true; /// Support for named return value optimization
217 bool isNaked
; /// The function is 'naked' (see inline ASM)
218 bool isGenerated
; /// The function is compiler generated (e.g. `opCmp`)
219 bool isIntroducing
; /// If this function introduces the overload set
220 bool hasSemantic3Errors
; /// If errors in semantic3 this function's frame ptr
221 bool hasNoEH
; /// No exception unwinding is needed
222 bool inferRetType
; /// Return type is to be inferred
223 bool hasDualContext
; /// has a dual-context 'this' parameter
225 bool hasAlwaysInlines
; /// Contains references to functions that must be inlined
226 bool isCrtCtor
; /// Has attribute pragma(crt_constructor)
227 bool isCrtDtor
; /// Has attribute pragma(crt_destructor)
228 bool hasEscapingSiblings
;/// Has sibling functions that escape
229 bool computedEscapingSiblings
; /// `hasEscapingSiblings` has been computed
230 bool dllImport
; /// __declspec(dllimport)
231 bool dllExport
; /// __declspec(dllexport)
234 /***********************************************************
235 * Tuple of result identifier (possibly null) and statement.
236 * This is used to store out contracts: out(id){ ensure }
238 extern (C
++) struct Ensure
245 return Ensure(id
, ensure
.syntaxCopy());
248 /*****************************************
249 * Do syntax copy of an array of Ensure's.
251 static Ensures
* arraySyntaxCopy(Ensures
* a
)
259 (*b
)[i
] = e
.syntaxCopy();
267 /***********************************************************
268 * Most functions don't have contracts, so save memory by grouping
269 * this information into a separate struct
271 private struct ContractInfo
273 Statements
* frequires
; /// in contracts
274 Ensures
* fensures
; /// out contracts
275 Statement frequire
; /// lowered in contract
276 Statement fensure
; /// lowered out contract
277 FuncDeclaration fdrequire
; /// function that does the in contract
278 FuncDeclaration fdensure
; /// function that does the out contract
279 Expressions
* fdrequireParams
; /// argument list for __require
280 Expressions
* fdensureParams
; /// argument list for __ensure
283 /***********************************************************
285 extern (C
++) class FuncDeclaration
: Declaration
287 Statement fbody
; /// function body
289 FuncDeclarations foverrides
; /// functions this function overrides
291 private ContractInfo
* contracts
; /// contract information
293 const(char)* mangleString
; /// mangled symbol created from mangleExact()
295 VarDeclaration vresult
; /// result variable for out contracts
296 LabelDsymbol returnLabel
; /// where the return goes
298 bool[size_t
] isTypeIsolatedCache
; /// cache for the potentially very expensive isTypeIsolated check
300 // used to prevent symbols in different
301 // scopes from having the same name
302 DsymbolTable localsymtab
;
303 VarDeclaration vthis
; /// 'this' parameter (member and nested)
304 VarDeclaration v_arguments
; /// '_arguments' parameter
306 VarDeclaration v_argptr
; /// '_argptr' variable
307 VarDeclarations
* parameters
; /// Array of VarDeclaration's for parameters
308 DsymbolTable labtab
; /// statement label symbol table
309 Dsymbol overnext
; /// next in overload list
310 FuncDeclaration overnext0
; /// next in overload list (only used during IFTI)
311 Loc endloc
; /// location of closing curly bracket
312 int vtblIndex
= -1; /// for member functions, index into vtbl[]
314 ILS inlineStatusStmt
= ILS
.uninitialized
;
315 ILS inlineStatusExp
= ILS
.uninitialized
;
316 PINLINE inlining
= PINLINE
.default_
;
318 int inlineNest
; /// !=0 if nested inline
320 ForeachStatement fes
; /// if foreach body, this is the foreach
321 BaseClass
* interfaceVirtual
; /// if virtual, but only appears in base interface vtbl[]
322 /** if !=NULL, then this is the type
323 of the 'introducing' function
324 this one is overriding
328 StorageClass storage_class2
; /// storage class for template onemember's
330 // Things that should really go into Scope
332 /// 1 if there's a return exp; statement
333 /// 2 if there's a throw statement
334 /// 4 if there's an assert(0)
335 /// 8 if there's inline asm
336 /// 16 if there are multiple return statements
339 VarDeclaration nrvo_var
; /// variable to replace with shidden
340 Symbol
* shidden
; /// hidden pointer passed to function
342 ReturnStatements
* returns
;
344 GotoStatements
* gotos
; /// Gotos with forward references
348 VarDeclarations
* alignSectionVars
; /// local variables with alignment needs larger than stackAlign
349 Symbol
* salignSection
; /// pointer to aligned section, if any
352 /// set if this is a known, builtin function we can evaluate at compile time
353 BUILTIN builtin
= BUILTIN
.unknown
;
355 /// set if someone took the address of this function
358 bool requiresClosure
; // this function needs a closure
360 /** local variables in this function which are referenced by nested functions
361 * (They'll get put into the "closure" for this function.)
363 VarDeclarations closureVars
;
365 /** Outer variables which are referenced by this nested function
366 * (the inverse of closureVars)
368 VarDeclarations outerVars
;
370 /// Sibling nested functions which called this one
371 FuncDeclarations siblingCallers
;
373 FuncDeclarations
*inlinedNestedCallees
;
375 /// In case of failed `@safe` inference, store the error that made the function `@system` for
376 /// better diagnostics
377 AttributeViolation
* safetyViolation
;
378 AttributeViolation
* nogcViolation
;
379 AttributeViolation
* pureViolation
;
380 AttributeViolation
* nothrowViolation
;
382 /// See the `FUNCFLAG` struct
383 import dmd
.common
.bitfields
;
384 mixin(generateBitFields
!(FUNCFLAG
, uint));
387 * Data for a function declaration that is needed for the Objective-C
390 ObjcFuncDeclaration objc
;
392 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, Identifier ident
, StorageClass storage_class
, Type type
, bool noreturn
= false)
395 //.printf("FuncDeclaration(id = '%s', type = %s)\n", ident.toChars(), type.toChars());
396 //.printf("storage_class = x%llx\n", storage_class);
397 this.storage_class
= storage_class
;
401 // Normalize storage_class, because function-type related attributes
402 // are already set in the 'type' in parsing phase.
403 this.storage_class
&= ~(STC
.TYPECTOR | STC
.FUNCATTR
);
405 this.endloc
= endloc
;
407 this.noreturn
= true;
409 /* The type given for "infer the return type" is a TypeFunction with
410 * NULL for the return type.
412 if (type
&& type
.nextOf() is null)
413 this.inferRetType
= true;
416 static FuncDeclaration
create(const ref Loc loc
, const ref Loc endloc
, Identifier id
, StorageClass storage_class
, Type type
, bool noreturn
= false)
418 return new FuncDeclaration(loc
, endloc
, id
, storage_class
, type
, noreturn
);
421 final nothrow pure @safe
423 private ref ContractInfo
getContracts()
426 contracts
= new ContractInfo();
431 inout(Statements
*) frequires() inout { return contracts ? contracts
.frequires
: null; }
432 inout(Ensures
*) fensures() inout { return contracts ? contracts
.fensures
: null; }
433 inout(Statement
) frequire() inout { return contracts ? contracts
.frequire
: null; }
434 inout(Statement
) fensure() inout { return contracts ? contracts
.fensure
: null; }
435 inout(FuncDeclaration
) fdrequire() inout { return contracts ? contracts
.fdrequire
: null; }
436 inout(FuncDeclaration
) fdensure() inout { return contracts ? contracts
.fdensure
: null; }
437 inout(Expressions
*) fdrequireParams() inout { return contracts ? contracts
.fdrequireParams
: null; }
438 inout(Expressions
*) fdensureParams() inout { return contracts ? contracts
.fdensureParams
: null; }
440 extern (D
) private static string
generateContractSetter(string field
, string type
)
442 return type
~ " " ~ field
~ "(" ~ type
~ " param)" ~
444 if (!param && !contracts) return null;
445 return getContracts()." ~ field
~ " = param;
449 mixin(generateContractSetter("frequires", "Statements*"));
450 mixin(generateContractSetter("fensures", "Ensures*"));
451 mixin(generateContractSetter("frequire", "Statement"));
452 mixin(generateContractSetter("fensure", "Statement"));
453 mixin(generateContractSetter("fdrequire", "FuncDeclaration"));
454 mixin(generateContractSetter("fdensure", "FuncDeclaration"));
455 mixin(generateContractSetter("fdrequireParams", "Expressions*"));
456 mixin(generateContractSetter("fdensureParams", "Expressions*"));
459 override FuncDeclaration
syntaxCopy(Dsymbol s
)
461 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
462 FuncDeclaration f
= s ?
cast(FuncDeclaration
)s
463 : new FuncDeclaration(loc
, endloc
, ident
, storage_class
, type
.syntaxCopy(), this.noreturn
!= 0);
464 f
.frequires
= frequires ? Statement
.arraySyntaxCopy(frequires
) : null;
465 f
.fensures
= fensures ? Ensure
.arraySyntaxCopy(fensures
) : null;
466 f
.fbody
= fbody ? fbody
.syntaxCopy() : null;
470 /****************************************************
471 * Check that this function type is properly resolved.
472 * If not, report "forward reference error" and return true.
474 extern (D
) final bool checkForwardRef(const ref Loc loc
)
476 if (!functionSemantic(this))
479 /* No deco means the functionSemantic() call could not resolve
480 * forward referenes in the type of this function.
484 bool inSemantic3
= (inferRetType
&& semanticRun
>= PASS
.semantic3
);
485 .error(loc
, "forward reference to %s`%s`",
486 (inSemantic3 ?
"inferred return type of function " : "").ptr
,
493 override final bool equals(const RootObject o
) const
498 if (auto s
= isDsymbol(o
))
501 auto fd2
= s
.isFuncDeclaration();
505 auto fa1
= fd1
.isFuncAliasDeclaration();
506 auto faf1
= fa1 ? fa1
.toAliasFunc() : fd1
;
508 auto fa2
= fd2
.isFuncAliasDeclaration();
509 auto faf2
= fa2 ? fa2
.toAliasFunc() : fd2
;
513 return faf1
.equals(faf2
) && fa1
.hasOverloads
== fa2
.hasOverloads
;
516 bool b1
= fa1
!is null;
517 if (b1
&& faf1
.isUnique() && !fa1
.hasOverloads
)
520 bool b2
= fa2
!is null;
521 if (b2
&& faf2
.isUnique() && !fa2
.hasOverloads
)
527 return faf1
.toParent().equals(faf2
.toParent()) &&
528 faf1
.ident
.equals(faf2
.ident
) &&
529 faf1
.type
.equals(faf2
.type
);
534 /****************************************************
535 * Determine if 'this' overrides fd.
536 * Return !=0 if it does.
538 extern (D
) final int overrides(FuncDeclaration fd
)
541 if (fd
.ident
== ident
)
543 import dmd
.typesem
: covariant
;
544 const cov
= type
.covariant(fd
.type
);
545 if (cov
!= Covariant
.distinct
)
547 ClassDeclaration cd1
= toParent().isClassDeclaration();
548 ClassDeclaration cd2
= fd
.toParent().isClassDeclaration();
549 if (cd1
&& cd2
&& cd2
.isBaseOf(cd1
, null))
556 /*************************************************
557 * Find index of function in vtbl[0..length] that
558 * this function overrides.
559 * Prefer an exact match to a covariant one.
561 * vtbl = vtable to use
562 * dim = maximal vtable dimension
565 * -2 can't determine because of forward references
567 final int findVtblIndex(Dsymbols
* vtbl
, int dim
)
569 //printf("findVtblIndex() %s\n", toChars());
570 import dmd
.typesem
: covariant
;
572 FuncDeclaration mismatch
= null;
573 StorageClass mismatchstc
= 0;
577 for (int vi
= 0; vi
< dim
; vi
++)
579 FuncDeclaration fdv
= (*vtbl
)[vi
].isFuncDeclaration();
580 if (fdv
&& fdv
.ident
== ident
)
582 if (type
.equals(fdv
.type
)) // if exact match
584 if (fdv
.parent
.isClassDeclaration())
589 continue; // keep looking
591 return vi
; // no need to look further
596 .error(loc
, "%s `%s` cannot determine overridden function", kind
, toPrettyChars
);
604 StorageClass
stc = 0;
605 const cov
= type
.covariant(fdv
.type
, &stc);
606 //printf("\tbaseclass cov = %d\n", cov);
609 case Covariant
.distinct
:
610 // types are distinct
614 bestvi
= vi
; // covariant, but not identical
616 // keep looking for an exact match
621 mismatch
= fdv
; // overrides, but is not covariant
623 // keep looking for an exact match
625 case Covariant
.fwdref
:
626 return -2; // forward references
630 if (_linkage
== LINK
.cpp
&& bestvi
!= -1)
632 StorageClass
stc = 0;
633 FuncDeclaration fdv
= (*vtbl
)[bestvi
].isFuncDeclaration();
634 assert(fdv
&& fdv
.ident
== ident
);
635 if (type
.covariant(fdv
.type
, &stc, /*cppCovariant=*/true) == Covariant
.no
)
637 /* https://issues.dlang.org/show_bug.cgi?id=22351
638 * Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not.
639 * For now, continue to allow D covariant rules to apply when `override` has been used,
640 * but issue a deprecation warning that this behaviour will change in the future.
641 * Otherwise, follow the C++ covariant rules, which will create a new vtable entry.
645 /* @@@DEPRECATED_2.110@@@
646 * After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch,
647 * but also the `cppCovariant` parameter from Type.covariant, and update the function
648 * so that both `LINK.cpp` covariant conditions within are always checked.
650 .deprecation(loc
, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated",
651 fdv
.toPrettyChars(), fdv
.type
.toTypeFunction().parameterList
.parametersTypeToChars(),
652 toPrettyChars(), type
.toTypeFunction().parameterList
.parametersTypeToChars(), type
.modToChars());
654 const char* where
= type
.isNaked() ?
"parameters" : "type";
655 deprecationSupplemental(loc
, "Either remove `override`, or adjust the `const` qualifiers of the "
656 ~ "overriding function %s", where
);
660 // Treat as if Covariant.no
668 if (bestvi
== -1 && mismatch
)
671 //mismatch.type.print();
672 //printf("%s %s\n", type.deco, mismatch.type.deco);
673 //printf("stc = %llx\n", mismatchstc);
676 // Fix it by modifying the type to add the storage classes
677 type
= type
.addStorageClass(mismatchstc
);
684 /*********************************
685 * If function a function in a base class,
686 * return that base class.
688 * base class if overriding, null if not
690 extern (D
) final BaseClass
* overrideInterface()
692 for (ClassDeclaration cd
= toParent2().isClassDeclaration(); cd
; cd
= cd
.baseClass
)
694 foreach (b
; cd
.interfaces
)
696 auto v
= findVtblIndex(&b
.sym
.vtbl
, cast(int)b
.sym
.vtbl
.length
);
704 /****************************************************
705 * Overload this FuncDeclaration with the new one f.
706 * Return true if successful; i.e. no conflict.
708 override bool overloadInsert(Dsymbol s
)
710 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
712 AliasDeclaration ad
= s
.isAliasDeclaration();
716 return overnext
.overloadInsert(ad
);
717 if (!ad
.aliassym
&& ad
.type
.ty
!= Tident
&& ad
.type
.ty
!= Tinstance
&& ad
.type
.ty
!= Ttypeof
)
719 //printf("\tad = '%s'\n", ad.type.toChars());
723 //printf("\ttrue: no conflict\n");
726 TemplateDeclaration td
= s
.isTemplateDeclaration();
732 return overnext
.overloadInsert(td
);
736 FuncDeclaration fd
= s
.isFuncDeclaration();
742 /* Disable this check because:
744 * semantic() isn't run yet on foo(), so the const hasn't been
749 printf("type = %s\n", type
.toChars());
750 printf("fd.type = %s\n", fd
.type
.toChars());
752 // fd.type can be NULL for overloaded constructors
753 if (type
&& fd
.type
&& fd
.type
.covariant(type
) && fd
.type
.mod
== type
.mod
&& !isFuncAliasDeclaration())
755 //printf("\tfalse: conflict %s\n", kind());
762 td
= overnext
.isTemplateDeclaration();
764 fd
.overloadInsert(td
);
766 return overnext
.overloadInsert(fd
);
769 //printf("\ttrue: no conflict\n");
773 /********************************************
774 * Find function in overload list that exactly matches t.
776 extern (D
) final FuncDeclaration
overloadExactMatch(Type t
)
779 overloadApply(this, (Dsymbol s
)
781 auto f
= s
.isFuncDeclaration();
784 if (f
.storage_class
& STC
.disable
)
786 if (t
.equals(f
.type
))
792 /* Allow covariant matches, as long as the return type
793 * is just a const conversion.
794 * This allows things like pure functions to match with an impure function type.
796 if (t
.ty
== Tfunction
)
798 import dmd
.typesem
: covariant
;
799 auto tf
= cast(TypeFunction
)f
.type
;
800 if (tf
.covariant(t
) == Covariant
.yes
&&
801 tf
.nextOf().implicitConvTo(t
.nextOf()) >= MATCH
.constant
)
812 /********************************************
813 * Find function in overload list that matches to the 'this' modifier.
814 * There's four result types.
816 * 1. If the 'tthis' matches only one candidate, it's an "exact match".
817 * Returns the function and 'hasOverloads' is set to false.
818 * eg. If 'tthis" is mutable and there's only one mutable method.
819 * 2. If there's two or more match candidates, but a candidate function will be
821 * Returns the better match function but 'hasOverloads' is set to true.
822 * eg. If 'tthis' is mutable, and there's both mutable and const methods,
823 * the mutable method will be a better match.
824 * 3. If there's two or more match candidates, but there's no better match,
825 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
826 * eg. If 'tthis' is mutable, and there's two or more mutable methods.
827 * 4. If there's no candidates, it's "no match" and returns null with error report.
828 * e.g. If 'tthis' is const but there's no const methods.
830 extern (D
) final FuncDeclaration
overloadModMatch(const ref Loc loc
, Type tthis
, ref bool hasOverloads
)
832 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
834 overloadApply(this, (Dsymbol s
)
836 auto f
= s
.isFuncDeclaration();
837 if (!f || f
== m
.lastf
) // skip duplicates
840 auto tf
= f
.type
.toTypeFunction();
841 //printf("tf = %s\n", tf.toChars());
844 if (tthis
) // non-static functions are preferred than static ones
847 match
= f
.isCtorDeclaration() ? MATCH
.exact
: MODmethodConv(tthis
.mod
, tf
.mod
);
849 match
= MATCH
.constant
; // keep static function in overload candidates
851 else // static functions are preferred than non-static ones
854 match
= MATCH
.convert
;
858 if (match
== MATCH
.nomatch
)
861 if (match
> m
.last
) goto LcurrIsBetter
;
862 if (match
< m
.last
) goto LlastIsBetter
;
864 // See if one of the matches overrides the other.
865 if (m
.lastf
.overrides(f
)) goto LlastIsBetter
;
866 if (f
.overrides(m
.lastf
)) goto LcurrIsBetter
;
868 //printf("\tambiguous\n");
874 //printf("\tlastbetter\n");
875 m
.count
++; // count up
879 //printf("\tisbetter\n");
880 if (m
.last
<= MATCH
.convert
)
882 // clear last secondary matching
888 m
.count
++; // count up
892 if (m
.count
== 1) // exact match
894 hasOverloads
= false;
896 else if (m
.count
> 1) // better or ambiguous match
903 auto tf
= this.type
.toTypeFunction();
905 assert(!MODimplicitConv(tthis
.mod
, tf
.mod
)); // modifier mismatch
907 OutBuffer thisBuf
, funcBuf
;
908 MODMatchToBuffer(&thisBuf
, tthis
.mod
, tf
.mod
);
909 MODMatchToBuffer(&funcBuf
, tf
.mod
, tthis
.mod
);
910 .error(loc
, "%smethod %s is not callable using a %sobject", kind
, toPrettyChars
,
911 funcBuf
.peekChars(), this.toPrettyChars(), thisBuf
.peekChars());
917 /********************************************
918 * find function template root in overload list
920 extern (D
) final TemplateDeclaration
findTemplateDeclRoot()
922 FuncDeclaration f
= this;
923 while (f
&& f
.overnext
)
925 //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
926 TemplateDeclaration td
= f
.overnext
.isTemplateDeclaration();
929 f
= f
.overnext
.isFuncDeclaration();
934 /********************************************
935 * Returns true if function was declared
936 * directly or indirectly in a unittest block
938 final bool inUnittest()
943 if (f
.isUnitTestDeclaration())
951 /*************************************
952 * Determine partial specialization order of functions `f` vs `g`.
953 * This is very similar to TemplateDeclaration::leastAsSpecialized().
956 * g = second function
957 * names = names of parameters
959 * match 'this' is at least as specialized as g
960 * 0 g is more specialized than 'this'
962 static MATCH
leastAsSpecialized(FuncDeclaration f
, FuncDeclaration g
, Identifiers
* names
)
964 enum LOG_LEASTAS
= 0;
965 static if (LOG_LEASTAS
)
967 import core
.stdc
.stdio
: printf
;
968 printf("leastAsSpecialized(%s, %s, %s)\n", f
.toChars(), g
.toChars(), names ? names
.toChars() : "null");
969 printf("%s, %s\n", f
.type
.toChars(), g
.type
.toChars());
972 /* This works by calling g() with f()'s parameters, and
973 * if that is possible, then f() is at least as specialized
977 TypeFunction tf
= f
.type
.toTypeFunction();
978 TypeFunction tg
= g
.type
.toTypeFunction();
980 /* If both functions have a 'this' pointer, and the mods are not
981 * the same and g's is not const, then this is less specialized.
983 if (f
.needThis() && g
.needThis() && tf
.mod
!= tg
.mod
)
985 if (f
.isCtorDeclaration())
987 if (!MODimplicitConv(tg
.mod
, tf
.mod
))
988 return MATCH
.nomatch
;
992 if (!MODimplicitConv(tf
.mod
, tg
.mod
))
993 return MATCH
.nomatch
;
997 /* Create a dummy array of arguments out of the parameters to f()
1000 foreach (u
, p
; tf
.parameterList
)
1003 if (p
.isReference())
1005 e
= new IdentifierExp(Loc
.initial
, p
.ident
);
1009 e
= p
.type
.defaultInitLiteral(Loc
.initial
);
1013 import dmd
.typesem
: callMatch
;
1014 MATCH m
= tg
.callMatch(null, ArgumentList(&args
, names
), 1);
1015 if (m
> MATCH
.nomatch
)
1017 /* A variadic parameter list is less specialized than a
1020 if (tf
.parameterList
.varargs
&& !tg
.parameterList
.varargs
)
1021 goto L1
; // less specialized
1023 static if (LOG_LEASTAS
)
1025 printf(" matches %d, so is least as specialized\n", m
);
1030 static if (LOG_LEASTAS
)
1032 printf(" doesn't match, so is not as specialized\n");
1034 return MATCH
.nomatch
;
1037 /********************************
1038 * Searches for a label with the given identifier. This function will insert a new
1039 * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
1042 * ident = identifier of the requested label
1043 * loc = location used when creating a new `LabelDsymbol`
1045 * Returns: the `LabelDsymbol` for `ident`
1047 final LabelDsymbol
searchLabel(Identifier ident
, const ref Loc loc
)
1051 labtab
= new DsymbolTable(); // guess we need one
1053 s
= labtab
.lookup(ident
);
1056 s
= new LabelDsymbol(ident
, loc
);
1059 return cast(LabelDsymbol
)s
;
1062 /*****************************************
1063 * Determine lexical level difference from `this` to nested function `fd`.
1065 * fd = target of call
1066 * intypeof = !=0 if inside typeof
1069 * >0 decrease nesting by number
1070 * -1 increase nesting by 1 (`fd` is nested within `this`)
1071 * LevelError error, `this` cannot call `fd`
1073 extern (D
) final int getLevel(FuncDeclaration fd
, int intypeof
)
1075 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
1076 Dsymbol fdparent
= fd
.toParent2();
1077 if (fdparent
== this)
1082 while (fd
!= s
&& fdparent
!= s
.toParent2())
1084 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
1085 if (auto thisfd
= s
.isFuncDeclaration())
1087 if (!thisfd
.isNested() && !thisfd
.vthis
&& !intypeof
)
1092 if (auto thiscd
= s
.isAggregateDeclaration())
1094 /* AggregateDeclaration::isNested returns true only when
1095 * it has a hidden pointer.
1096 * But, calling the function belongs unrelated lexical scope
1097 * is still allowed inside typeof.
1099 * struct Map(alias fun) {
1100 * typeof({ return fun(); }) RetType;
1101 * // No member function makes Map struct 'not nested'.
1104 if (!thiscd
.isNested() && !intypeof
)
1111 s
= s
.toParentP(fd
);
1118 /***********************************
1119 * Determine lexical level difference from `this` to nested function `fd`.
1120 * Issue error if `this` cannot call `fd`.
1123 * loc = location for error messages
1125 * fd = target of call
1126 * decl = The `Declaration` that triggered this check.
1127 * Used to provide a better error message only.
1130 * >0 decrease nesting by number
1131 * -1 increase nesting by 1 (`fd` is nested within 'this')
1134 extern (D
) final int getLevelAndCheck(const ref Loc loc
, Scope
* sc
, FuncDeclaration fd
,
1137 int level
= getLevel(fd
, sc
.intypeof
);
1138 if (level
!= LevelError
)
1141 // Don't give error if in template constraint
1142 if (!(sc
.flags
& SCOPE
.constraint
))
1144 const(char)* xstatic
= isStatic() ?
"`static` " : "";
1145 // better diagnostics for static functions
1146 .error(loc
, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
1147 xstatic
, kind(), toPrettyChars(), decl
.kind(), decl
.toChars(),
1148 fd
.toPrettyChars());
1149 .errorSupplemental(decl
.loc
, "`%s` declared here", decl
.toChars());
1155 enum LevelError
= -2;
1157 override const(char)* toPrettyChars(bool QualifyTypes
= false)
1162 return Dsymbol
.toPrettyChars(QualifyTypes
);
1165 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
1166 final const(char)* toFullSignature()
1169 functionToBufferWithIdent(type
.toTypeFunction(), buf
, toChars(), isStatic
);
1170 return buf
.extractChars();
1173 final bool isMain() const
1175 return ident
== Id
.main
&& resolvedLinkage() != LINK
.c
&& !isMember() && !isNested();
1178 final bool isCMain() const
1180 return ident
== Id
.main
&& resolvedLinkage() == LINK
.c
&& !isMember() && !isNested();
1183 final bool isWinMain() const
1185 //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1188 bool x
= ident
== Id
.WinMain
&& resolvedLinkage() != LINK
.c
&& !isMember();
1189 printf("%s\n", x ?
"yes" : "no");
1194 return ident
== Id
.WinMain
&& resolvedLinkage() != LINK
.c
&& !isMember();
1198 final bool isDllMain() const
1200 return ident
== Id
.DllMain
&& resolvedLinkage() != LINK
.c
&& !isMember();
1203 final bool isRtInit() const
1205 return ident
== Id
.rt_init
&& resolvedLinkage() == LINK
.c
&& !isMember() && !isNested();
1208 override final bool isExport() const
1210 return visibility
.kind
== Visibility
.Kind
.export_ || dllExport
;
1213 override final bool isImportedSymbol() const
1215 //printf("isImportedSymbol()\n");
1216 //printf("protection = %d\n", visibility);
1217 return (visibility
.kind
== Visibility
.Kind
.export_ || dllImport
) && !fbody
;
1220 override final bool isCodeseg() const pure nothrow @nogc @safe
1222 return true; // functions are always in the code segment
1225 override final bool isOverloadable() const
1227 return true; // functions can be overloaded
1230 /***********************************
1231 * Override so it can work even if semantic() hasn't yet
1234 override final bool isAbstract()
1236 if (storage_class
& STC
.abstract_
)
1238 if (semanticRun
>= PASS
.semanticdone
)
1243 if (_scope
.stc & STC
.abstract_
)
1245 parent
= _scope
.parent
;
1246 Dsymbol parent
= toParent();
1247 if (parent
.isInterfaceDeclaration())
1253 /**********************************
1254 * Decide if attributes for this function can be inferred from examining
1255 * the function body.
1259 final bool canInferAttributes(Scope
* sc
)
1264 if (isVirtualMethod() &&
1266 * https://issues.dlang.org/show_bug.cgi?id=21719
1268 * If we have an auto virtual function we can infer
1271 !(inferRetType
&& !isCtorDeclaration()))
1272 return false; // since they may be overridden
1275 /********** this is for backwards compatibility for the moment ********/
1276 (!isMember() || sc
.func
.isSafeBypassingInference() && !isInstantiated()))
1279 if (isFuncLiteralDeclaration() ||
// externs are not possible with literals
1280 (storage_class
& STC
.inference
) ||
// do attribute inference
1281 (inferRetType
&& !isCtorDeclaration()))
1284 if (isInstantiated())
1286 auto ti
= parent
.isTemplateInstance();
1287 if (ti
is null || ti
.isTemplateMixin() || ti
.tempdecl
.ident
== ident
)
1294 /*****************************************
1295 * Initialize for inferring the attributes of this function.
1297 final void initInferAttributes()
1299 //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1300 TypeFunction tf
= type
.toTypeFunction();
1301 if (tf
.purity
== PURE
.impure
) // purity not specified
1302 purityInprocess
= true;
1304 if (tf
.trust
== TRUST
.default_
)
1305 safetyInprocess
= true;
1308 nothrowInprocess
= true;
1311 nogcInprocess
= true;
1313 if (!isVirtual() ||
this.isIntroducing())
1314 returnInprocess
= true;
1316 // Initialize for inferring STC.scope_
1322 //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1324 import dmd
.typesem
: purityLevel
;
1326 TypeFunction tf
= type
.toTypeFunction();
1327 if (purityInprocess
)
1329 if (tf
.purity
== PURE
.fwdref
)
1331 PURE purity
= tf
.purity
;
1332 if (purity
> PURE
.weak
&& isNested())
1334 if (purity
> PURE
.weak
&& needThis())
1336 // The attribute of the 'this' reference affects purity strength
1337 if (type
.mod
& MODFlags
.immutable_
)
1340 else if (type
.mod
& (MODFlags
.const_ | MODFlags
.wild
) && purity
>= PURE
.const_
)
1341 purity
= PURE
.const_
;
1346 // ^ This rely on the current situation that every FuncDeclaration has a
1347 // unique TypeFunction.
1351 extern (D
) final PURE
isPureBypassingInference()
1353 if (purityInprocess
)
1359 /**************************************
1360 * The function is doing something impure, so mark it as impure.
1363 * loc = location of impure action
1364 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1365 * arg0 = (optional) argument to format string
1367 * Returns: `true` if there's a purity error
1369 extern (D
) final bool setImpure(Loc loc
= Loc
.init
, const(char)* fmt
= null, RootObject arg0
= null)
1371 if (purityInprocess
)
1373 purityInprocess
= false;
1375 pureViolation
= new AttributeViolation(loc
, fmt
, this, arg0
); // impure action
1377 pureViolation
= new AttributeViolation(loc
, fmt
, arg0
); // call to impure function
1380 fes
.func
.setImpure(loc
, fmt
, arg0
);
1387 extern (D
) final uint flags()
1392 extern (D
) final uint flags(uint f
)
1400 if (safetyInprocess
)
1402 return type
.toTypeFunction().trust
== TRUST
.safe
;
1405 extern (D
) final bool isSafeBypassingInference()
1407 return !(safetyInprocess
) && isSafe();
1410 final bool isTrusted()
1412 if (safetyInprocess
)
1414 return type
.toTypeFunction().trust
== TRUST
.trusted
;
1417 /**************************************
1418 * The function is doing something unsafe, so mark it as unsafe.
1421 * gag = surpress error message (used in escape.d)
1422 * loc = location of error
1423 * fmt = printf-style format string
1424 * arg0 = (optional) argument for first %s format specifier
1425 * arg1 = (optional) argument for second %s format specifier
1426 * arg2 = (optional) argument for third %s format specifier
1427 * Returns: whether there's a safe error
1429 extern (D
) final bool setUnsafe(
1430 bool gag
= false, Loc loc
= Loc
.init
, const(char)* fmt
= null,
1431 RootObject arg0
= null, RootObject arg1
= null, RootObject arg2
= null)
1433 if (safetyInprocess
)
1435 safetyInprocess
= false;
1436 type
.toTypeFunction().trust
= TRUST
.system
;
1438 safetyViolation
= new AttributeViolation(loc
, fmt
, arg0
, arg1
, arg2
);
1441 fes
.func
.setUnsafe();
1446 .error(loc
, fmt
, arg0 ? arg0
.toChars() : "", arg1 ? arg1
.toChars() : "", arg2 ? arg2
.toChars() : "");
1453 /**************************************
1454 * The function is calling `@system` function `f`, so mark it as unsafe.
1457 * f = function being called (needed for diagnostic of inferred functions)
1458 * Returns: whether there's a safe error
1460 extern (D
) final bool setUnsafeCall(FuncDeclaration f
)
1462 return setUnsafe(false, f
.loc
, null, f
, null);
1467 //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1470 return type
.toTypeFunction().isnogc
;
1473 extern (D
) final bool isNogcBypassingInference()
1475 return !nogcInprocess
&& isNogc();
1478 /**************************************
1479 * The function is doing something that may allocate with the GC,
1480 * so mark it as not nogc (not no-how).
1483 * loc = location of impure action
1484 * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
1485 * arg0 = (optional) argument to format string
1488 * true if function is marked as @nogc, meaning a user error occurred
1490 extern (D
) final bool setGC(Loc loc
, const(char)* fmt
, RootObject arg0
= null)
1492 //printf("setGC() %s\n", toChars());
1493 if (nogcInprocess
&& semanticRun
< PASS
.semantic3
&& _scope
)
1495 this.semantic2(_scope
);
1496 this.semantic3(_scope
);
1501 nogcInprocess
= false;
1503 nogcViolation
= new AttributeViolation(loc
, fmt
, this, arg0
); // action that requires GC
1505 nogcViolation
= new AttributeViolation(loc
, fmt
, arg0
); // call to non-@nogc function
1507 type
.toTypeFunction().isnogc
= false;
1509 fes
.func
.setGC(Loc
.init
, null, null);
1516 /**************************************
1517 * The function calls non-`@nogc` function f, mark it as not nogc.
1519 * f = function being called
1521 * true if function is marked as @nogc, meaning a user error occurred
1523 extern (D
) final bool setGCCall(FuncDeclaration f
)
1525 return setGC(loc
, null, f
);
1528 /**************************************
1529 * The function is doing something that may throw an exception, register that in case nothrow is being inferred
1532 * loc = location of action
1533 * fmt = format string for error message
1534 * arg0 = (optional) argument to format string
1536 extern (D
) final void setThrow(Loc loc
, const(char)* fmt
, RootObject arg0
= null)
1538 if (nothrowInprocess
&& !nothrowViolation
)
1540 nothrowViolation
= new AttributeViolation(loc
, fmt
, arg0
); // action that requires GC
1544 /**************************************
1545 * The function calls non-`nothrow` function f, register that in case nothrow is being inferred
1547 * loc = location of call
1548 * f = function being called
1550 extern (D
) final void setThrowCall(Loc loc
, FuncDeclaration f
)
1552 return setThrow(loc
, null, f
);
1555 extern (D
) final void printGCUsage(const ref Loc loc
, const(char)* warn
)
1557 if (!global
.params
.v
.gc
)
1560 Module m
= getModule();
1561 if (m
&& m
.isRoot() && !inUnittest())
1563 message(loc
, "vgc: %s", warn
);
1567 /********************************************
1568 * See if pointers from function parameters, mutable globals, or uplevel functions
1569 * could leak into return value.
1571 * true if the function return value is isolated from
1572 * any inputs to the function
1574 extern (D
) final bool isReturnIsolated()
1576 //printf("isReturnIsolated(this: %s)\n", this.toChars);
1577 TypeFunction tf
= type
.toTypeFunction();
1580 Type treti
= tf
.next
;
1582 return isTypeIsolatedIndirect(treti
); // check influence from parameters
1584 return isTypeIsolated(treti
);
1587 /********************
1588 * See if pointers from function parameters, mutable globals, or uplevel functions
1589 * could leak into type `t`.
1591 * t = type to check if it is isolated
1593 * true if `t` is isolated from
1594 * any inputs to the function
1596 extern (D
) final bool isTypeIsolated(Type t
)
1598 StringTable
!Type parentTypes
;
1599 const uniqueTypeID
= t
.getUniqueID();
1602 const cacheResultPtr
= uniqueTypeID
in isTypeIsolatedCache
;
1603 if (cacheResultPtr
!is null)
1604 return *cacheResultPtr
;
1606 parentTypes
._init();
1607 const isIsolated
= isTypeIsolated(t
, parentTypes
);
1608 isTypeIsolatedCache
[uniqueTypeID
] = isIsolated
;
1613 parentTypes
._init();
1614 return isTypeIsolated(t
, parentTypes
);
1619 extern (D
) final bool isTypeIsolated(Type t
, ref StringTable
!Type parentTypes
)
1621 //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
1628 return isTypeIsolatedIndirect(t
.nextOf()); // go down one level
1632 return isTypeIsolatedIndirect(t
);
1635 /* Drill down and check the struct's fields
1637 import dmd
.typesem
: toDsymbol
;
1638 auto sym
= t
.toDsymbol(null).isStructDeclaration();
1639 const tName
= t
.toChars
.toDString
;
1640 const entry
= parentTypes
.insert(tName
, t
);
1643 //we've already seen this type in a parent, not isolated
1646 foreach (v
; sym
.fields
)
1648 Type tmi
= v
.type
.addMod(t
.mod
);
1649 //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
1650 // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
1651 if (!isTypeIsolated(tmi
, parentTypes
))
1661 /********************************************
1663 * t = type of object to test one level of indirection down
1665 * true if an object typed `t` has no indirections
1666 * which could have come from the function's parameters, mutable
1667 * globals, or uplevel functions.
1669 private bool isTypeIsolatedIndirect(Type t
)
1671 //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1674 /* Since `t` is one level down from an indirection, it could pick
1675 * up a reference to a mutable global or an outer function, so
1678 if (!isPureBypassingInference() ||
isNested())
1681 TypeFunction tf
= type
.toTypeFunction();
1683 //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1685 foreach (i
, fparam
; tf
.parameterList
)
1687 Type tp
= fparam
.type
;
1691 if (fparam
.isLazy() || fparam
.isReference())
1693 if (!traverseIndirections(tp
, t
))
1698 /* Goes down one level of indirection, then calls traverseIndirection() on
1701 * true if t is isolated from tp
1703 static bool traverse(Type tp
, Type t
)
1705 tp
= tp
.baseElemOf();
1710 return traverseIndirections(tp
.nextOf(), t
);
1714 return traverseIndirections(tp
, t
);
1717 /* Drill down and check the struct's fields
1719 import dmd
.typesem
: toDsymbol
;
1720 auto sym
= tp
.toDsymbol(null).isStructDeclaration();
1721 foreach (v
; sym
.fields
)
1723 Type tprmi
= v
.type
.addMod(tp
.mod
);
1724 //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1725 if (!traverse(tprmi
, t
))
1735 if (!traverse(tp
, t
))
1738 // The 'this' reference is a parameter, too
1739 if (AggregateDeclaration ad
= isCtorDeclaration() ?
null : isThis())
1741 Type tthis
= ad
.getType().addMod(tf
.mod
);
1742 //printf("\ttthis = %s\n", tthis.toChars());
1743 if (!traverseIndirections(tthis
, t
))
1750 /****************************************
1751 * Determine if function needs a static frame pointer.
1753 * `true` if function is really nested within other function.
1755 * If isNested() returns true, isThis() should return false,
1756 * unless the function needs a dual-context pointer.
1758 bool isNested() const
1760 auto f
= toAliasFunc();
1761 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1762 return ((f
.storage_class
& STC
.static_
) == 0) &&
1763 (f
._linkage
== LINK
.d
) &&
1764 (f
.toParent2().isFuncDeclaration() !is null ||
1765 f
.toParent2() !is f
.toParentLocal());
1768 /****************************************
1769 * Determine if function is a non-static member function
1770 * that has an implicit 'this' expression.
1772 * The aggregate it is a member of, or null.
1774 * Both isThis() and isNested() should return true if function needs a dual-context pointer,
1775 * otherwise if isThis() returns true, isNested() should return false.
1777 override inout(AggregateDeclaration
) isThis() inout
1779 //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1780 auto ad
= (storage_class
& STC
.static_
) ?
.objc
.isThis(this) : isMemberLocal();
1781 //printf("-FuncDeclaration::isThis() %p\n", ad);
1785 override final bool needThis()
1787 //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1788 return toAliasFunc().isThis() !is null;
1791 // Determine if a function is pedantically virtual
1792 final bool isVirtualMethod()
1794 if (toAliasFunc() != this)
1795 return toAliasFunc().isVirtualMethod();
1797 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1800 // If it's a final method, and does not override anything, then it is not virtual
1801 if (isFinalFunc() && foverrides
.length
== 0)
1808 // Determine if function goes into virtual function pointer table
1809 bool isVirtual() const
1811 if (toAliasFunc() != this)
1812 return toAliasFunc().isVirtual();
1814 auto p
= toParent();
1816 if (!isMember ||
!p
.isClassDeclaration
)
1819 if (p
.isClassDeclaration
.classKind
== ClassKind
.objc
)
1820 return .objc
.isVirtual(this);
1824 printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1825 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), visibility
== Visibility
.Kind
.private_
, isCtorDeclaration(), linkage
!= LINK
.d
);
1826 printf("result is %d\n", isMember() && !(isStatic() || visibility
== Visibility
.Kind
.private_ || visibility
== Visibility
.Kind
.package_
) && p
.isClassDeclaration() && !(p
.isInterfaceDeclaration() && isFinalFunc()));
1828 return !(isStatic() || visibility
.kind
== Visibility
.Kind
.private_ || visibility
.kind
== Visibility
.Kind
.package_
) && !(p
.isInterfaceDeclaration() && isFinalFunc());
1831 final bool isFinalFunc() const
1833 if (toAliasFunc() != this)
1834 return toAliasFunc().isFinalFunc();
1838 auto cd
= toParent().isClassDeclaration();
1839 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration
.isFinal());
1840 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration
.isFinal(), ((cd
= toParent().isClassDeclaration()) !is null && cd
.storage_class
& STC
.final_
));
1841 printf("result is %d\n", isMember() && (Declaration
.isFinal() ||
(cd
!is null && cd
.storage_class
& STC
.final_
)));
1843 printf("\tmember of %s\n", cd
.toChars());
1847 if (Declaration
.isFinal())
1849 auto cd
= toParent().isClassDeclaration();
1850 return (cd
!is null) && (cd
.storage_class
& STC
.final_
);
1853 bool addPreInvariant()
1856 ClassDeclaration cd
= ad ? ad
.isClassDeclaration() : null;
1857 return (ad
&& !(cd
&& cd
.isCPPclass()) && global
.params
.useInvariants
== CHECKENABLE
.on
&& (visibility
.kind
== Visibility
.Kind
.protected_ || visibility
.kind
== Visibility
.Kind
.public_ || visibility
.kind
== Visibility
.Kind
.export_
) && !this.isNaked());
1860 bool addPostInvariant()
1863 ClassDeclaration cd
= ad ? ad
.isClassDeclaration() : null;
1864 return (ad
&& !(cd
&& cd
.isCPPclass()) && ad
.inv
&& global
.params
.useInvariants
== CHECKENABLE
.on
&& (visibility
.kind
== Visibility
.Kind
.protected_ || visibility
.kind
== Visibility
.Kind
.public_ || visibility
.kind
== Visibility
.Kind
.export_
) && !this.isNaked());
1867 override const(char)* kind() const
1869 return this.isGenerated() ?
"generated function" : "function";
1872 /********************************************
1874 * true if there are no overloads of this function
1876 final bool isUnique() const
1878 bool result
= false;
1879 overloadApply(cast() this, (Dsymbol s
)
1881 auto f
= s
.isFuncDeclaration();
1882 auto td
= s
.isTemplateDeclaration();
1888 return 1; // ambiguous, done
1899 /*********************************************
1900 * In the current function, we are calling 'this' function.
1901 * 1. Check to see if the current function can call 'this' function, issue error if not.
1902 * 2. If the current function is not the parent of 'this' function, then add
1903 * the current function to the list of siblings of 'this' function.
1904 * 3. If the current function is a literal, and it's accessing an uplevel scope,
1905 * then mark it as a delegate.
1906 * Returns true if error occurs.
1908 extern (D
) final bool checkNestedReference(Scope
* sc
, const ref Loc loc
)
1910 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
1912 if (auto fld = this.isFuncLiteralDeclaration())
1914 if (fld.tok
== TOK
.reserved
)
1916 fld.tok
= TOK
.function_
;
1921 if (!parent || parent
== sc
.parent
)
1923 if (ident
== Id
.require || ident
== Id
.ensure
)
1925 if (!isThis() && !isNested())
1928 // The current function
1929 FuncDeclaration fdthis
= sc
.parent
.isFuncDeclaration();
1931 return false; // out of function scope
1933 Dsymbol p
= toParentLocal();
1934 Dsymbol p2
= toParent2();
1936 // Function literals from fdthis to p must be delegates
1937 ensureStaticLinkTo(fdthis
, p
);
1939 ensureStaticLinkTo(fdthis
, p2
);
1943 // The function that this function is in
1944 bool checkEnclosing(FuncDeclaration fdv
)
1951 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
1952 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
1953 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
1955 // Add this function to the list of those which called us
1959 for (size_t i
= 0; i
< siblingCallers
.length
; ++i
)
1961 if (siblingCallers
[i
] == fdthis
)
1966 //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
1967 if (!sc
.intypeof
&& !(sc
.flags
& SCOPE
.compile
))
1969 siblingCallers
.push(fdthis
);
1970 computedEscapingSiblings
= false;
1975 const lv
= fdthis
.getLevelAndCheck(loc
, sc
, fdv
, this);
1976 if (lv
== LevelError
)
1977 return true; // error
1979 return false; // downlevel call
1981 return false; // same level call
1983 return false; // Uplevel call
1986 if (checkEnclosing(p
.isFuncDeclaration()))
1988 if (checkEnclosing(p
== p2 ?
null : p2
.isFuncDeclaration()))
1994 /*******************************
1995 * Look at all the variables in this function that are referenced
1996 * by nested functions, and determine if a closure needs to be
1999 final bool needsClosure()
2001 /* Need a closure for all the closureVars[] if any of the
2002 * closureVars[] are accessed by a
2003 * function that escapes the scope of this function.
2004 * We take the conservative approach and decide that a function needs
2006 * 1) is a virtual function
2007 * 2) has its address taken
2008 * 3) has a parent that escapes
2009 * 4) calls another nested function that needs a closure
2011 * Note that since a non-virtual function can be called by
2012 * a virtual one, if that non-virtual function accesses a closure
2013 * var, the closure still has to be taken. Hence, we check for isThis()
2014 * instead of isVirtual(). (thanks to David Friedman)
2016 * When the function returns a local struct or class, `requiresClosure`
2017 * is already set to `true` upon entering this function when the
2018 * struct/class refers to a local variable and a closure is needed.
2020 //printf("FuncDeclaration::needsClosure() %s\n", toPrettyChars());
2022 if (requiresClosure
)
2025 for (size_t i
= 0; i
< closureVars
.length
; i
++)
2027 VarDeclaration v
= closureVars
[i
];
2028 //printf("\tv = %s\n", v.toChars());
2030 for (size_t j
= 0; j
< v
.nestedrefs
.length
; j
++)
2032 FuncDeclaration f
= v
.nestedrefs
[j
];
2035 /* __require and __ensure will always get called directly,
2036 * so they never make outer functions closure.
2038 if (f
.ident
== Id
.require || f
.ident
== Id
.ensure
)
2041 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
2043 /* Look to see if f escapes. We consider all parents of f within
2044 * this, and also all siblings which call f; if any of them escape,
2046 * Mark all affected functions as requiring closures.
2048 for (Dsymbol s
= f
; s
&& s
!= this; s
= s
.toParentP(this))
2050 FuncDeclaration fx
= s
.isFuncDeclaration();
2053 if (fx
.isThis() || fx
.tookAddressOf
)
2055 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
2057 /* Mark as needing closure any functions between this and f
2059 markAsNeedingClosure((fx
== f
) ? fx
.toParentP(this) : fx
, this);
2061 requiresClosure
= true;
2064 /* We also need to check if any sibling functions that
2065 * called us, have escaped. This is recursive: we need
2066 * to check the callers of our siblings.
2068 if (checkEscapingSiblings(fx
, this))
2069 requiresClosure
= true;
2071 /* https://issues.dlang.org/show_bug.cgi?id=12406
2072 * Iterate all closureVars to mark all descendant
2073 * nested functions that access to the closing context of this function.
2078 if (requiresClosure
)
2087 /***********************************************
2088 * Check that the function contains any closure.
2089 * If it's @nogc, report suitable errors.
2090 * This is mostly consistent with FuncDeclaration::needsClosure().
2093 * true if any errors occur.
2095 extern (C
++) final bool checkClosure()
2097 //printf("checkClosure() %s\n", toPrettyChars());
2098 if (!needsClosure())
2101 if (setGC(loc
, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", this))
2103 .error(loc
, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", kind
, toPrettyChars
, toChars());
2104 if (global
.gag
) // need not report supplemental errors
2107 else if (!global
.params
.useGC
)
2109 .error(loc
, "%s `%s` is `-betterC` yet allocates closure for `%s()` with the GC", kind
, toPrettyChars
, toChars());
2110 if (global
.gag
) // need not report supplemental errors
2115 printGCUsage(loc
, "using closure causes GC allocation");
2120 foreach (v
; closureVars
)
2122 foreach (f
; v
.nestedrefs
)
2126 LcheckAncestorsOfANestedRef
:
2127 for (Dsymbol s
= f
; s
&& s
!is this; s
= s
.toParentP(this))
2129 auto fx
= s
.isFuncDeclaration();
2134 checkEscapingSiblings(fx
, this))
2139 break LcheckAncestorsOfANestedRef
;
2142 .errorSupplemental(f
.loc
, "%s `%s` closes over variable `%s`",
2143 f
.kind
, f
.toPrettyChars(), v
.toChars());
2144 if (v
.ident
!= Id
.This
)
2145 .errorSupplemental(v
.loc
, "`%s` declared here", v
.toChars());
2147 break LcheckAncestorsOfANestedRef
;
2156 /***********************************************
2157 * Determine if function's variables are referenced by a function
2160 final bool hasNestedFrameRefs()
2162 if (closureVars
.length
)
2165 /* If a virtual function has contracts, assume its variables are referenced
2166 * by those contracts, even if they aren't. Because they might be referenced
2167 * by the overridden or overriding function's contracts.
2168 * This can happen because frequire and fensure are implemented as nested functions,
2169 * and they can be called directly by an overriding function and the overriding function's
2170 * context had better match, or
2171 * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
2173 if (fdrequire || fdensure
)
2176 if (foverrides
.length
&& isVirtualMethod())
2178 for (size_t i
= 0; i
< foverrides
.length
; i
++)
2180 FuncDeclaration fdv
= foverrides
[i
];
2181 if (fdv
.hasNestedFrameRefs())
2188 /****************************************************
2189 * Check whether result variable can be built.
2191 * `true` if the function has a return type that
2192 * is different from `void`.
2194 extern (D
) private bool canBuildResultVar()
2196 auto f
= cast(TypeFunction
)type
;
2197 return f
&& f
.nextOf() && f
.nextOf().toBasetype().ty
!= Tvoid
;
2200 /****************************************************
2201 * Declare result variable lazily.
2203 extern (D
) final void buildResultVar(Scope
* sc
, Type tret
)
2207 Loc loc
= fensure ? fensure
.loc
: this.loc
;
2209 /* If inferRetType is true, tret may not be a correct return type yet.
2210 * So, in here it may be a temporary type for vresult, and after
2211 * fbody.dsymbolSemantic() running, vresult.type might be modified.
2213 vresult
= new VarDeclaration(loc
, tret
, Id
.result
, null);
2214 vresult
.storage_class |
= STC
.nodtor | STC
.temp
;
2216 vresult
.storage_class |
= STC
.const_
;
2217 vresult
.storage_class |
= STC
.result
;
2219 // set before the semantic() for checkNestedReference()
2220 vresult
.parent
= this;
2223 if (sc
&& vresult
.semanticRun
== PASS
.initial
)
2225 TypeFunction tf
= type
.toTypeFunction();
2227 vresult
.storage_class |
= STC
.ref_
;
2228 vresult
.type
= tret
;
2230 vresult
.dsymbolSemantic(sc
);
2232 if (!sc
.insert(vresult
))
2233 .error(loc
, "%s `%s` out result %s is already defined", kind
, toPrettyChars
, vresult
.toChars());
2234 assert(vresult
.parent
== this);
2238 /****************************************************
2239 * Merge into this function the 'in' contracts of all it overrides.
2240 * 'in's are OR'd together, i.e. only one of them needs to pass.
2242 extern (D
) final Statement
mergeFrequire(Statement sf
, Expressions
* params
)
2244 /* If a base function and its override both have an IN contract, then
2245 * only one of them needs to succeed. This is done by generating:
2247 * void derived.in() {
2252 * ... body of derived.in() ...
2256 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2257 * If base.in() throws, then derived.in()'s body is executed.
2260 foreach (fdv
; foverrides
)
2262 /* The semantic pass on the contracts of the overridden functions must
2263 * be completed before code generation occurs.
2264 * https://issues.dlang.org/show_bug.cgi?id=3602
2266 if (fdv
.frequires
&& fdv
.semanticRun
!= PASS
.semantic3done
)
2269 Scope
* sc
= fdv
._scope
.push();
2270 sc
.stc &= ~STC
.override_
;
2275 sf
= fdv
.mergeFrequire(sf
, params
);
2276 if (!sf ||
!fdv
.fdrequire
)
2278 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2280 * try { __require(params); }
2281 * catch (Throwable) { frequire; }
2283 params
= Expression
.arraySyntaxCopy(params
);
2284 Expression e
= new CallExp(loc
, new VarExp(loc
, fdv
.fdrequire
, false), params
);
2285 Statement s2
= new ExpStatement(loc
, e
);
2287 auto c
= new Catch(loc
, getThrowable(), null, sf
);
2288 c
.internalCatch
= true;
2289 auto catches
= new Catches();
2291 sf
= new TryCatchStatement(loc
, s2
, catches
);
2296 /****************************************************
2297 * Merge into this function the 'in' contracts of all it overrides.
2299 extern (D
) final Statement
mergeFrequireInclusivePreview(Statement sf
, Expressions
* params
)
2301 /* If a base function and its override both have an IN contract, then
2302 * the override in contract must widen the guarantee of the base contract.
2303 * This is checked by generating:
2305 * void derived.in() {
2307 * ... body of derived.in() ...
2310 * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
2312 * assert(false, "Logic error: " ~ thr.msg);
2317 foreach (fdv
; foverrides
)
2319 /* The semantic pass on the contracts of the overridden functions must
2320 * be completed before code generation occurs.
2321 * https://issues.dlang.org/show_bug.cgi?id=3602
2323 if (fdv
.frequires
&& fdv
.semanticRun
!= PASS
.semantic3done
)
2326 Scope
* sc
= fdv
._scope
.push();
2327 sc
.stc &= ~STC
.override_
;
2332 sf
= fdv
.mergeFrequireInclusivePreview(sf
, params
);
2333 if (sf
&& fdv
.fdrequire
)
2335 const loc
= this.fdrequire
.loc
;
2337 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2340 * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
2342 Identifier id
= Identifier
.generateId("thr");
2343 params
= Expression
.arraySyntaxCopy(params
);
2344 Expression e
= new CallExp(loc
, new VarExp(loc
, fdv
.fdrequire
, false), params
);
2345 Statement s2
= new ExpStatement(loc
, e
);
2346 // assert(false, ...)
2347 // TODO make this a runtime helper to allow:
2348 // - chaining the original expression
2349 // - nogc concatenation
2350 Expression msg
= new StringExp(loc
, "Logic error: in-contract was tighter than parent in-contract");
2351 Statement fail
= new ExpStatement(loc
, new AssertExp(loc
, IntegerExp
.literal
!0, msg
));
2353 Statement s3
= new CompoundStatement(loc
, s2
, fail
);
2355 auto c
= new Catch(loc
, getThrowable(), id
, s3
);
2356 c
.internalCatch
= true;
2357 auto catches
= new Catches();
2359 sf
= new TryCatchStatement(loc
, sf
, catches
);
2367 /****************************************************
2368 * Determine whether an 'out' contract is declared inside
2369 * the given function or any of its overrides.
2371 * fd = the function to search
2373 * true found an 'out' contract
2375 static bool needsFensure(FuncDeclaration fd
) @safe
2380 foreach (fdv
; fd
.foverrides
)
2382 if (needsFensure(fdv
))
2388 /****************************************************
2389 * Rewrite contracts as statements.
2391 final void buildEnsureRequire()
2396 /* in { statements1... }
2397 * in { statements2... }
2400 * in { { statements1... } { statements2... } ... }
2402 assert(frequires
.length
);
2403 auto loc
= (*frequires
)[0].loc
;
2404 auto s
= new Statements
;
2405 foreach (r
; *frequires
)
2407 s
.push(new ScopeStatement(r
.loc
, r
, r
.loc
));
2409 frequire
= new CompoundStatement(loc
, s
);
2414 /* out(id1) { statements1... }
2415 * out(id2) { statements2... }
2418 * out(__result) { { ref id1 = __result; { statements1... } }
2419 * { ref id2 = __result; { statements2... } } ... }
2421 assert(fensures
.length
);
2422 auto loc
= (*fensures
)[0].ensure
.loc
;
2423 auto s
= new Statements
;
2424 foreach (r
; *fensures
)
2426 if (r
.id
&& canBuildResultVar())
2428 auto rloc
= r
.ensure
.loc
;
2429 auto resultId
= new IdentifierExp(rloc
, Id
.result
);
2430 auto init
= new ExpInitializer(rloc
, resultId
);
2431 auto stc = STC
.ref_ | STC
.temp | STC
.result
;
2432 auto decl
= new VarDeclaration(rloc
, null, r
.id
, init
, stc);
2433 auto sdecl
= new ExpStatement(rloc
, decl
);
2434 s
.push(new ScopeStatement(rloc
, new CompoundStatement(rloc
, sdecl
, r
.ensure
), rloc
));
2441 fensure
= new CompoundStatement(loc
, s
);
2447 /* Rewrite contracts as nested functions, then call them. Doing it as nested
2448 * functions means that overriding functions can call them.
2450 TypeFunction f
= cast(TypeFunction
) type
;
2452 /* Make a copy of the parameters and make them all ref */
2453 static Parameters
* toRefCopy(ParameterList parameterList
)
2455 auto result
= new Parameters();
2457 foreach (n
, p
; parameterList
)
2461 p
.storageClass
= (p
.storageClass | STC
.ref_
) & ~STC
.out_
;
2462 p
.defaultArg
= null; // won't be the same with ref
2473 * void __require(ref params) { ... }
2474 * __require(params);
2476 Loc loc
= frequire
.loc
;
2477 fdrequireParams
= new Expressions();
2480 foreach (vd
; *parameters
)
2481 fdrequireParams
.push(new VarExp(loc
, vd
));
2483 auto fo
= cast(TypeFunction
)(originalType ? originalType
: f
);
2484 auto fparams
= toRefCopy(fo
.parameterList
);
2485 auto tf
= new TypeFunction(ParameterList(fparams
), Type
.tvoid
, LINK
.d
);
2486 tf
.isnothrow
= f
.isnothrow
;
2487 tf
.isnogc
= f
.isnogc
;
2488 tf
.purity
= f
.purity
;
2490 auto fd
= new FuncDeclaration(loc
, loc
, Id
.require
, STC
.undefined_
, tf
);
2491 fd
.fbody
= frequire
;
2492 Statement s1
= new ExpStatement(loc
, fd
);
2493 Expression e
= new CallExp(loc
, new VarExp(loc
, fd
, false), fdrequireParams
);
2494 Statement s2
= new ExpStatement(loc
, e
);
2495 frequire
= new CompoundStatement(loc
, s1
, s2
);
2499 /* We need to set fdensureParams here and not in the block below to
2500 * have the parameters available when calling a base class ensure(),
2501 * even if this function doesn't have an out contract.
2503 fdensureParams
= new Expressions();
2504 if (canBuildResultVar())
2505 fdensureParams
.push(new IdentifierExp(loc
, Id
.result
));
2508 foreach (vd
; *parameters
)
2509 fdensureParams
.push(new VarExp(loc
, vd
));
2514 /* out (result) { ... }
2516 * void __ensure(ref tret result, ref params) { ... }
2517 * __ensure(result, params);
2519 Loc loc
= fensure
.loc
;
2520 auto fparams
= new Parameters();
2521 if (canBuildResultVar())
2523 Parameter p
= new Parameter(loc
, STC
.ref_ | STC
.const_
, f
.nextOf(), Id
.result
, null, null);
2526 auto fo
= cast(TypeFunction
)(originalType ? originalType
: f
);
2527 fparams
.pushSlice((*toRefCopy(fo
.parameterList
))[]);
2528 auto tf
= new TypeFunction(ParameterList(fparams
), Type
.tvoid
, LINK
.d
);
2529 tf
.isnothrow
= f
.isnothrow
;
2530 tf
.isnogc
= f
.isnogc
;
2531 tf
.purity
= f
.purity
;
2533 auto fd
= new FuncDeclaration(loc
, loc
, Id
.ensure
, STC
.undefined_
, tf
);
2535 Statement s1
= new ExpStatement(loc
, fd
);
2536 Expression e
= new CallExp(loc
, new VarExp(loc
, fd
, false), fdensureParams
);
2537 Statement s2
= new ExpStatement(loc
, e
);
2538 fensure
= new CompoundStatement(loc
, s1
, s2
);
2543 /****************************************************
2544 * Merge into this function the 'out' contracts of all it overrides.
2545 * 'out's are AND'd together, i.e. all of them need to pass.
2547 extern (D
) final Statement
mergeFensure(Statement sf
, Identifier oid
, Expressions
* params
)
2549 /* Same comments as for mergeFrequire(), except that we take care
2550 * of generating a consistent reference to the 'result' local by
2551 * explicitly passing 'result' to the nested function as a reference
2553 * This won't work for the 'this' parameter as it would require changing
2554 * the semantic code for the nested function so that it looks on the parameter
2555 * list for the 'this' pointer, something that would need an unknown amount
2556 * of tweaking of various parts of the compiler that I'd rather leave alone.
2558 foreach (fdv
; foverrides
)
2560 /* The semantic pass on the contracts of the overridden functions must
2561 * be completed before code generation occurs.
2562 * https://issues.dlang.org/show_bug.cgi?id=3602 and
2563 * https://issues.dlang.org/show_bug.cgi?id=5230
2565 if (needsFensure(fdv
) && fdv
.semanticRun
!= PASS
.semantic3done
)
2568 Scope
* sc
= fdv
._scope
.push();
2569 sc
.stc &= ~STC
.override_
;
2574 sf
= fdv
.mergeFensure(sf
, oid
, params
);
2577 //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2578 // Make the call: __ensure(result, params)
2579 params
= Expression
.arraySyntaxCopy(params
);
2580 if (canBuildResultVar())
2582 Type t1
= fdv
.type
.nextOf().toBasetype();
2583 Type t2
= this.type
.nextOf().toBasetype();
2584 import dmd
.typesem
: isBaseOf
;
2585 if (t1
.isBaseOf(t2
, null))
2587 /* Making temporary reference variable is necessary
2588 * in covariant return.
2589 * https://issues.dlang.org/show_bug.cgi?id=5204
2590 * https://issues.dlang.org/show_bug.cgi?id=10479
2592 Expression
* eresult
= &(*params
)[0];
2593 auto ei
= new ExpInitializer(Loc
.initial
, *eresult
);
2594 auto v
= new VarDeclaration(Loc
.initial
, t1
, Identifier
.generateId("__covres"), ei
);
2595 v
.storage_class |
= STC
.temp
;
2596 auto de = new DeclarationExp(Loc
.initial
, v
);
2597 auto ve
= new VarExp(Loc
.initial
, v
);
2598 *eresult
= new CommaExp(Loc
.initial
, de, ve
);
2601 Expression e
= new CallExp(loc
, new VarExp(loc
, fdv
.fdensure
, false), params
);
2602 Statement s2
= new ExpStatement(loc
, e
);
2606 sf
= new CompoundStatement(sf
.loc
, s2
, sf
);
2615 /*********************************************
2616 * Returns: the function's parameter list, and whether
2617 * it is variadic or not.
2619 final ParameterList
getParameterList()
2623 TypeFunction fdtype
= type
.isTypeFunction();
2624 if (fdtype
) // Could also be TypeError
2625 return fdtype
.parameterList
;
2628 return ParameterList(null, VarArg
.none
);
2631 /**********************************
2632 * Generate a FuncDeclaration for a runtime library function.
2634 static FuncDeclaration
genCfunc(Parameters
* fparams
, Type treturn
, const(char)* name
, StorageClass
stc = 0)
2636 return genCfunc(fparams
, treturn
, Identifier
.idPool(name
[0 .. strlen(name
)]), stc);
2639 static FuncDeclaration
genCfunc(Parameters
* fparams
, Type treturn
, Identifier id
, StorageClass
stc = 0)
2644 __gshared DsymbolTable st
= null;
2646 //printf("genCfunc(name = '%s')\n", id.toChars());
2647 //printf("treturn\n\t"); treturn.print();
2649 // See if already in table
2651 st
= new DsymbolTable();
2655 fd
= s
.isFuncDeclaration();
2657 assert(fd
.type
.nextOf().equals(treturn
));
2661 tf
= new TypeFunction(ParameterList(fparams
), treturn
, LINK
.c
, stc);
2662 fd
= new FuncDeclaration(Loc
.initial
, Loc
.initial
, id
, STC
.static_
, tf
);
2663 fd
.visibility
= Visibility(Visibility
.Kind
.public_
);
2664 fd
._linkage
= LINK
.c
;
2672 + Checks the parameter and return types iff this is a `main` function.
2674 + The following signatures are allowed for a `D main`:
2675 + - Either no or a single parameter of type `string[]`
2676 + - Return type is either `void`, `int` or `noreturn`
2678 + The following signatures are standard C:
2680 + - `int main(int, char**)`
2682 + This function accepts the following non-standard extensions:
2683 + - `char** envp` as a third parameter
2684 + - `void` / `noreturn` as return type
2686 + This function will issue errors for unexpected arguments / return types.
2688 extern (D
) final void checkMain()
2690 if (ident
!= Id
.main ||
isMember() ||
isNested())
2691 return; // Not a main function
2693 TypeFunction tf
= type
.toTypeFunction();
2695 Type retType
= tf
.nextOf();
2698 // auto main(), check after semantic
2699 assert(this.inferRetType
);
2703 /// Checks whether `t` is equivalent to `char**`
2704 /// Ignores qualifiers and treats enums according to their base type
2705 static bool isCharPtrPtr(Type t
)
2707 auto tp
= t
.toBasetype().isTypePointer();
2711 tp
= tp
.next
.toBasetype().isTypePointer();
2715 return tp
.next
.toBasetype().ty
== Tchar
;
2718 // Neither of these qualifiers is allowed because they affect the ABI
2719 enum invalidSTC
= STC
.out_ | STC
.ref_ | STC
.lazy_
;
2721 const nparams
= tf
.parameterList
.length
;
2724 const linkage
= resolvedLinkage();
2725 if (linkage
== LINK
.d
)
2729 auto fparam0
= tf
.parameterList
[0];
2730 auto t
= fparam0
.type
.toBasetype();
2731 if (t
.ty
!= Tarray ||
2732 t
.nextOf().ty
!= Tarray ||
2733 t
.nextOf().nextOf().ty
!= Tchar ||
2734 fparam0
.storageClass
& invalidSTC
)
2740 if (tf
.parameterList
.varargs || nparams
>= 2 || argerr
)
2741 .error(loc
, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", kind
, toPrettyChars
);
2744 else if (linkage
== LINK
.c
)
2746 if (nparams
== 2 || nparams
== 3)
2748 // Argument count must be int
2749 auto argCount
= tf
.parameterList
[0];
2750 argerr |
= !!(argCount
.storageClass
& invalidSTC
);
2751 argerr |
= argCount
.type
.toBasetype().ty
!= Tint32
;
2753 // Argument pointer must be char**
2754 auto argPtr
= tf
.parameterList
[1];
2755 argerr |
= !!(argPtr
.storageClass
& invalidSTC
);
2756 argerr |
= !isCharPtrPtr(argPtr
.type
);
2758 // `char** environ` is a common extension, see J.5.1 of the C standard
2761 auto envPtr
= tf
.parameterList
[2];
2762 argerr |
= !!(envPtr
.storageClass
& invalidSTC
);
2763 argerr |
= !isCharPtrPtr(envPtr
.type
);
2767 argerr
= nparams
!= 0;
2769 // Disallow variadic main() - except for K&R declarations in C files.
2770 // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
2771 if (tf
.parameterList
.varargs
&& (!this.isCsymbol() ||
(!tf
.parameterList
.hasIdentifierList
&& nparams
)))
2776 .error(loc
, "%s `%s` parameters must match one of the following signatures", kind
, toPrettyChars
);
2777 loc
.errorSupplemental("`main()`");
2778 loc
.errorSupplemental("`main(int argc, char** argv)`");
2779 loc
.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
2783 return; // Neither C nor D main, ignore (should probably be an error)
2785 // Allow enums with appropriate base types (same ABI)
2786 retType
= retType
.toBasetype();
2788 if (retType
.ty
!= Tint32
&& retType
.ty
!= Tvoid
&& retType
.ty
!= Tnoreturn
)
2789 .error(loc
, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", kind
, toPrettyChars
, tf
.nextOf().toChars());
2792 /***********************************************
2793 * Check all return statements for a function to verify that returning
2794 * using NRVO is possible.
2797 * `false` if the result cannot be returned by hidden reference.
2799 extern (D
) final bool checkNRVO()
2801 if (!isNRVO() || returns
is null)
2804 auto tf
= type
.toTypeFunction();
2808 foreach (rs
; *returns
)
2810 if (auto ve
= rs
.exp
.isVarExp())
2812 auto v
= ve
.var
.isVarDeclaration();
2813 if (!v || v
.isReference())
2815 else if (nrvo_var
is null)
2817 // Variables in the data segment (e.g. globals, TLS or not),
2818 // parameters and closure variables cannot be NRVOed.
2819 if (v
.isDataseg() || v
.isParameter() || v
.toParent2() != this)
2821 if (v
.nestedrefs
.length
&& needsClosure())
2823 // don't know if the return storage is aligned
2826 if (alignSectionVars
&& (*alignSectionVars
).contains(v
))
2829 // The variable type needs to be equivalent to the return type.
2830 if (!v
.type
.equivalent(tf
.next
))
2832 //printf("Setting nrvo to %s\n", v.toChars());
2835 else if (nrvo_var
!= v
)
2838 else //if (!exp.isLvalue()) // keep NRVO-ability
2844 override final inout(FuncDeclaration
) isFuncDeclaration() inout
2849 inout(FuncDeclaration
) toAliasFunc() inout
2854 override void accept(Visitor v
)
2860 /********************************************************
2861 * Generate Expression to call the invariant.
2863 * ad aggregate with the invariant
2864 * vthis variable with 'this'
2866 * void expression that calls the invariant
2868 Expression
addInvariant(AggregateDeclaration ad
, VarDeclaration vthis
)
2870 Expression e
= null;
2871 // Call invariant directly only if it exists
2872 FuncDeclaration inv
= ad
.inv
;
2873 ClassDeclaration cd
= ad
.isClassDeclaration();
2886 // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
2887 // For the correct mangling,
2888 // run attribute inference on inv if needed.
2889 functionSemantic(inv
);
2892 //e = new DsymbolExp(Loc.initial, inv);
2893 //e = new CallExp(Loc.initial, e);
2894 //e = e.semantic(sc2);
2896 /* https://issues.dlang.org/show_bug.cgi?id=13113
2897 * Currently virtual invariant calls completely
2898 * bypass attribute enforcement.
2899 * Change the behavior of pre-invariant call by following it.
2901 e
= new ThisExp(Loc
.initial
);
2902 e
.type
= ad
.type
.addMod(vthis
.type
.mod
);
2903 e
= new DotVarExp(Loc
.initial
, e
, inv
, false);
2905 e
= new CallExp(Loc
.initial
, e
);
2906 e
.type
= Type
.tvoid
;
2911 /***************************************************
2912 * Visit each overloaded function/template in turn, and call dg(s) on it.
2913 * Exit when no more, or dg(s) returns nonzero.
2916 * fstart = symbol to start from
2917 * dg = the delegate to be called on the overload
2918 * sc = context used to check if symbol is accessible (and therefore visible),
2923 * !=0 done (and the return value from the last dg() call)
2925 extern (D
) int overloadApply(Dsymbol fstart
, scope int delegate(Dsymbol
) dg
, Scope
* sc
= null)
2929 int overloadApplyRecurse(Dsymbol fstart
, scope int delegate(Dsymbol
) dg
, Scope
* sc
)
2931 // Detect cyclic calls.
2932 if (visited
.contains(fstart
))
2934 visited
.push(fstart
);
2937 for (auto d
= fstart
; d
; d
= next
)
2939 import dmd
.access
: checkSymbolAccess
;
2940 if (auto od
= d
.isOverDeclaration())
2942 /* The scope is needed here to check whether a function in
2943 an overload set was added by means of a private alias (or a
2944 selective import). If the scope where the alias is created
2945 is imported somewhere, the overload set is visible, but the private
2950 if (checkSymbolAccess(sc
, od
))
2952 if (int r
= overloadApplyRecurse(od
.aliassym
, dg
, sc
))
2956 else if (int r
= overloadApplyRecurse(od
.aliassym
, dg
, sc
))
2960 else if (auto fa
= d
.isFuncAliasDeclaration())
2962 if (fa
.hasOverloads
)
2964 if (int r
= overloadApplyRecurse(fa
.funcalias
, dg
, sc
))
2967 else if (auto fd
= fa
.toAliasFunc())
2974 .error(d
.loc
, "%s `%s` is aliased to a function", d
.kind
, d
.toPrettyChars
);
2979 else if (auto ad
= d
.isAliasDeclaration())
2983 if (checkSymbolAccess(sc
, ad
))
2984 next
= ad
.toAlias();
2987 next
= ad
.toAlias();
2993 else if (auto td
= d
.isTemplateDeclaration())
2999 else if (auto fd
= d
.isFuncDeclaration())
3005 else if (auto os
= d
.isOverloadSet())
3013 .error(d
.loc
, "%s `%s` is aliased to a function", d
.kind
, d
.toPrettyChars
);
3015 // BUG: should print error message?
3020 return overloadApplyRecurse(fstart
, dg
, sc
);
3024 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
3025 mismatching modifiers to `buf`.
3027 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
3028 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
3031 buf = output buffer to write to
3032 lhsMod = modifier on the left-hand side
3033 lhsMod = modifier on the right-hand side
3037 A tuple with `isMutable` and `isNotShared` set
3038 if the `lhsMod` is missing those modifiers (compared to rhs).
3040 auto MODMatchToBuffer(OutBuffer
* buf
, ubyte lhsMod
, ubyte rhsMod
)
3042 static struct Mismatches
3048 Mismatches mismatches
;
3050 bool bothMutable
= ((lhsMod
& rhsMod
) == 0);
3051 bool sharedMismatch
= ((lhsMod ^ rhsMod
) & MODFlags
.shared_
) != 0;
3052 bool sharedMismatchOnly
= ((lhsMod ^ rhsMod
) == MODFlags
.shared_
);
3054 if (lhsMod
& MODFlags
.shared_
)
3055 buf
.writestring("`shared` ");
3056 else if (sharedMismatch
&& !(lhsMod
& MODFlags
.immutable_
))
3058 buf
.writestring("non-shared ");
3059 mismatches
.isNotShared
= true;
3062 if (bothMutable
&& sharedMismatchOnly
)
3065 else if (lhsMod
& MODFlags
.immutable_
)
3066 buf
.writestring("`immutable` ");
3067 else if (lhsMod
& MODFlags
.const_
)
3068 buf
.writestring("`const` ");
3069 else if (lhsMod
& MODFlags
.wild
)
3070 buf
.writestring("`inout` ");
3073 buf
.writestring("mutable ");
3074 mismatches
.isMutable
= true;
3084 auto mismatches
= MODMatchToBuffer(&buf
, MODFlags
.shared_
, 0);
3085 assert(buf
[] == "`shared` ");
3086 assert(!mismatches
.isNotShared
);
3089 mismatches
= MODMatchToBuffer(&buf
, 0, MODFlags
.shared_
);
3090 assert(buf
[] == "non-shared ");
3091 assert(mismatches
.isNotShared
);
3094 mismatches
= MODMatchToBuffer(&buf
, MODFlags
.const_
, 0);
3095 assert(buf
[] == "`const` ");
3096 assert(!mismatches
.isMutable
);
3099 mismatches
= MODMatchToBuffer(&buf
, 0, MODFlags
.const_
);
3100 assert(buf
[] == "mutable ");
3101 assert(mismatches
.isMutable
);
3104 /// Flag used by $(LREF resolveFuncCall).
3105 enum FuncResolveFlag
: ubyte
3107 standard
= 0, /// issue error messages, solve the call.
3108 quiet
= 1, /// do not issue error message on no match, just return `null`.
3109 overloadOnly
= 2, /// only resolve overloads, i.e. do not issue error on ambiguous
3110 /// matches and need explicit this.
3111 ufcs
= 4, /// trying to resolve UFCS call
3114 /*******************************************
3115 * Given a symbol that could be either a FuncDeclaration or
3116 * a function template, resolve it to a function symbol.
3118 * loc = instantiation location
3119 * sc = instantiation scope
3120 * s = instantiation symbol
3121 * tiargs = initial list of template arguments
3122 * tthis = if !NULL, the `this` argument type
3123 * argumentList = arguments to function
3124 * flags = see $(LREF FuncResolveFlag).
3126 * if match is found, then function symbol, else null
3128 FuncDeclaration
resolveFuncCall(const ref Loc loc
, Scope
* sc
, Dsymbol s
,
3129 Objects
* tiargs
, Type tthis
, ArgumentList argumentList
, FuncResolveFlag flags
)
3131 auto fargs
= argumentList
.arguments
;
3133 return null; // no match
3137 printf("resolveFuncCall('%s')\n", s
.toChars());
3139 printf("\tthis: %s\n", tthis
.toChars());
3142 for (size_t i
= 0; i
< fargs
.length
; i
++)
3144 Expression arg
= (*fargs
)[i
];
3146 printf("\t%s: %s\n", arg
.toChars(), arg
.type
.toChars());
3149 printf("\tfnames: %s\n", fnames ? fnames
.toChars() : "null");
3152 if (tiargs
&& arrayObjectIsError(*tiargs
))
3155 foreach (arg
; *fargs
)
3160 functionResolve(m
, s
, loc
, sc
, tiargs
, tthis
, argumentList
);
3163 if (m
.last
> MATCH
.nomatch
&& m
.lastf
)
3165 if (m
.count
== 1) // exactly one match
3167 if (!(flags
& FuncResolveFlag
.quiet
))
3168 functionSemantic(m
.lastf
);
3171 if ((flags
& FuncResolveFlag
.overloadOnly
) && !tthis
&& m
.lastf
.needThis())
3177 /* Failed to find a best match.
3178 * Do nothing or print error.
3180 if (m
.last
== MATCH
.nomatch
)
3182 // error was caused on matched function, not on the matching itself,
3183 // so return the function to produce a better diagnostic
3188 // We are done at this point, as the rest of this function generate
3189 // a diagnostic on invalid match
3190 if (flags
& FuncResolveFlag
.quiet
)
3193 auto fd
= s
.isFuncDeclaration();
3194 auto od
= s
.isOverDeclaration();
3195 auto td
= s
.isTemplateDeclaration();
3196 if (td
&& td
.funcroot
)
3197 s
= fd
= td
.funcroot
;
3199 OutBuffer tiargsBuf
;
3200 arrayObjectsToBuffer(tiargsBuf
, tiargs
);
3203 fargsBuf
.writeByte('(');
3204 argExpTypesToCBuffer(fargsBuf
, fargs
);
3205 fargsBuf
.writeByte(')');
3207 tthis
.modToBuffer(fargsBuf
);
3209 // The call is ambiguous
3210 if (m
.lastf
&& m
.nextf
)
3212 TypeFunction tf1
= m
.lastf
.type
.toTypeFunction();
3213 TypeFunction tf2
= m
.nextf
.type
.toTypeFunction();
3214 const(char)* lastprms
= parametersTypeToChars(tf1
.parameterList
);
3215 const(char)* nextprms
= parametersTypeToChars(tf2
.parameterList
);
3217 .error(loc
, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
3218 s
.parent
.toPrettyChars(), s
.ident
.toChars(),
3219 fargsBuf
.peekChars(),
3220 m
.lastf
.loc
.toChars(), m
.lastf
.toPrettyChars(), lastprms
, tf1
.modToChars(),
3221 m
.nextf
.loc
.toChars(), m
.nextf
.toPrettyChars(), nextprms
, tf2
.modToChars());
3225 // no match, generate an error messages
3226 if (flags
& FuncResolveFlag
.ufcs
)
3228 auto arg
= (*fargs
)[0];
3229 .error(loc
, "no property `%s` for `%s` of type `%s`", s
.ident
.toChars(), arg
.toChars(), arg
.type
.toChars());
3230 .errorSupplemental(loc
, "the following error occured while looking for a UFCS match");
3235 // all of overloads are templates
3238 if (!od
&& !td
.overnext
)
3240 .error(loc
, "%s `%s` is not callable using argument types `!(%s)%s`",
3241 td
.kind(), td
.ident
.toChars(), tiargsBuf
.peekChars(), fargsBuf
.peekChars());
3245 .error(loc
, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`",
3246 td
.kind(), td
.parent
.toPrettyChars(), td
.ident
.toChars(),
3247 tiargsBuf
.peekChars(), fargsBuf
.peekChars());
3251 if (!global
.gag || global
.params
.v
.showGaggedErrors
)
3252 printCandidates(loc
, td
, sc
.isDeprecated());
3255 /* This case used to happen when several ctors are mixed in an agregate.
3256 A (bad) error message is already generated in overloadApply().
3257 see https://issues.dlang.org/show_bug.cgi?id=19729
3258 and https://issues.dlang.org/show_bug.cgi?id=17259
3266 .error(loc
, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
3267 od
.ident
.toChars(), tiargsBuf
.peekChars(), fargsBuf
.peekChars());
3271 // remove when deprecation period of class allocators and deallocators is over
3272 if (fd
.isNewDeclaration() && fd
.checkDisabled(loc
, sc
))
3275 bool hasOverloads
= fd
.overnext
!is null;
3276 auto tf
= fd
.type
.isTypeFunction();
3277 // if type is an error, the original type should be there for better diagnostics
3279 tf
= fd
.originalType
.toTypeFunction();
3281 // modifier mismatch
3282 if (tthis
&& (fd
.isCtorDeclaration() ?
3283 !MODimplicitConv(tf
.mod
, tthis
.mod
) :
3284 !MODimplicitConv(tthis
.mod
, tf
.mod
)))
3286 OutBuffer thisBuf
, funcBuf
;
3287 MODMatchToBuffer(&thisBuf
, tthis
.mod
, tf
.mod
);
3288 auto mismatches
= MODMatchToBuffer(&funcBuf
, tf
.mod
, tthis
.mod
);
3292 buf
.argExpTypesToCBuffer(fargs
);
3293 if (fd
.isCtorDeclaration())
3294 .error(loc
, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`",
3295 fd
.toChars(), thisBuf
.peekChars(), buf
.peekChars());
3297 .error(loc
, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`",
3298 fd
.toChars(), thisBuf
.peekChars(), buf
.peekChars());
3300 if (!global
.gag || global
.params
.v
.showGaggedErrors
)
3301 printCandidates(loc
, fd
, sc
.isDeprecated());
3306 void errorHelper(const(char)* failMessage
) scope
3308 .error(loc
, "%s `%s%s%s` is not callable using argument types `%s`",
3309 fd
.kind(), fd
.toPrettyChars(), parametersTypeToChars(tf
.parameterList
),
3310 tf
.modToChars(), fargsBuf
.peekChars());
3311 errorSupplemental(loc
, failMessage
);
3312 calledHelper
= true;
3315 functionResolve(m
, orig_s
, loc
, sc
, tiargs
, tthis
, argumentList
, &errorHelper
);
3319 if (fd
.isCtorDeclaration())
3320 .error(loc
, "%s%s `%s` cannot construct a %sobject",
3321 funcBuf
.peekChars(), fd
.kind(), fd
.toPrettyChars(), thisBuf
.peekChars());
3323 .error(loc
, "%smethod `%s` is not callable using a %sobject",
3324 funcBuf
.peekChars(), fd
.toPrettyChars(), thisBuf
.peekChars());
3326 if (mismatches
.isNotShared
)
3327 .errorSupplemental(fd
.loc
, "Consider adding `shared` here");
3328 else if (mismatches
.isMutable
)
3329 .errorSupplemental(fd
.loc
, "Consider adding `const` or `inout` here");
3333 //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
3336 .error(loc
, "none of the overloads of `%s` are callable using argument types `%s`",
3337 fd
.toChars(), fargsBuf
.peekChars());
3338 if (!global
.gag || global
.params
.v
.showGaggedErrors
)
3339 printCandidates(loc
, fd
, sc
.isDeprecated());
3343 .error(loc
, "%s `%s%s%s` is not callable using argument types `%s`",
3344 fd
.kind(), fd
.toPrettyChars(), parametersTypeToChars(tf
.parameterList
),
3345 tf
.modToChars(), fargsBuf
.peekChars());
3347 // re-resolve to check for supplemental message
3348 if (!global
.gag || global
.params
.v
.showGaggedErrors
)
3352 if (auto classType
= tthis
.isTypeClass())
3354 if (auto baseClass
= classType
.sym
.baseClass
)
3356 if (auto baseFunction
= baseClass
.search(baseClass
.loc
, fd
.ident
))
3358 MatchAccumulator mErr
;
3359 functionResolve(mErr
, baseFunction
, loc
, sc
, tiargs
, baseClass
.type
, argumentList
);
3360 if (mErr
.last
> MATCH
.nomatch
&& mErr
.lastf
)
3362 errorSupplemental(loc
, "%s `%s` hides base class function `%s`",
3363 fd
.kind
, fd
.toPrettyChars(), mErr
.lastf
.toPrettyChars());
3364 errorSupplemental(loc
, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
3365 fd
.toChars(), mErr
.lastf
.toPrettyChars(), tthis
.toChars());
3373 void errorHelper2(const(char)* failMessage
) scope
3375 errorSupplemental(loc
, failMessage
);
3378 functionResolve(m
, orig_s
, loc
, sc
, tiargs
, tthis
, argumentList
, &errorHelper2
);
3383 /*******************************************
3384 * Prints template and function overload candidates as supplemental errors.
3386 * loc = instantiation location
3387 * declaration = the declaration to print overload candidates for
3388 * showDeprecated = If `false`, `deprecated` function won't be shown
3390 private void printCandidates(Decl
)(const ref Loc loc
, Decl declaration
, bool showDeprecated
)
3391 if (is(Decl
== TemplateDeclaration
) ||
is(Decl
== FuncDeclaration
))
3393 // max num of overloads to print (-v or -verror-supplements overrides this).
3394 const uint DisplayLimit
= global
.params
.v
.errorSupplementCount();
3395 const(char)* constraintsTip
;
3396 // determine if the first candidate was printed
3399 bool matchSymbol(Dsymbol s
, bool print
, bool single_candidate
= false)
3401 if (auto fd
= s
.isFuncDeclaration())
3403 // Don't print overloads which have errors.
3404 // Not that if the whole overload set has errors, we'll never reach
3405 // this point so there's no risk of printing no candidate
3406 if (fd
.errors || fd
.type
.ty
== Terror
)
3408 // Don't print disabled functions, or `deprecated` outside of deprecated scope
3409 if (fd
.storage_class
& STC
.disable ||
(fd
.isDeprecated() && !showDeprecated
))
3413 auto tf
= cast(TypeFunction
) fd
.type
;
3415 buf
.writestring(fd
.toPrettyChars());
3416 buf
.writestring(parametersTypeToChars(tf
.parameterList
));
3420 buf
.MODtoBuffer(tf
.mod
);
3422 .errorSupplemental(fd
.loc
,
3424 single_candidate ?
"Candidate is: `%s`" : "Candidates are: `%s`", buf
.peekChars());
3426 else if (auto td
= s
.isTemplateDeclaration())
3428 import dmd
.staticcond
;
3434 hgs
.skipConstraints
= true;
3435 toCharsMaybeConstraints(td
, buf
, hgs
);
3436 const tmsg
= buf
.peekChars();
3437 const cmsg
= td
.getConstraintEvalError(constraintsTip
);
3439 // add blank space if there are multiple candidates
3440 // the length of the blank space is `strlen("Candidates are: ")`
3444 .errorSupplemental(td
.loc
,
3445 printed ?
" `%s`\n%s" :
3446 single_candidate ?
"Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
3451 .errorSupplemental(td
.loc
,
3453 single_candidate ?
"Candidate is: `%s`" : "Candidates are: `%s`",
3459 // determine if there's > 1 candidate
3461 overloadApply(declaration
, (s
) {
3462 if (matchSymbol(s
, false))
3467 overloadApply(declaration
, (s
) {
3468 if (global
.params
.v
.verbose || printed
< DisplayLimit
)
3470 if (matchSymbol(s
, true, count
== 1))
3475 // Too many overloads to sensibly display.
3476 // Just show count of remaining overloads.
3477 if (matchSymbol(s
, false))
3483 .errorSupplemental(loc
, "... (%d more, -v to show) ...", skipped
);
3485 // Nothing was displayed, all overloads are either disabled or deprecated
3487 .errorSupplemental(loc
, "All possible candidates are marked as `deprecated` or `@disable`");
3488 // should be only in verbose mode
3490 .tip(constraintsTip
);
3493 /**************************************
3494 * Returns an indirect type one step from t.
3496 Type
getIndirection(Type t
)
3498 import dmd
.typesem
: hasPointers
;
3500 if (t
.ty
== Tarray || t
.ty
== Tpointer
)
3501 return t
.nextOf().toBasetype();
3502 if (t
.ty
== Taarray || t
.ty
== Tclass
)
3504 if (t
.ty
== Tstruct
)
3505 return t
.hasPointers() ? t
: null; // TODO
3507 // should consider TypeDelegate?
3511 /**************************************
3512 * Performs type-based alias analysis between a newly created value and a pre-
3513 * existing memory reference:
3515 * Assuming that a reference A to a value of type `ta` was available to the code
3516 * that created a reference B to a value of type `tb`, it returns whether B
3517 * might alias memory reachable from A based on the types involved (either
3518 * directly or via any number of indirections in either A or B).
3520 * This relation is not symmetric in the two arguments. For example, a
3521 * a `const(int)` reference can point to a pre-existing `int`, but not the other
3527 * `const(int)`, `int`, `false`
3528 * `int`, `const(int)`, `true`
3529 * `int`, `immutable(int)`, `false`
3530 * const(immutable(int)*), immutable(int)*, false // BUG: returns true
3533 * ta = value type being referred to
3534 * tb = referred to value type that could be constructed from ta
3537 * true if reference to `tb` is isolated from reference to `ta`
3539 private bool traverseIndirections(Type ta
, Type tb
)
3541 //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
3543 static bool traverse(Type ta
, Type tb
, ref scope AssocArray
!(const(char)*, bool) table
, bool reversePass
)
3545 import dmd
.typesem
: hasPointers
;
3546 //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
3547 ta
= ta
.baseElemOf();
3548 tb
= tb
.baseElemOf();
3550 // First, check if the pointed-to types are convertible to each other such
3551 // that they might alias directly.
3552 static bool mayAliasDirect(Type source
, Type target
)
3555 // if source is the same as target or can be const-converted to target
3556 source
.constConv(target
) != MATCH
.nomatch ||
3557 // if target is void and source can be const-converted to target
3558 (target
.ty
== Tvoid
&& MODimplicitConv(source
.mod
, target
.mod
));
3561 if (mayAliasDirect(reversePass ? tb
: ta
, reversePass ? ta
: tb
))
3563 //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3566 if (ta
.nextOf() && ta
.nextOf() == tb
.nextOf())
3568 //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3572 if (tb
.ty
== Tclass || tb
.ty
== Tstruct
)
3574 /* Traverse the type of each field of the aggregate
3576 bool* found
= table
.getLvalue(tb
.deco
);
3578 return true; // We have already seen this symbol, break the cycle
3582 import dmd
.typesem
: toDsymbol
;
3583 AggregateDeclaration sym
= tb
.toDsymbol(null).isAggregateDeclaration();
3584 foreach (v
; sym
.fields
)
3586 Type tprmi
= v
.type
.addMod(tb
.mod
);
3587 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
3588 if (!traverse(ta
, tprmi
, table
, reversePass
))
3592 else if (tb
.ty
== Tarray || tb
.ty
== Taarray || tb
.ty
== Tpointer
)
3594 Type tind
= tb
.nextOf();
3595 if (!traverse(ta
, tind
, table
, reversePass
))
3598 else if (tb
.hasPointers())
3600 // BUG: consider the context pointer of delegate types
3604 // Still no match, so try breaking up ta if we have not done so yet.
3607 scope newTable
= AssocArray
!(const(char)*, bool)();
3608 return traverse(tb
, ta
, newTable
, true);
3614 // To handle arbitrary levels of indirections in both parameters, we
3615 // recursively descend into aggregate members/levels of indirection in both
3616 // `ta` and `tb` while avoiding cycles. Start with the original types.
3617 scope table
= AssocArray
!(const(char)*, bool)();
3618 const result
= traverse(ta
, tb
, table
, false);
3619 //printf(" returns %d\n", result);
3623 /* For all functions between outerFunc and f, mark them as needing
3626 private void markAsNeedingClosure(Dsymbol f
, FuncDeclaration outerFunc
)
3628 for (Dsymbol sx
= f
; sx
&& sx
!= outerFunc
; sx
= sx
.toParentP(outerFunc
))
3630 FuncDeclaration fy
= sx
.isFuncDeclaration();
3631 if (fy
&& fy
.closureVars
.length
)
3633 /* fy needs a closure if it has closureVars[],
3634 * because the frame pointer in the closure will be accessed.
3636 fy
.requiresClosure
= true;
3642 * Given a nested function f inside a function outerFunc, check
3643 * if any sibling callers of f have escaped. If so, mark
3644 * all the enclosing functions as needing closures.
3645 * This is recursive: we need to check the callers of our siblings.
3646 * Note that nested functions can only call lexically earlier nested
3647 * functions, so loops are impossible.
3649 * f = inner function (nested within outerFunc)
3650 * outerFunc = outer function
3651 * p = for internal recursion use
3653 * true if any closures were needed
3655 private bool checkEscapingSiblings(FuncDeclaration f
, FuncDeclaration outerFunc
, void* p
= null)
3657 static struct PrevSibling
3663 if (f
.computedEscapingSiblings
)
3664 return f
.hasEscapingSiblings
;
3667 ps
.p
= cast(PrevSibling
*)p
;
3670 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
3671 bool bAnyClosures
= false;
3672 for (size_t i
= 0; i
< f
.siblingCallers
.length
; ++i
)
3674 FuncDeclaration g
= f
.siblingCallers
[i
];
3675 if (g
.isThis() || g
.tookAddressOf
)
3677 markAsNeedingClosure(g
, outerFunc
);
3678 bAnyClosures
= true;
3681 for (auto parent
= g
.toParentP(outerFunc
); parent
&& parent
!is outerFunc
; parent
= parent
.toParentP(outerFunc
))
3683 // A parent of the sibling had its address taken.
3684 // Assume escaping of parent affects its children, so needs propagating.
3685 // see https://issues.dlang.org/show_bug.cgi?id=19679
3686 FuncDeclaration parentFunc
= parent
.isFuncDeclaration
;
3687 if (parentFunc
&& parentFunc
.tookAddressOf
)
3689 markAsNeedingClosure(parentFunc
, outerFunc
);
3690 bAnyClosures
= true;
3694 PrevSibling
* prev
= cast(PrevSibling
*)p
;
3699 bAnyClosures |
= checkEscapingSiblings(g
, outerFunc
, &ps
);
3707 f
.hasEscapingSiblings
= bAnyClosures
;
3708 f
.computedEscapingSiblings
= true;
3709 //printf("\t%d\n", bAnyClosures);
3710 return bAnyClosures
;
3713 /***********************************************************
3714 * Used as a way to import a set of functions from another scope into this one.
3716 extern (C
++) final class FuncAliasDeclaration
: FuncDeclaration
3718 FuncDeclaration funcalias
;
3721 extern (D
) this(Identifier ident
, FuncDeclaration funcalias
, bool hasOverloads
= true)
3723 super(funcalias
.loc
, funcalias
.endloc
, ident
, funcalias
.storage_class
, funcalias
.type
);
3724 assert(funcalias
!= this);
3725 this.funcalias
= funcalias
;
3727 this.hasOverloads
= hasOverloads
;
3730 if (FuncAliasDeclaration fad
= funcalias
.isFuncAliasDeclaration())
3731 this.hasOverloads
= fad
.hasOverloads
;
3736 assert(!funcalias
.isFuncAliasDeclaration());
3737 this.hasOverloads
= false;
3739 userAttribDecl
= funcalias
.userAttribDecl
;
3742 override inout(FuncAliasDeclaration
) isFuncAliasDeclaration() inout
3747 override const(char)* kind() const
3749 return "function alias";
3752 override inout(FuncDeclaration
) toAliasFunc() inout
3754 return funcalias
.toAliasFunc();
3757 override void accept(Visitor v
)
3763 /***********************************************************
3765 extern (C
++) final class FuncLiteralDeclaration
: FuncDeclaration
3767 TOK tok
; // TOK.function_ or TOK.delegate_
3768 Type treq
; // target of return type inference
3773 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, Type type
, TOK tok
, ForeachStatement fes
, Identifier id
= null, StorageClass storage_class
= STC
.undefined_
)
3775 super(loc
, endloc
, null, storage_class
, type
);
3776 this.ident
= id ? id
: Id
.empty
;
3779 // Always infer scope for function literals
3780 // See https://issues.dlang.org/show_bug.cgi?id=20362
3781 this.inferScope
= true;
3782 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
3785 override FuncLiteralDeclaration
syntaxCopy(Dsymbol s
)
3787 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
3789 auto f
= new FuncLiteralDeclaration(loc
, endloc
, type
.syntaxCopy(), tok
, fes
, ident
, storage_class
& STC
.auto_
);
3790 f
.treq
= treq
; // don't need to copy
3791 FuncDeclaration
.syntaxCopy(f
);
3795 override bool isNested() const
3797 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
3798 return (tok
!= TOK
.function_
) && !isThis();
3801 override inout(AggregateDeclaration
) isThis() inout
3803 return tok
== TOK
.delegate_ ?
super.isThis() : null;
3806 override bool isVirtual() const
3811 override bool addPreInvariant()
3816 override bool addPostInvariant()
3821 /*******************************
3822 * Modify all expression type of return statements to tret.
3824 * On function literals, return type may be modified based on the context type
3825 * after its semantic3 is done, in FuncExp::implicitCastTo.
3827 * A function() dg = (){ return new B(); } // OK if is(B : A) == true
3829 * If B to A conversion is convariant that requires offseet adjusting,
3830 * all return statements should be adjusted to return expressions typed A.
3832 extern (D
) void modifyReturns(Scope
* sc
, Type tret
)
3834 import dmd
.statement_rewrite_walker
;
3836 extern (C
++) final class RetWalker
: StatementRewriteWalker
3838 alias visit
= typeof(super).visit
;
3842 FuncLiteralDeclaration
fld;
3844 override void visit(ReturnStatement s
)
3846 Expression exp
= s
.exp
;
3847 if (exp
&& !exp
.type
.equals(tret
))
3848 s
.exp
= exp
.implicitCastTo(sc
, tret
);
3852 if (semanticRun
< PASS
.semantic3done
)
3858 scope RetWalker w
= new RetWalker();
3864 // Also update the inferred function type to match the new return type.
3865 // This is required so the code generator does not try to cast the
3866 // modified returns back to the original type.
3867 if (inferRetType
&& type
.nextOf() != tret
)
3868 type
.toTypeFunction().next
= tret
;
3871 override inout(FuncLiteralDeclaration
) isFuncLiteralDeclaration() inout
3876 override const(char)* kind() const
3878 // GCC requires the (char*) casts
3879 return (tok
!= TOK
.function_
) ?
"delegate" : "function";
3882 override const(char)* toPrettyChars(bool QualifyTypes
= false)
3886 TemplateInstance ti
= parent
.isTemplateInstance();
3888 return ti
.tempdecl
.toPrettyChars(QualifyTypes
);
3890 return Dsymbol
.toPrettyChars(QualifyTypes
);
3893 override void accept(Visitor v
)
3899 /***********************************************************
3901 extern (C
++) final class CtorDeclaration
: FuncDeclaration
3904 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc, Type type
, bool isCpCtor
= false)
3906 super(loc
, endloc
, Id
.ctor
, stc, type
);
3907 this.isCpCtor
= isCpCtor
;
3908 //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
3911 override CtorDeclaration
syntaxCopy(Dsymbol s
)
3914 auto f
= new CtorDeclaration(loc
, endloc
, storage_class
, type
.syntaxCopy());
3915 FuncDeclaration
.syntaxCopy(f
);
3919 override const(char)* kind() const
3921 return isCpCtor ?
"copy constructor" : "constructor";
3924 override const(char)* toChars() const
3929 override bool isVirtual() const
3934 override bool addPreInvariant()
3939 override bool addPostInvariant()
3941 return (isThis() && vthis
&& global
.params
.useInvariants
== CHECKENABLE
.on
);
3944 override inout(CtorDeclaration
) isCtorDeclaration() inout
3949 override void accept(Visitor v
)
3955 /***********************************************************
3957 extern (C
++) final class PostBlitDeclaration
: FuncDeclaration
3959 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc, Identifier id
)
3961 super(loc
, endloc
, id
, stc, null);
3964 override PostBlitDeclaration
syntaxCopy(Dsymbol s
)
3967 auto dd = new PostBlitDeclaration(loc
, endloc
, storage_class
, ident
);
3968 FuncDeclaration
.syntaxCopy(dd);
3972 override bool isVirtual() const
3977 override bool addPreInvariant()
3982 override bool addPostInvariant()
3984 return (isThis() && vthis
&& global
.params
.useInvariants
== CHECKENABLE
.on
);
3987 override bool overloadInsert(Dsymbol s
)
3989 return false; // cannot overload postblits
3992 override inout(PostBlitDeclaration
) isPostBlitDeclaration() inout
3997 override void accept(Visitor v
)
4003 /***********************************************************
4005 extern (C
++) final class DtorDeclaration
: FuncDeclaration
4007 extern (D
) this(const ref Loc loc
, const ref Loc endloc
)
4009 super(loc
, endloc
, Id
.dtor
, STC
.undefined_
, null);
4012 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc, Identifier id
)
4014 super(loc
, endloc
, id
, stc, null);
4017 override DtorDeclaration
syntaxCopy(Dsymbol s
)
4020 auto dd = new DtorDeclaration(loc
, endloc
, storage_class
, ident
);
4021 FuncDeclaration
.syntaxCopy(dd);
4025 override const(char)* kind() const
4027 return "destructor";
4030 override const(char)* toChars() const
4035 override bool isVirtual() const
4037 // D dtor's don't get put into the vtbl[]
4038 // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
4039 return vtblIndex
!= -1;
4042 override bool addPreInvariant()
4044 return (isThis() && vthis
&& global
.params
.useInvariants
== CHECKENABLE
.on
);
4047 override bool addPostInvariant()
4052 override bool overloadInsert(Dsymbol s
)
4054 return false; // cannot overload destructors
4057 override inout(DtorDeclaration
) isDtorDeclaration() inout
4062 override void accept(Visitor v
)
4068 /***********************************************************
4070 extern (C
++) class StaticCtorDeclaration
: FuncDeclaration
4072 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc)
4074 super(loc
, endloc
, Identifier
.generateIdWithLoc("_staticCtor", loc
), STC
.static_ |
stc, null);
4077 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, string name
, StorageClass
stc)
4079 super(loc
, endloc
, Identifier
.generateIdWithLoc(name
, loc
), STC
.static_ |
stc, null);
4082 override StaticCtorDeclaration
syntaxCopy(Dsymbol s
)
4085 auto scd
= new StaticCtorDeclaration(loc
, endloc
, storage_class
);
4086 FuncDeclaration
.syntaxCopy(scd
);
4090 override final inout(AggregateDeclaration
) isThis() inout @nogc nothrow pure @safe
4095 override final bool isVirtual() const @nogc nothrow pure @safe
4100 override final bool addPreInvariant() @nogc nothrow pure @safe
4105 override final bool addPostInvariant() @nogc nothrow pure @safe
4110 override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
4115 override final inout(StaticCtorDeclaration
) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
4120 override void accept(Visitor v
)
4126 /***********************************************************
4128 extern (C
++) final class SharedStaticCtorDeclaration
: StaticCtorDeclaration
4130 /// Exclude this constructor from cyclic dependency check
4133 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc)
4135 super(loc
, endloc
, "_sharedStaticCtor", stc);
4138 override SharedStaticCtorDeclaration
syntaxCopy(Dsymbol s
)
4141 auto scd
= new SharedStaticCtorDeclaration(loc
, endloc
, storage_class
);
4142 FuncDeclaration
.syntaxCopy(scd
);
4146 override inout(SharedStaticCtorDeclaration
) isSharedStaticCtorDeclaration() inout
4151 override void accept(Visitor v
)
4157 /***********************************************************
4159 extern (C
++) class StaticDtorDeclaration
: FuncDeclaration
4161 VarDeclaration vgate
; // 'gate' variable
4163 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc)
4165 super(loc
, endloc
, Identifier
.generateIdWithLoc("_staticDtor", loc
), STC
.static_ |
stc, null);
4168 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, string name
, StorageClass
stc)
4170 super(loc
, endloc
, Identifier
.generateIdWithLoc(name
, loc
), STC
.static_ |
stc, null);
4173 override StaticDtorDeclaration
syntaxCopy(Dsymbol s
)
4176 auto sdd
= new StaticDtorDeclaration(loc
, endloc
, storage_class
);
4177 FuncDeclaration
.syntaxCopy(sdd
);
4181 override final inout(AggregateDeclaration
) isThis() inout
4186 override final bool isVirtual() const
4191 override final bool hasStaticCtorOrDtor()
4196 override final bool addPreInvariant()
4201 override final bool addPostInvariant()
4206 override final inout(StaticDtorDeclaration
) isStaticDtorDeclaration() inout
4211 override void accept(Visitor v
)
4217 /***********************************************************
4219 extern (C
++) final class SharedStaticDtorDeclaration
: StaticDtorDeclaration
4221 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc)
4223 super(loc
, endloc
, "_sharedStaticDtor", stc);
4226 override SharedStaticDtorDeclaration
syntaxCopy(Dsymbol s
)
4229 auto sdd
= new SharedStaticDtorDeclaration(loc
, endloc
, storage_class
);
4230 FuncDeclaration
.syntaxCopy(sdd
);
4234 override inout(SharedStaticDtorDeclaration
) isSharedStaticDtorDeclaration() inout
4239 override void accept(Visitor v
)
4245 /***********************************************************
4247 extern (C
++) final class InvariantDeclaration
: FuncDeclaration
4249 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc, Identifier id
, Statement fbody
)
4251 // Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list.
4252 super(loc
, endloc
, id ? id
: Identifier
.generateId("__invariant"), stc, null);
4256 override InvariantDeclaration
syntaxCopy(Dsymbol s
)
4259 auto id
= new InvariantDeclaration(loc
, endloc
, storage_class
, null, null);
4260 FuncDeclaration
.syntaxCopy(id
);
4264 override bool isVirtual() const
4269 override bool addPreInvariant()
4274 override bool addPostInvariant()
4279 override inout(InvariantDeclaration
) isInvariantDeclaration() inout
4284 override void accept(Visitor v
)
4289 extern (D
) void fixupInvariantIdent(size_t offset
)
4292 idBuf
.writestring("__invariant");
4293 idBuf
.print(offset
);
4295 ident
= Identifier
.idPool(idBuf
[]);
4300 /***********************************************************
4302 extern (C
++) final class UnitTestDeclaration
: FuncDeclaration
4304 char* codedoc
; // for documented unittest
4306 // toObjFile() these nested functions after this one
4307 FuncDeclarations deferredNested
;
4309 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc, char* codedoc
)
4311 super(loc
, endloc
, Identifier
.generateIdWithLoc("__unittest", loc
), stc, null);
4312 this.codedoc
= codedoc
;
4315 override UnitTestDeclaration
syntaxCopy(Dsymbol s
)
4318 auto utd
= new UnitTestDeclaration(loc
, endloc
, storage_class
, codedoc
);
4319 FuncDeclaration
.syntaxCopy(utd
);
4323 override inout(AggregateDeclaration
) isThis() inout
4328 override bool isVirtual() const
4333 override bool addPreInvariant()
4338 override bool addPostInvariant()
4343 override inout(UnitTestDeclaration
) isUnitTestDeclaration() inout
4348 override void accept(Visitor v
)
4354 /***********************************************************
4356 extern (C
++) final class NewDeclaration
: FuncDeclaration
4358 extern (D
) this(const ref Loc loc
, StorageClass
stc)
4360 super(loc
, Loc
.initial
, Id
.classNew
, STC
.static_ |
stc, null);
4363 override NewDeclaration
syntaxCopy(Dsymbol s
)
4366 auto f
= new NewDeclaration(loc
, storage_class
);
4367 FuncDeclaration
.syntaxCopy(f
);
4371 override const(char)* kind() const
4376 override bool isVirtual() const
4381 override bool addPreInvariant()
4386 override bool addPostInvariant()
4391 override inout(NewDeclaration
) isNewDeclaration() inout
4396 override void accept(Visitor v
)
4402 /**************************************
4403 * When a traits(compiles) is used on a function literal call
4404 * we need to take into account if the body of the function
4405 * violates any attributes, however, we must not affect the
4406 * attribute inference on the outer function. The attributes
4407 * of the function literal still need to be inferred, therefore
4408 * we need a way to check for the scope that the traits compiles
4412 * sc = scope to be checked for
4414 * Returns: `true` if the provided scope is the root
4415 * of the traits compiles list of scopes.
4417 bool isRootTraitsCompilesScope(Scope
* sc
)
4419 return (sc
.flags
& SCOPE
.compile
) && !(sc
.func
.flags
& SCOPE
.compile
);
4422 /**************************************
4423 * A statement / expression in this scope is not `@safe`,
4424 * so mark the enclosing function as `@system`
4427 * sc = scope that the unsafe statement / expression is in
4428 * gag = surpress error message (used in escape.d)
4429 * loc = location of error
4430 * fmt = printf-style format string
4431 * arg0 = (optional) argument for first %s format specifier
4432 * arg1 = (optional) argument for second %s format specifier
4433 * arg2 = (optional) argument for third %s format specifier
4434 * Returns: whether there's a safe error
4436 bool setUnsafe(Scope
* sc
,
4437 bool gag
= false, Loc loc
= Loc
.init
, const(char)* fmt
= null,
4438 RootObject arg0
= null, RootObject arg1
= null, RootObject arg2
= null)
4441 return false; // typeof(cast(int*)0) is safe
4443 if (sc
.flags
& SCOPE
.debug_
) // debug {} scopes are permissive
4450 if (sc
.varDecl
.storage_class
& STC
.safe
)
4452 .error(loc
, fmt
, arg0 ? arg0
.toChars() : "", arg1 ? arg1
.toChars() : "", arg2 ? arg2
.toChars() : "");
4455 else if (!(sc
.varDecl
.storage_class
& STC
.trusted
))
4457 sc
.varDecl
.storage_class |
= STC
.system
;
4458 sc
.varDecl
.systemInferred
= true;
4465 if (isRootTraitsCompilesScope(sc
)) // __traits(compiles, x)
4467 if (sc
.func
.isSafeBypassingInference())
4469 // Message wil be gagged, but still call error() to update global.errors and for
4471 .error(loc
, fmt
, arg0 ? arg0
.toChars() : "", arg1 ? arg1
.toChars() : "", arg2 ? arg2
.toChars() : "");
4477 return sc
.func
.setUnsafe(gag
, loc
, fmt
, arg0
, arg1
, arg2
);
4480 /***************************************
4481 * Like `setUnsafe`, but for safety errors still behind preview switches
4483 * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
4484 * the behavior changes based on the setting:
4486 * - In case of `-revert=fs`, it does nothing.
4487 * - In case of `-preview=fs`, it's the same as `setUnsafe`
4488 * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
4491 * sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
4492 * fs = feature state from the preview flag
4493 * gag = surpress error message
4494 * loc = location of error
4495 * msg = printf-style format string
4496 * arg0 = (optional) argument for first %s format specifier
4497 * arg1 = (optional) argument for second %s format specifier
4498 * arg2 = (optional) argument for third %s format specifier
4499 * Returns: whether an actual safe error (not deprecation) occured
4501 bool setUnsafePreview(Scope
* sc
, FeatureState fs
, bool gag
, Loc loc
, const(char)* msg
,
4502 RootObject arg0
= null, RootObject arg1
= null, RootObject arg2
= null)
4504 //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
4505 with (FeatureState
) final switch (fs
)
4511 return sc
.setUnsafe(gag
, loc
, msg
, arg0
, arg1
, arg2
);
4516 if (sc
.func
.isSafeBypassingInference())
4520 warning(loc
, msg
, arg0 ? arg0
.toChars() : "", arg1 ? arg1
.toChars() : "", arg2 ? arg2
.toChars() : "");
4523 else if (!sc
.func
.safetyViolation
)
4525 import dmd
.func
: AttributeViolation
;
4526 sc
.func
.safetyViolation
= new AttributeViolation(loc
, msg
, arg0
, arg1
, arg2
);
4532 /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
4535 /// - a regular safety error, stored in (fmtStr, arg0, arg1)
4536 /// - a call to a function without the attribute, which is a special case, because in that case,
4537 /// that function might recursively also have a `AttributeViolation`. This way, in case
4538 /// of a big call stack, the error can go down all the way to the root cause.
4539 /// The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`.
4540 struct AttributeViolation
4542 /// location of error
4544 /// printf-style format string
4545 const(char)* fmtStr
= null;
4546 /// Arguments for up to two `%s` format specifiers in format string
4547 RootObject arg0
= null;
4549 RootObject arg1
= null;
4551 RootObject arg2
= null;
4554 /// Print the reason why `fd` was inferred `@system` as a supplemental error
4556 /// fd = function to check
4557 /// maxDepth = up to how many functions deep to report errors
4558 /// deprecation = print deprecations instead of errors
4559 /// stc = storage class of attribute to check
4560 void errorSupplementalInferredAttr(FuncDeclaration fd
, int maxDepth
, bool deprecation
, STC
stc)
4562 auto errorFunc
= deprecation ?
&deprecationSupplemental
: &errorSupplemental
;
4564 AttributeViolation
* s
;
4568 s
= fd
.safetyViolation
;
4571 else if (stc & STC
.pure_
)
4573 s
= fd
.pureViolation
;
4576 else if (stc & STC
.nothrow_
)
4578 s
= fd
.nothrowViolation
;
4581 else if (stc & STC
.nogc
)
4583 s
= fd
.nogcViolation
;
4591 errorFunc(s
.loc
, deprecation ?
4592 "which wouldn't be `%s` because of:" :
4593 "which wasn't inferred `%s` because of:", attr
);
4594 if (stc == STC
.nogc ||
stc == STC
.pure_
)
4596 auto f
= (cast(Dsymbol
) s
.arg0
).isFuncDeclaration();
4597 errorFunc(s
.loc
, s
.fmtStr
, f
.kind(), f
.toPrettyChars(), s
.arg1 ? s
.arg1
.toChars() : "");
4601 errorFunc(s
.loc
, s
.fmtStr
,
4602 s
.arg0 ? s
.arg0
.toChars() : "", s
.arg1 ? s
.arg1
.toChars() : "", s
.arg2 ? s
.arg2
.toChars() : "");
4605 else if (auto sa
= s
.arg0
.isDsymbol())
4607 if (FuncDeclaration fd2
= sa
.isFuncDeclaration())
4611 errorFunc(s
.loc
, "which calls `%s`", fd2
.toPrettyChars());
4612 errorSupplementalInferredAttr(fd2
, maxDepth
- 1, deprecation
, stc);