2 * Defines a function declaration.
5 * - function/delegate literals
7 * - (static/shared) constructors/destructors/post-blits
11 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
12 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
13 * License: $(LINK2 http://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
;
29 import dmd
.declaration
;
30 import dmd
.delegatize
;
31 import dmd
.dinterpret
;
36 import dmd
.dsymbolsem
;
40 import dmd
.expression
;
44 import dmd
.identifier
;
49 import dmd
.common
.outbuffer
;
50 import dmd
.root
.rootobject
;
51 import dmd
.root
.string
;
52 import dmd
.root
.stringtable
;
55 import dmd
.statement_rewrite_walker
;
57 import dmd
.statementsem
;
64 uninitialized
, /// not computed yet
71 unknown
= 255, /// not known if this is a builtin
72 unimp
= 0, /// this is not a builtin
73 gcc
, /// this is a GCC builtin
74 llvm
, /// this is an LLVM builtin
110 /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
112 extern (C
++) final class NrvoWalker
: StatementRewriteWalker
114 alias visit
= typeof(super).visit
;
119 override void visit(ReturnStatement s
)
121 // See if all returns are instead to be replaced with a goto returnLabel;
127 * vresult = exp; goto Lresult;
129 auto gs
= new GotoStatement(s
.loc
, Id
.returnLabel
);
130 gs
.label
= fd
.returnLabel
;
134 s1
= new CompoundStatement(s
.loc
, new ExpStatement(s
.loc
, s
.exp
), gs
);
140 override void visit(TryFinallyStatement s
)
142 DtorExpStatement des
;
143 if (fd
.nrvo_can
&& s
.finalbody
&& (des
= s
.finalbody
.isDtorExpStatement()) !is null &&
144 fd
.nrvo_var
== des
.var
)
146 if (!(global
.params
.useExceptions
&& ClassDeclaration
.throwable
))
148 /* Don't need to call destructor at all, since it is nrvo
150 replaceCurrent(s
._body
);
151 s
._body
.accept(this);
155 /* Normally local variable dtors are called regardless exceptions.
156 * But for nrvo_var, its dtor should be called only when exception is thrown.
159 * try { s.body; } finally { nrvo_var.edtor; }
160 * // equivalent with:
161 * // s.body; scope(exit) nrvo_var.edtor;
163 * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
164 * // equivalent with:
165 * // s.body; scope(failure) nrvo_var.edtor;
167 Statement sexception
= new DtorExpStatement(Loc
.initial
, fd
.nrvo_var
.edtor
, fd
.nrvo_var
);
168 Identifier id
= Identifier
.generateId("__o");
170 Statement handler
= new PeelStatement(sexception
);
171 if (sexception
.blockExit(fd
, false) & BE
.fallthru
)
173 auto ts
= new ThrowStatement(Loc
.initial
, new IdentifierExp(Loc
.initial
, id
));
174 ts
.internalThrow
= true;
175 handler
= new CompoundStatement(Loc
.initial
, handler
, ts
);
178 auto catches
= new Catches();
179 auto ctch
= new Catch(Loc
.initial
, getThrowable(), id
, handler
);
180 ctch
.internalCatch
= true;
181 ctch
.catchSemantic(sc
); // Run semantic to resolve identifier '__o'
184 Statement s2
= new TryCatchStatement(Loc
.initial
, s
._body
, catches
);
190 StatementRewriteWalker
.visit(s
);
196 purityInprocess
= 1, /// working on determining purity
197 safetyInprocess
= 2, /// working on determining safety
198 nothrowInprocess
= 4, /// working on determining nothrow
199 nogcInprocess
= 8, /// working on determining @nogc
200 returnInprocess
= 0x10, /// working on inferring 'return' for parameters
201 inlineScanned
= 0x20, /// function has been scanned for inline possibilities
202 inferScope
= 0x40, /// infer 'scope' for parameters
203 hasCatches
= 0x80, /// function has try-catch statements
204 compileTimeOnly
= 0x100, /// is a compile time only function; no code will be generated for it
205 printf
= 0x200, /// is a printf-like function
206 scanf
= 0x400, /// is a scanf-like function
207 noreturn
= 0x800, /// the function does not return
210 /***********************************************************
211 * Tuple of result identifier (possibly null) and statement.
212 * This is used to store out contracts: out(id){ ensure }
214 extern (C
++) struct Ensure
221 return Ensure(id
, ensure
.syntaxCopy());
224 /*****************************************
225 * Do syntax copy of an array of Ensure's.
227 static Ensures
* arraySyntaxCopy(Ensures
* a
)
235 (*b
)[i
] = e
.syntaxCopy();
243 /***********************************************************
245 extern (C
++) class FuncDeclaration
: Declaration
247 Statements
* frequires
; /// in contracts
248 Ensures
* fensures
; /// out contracts
249 Statement frequire
; /// lowered in contract
250 Statement fensure
; /// lowered out contract
251 Statement fbody
; /// function body
253 FuncDeclarations foverrides
; /// functions this function overrides
254 FuncDeclaration fdrequire
; /// function that does the in contract
255 FuncDeclaration fdensure
; /// function that does the out contract
257 Expressions
* fdrequireParams
; /// argument list for __require
258 Expressions
* fdensureParams
; /// argument list for __ensure
260 const(char)* mangleString
; /// mangled symbol created from mangleExact()
262 VarDeclaration vresult
; /// result variable for out contracts
263 LabelDsymbol returnLabel
; /// where the return goes
265 bool[size_t
] isTypeIsolatedCache
; /// cache for the potentially very expensive isTypeIsolated check
267 // used to prevent symbols in different
268 // scopes from having the same name
269 DsymbolTable localsymtab
;
270 VarDeclaration vthis
; /// 'this' parameter (member and nested)
271 bool isThis2
; /// has a dual-context 'this' parameter
272 VarDeclaration v_arguments
; /// '_arguments' parameter
274 VarDeclaration v_argptr
; /// '_argptr' variable
275 VarDeclarations
* parameters
; /// Array of VarDeclaration's for parameters
276 DsymbolTable labtab
; /// statement label symbol table
277 Dsymbol overnext
; /// next in overload list
278 FuncDeclaration overnext0
; /// next in overload list (only used during IFTI)
279 Loc endloc
; /// location of closing curly bracket
280 int vtblIndex
= -1; /// for member functions, index into vtbl[]
281 bool naked
; /// true if naked
282 bool generated
; /// true if function was generated by the compiler rather than
283 /// supplied by the user
284 bool hasAlwaysInlines
; /// contains references to functions that must be inlined
285 ubyte isCrtCtorDtor
; /// has attribute pragma(crt_constructor(1)/crt_destructor(2))
286 /// not set before the glue layer
288 ILS inlineStatusStmt
= ILS
.uninitialized
;
289 ILS inlineStatusExp
= ILS
.uninitialized
;
290 PINLINE inlining
= PINLINE
.default_
;
292 int inlineNest
; /// !=0 if nested inline
293 bool eh_none
; /// true if no exception unwinding is needed
295 bool semantic3Errors
; /// true if errors in semantic3 this function's frame ptr
296 ForeachStatement fes
; /// if foreach body, this is the foreach
297 BaseClass
* interfaceVirtual
; /// if virtual, but only appears in base interface vtbl[]
298 bool introducing
; /// true if 'introducing' function
299 /** if !=NULL, then this is the type
300 of the 'introducing' function
301 this one is overriding
305 bool inferRetType
; /// true if return type is to be inferred
306 StorageClass storage_class2
; /// storage class for template onemember's
308 // Things that should really go into Scope
310 /// 1 if there's a return exp; statement
311 /// 2 if there's a throw statement
312 /// 4 if there's an assert(0)
313 /// 8 if there's inline asm
314 /// 16 if there are multiple return statements
317 // Support for NRVO (named return value optimization)
318 bool nrvo_can
= true; /// true means we can do NRVO
319 VarDeclaration nrvo_var
; /// variable to replace with shidden
320 Symbol
* shidden
; /// hidden pointer passed to function
322 ReturnStatements
* returns
;
324 GotoStatements
* gotos
; /// Gotos with forward references
326 /// set if this is a known, builtin function we can evaluate at compile time
327 BUILTIN builtin
= BUILTIN
.unknown
;
329 /// set if someone took the address of this function
332 bool requiresClosure
; // this function needs a closure
334 /** local variables in this function which are referenced by nested functions
335 * (They'll get put into the "closure" for this function.)
337 VarDeclarations closureVars
;
339 /** Outer variables which are referenced by this nested function
340 * (the inverse of closureVars)
342 VarDeclarations outerVars
;
344 /// Sibling nested functions which called this one
345 FuncDeclarations siblingCallers
;
347 FuncDeclarations
*inlinedNestedCallees
;
349 uint flags
; /// FUNCFLAG.xxxxx
352 * Data for a function declaration that is needed for the Objective-C
355 ObjcFuncDeclaration objc
;
357 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, Identifier ident
, StorageClass storage_class
, Type type
, bool noreturn
= false)
360 //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type);
361 //printf("storage_class = x%x\n", storage_class);
362 this.storage_class
= storage_class
;
366 // Normalize storage_class, because function-type related attributes
367 // are already set in the 'type' in parsing phase.
368 this.storage_class
&= ~(STC
.TYPECTOR | STC
.FUNCATTR
);
370 this.endloc
= endloc
;
372 this.flags |
= FUNCFLAG
.noreturn
;
374 /* The type given for "infer the return type" is a TypeFunction with
375 * NULL for the return type.
377 inferRetType
= (type
&& type
.nextOf() is null);
380 static FuncDeclaration
create(const ref Loc loc
, const ref Loc endloc
, Identifier id
, StorageClass storage_class
, Type type
, bool noreturn
= false)
382 return new FuncDeclaration(loc
, endloc
, id
, storage_class
, type
, noreturn
);
385 override FuncDeclaration
syntaxCopy(Dsymbol s
)
387 //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
388 FuncDeclaration f
= s ?
cast(FuncDeclaration
)s
389 : new FuncDeclaration(loc
, endloc
, ident
, storage_class
, type
.syntaxCopy(), (flags
& FUNCFLAG
.noreturn
) != 0);
390 f
.frequires
= frequires ? Statement
.arraySyntaxCopy(frequires
) : null;
391 f
.fensures
= fensures ? Ensure
.arraySyntaxCopy(fensures
) : null;
392 f
.fbody
= fbody ? fbody
.syntaxCopy() : null;
396 /****************************************************
397 * Resolve forward reference of function signature -
398 * parameter types, return type, and attributes.
400 * false if any errors exist in the signature.
402 final bool functionSemantic()
404 //printf("functionSemantic() %p %s\n", this, toChars());
408 this.cppnamespace
= _scope
.namespace
;
410 if (!originalType
) // semantic not yet run
412 TemplateInstance spec
= isSpeculative();
413 uint olderrs
= global
.errors
;
414 uint oldgag
= global
.gag
;
415 if (global
.gag
&& !spec
)
417 dsymbolSemantic(this, _scope
);
419 if (spec
&& global
.errors
!= olderrs
)
420 spec
.errors
= (global
.errors
- olderrs
!= 0);
421 if (olderrs
!= global
.errors
) // if errors compiling this function
425 // if inferring return type, sematic3 needs to be run
426 // - When the function body contains any errors, we cannot assume
427 // the inferred return type is valid.
428 // So, the body errors should become the function signature error.
429 if (inferRetType
&& type
&& !type
.nextOf())
430 return functionSemantic3();
433 if (isInstantiated() && !isVirtualMethod() &&
434 ((ti
= parent
.isTemplateInstance()) is null || ti
.isTemplateMixin() || ti
.tempdecl
.ident
== ident
))
436 AggregateDeclaration ad
= isMemberLocal();
437 if (ad
&& ad
.sizeok
!= Sizeok
.done
)
439 /* Currently dmd cannot resolve forward references per methods,
440 * then setting SIZOKfwd is too conservative and would break existing code.
441 * So, just stop method attributes inference until ad.dsymbolSemantic() done.
443 //ad.sizeok = Sizeok.fwd;
446 return functionSemantic3() ||
!errors
;
449 if (storage_class
& STC
.inference
)
450 return functionSemantic3() ||
!errors
;
455 /****************************************************
456 * Resolve forward reference of function body.
457 * Returns false if any errors exist in the body.
459 final bool functionSemantic3()
461 if (semanticRun
< PASS
.semantic3
&& _scope
)
463 /* Forward reference - we need to run semantic3 on this function.
464 * If errors are gagged, and it's not part of a template instance,
465 * we need to temporarily ungag errors.
467 TemplateInstance spec
= isSpeculative();
468 uint olderrs
= global
.errors
;
469 uint oldgag
= global
.gag
;
470 if (global
.gag
&& !spec
)
472 semantic3(this, _scope
);
475 // If it is a speculatively-instantiated template, and errors occur,
476 // we need to mark the template as having errors.
477 if (spec
&& global
.errors
!= olderrs
)
478 spec
.errors
= (global
.errors
- olderrs
!= 0);
479 if (olderrs
!= global
.errors
) // if errors compiling this function
483 return !errors
&& !semantic3Errors
;
486 /****************************************************
487 * Check that this function type is properly resolved.
488 * If not, report "forward reference error" and return true.
490 extern (D
) final bool checkForwardRef(const ref Loc loc
)
492 if (!functionSemantic())
495 /* No deco means the functionSemantic() call could not resolve
496 * forward referenes in the type of this function.
500 bool inSemantic3
= (inferRetType
&& semanticRun
>= PASS
.semantic3
);
501 .error(loc
, "forward reference to %s`%s`",
502 (inSemantic3 ?
"inferred return type of function " : "").ptr
,
509 // called from semantic3
511 * Creates and returns the hidden parameters for this function declaration.
513 * Hidden parameters include the `this` parameter of a class, struct or
514 * nested function and the selector parameter for Objective-C methods.
516 extern (D
) final void declareThis(Scope
* sc
)
518 isThis2
= toParent2() != toParentLocal();
520 if (!isThis2
&& !ad
&& !isNested())
523 objc
.selectorParameter
= null;
527 Type
addModStc(Type t
)
529 return t
.addMod(type
.mod
).addStorageClass(storage_class
);
532 if (isThis2 ||
isNested())
534 /* The 'this' for a nested function is the link to the
535 * enclosing function's stack frame.
536 * Note that nested functions and member functions are disjoint.
538 Type tthis
= addModStc(isThis2 ?
539 Type
.tvoidptr
.sarrayOf(2).pointerTo() :
540 Type
.tvoid
.pointerTo());
541 vthis
= new VarDeclaration(loc
, tthis
, isThis2 ? Id
.this2
: Id
.capture
, null);
542 vthis
.storage_class |
= STC
.parameter | STC
.nodtor
;
546 Type thandle
= addModStc(ad
.handleType());
547 vthis
= new ThisDeclaration(loc
, thandle
);
548 vthis
.storage_class |
= STC
.parameter
;
549 if (thandle
.ty
== Tstruct
)
551 vthis
.storage_class |
= STC
.ref_
;
552 // if member function is marked 'inout', then 'this' is 'return ref'
553 if (type
.ty
== Tfunction
&& (cast(TypeFunction
)type
).isInOutQual())
554 vthis
.storage_class |
= STC
.return_
;
558 if (auto tf
= type
.isTypeFunction())
561 vthis
.storage_class |
= STC
.return_
;
563 vthis
.storage_class |
= STC
.scope_
;
565 /* Add STC.returnScope like typesem.d does for TypeFunction parameters,
566 * at least it should be the same. At the moment, we'll just
567 * do existing practice. But we should examine how TypeFunction does
568 * it, for consistency.
570 if (!tf
.isref
&& isRefReturnScope(vthis
.storage_class
))
572 /* if `ref return scope`, evaluate to `ref` `return scope`
574 vthis
.storage_class |
= STC
.returnScope
;
577 if (flags
& FUNCFLAG
.inferScope
&& !(vthis
.storage_class
& STC
.scope_
))
578 vthis
.storage_class |
= STC
.maybescope
;
580 vthis
.dsymbolSemantic(sc
);
581 if (!sc
.insert(vthis
))
585 objc
.selectorParameter
= .objc
.createSelectorParameter(this, sc
);
588 override final bool equals(const RootObject o
) const
593 if (auto s
= isDsymbol(o
))
596 auto fd2
= s
.isFuncDeclaration();
600 auto fa1
= fd1
.isFuncAliasDeclaration();
601 auto faf1
= fa1 ? fa1
.toAliasFunc() : fd1
;
603 auto fa2
= fd2
.isFuncAliasDeclaration();
604 auto faf2
= fa2 ? fa2
.toAliasFunc() : fd2
;
608 return faf1
.equals(faf2
) && fa1
.hasOverloads
== fa2
.hasOverloads
;
611 bool b1
= fa1
!is null;
612 if (b1
&& faf1
.isUnique() && !fa1
.hasOverloads
)
615 bool b2
= fa2
!is null;
616 if (b2
&& faf2
.isUnique() && !fa2
.hasOverloads
)
622 return faf1
.toParent().equals(faf2
.toParent()) &&
623 faf1
.ident
.equals(faf2
.ident
) &&
624 faf1
.type
.equals(faf2
.type
);
629 /****************************************************
630 * Determine if 'this' overrides fd.
631 * Return !=0 if it does.
633 final int overrides(FuncDeclaration fd
)
636 if (fd
.ident
== ident
)
638 const cov
= type
.covariant(fd
.type
);
639 if (cov
!= Covariant
.distinct
)
641 ClassDeclaration cd1
= toParent().isClassDeclaration();
642 ClassDeclaration cd2
= fd
.toParent().isClassDeclaration();
643 if (cd1
&& cd2
&& cd2
.isBaseOf(cd1
, null))
650 /*************************************************
651 * Find index of function in vtbl[0..dim] that
652 * this function overrides.
653 * Prefer an exact match to a covariant one.
655 * vtbl = vtable to use
656 * dim = maximal vtable dimension
659 * -2 can't determine because of forward references
661 final int findVtblIndex(Dsymbols
* vtbl
, int dim
)
663 //printf("findVtblIndex() %s\n", toChars());
664 FuncDeclaration mismatch
= null;
665 StorageClass mismatchstc
= 0;
669 for (int vi
= 0; vi
< dim
; vi
++)
671 FuncDeclaration fdv
= (*vtbl
)[vi
].isFuncDeclaration();
672 if (fdv
&& fdv
.ident
== ident
)
674 if (type
.equals(fdv
.type
)) // if exact match
676 if (fdv
.parent
.isClassDeclaration())
681 continue; // keep looking
683 return vi
; // no need to look further
688 error("cannot determine overridden function");
696 StorageClass
stc = 0;
697 const cov
= type
.covariant(fdv
.type
, &stc);
698 //printf("\tbaseclass cov = %d\n", cov);
701 case Covariant
.distinct
:
702 // types are distinct
706 bestvi
= vi
; // covariant, but not identical
708 // keep looking for an exact match
713 mismatch
= fdv
; // overrides, but is not covariant
715 // keep looking for an exact match
717 case Covariant
.fwdref
:
718 return -2; // forward references
722 if (bestvi
== -1 && mismatch
)
725 //mismatch.type.print();
726 //printf("%s %s\n", type.deco, mismatch.type.deco);
727 //printf("stc = %llx\n", mismatchstc);
730 // Fix it by modifying the type to add the storage classes
731 type
= type
.addStorageClass(mismatchstc
);
738 /*********************************
739 * If function a function in a base class,
740 * return that base class.
742 * base class if overriding, null if not
744 final BaseClass
* overrideInterface()
746 for (ClassDeclaration cd
= toParent2().isClassDeclaration(); cd
; cd
= cd
.baseClass
)
748 foreach (b
; cd
.interfaces
)
750 auto v
= findVtblIndex(&b
.sym
.vtbl
, cast(int)b
.sym
.vtbl
.dim
);
758 /****************************************************
759 * Overload this FuncDeclaration with the new one f.
760 * Return true if successful; i.e. no conflict.
762 override bool overloadInsert(Dsymbol s
)
764 //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
766 AliasDeclaration ad
= s
.isAliasDeclaration();
770 return overnext
.overloadInsert(ad
);
771 if (!ad
.aliassym
&& ad
.type
.ty
!= Tident
&& ad
.type
.ty
!= Tinstance
&& ad
.type
.ty
!= Ttypeof
)
773 //printf("\tad = '%s'\n", ad.type.toChars());
777 //printf("\ttrue: no conflict\n");
780 TemplateDeclaration td
= s
.isTemplateDeclaration();
786 return overnext
.overloadInsert(td
);
790 FuncDeclaration fd
= s
.isFuncDeclaration();
796 /* Disable this check because:
798 * semantic() isn't run yet on foo(), so the const hasn't been
803 printf("type = %s\n", type
.toChars());
804 printf("fd.type = %s\n", fd
.type
.toChars());
806 // fd.type can be NULL for overloaded constructors
807 if (type
&& fd
.type
&& fd
.type
.covariant(type
) && fd
.type
.mod
== type
.mod
&& !isFuncAliasDeclaration())
809 //printf("\tfalse: conflict %s\n", kind());
816 td
= overnext
.isTemplateDeclaration();
818 fd
.overloadInsert(td
);
820 return overnext
.overloadInsert(fd
);
823 //printf("\ttrue: no conflict\n");
827 /********************************************
828 * Find function in overload list that exactly matches t.
830 extern (D
) final FuncDeclaration
overloadExactMatch(Type t
)
833 overloadApply(this, (Dsymbol s
)
835 auto f
= s
.isFuncDeclaration();
838 if (t
.equals(f
.type
))
844 /* Allow covariant matches, as long as the return type
845 * is just a const conversion.
846 * This allows things like pure functions to match with an impure function type.
848 if (t
.ty
== Tfunction
)
850 auto tf
= cast(TypeFunction
)f
.type
;
851 if (tf
.covariant(t
) == Covariant
.yes
&&
852 tf
.nextOf().implicitConvTo(t
.nextOf()) >= MATCH
.constant
)
863 /********************************************
864 * Find function in overload list that matches to the 'this' modifier.
865 * There's four result types.
867 * 1. If the 'tthis' matches only one candidate, it's an "exact match".
868 * Returns the function and 'hasOverloads' is set to false.
869 * eg. If 'tthis" is mutable and there's only one mutable method.
870 * 2. If there's two or more match candidates, but a candidate function will be
872 * Returns the better match function but 'hasOverloads' is set to true.
873 * eg. If 'tthis' is mutable, and there's both mutable and const methods,
874 * the mutable method will be a better match.
875 * 3. If there's two or more match candidates, but there's no better match,
876 * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
877 * eg. If 'tthis' is mutable, and there's two or more mutable methods.
878 * 4. If there's no candidates, it's "no match" and returns null with error report.
879 * e.g. If 'tthis' is const but there's no const methods.
881 extern (D
) final FuncDeclaration
overloadModMatch(const ref Loc loc
, Type tthis
, ref bool hasOverloads
)
883 //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
885 overloadApply(this, (Dsymbol s
)
887 auto f
= s
.isFuncDeclaration();
888 if (!f || f
== m
.lastf
) // skip duplicates
891 auto tf
= f
.type
.toTypeFunction();
892 //printf("tf = %s\n", tf.toChars());
895 if (tthis
) // non-static functions are preferred than static ones
898 match
= f
.isCtorDeclaration() ? MATCH
.exact
: MODmethodConv(tthis
.mod
, tf
.mod
);
900 match
= MATCH
.constant
; // keep static function in overload candidates
902 else // static functions are preferred than non-static ones
905 match
= MATCH
.convert
;
909 if (match
== MATCH
.nomatch
)
912 if (match
> m
.last
) goto LcurrIsBetter
;
913 if (match
< m
.last
) goto LlastIsBetter
;
915 // See if one of the matches overrides the other.
916 if (m
.lastf
.overrides(f
)) goto LlastIsBetter
;
917 if (f
.overrides(m
.lastf
)) goto LcurrIsBetter
;
919 //printf("\tambiguous\n");
925 //printf("\tlastbetter\n");
926 m
.count
++; // count up
930 //printf("\tisbetter\n");
931 if (m
.last
<= MATCH
.convert
)
933 // clear last secondary matching
939 m
.count
++; // count up
943 if (m
.count
== 1) // exact match
945 hasOverloads
= false;
947 else if (m
.count
> 1) // better or ambiguous match
954 auto tf
= this.type
.toTypeFunction();
956 assert(!MODimplicitConv(tthis
.mod
, tf
.mod
)); // modifier mismatch
958 OutBuffer thisBuf
, funcBuf
;
959 MODMatchToBuffer(&thisBuf
, tthis
.mod
, tf
.mod
);
960 MODMatchToBuffer(&funcBuf
, tf
.mod
, tthis
.mod
);
961 .error(loc
, "%smethod %s is not callable using a %sobject",
962 funcBuf
.peekChars(), this.toPrettyChars(), thisBuf
.peekChars());
968 /********************************************
969 * find function template root in overload list
971 extern (D
) final TemplateDeclaration
findTemplateDeclRoot()
973 FuncDeclaration f
= this;
974 while (f
&& f
.overnext
)
976 //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
977 TemplateDeclaration td
= f
.overnext
.isTemplateDeclaration();
980 f
= f
.overnext
.isFuncDeclaration();
985 /********************************************
986 * Returns true if function was declared
987 * directly or indirectly in a unittest block
989 final bool inUnittest()
994 if (f
.isUnitTestDeclaration())
1002 /*************************************
1003 * Determine partial specialization order of 'this' vs g.
1004 * This is very similar to TemplateDeclaration::leastAsSpecialized().
1006 * match 'this' is at least as specialized as g
1007 * 0 g is more specialized than 'this'
1009 final MATCH
leastAsSpecialized(FuncDeclaration g
)
1011 enum LOG_LEASTAS
= 0;
1012 static if (LOG_LEASTAS
)
1014 printf("%s.leastAsSpecialized(%s)\n", toChars(), g
.toChars());
1015 printf("%s, %s\n", type
.toChars(), g
.type
.toChars());
1018 /* This works by calling g() with f()'s parameters, and
1019 * if that is possible, then f() is at least as specialized
1023 TypeFunction tf
= type
.toTypeFunction();
1024 TypeFunction tg
= g
.type
.toTypeFunction();
1026 /* If both functions have a 'this' pointer, and the mods are not
1027 * the same and g's is not const, then this is less specialized.
1029 if (needThis() && g
.needThis() && tf
.mod
!= tg
.mod
)
1031 if (isCtorDeclaration())
1033 if (!MODimplicitConv(tg
.mod
, tf
.mod
))
1034 return MATCH
.nomatch
;
1038 if (!MODimplicitConv(tf
.mod
, tg
.mod
))
1039 return MATCH
.nomatch
;
1043 /* Create a dummy array of arguments out of the parameters to f()
1046 foreach (u
, p
; tf
.parameterList
)
1049 if (p
.isReference())
1051 e
= new IdentifierExp(Loc
.initial
, p
.ident
);
1055 e
= p
.type
.defaultInitLiteral(Loc
.initial
);
1059 MATCH m
= tg
.callMatch(null, args
[], 1);
1060 if (m
> MATCH
.nomatch
)
1062 /* A variadic parameter list is less specialized than a
1065 if (tf
.parameterList
.varargs
&& !tg
.parameterList
.varargs
)
1066 goto L1
; // less specialized
1068 static if (LOG_LEASTAS
)
1070 printf(" matches %d, so is least as specialized\n", m
);
1075 static if (LOG_LEASTAS
)
1077 printf(" doesn't match, so is not as specialized\n");
1079 return MATCH
.nomatch
;
1082 /********************************
1083 * Searches for a label with the given identifier. This function will insert a new
1084 * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
1087 * ident = identifier of the requested label
1088 * loc = location used when creating a new `LabelDsymbol`
1090 * Returns: the `LabelDsymbol` for `ident`
1092 final LabelDsymbol
searchLabel(Identifier ident
, const ref Loc loc
= Loc
.initial
)
1096 labtab
= new DsymbolTable(); // guess we need one
1098 s
= labtab
.lookup(ident
);
1101 s
= new LabelDsymbol(ident
, loc
);
1104 return cast(LabelDsymbol
)s
;
1107 /*****************************************
1108 * Determine lexical level difference from `this` to nested function `fd`.
1110 * fd = target of call
1111 * intypeof = !=0 if inside typeof
1114 * >0 decrease nesting by number
1115 * -1 increase nesting by 1 (`fd` is nested within `this`)
1116 * LevelError error, `this` cannot call `fd`
1118 final int getLevel(FuncDeclaration fd
, int intypeof
)
1120 //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
1121 Dsymbol fdparent
= fd
.toParent2();
1122 if (fdparent
== this)
1127 while (fd
!= s
&& fdparent
!= s
.toParent2())
1129 //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
1130 if (auto thisfd
= s
.isFuncDeclaration())
1132 if (!thisfd
.isNested() && !thisfd
.vthis
&& !intypeof
)
1137 if (auto thiscd
= s
.isAggregateDeclaration())
1139 /* AggregateDeclaration::isNested returns true only when
1140 * it has a hidden pointer.
1141 * But, calling the function belongs unrelated lexical scope
1142 * is still allowed inside typeof.
1144 * struct Map(alias fun) {
1145 * typeof({ return fun(); }) RetType;
1146 * // No member function makes Map struct 'not nested'.
1149 if (!thiscd
.isNested() && !intypeof
)
1156 s
= s
.toParentP(fd
);
1163 /***********************************
1164 * Determine lexical level difference from `this` to nested function `fd`.
1165 * Issue error if `this` cannot call `fd`.
1168 * loc = location for error messages
1170 * fd = target of call
1171 * decl = The `Declaration` that triggered this check.
1172 * Used to provide a better error message only.
1175 * >0 decrease nesting by number
1176 * -1 increase nesting by 1 (`fd` is nested within 'this')
1179 final int getLevelAndCheck(const ref Loc loc
, Scope
* sc
, FuncDeclaration fd
,
1182 int level
= getLevel(fd
, sc
.intypeof
);
1183 if (level
!= LevelError
)
1186 // Don't give error if in template constraint
1187 if (!(sc
.flags
& SCOPE
.constraint
))
1189 const(char)* xstatic
= isStatic() ?
"`static` " : "";
1190 // better diagnostics for static functions
1191 .error(loc
, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
1192 xstatic
, kind(), toPrettyChars(), decl
.kind(), decl
.toChars(),
1193 fd
.toPrettyChars());
1194 .errorSupplemental(decl
.loc
, "`%s` declared here", decl
.toChars());
1200 enum LevelError
= -2;
1202 override const(char)* toPrettyChars(bool QualifyTypes
= false)
1207 return Dsymbol
.toPrettyChars(QualifyTypes
);
1210 /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
1211 final const(char)* toFullSignature()
1214 functionToBufferWithIdent(type
.toTypeFunction(), &buf
, toChars(), isStatic
);
1215 return buf
.extractChars();
1218 final bool isMain() const
1220 return ident
== Id
.main
&& linkage
!= LINK
.c
&& !isMember() && !isNested();
1223 final bool isCMain() const
1225 return ident
== Id
.main
&& linkage
== LINK
.c
&& !isMember() && !isNested();
1228 final bool isWinMain() const
1230 //printf("FuncDeclaration::isWinMain() %s\n", toChars());
1233 bool x
= ident
== Id
.WinMain
&& linkage
!= LINK
.c
&& !isMember();
1234 printf("%s\n", x ?
"yes" : "no");
1239 return ident
== Id
.WinMain
&& linkage
!= LINK
.c
&& !isMember();
1243 final bool isDllMain() const
1245 return ident
== Id
.DllMain
&& linkage
!= LINK
.c
&& !isMember();
1248 final bool isRtInit() const
1250 return ident
== Id
.rt_init
&& linkage
== LINK
.c
&& !isMember() && !isNested();
1253 override final bool isExport() const
1255 return visibility
.kind
== Visibility
.Kind
.export_
;
1258 override final bool isImportedSymbol() const
1260 //printf("isImportedSymbol()\n");
1261 //printf("protection = %d\n", visibility);
1262 return (visibility
.kind
== Visibility
.Kind
.export_
) && !fbody
;
1265 override final bool isCodeseg() const pure nothrow @nogc @safe
1267 return true; // functions are always in the code segment
1270 override final bool isOverloadable() const
1272 return true; // functions can be overloaded
1275 /***********************************
1276 * Override so it can work even if semantic() hasn't yet
1279 override final bool isAbstract()
1281 if (storage_class
& STC
.abstract_
)
1283 if (semanticRun
>= PASS
.semanticdone
)
1288 if (_scope
.stc & STC
.abstract_
)
1290 parent
= _scope
.parent
;
1291 Dsymbol parent
= toParent();
1292 if (parent
.isInterfaceDeclaration())
1298 /**********************************
1299 * Decide if attributes for this function can be inferred from examining
1300 * the function body.
1304 final bool canInferAttributes(Scope
* sc
)
1309 if (isVirtualMethod() &&
1311 * https://issues.dlang.org/show_bug.cgi?id=21719
1313 * If we have an auto virtual function we can infer
1316 !(inferRetType
&& !isCtorDeclaration()))
1317 return false; // since they may be overridden
1320 /********** this is for backwards compatibility for the moment ********/
1321 (!isMember() || sc
.func
.isSafeBypassingInference() && !isInstantiated()))
1324 if (isFuncLiteralDeclaration() ||
// externs are not possible with literals
1325 (storage_class
& STC
.inference
) ||
// do attribute inference
1326 (inferRetType
&& !isCtorDeclaration()))
1329 if (isInstantiated())
1331 auto ti
= parent
.isTemplateInstance();
1332 if (ti
is null || ti
.isTemplateMixin() || ti
.tempdecl
.ident
== ident
)
1339 /*****************************************
1340 * Initialize for inferring the attributes of this function.
1342 final void initInferAttributes()
1344 //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
1345 TypeFunction tf
= type
.toTypeFunction();
1346 if (tf
.purity
== PURE
.impure
) // purity not specified
1347 flags |
= FUNCFLAG
.purityInprocess
;
1349 if (tf
.trust
== TRUST
.default_
)
1350 flags |
= FUNCFLAG
.safetyInprocess
;
1353 flags |
= FUNCFLAG
.nothrowInprocess
;
1356 flags |
= FUNCFLAG
.nogcInprocess
;
1358 if (!isVirtual() || introducing
)
1359 flags |
= FUNCFLAG
.returnInprocess
;
1361 // Initialize for inferring STC.scope_
1362 if (global
.params
.useDIP1000
== FeatureState
.enabled
)
1363 flags |
= FUNCFLAG
.inferScope
;
1368 //printf("FuncDeclaration::isPure() '%s'\n", toChars());
1369 TypeFunction tf
= type
.toTypeFunction();
1370 if (flags
& FUNCFLAG
.purityInprocess
)
1372 if (tf
.purity
== PURE
.fwdref
)
1374 PURE purity
= tf
.purity
;
1375 if (purity
> PURE
.weak
&& isNested())
1377 if (purity
> PURE
.weak
&& needThis())
1379 // The attribute of the 'this' reference affects purity strength
1380 if (type
.mod
& MODFlags
.immutable_
)
1383 else if (type
.mod
& (MODFlags
.const_ | MODFlags
.wild
) && purity
>= PURE
.const_
)
1384 purity
= PURE
.const_
;
1389 // ^ This rely on the current situation that every FuncDeclaration has a
1390 // unique TypeFunction.
1394 final PURE
isPureBypassingInference()
1396 if (flags
& FUNCFLAG
.purityInprocess
)
1402 /**************************************
1403 * The function is doing something impure,
1404 * so mark it as impure.
1405 * If there's a purity error, return true.
1407 extern (D
) final bool setImpure()
1409 if (flags
& FUNCFLAG
.purityInprocess
)
1411 flags
&= ~FUNCFLAG
.purityInprocess
;
1413 fes
.func
.setImpure();
1422 if (flags
& FUNCFLAG
.safetyInprocess
)
1424 return type
.toTypeFunction().trust
== TRUST
.safe
;
1427 final bool isSafeBypassingInference()
1429 return !(flags
& FUNCFLAG
.safetyInprocess
) && isSafe();
1432 final bool isTrusted()
1434 if (flags
& FUNCFLAG
.safetyInprocess
)
1436 return type
.toTypeFunction().trust
== TRUST
.trusted
;
1439 /**************************************
1440 * The function is doing something unsafe,
1441 * so mark it as unsafe.
1442 * If there's a safe error, return true.
1444 extern (D
) final bool setUnsafe()
1446 if (flags
& FUNCFLAG
.safetyInprocess
)
1448 flags
&= ~FUNCFLAG
.safetyInprocess
;
1449 type
.toTypeFunction().trust
= TRUST
.system
;
1451 fes
.func
.setUnsafe();
1460 //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
1461 if (flags
& FUNCFLAG
.nogcInprocess
)
1463 return type
.toTypeFunction().isnogc
;
1466 final bool isNogcBypassingInference()
1468 return !(flags
& FUNCFLAG
.nogcInprocess
) && isNogc();
1471 /**************************************
1472 * The function is doing something that may allocate with the GC,
1473 * so mark it as not nogc (not no-how).
1475 * true if function is marked as @nogc, meaning a user error occurred
1477 extern (D
) final bool setGC()
1479 //printf("setGC() %s\n", toChars());
1480 if (flags
& FUNCFLAG
.nogcInprocess
&& semanticRun
< PASS
.semantic3
&& _scope
)
1482 this.semantic2(_scope
);
1483 this.semantic3(_scope
);
1486 if (flags
& FUNCFLAG
.nogcInprocess
)
1488 flags
&= ~FUNCFLAG
.nogcInprocess
;
1489 type
.toTypeFunction().isnogc
= false;
1498 extern (D
) final void printGCUsage(const ref Loc loc
, const(char)* warn
)
1500 if (!global
.params
.vgc
)
1503 Module m
= getModule();
1504 if (m
&& m
.isRoot() && !inUnittest())
1506 message(loc
, "vgc: %s", warn
);
1510 /********************************************
1511 * See if pointers from function parameters, mutable globals, or uplevel functions
1512 * could leak into return value.
1514 * true if the function return value is isolated from
1515 * any inputs to the function
1517 extern (D
) final bool isReturnIsolated()
1519 //printf("isReturnIsolated(this: %s)\n", this.toChars);
1520 TypeFunction tf
= type
.toTypeFunction();
1523 Type treti
= tf
.next
;
1525 return isTypeIsolatedIndirect(treti
); // check influence from parameters
1527 return isTypeIsolated(treti
);
1530 /********************
1531 * See if pointers from function parameters, mutable globals, or uplevel functions
1532 * could leak into type `t`.
1534 * t = type to check if it is isolated
1536 * true if `t` is isolated from
1537 * any inputs to the function
1539 extern (D
) final bool isTypeIsolated(Type t
)
1541 StringTable
!Type parentTypes
;
1542 const uniqueTypeID
= t
.getUniqueID();
1545 const cacheResultPtr
= uniqueTypeID
in isTypeIsolatedCache
;
1546 if (cacheResultPtr
!is null)
1547 return *cacheResultPtr
;
1549 parentTypes
._init();
1550 const isIsolated
= isTypeIsolated(t
, parentTypes
);
1551 isTypeIsolatedCache
[uniqueTypeID
] = isIsolated
;
1556 parentTypes
._init();
1557 return isTypeIsolated(t
, parentTypes
);
1562 extern (D
) final bool isTypeIsolated(Type t
, ref StringTable
!Type parentTypes
)
1564 //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
1571 return isTypeIsolatedIndirect(t
.nextOf()); // go down one level
1575 return isTypeIsolatedIndirect(t
);
1578 /* Drill down and check the struct's fields
1580 auto sym
= t
.toDsymbol(null).isStructDeclaration();
1581 const tName
= t
.toChars
.toDString
;
1582 const entry
= parentTypes
.insert(tName
, t
);
1585 //we've already seen this type in a parent, not isolated
1588 foreach (v
; sym
.fields
)
1590 Type tmi
= v
.type
.addMod(t
.mod
);
1591 //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
1592 // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
1593 if (!isTypeIsolated(tmi
, parentTypes
))
1603 /********************************************
1605 * t = type of object to test one level of indirection down
1607 * true if an object typed `t` has no indirections
1608 * which could have come from the function's parameters, mutable
1609 * globals, or uplevel functions.
1611 private bool isTypeIsolatedIndirect(Type t
)
1613 //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
1616 /* Since `t` is one level down from an indirection, it could pick
1617 * up a reference to a mutable global or an outer function, so
1620 if (!isPureBypassingInference() ||
isNested())
1623 TypeFunction tf
= type
.toTypeFunction();
1625 //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
1627 foreach (i
, fparam
; tf
.parameterList
)
1629 Type tp
= fparam
.type
;
1633 if (fparam
.storageClass
& (STC
.lazy_ | STC
.out_ | STC
.ref_
))
1635 if (!traverseIndirections(tp
, t
))
1640 /* Goes down one level of indirection, then calls traverseIndirection() on
1643 * true if t is isolated from tp
1645 static bool traverse(Type tp
, Type t
)
1647 tp
= tp
.baseElemOf();
1652 return traverseIndirections(tp
.nextOf(), t
);
1656 return traverseIndirections(tp
, t
);
1659 /* Drill down and check the struct's fields
1661 auto sym
= tp
.toDsymbol(null).isStructDeclaration();
1662 foreach (v
; sym
.fields
)
1664 Type tprmi
= v
.type
.addMod(tp
.mod
);
1665 //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
1666 if (!traverse(tprmi
, t
))
1676 if (!traverse(tp
, t
))
1679 // The 'this' reference is a parameter, too
1680 if (AggregateDeclaration ad
= isCtorDeclaration() ?
null : isThis())
1682 Type tthis
= ad
.getType().addMod(tf
.mod
);
1683 //printf("\ttthis = %s\n", tthis.toChars());
1684 if (!traverseIndirections(tthis
, t
))
1691 /****************************************
1692 * Determine if function needs a static frame pointer.
1694 * `true` if function is really nested within other function.
1696 * If isNested() returns true, isThis() should return false,
1697 * unless the function needs a dual-context pointer.
1699 bool isNested() const
1701 auto f
= toAliasFunc();
1702 //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
1703 return ((f
.storage_class
& STC
.static_
) == 0) &&
1704 (f
.linkage
== LINK
.d
) &&
1705 (f
.toParent2().isFuncDeclaration() !is null ||
1706 f
.toParent2() !is f
.toParentLocal());
1709 /****************************************
1710 * Determine if function is a non-static member function
1711 * that has an implicit 'this' expression.
1713 * The aggregate it is a member of, or null.
1715 * Both isThis() and isNested() should return true if function needs a dual-context pointer,
1716 * otherwise if isThis() returns true, isNested() should return false.
1718 override inout(AggregateDeclaration
) isThis() inout
1720 //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
1721 auto ad
= (storage_class
& STC
.static_
) ?
.objc
.isThis(this) : isMemberLocal();
1722 //printf("-FuncDeclaration::isThis() %p\n", ad);
1726 override final bool needThis()
1728 //printf("FuncDeclaration::needThis() '%s'\n", toChars());
1729 return toAliasFunc().isThis() !is null;
1732 // Determine if a function is pedantically virtual
1733 final bool isVirtualMethod()
1735 if (toAliasFunc() != this)
1736 return toAliasFunc().isVirtualMethod();
1738 //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
1741 // If it's a final method, and does not override anything, then it is not virtual
1742 if (isFinalFunc() && foverrides
.dim
== 0)
1749 // Determine if function goes into virtual function pointer table
1750 bool isVirtual() const
1752 if (toAliasFunc() != this)
1753 return toAliasFunc().isVirtual();
1755 auto p
= toParent();
1757 if (!isMember ||
!p
.isClassDeclaration
)
1760 if (p
.isClassDeclaration
.classKind
== ClassKind
.objc
)
1761 return .objc
.isVirtual(this);
1765 printf("FuncDeclaration::isVirtual(%s)\n", toChars());
1766 printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), visibility
== Visibility
.Kind
.private_
, isCtorDeclaration(), linkage
!= LINK
.d
);
1767 printf("result is %d\n", isMember() && !(isStatic() || visibility
== Visibility
.Kind
.private_ || visibility
== Visibility
.Kind
.package_
) && p
.isClassDeclaration() && !(p
.isInterfaceDeclaration() && isFinalFunc()));
1769 return !(isStatic() || visibility
.kind
== Visibility
.Kind
.private_ || visibility
.kind
== Visibility
.Kind
.package_
) && !(p
.isInterfaceDeclaration() && isFinalFunc());
1772 final bool isFinalFunc() const
1774 if (toAliasFunc() != this)
1775 return toAliasFunc().isFinalFunc();
1779 auto cd
= toParent().isClassDeclaration();
1780 printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration
.isFinal());
1781 printf("%p %d %d %d\n", isMember(), isStatic(), Declaration
.isFinal(), ((cd
= toParent().isClassDeclaration()) !is null && cd
.storage_class
& STC
.final_
));
1782 printf("result is %d\n", isMember() && (Declaration
.isFinal() ||
(cd
!is null && cd
.storage_class
& STC
.final_
)));
1784 printf("\tmember of %s\n", cd
.toChars());
1788 if (Declaration
.isFinal())
1790 auto cd
= toParent().isClassDeclaration();
1791 return (cd
!is null) && (cd
.storage_class
& STC
.final_
);
1794 bool addPreInvariant()
1797 ClassDeclaration cd
= ad ? ad
.isClassDeclaration() : null;
1798 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_
) && !naked
);
1801 bool addPostInvariant()
1804 ClassDeclaration cd
= ad ? ad
.isClassDeclaration() : null;
1805 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_
) && !naked
);
1808 override const(char)* kind() const
1810 return generated ?
"generated function" : "function";
1813 /********************************************
1815 * true if there are no overloads of this function
1817 final bool isUnique() const
1819 bool result
= false;
1820 overloadApply(cast() this, (Dsymbol s
)
1822 auto f
= s
.isFuncDeclaration();
1828 return 1; // ambiguous, done
1839 /*********************************************
1840 * In the current function, we are calling 'this' function.
1841 * 1. Check to see if the current function can call 'this' function, issue error if not.
1842 * 2. If the current function is not the parent of 'this' function, then add
1843 * the current function to the list of siblings of 'this' function.
1844 * 3. If the current function is a literal, and it's accessing an uplevel scope,
1845 * then mark it as a delegate.
1846 * Returns true if error occurs.
1848 extern (D
) final bool checkNestedReference(Scope
* sc
, const ref Loc loc
)
1850 //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
1852 if (auto fld = this.isFuncLiteralDeclaration())
1854 if (fld.tok
== TOK
.reserved
)
1856 fld.tok
= TOK
.function_
;
1861 if (!parent || parent
== sc
.parent
)
1863 if (ident
== Id
.require || ident
== Id
.ensure
)
1865 if (!isThis() && !isNested())
1868 // The current function
1869 FuncDeclaration fdthis
= sc
.parent
.isFuncDeclaration();
1871 return false; // out of function scope
1873 Dsymbol p
= toParentLocal();
1874 Dsymbol p2
= toParent2();
1876 // Function literals from fdthis to p must be delegates
1877 ensureStaticLinkTo(fdthis
, p
);
1879 ensureStaticLinkTo(fdthis
, p2
);
1883 // The function that this function is in
1884 bool checkEnclosing(FuncDeclaration fdv
)
1891 //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
1892 //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
1893 //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
1895 // Add this function to the list of those which called us
1899 for (size_t i
= 0; i
< siblingCallers
.dim
; ++i
)
1901 if (siblingCallers
[i
] == fdthis
)
1906 //printf("\tadding sibling %s\n", fdthis.toPrettyChars());
1907 if (!sc
.intypeof
&& !(sc
.flags
& SCOPE
.compile
))
1908 siblingCallers
.push(fdthis
);
1912 const lv
= fdthis
.getLevelAndCheck(loc
, sc
, fdv
, this);
1913 if (lv
== LevelError
)
1914 return true; // error
1916 return false; // downlevel call
1918 return false; // same level call
1920 return false; // Uplevel call
1923 if (checkEnclosing(p
.isFuncDeclaration()))
1925 if (checkEnclosing(p
== p2 ?
null : p2
.isFuncDeclaration()))
1931 /*******************************
1932 * Look at all the variables in this function that are referenced
1933 * by nested functions, and determine if a closure needs to be
1936 final bool needsClosure()
1938 /* Need a closure for all the closureVars[] if any of the
1939 * closureVars[] are accessed by a
1940 * function that escapes the scope of this function.
1941 * We take the conservative approach and decide that a function needs
1943 * 1) is a virtual function
1944 * 2) has its address taken
1945 * 3) has a parent that escapes
1946 * 4) calls another nested function that needs a closure
1948 * Note that since a non-virtual function can be called by
1949 * a virtual one, if that non-virtual function accesses a closure
1950 * var, the closure still has to be taken. Hence, we check for isThis()
1951 * instead of isVirtual(). (thanks to David Friedman)
1953 * When the function returns a local struct or class, `requiresClosure`
1954 * is already set to `true` upon entering this function when the
1955 * struct/class refers to a local variable and a closure is needed.
1958 //printf("FuncDeclaration::needsClosure() %s\n", toChars());
1960 if (requiresClosure
)
1963 for (size_t i
= 0; i
< closureVars
.dim
; i
++)
1965 VarDeclaration v
= closureVars
[i
];
1966 //printf("\tv = %s\n", v.toChars());
1968 for (size_t j
= 0; j
< v
.nestedrefs
.dim
; j
++)
1970 FuncDeclaration f
= v
.nestedrefs
[j
];
1973 /* __require and __ensure will always get called directly,
1974 * so they never make outer functions closure.
1976 if (f
.ident
== Id
.require || f
.ident
== Id
.ensure
)
1979 //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
1981 /* Look to see if f escapes. We consider all parents of f within
1982 * this, and also all siblings which call f; if any of them escape,
1984 * Mark all affected functions as requiring closures.
1986 for (Dsymbol s
= f
; s
&& s
!= this; s
= s
.toParentP(this))
1988 FuncDeclaration fx
= s
.isFuncDeclaration();
1991 if (fx
.isThis() || fx
.tookAddressOf
)
1993 //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
1995 /* Mark as needing closure any functions between this and f
1997 markAsNeedingClosure((fx
== f
) ? fx
.toParentP(this) : fx
, this);
1999 requiresClosure
= true;
2002 /* We also need to check if any sibling functions that
2003 * called us, have escaped. This is recursive: we need
2004 * to check the callers of our siblings.
2006 if (checkEscapingSiblings(fx
, this))
2007 requiresClosure
= true;
2009 /* https://issues.dlang.org/show_bug.cgi?id=12406
2010 * Iterate all closureVars to mark all descendant
2011 * nested functions that access to the closing context of this function.
2016 if (requiresClosure
)
2022 //printf("\tneeds closure\n");
2026 /***********************************************
2027 * Check that the function contains any closure.
2028 * If it's @nogc, report suitable errors.
2029 * This is mostly consistent with FuncDeclaration::needsClosure().
2032 * true if any errors occur.
2034 extern (D
) final bool checkClosure()
2036 if (!needsClosure())
2041 error("is `@nogc` yet allocates closures with the GC");
2042 if (global
.gag
) // need not report supplemental errors
2047 printGCUsage(loc
, "using closure causes GC allocation");
2052 foreach (v
; closureVars
)
2054 foreach (f
; v
.nestedrefs
)
2058 LcheckAncestorsOfANestedRef
:
2059 for (Dsymbol s
= f
; s
&& s
!is this; s
= s
.toParentP(this))
2061 auto fx
= s
.isFuncDeclaration();
2066 checkEscapingSiblings(fx
, this))
2071 break LcheckAncestorsOfANestedRef
;
2074 .errorSupplemental(f
.loc
, "%s closes over variable %s at %s",
2075 f
.toPrettyChars(), v
.toChars(), v
.loc
.toChars());
2076 break LcheckAncestorsOfANestedRef
;
2085 /***********************************************
2086 * Determine if function's variables are referenced by a function
2089 final bool hasNestedFrameRefs()
2091 if (closureVars
.dim
)
2094 /* If a virtual function has contracts, assume its variables are referenced
2095 * by those contracts, even if they aren't. Because they might be referenced
2096 * by the overridden or overriding function's contracts.
2097 * This can happen because frequire and fensure are implemented as nested functions,
2098 * and they can be called directly by an overriding function and the overriding function's
2099 * context had better match, or
2100 * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
2102 if (fdrequire || fdensure
)
2105 if (foverrides
.dim
&& isVirtualMethod())
2107 for (size_t i
= 0; i
< foverrides
.dim
; i
++)
2109 FuncDeclaration fdv
= foverrides
[i
];
2110 if (fdv
.hasNestedFrameRefs())
2117 /****************************************************
2118 * Check whether result variable can be built.
2120 * `true` if the function has a return type that
2121 * is different from `void`.
2123 extern (D
) private bool canBuildResultVar()
2125 auto f
= cast(TypeFunction
)type
;
2126 return f
&& f
.nextOf() && f
.nextOf().toBasetype().ty
!= Tvoid
;
2129 /****************************************************
2130 * Declare result variable lazily.
2132 extern (D
) final void buildResultVar(Scope
* sc
, Type tret
)
2136 Loc loc
= fensure ? fensure
.loc
: this.loc
;
2138 /* If inferRetType is true, tret may not be a correct return type yet.
2139 * So, in here it may be a temporary type for vresult, and after
2140 * fbody.dsymbolSemantic() running, vresult.type might be modified.
2142 vresult
= new VarDeclaration(loc
, tret
, Id
.result
, null);
2143 vresult
.storage_class |
= STC
.nodtor | STC
.temp
;
2145 vresult
.storage_class |
= STC
.const_
;
2146 vresult
.storage_class |
= STC
.result
;
2148 // set before the semantic() for checkNestedReference()
2149 vresult
.parent
= this;
2152 if (sc
&& vresult
.semanticRun
== PASS
.init
)
2154 TypeFunction tf
= type
.toTypeFunction();
2156 vresult
.storage_class |
= STC
.ref_
;
2157 vresult
.type
= tret
;
2159 vresult
.dsymbolSemantic(sc
);
2161 if (!sc
.insert(vresult
))
2162 error("out result %s is already defined", vresult
.toChars());
2163 assert(vresult
.parent
== this);
2167 /****************************************************
2168 * Merge into this function the 'in' contracts of all it overrides.
2169 * 'in's are OR'd together, i.e. only one of them needs to pass.
2171 extern (D
) final Statement
mergeFrequire(Statement sf
, Expressions
* params
)
2173 /* If a base function and its override both have an IN contract, then
2174 * only one of them needs to succeed. This is done by generating:
2176 * void derived.in() {
2181 * ... body of derived.in() ...
2185 * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
2186 * If base.in() throws, then derived.in()'s body is executed.
2189 foreach (fdv
; foverrides
)
2191 /* The semantic pass on the contracts of the overridden functions must
2192 * be completed before code generation occurs.
2193 * https://issues.dlang.org/show_bug.cgi?id=3602
2195 if (fdv
.frequires
&& fdv
.semanticRun
!= PASS
.semantic3done
)
2198 Scope
* sc
= fdv
._scope
.push();
2199 sc
.stc &= ~STC
.override_
;
2204 sf
= fdv
.mergeFrequire(sf
, params
);
2205 if (!sf ||
!fdv
.fdrequire
)
2207 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2209 * try { __require(params); }
2210 * catch (Throwable) { frequire; }
2212 params
= Expression
.arraySyntaxCopy(params
);
2213 Expression e
= new CallExp(loc
, new VarExp(loc
, fdv
.fdrequire
, false), params
);
2214 Statement s2
= new ExpStatement(loc
, e
);
2216 auto c
= new Catch(loc
, getThrowable(), null, sf
);
2217 c
.internalCatch
= true;
2218 auto catches
= new Catches();
2220 sf
= new TryCatchStatement(loc
, s2
, catches
);
2225 /****************************************************
2226 * Merge into this function the 'in' contracts of all it overrides.
2228 extern (D
) final Statement
mergeFrequireInclusivePreview(Statement sf
, Expressions
* params
)
2230 /* If a base function and its override both have an IN contract, then
2231 * the override in contract must widen the guarantee of the base contract.
2232 * This is checked by generating:
2234 * void derived.in() {
2236 * ... body of derived.in() ...
2239 * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
2241 * assert(false, "Logic error: " ~ thr.msg);
2245 foreach (fdv
; foverrides
)
2247 /* The semantic pass on the contracts of the overridden functions must
2248 * be completed before code generation occurs.
2249 * https://issues.dlang.org/show_bug.cgi?id=3602
2251 if (fdv
.frequires
&& fdv
.semanticRun
!= PASS
.semantic3done
)
2254 Scope
* sc
= fdv
._scope
.push();
2255 sc
.stc &= ~STC
.override_
;
2260 sf
= fdv
.mergeFrequireInclusivePreview(sf
, params
);
2261 if (sf
&& fdv
.fdrequire
)
2263 const loc
= this.fdrequire
.loc
;
2265 //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
2268 * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
2270 Identifier id
= Identifier
.generateId("thr");
2271 params
= Expression
.arraySyntaxCopy(params
);
2272 Expression e
= new CallExp(loc
, new VarExp(loc
, fdv
.fdrequire
, false), params
);
2273 Statement s2
= new ExpStatement(loc
, e
);
2274 // assert(false, ...)
2275 // TODO make this a runtime helper to allow:
2276 // - chaining the original expression
2277 // - nogc concatenation
2278 Expression msg
= new StringExp(loc
, "Logic error: in-contract was tighter than parent in-contract");
2279 Statement fail
= new ExpStatement(loc
, new AssertExp(loc
, IntegerExp
.literal
!0, msg
));
2281 Statement s3
= new CompoundStatement(loc
, s2
, fail
);
2283 auto c
= new Catch(loc
, getThrowable(), id
, s3
);
2284 c
.internalCatch
= true;
2285 auto catches
= new Catches();
2287 sf
= new TryCatchStatement(loc
, sf
, catches
);
2295 /****************************************************
2296 * Determine whether an 'out' contract is declared inside
2297 * the given function or any of its overrides.
2299 * fd = the function to search
2301 * true found an 'out' contract
2303 static bool needsFensure(FuncDeclaration fd
)
2308 foreach (fdv
; fd
.foverrides
)
2310 if (needsFensure(fdv
))
2316 /****************************************************
2317 * Rewrite contracts as statements.
2319 final void buildEnsureRequire()
2324 /* in { statements1... }
2325 * in { statements2... }
2328 * in { { statements1... } { statements2... } ... }
2330 assert(frequires
.dim
);
2331 auto loc
= (*frequires
)[0].loc
;
2332 auto s
= new Statements
;
2333 foreach (r
; *frequires
)
2335 s
.push(new ScopeStatement(r
.loc
, r
, r
.loc
));
2337 frequire
= new CompoundStatement(loc
, s
);
2342 /* out(id1) { statements1... }
2343 * out(id2) { statements2... }
2346 * out(__result) { { ref id1 = __result; { statements1... } }
2347 * { ref id2 = __result; { statements2... } } ... }
2349 assert(fensures
.dim
);
2350 auto loc
= (*fensures
)[0].ensure
.loc
;
2351 auto s
= new Statements
;
2352 foreach (r
; *fensures
)
2354 if (r
.id
&& canBuildResultVar())
2356 auto rloc
= r
.ensure
.loc
;
2357 auto resultId
= new IdentifierExp(rloc
, Id
.result
);
2358 auto init
= new ExpInitializer(rloc
, resultId
);
2359 auto stc = STC
.ref_ | STC
.temp | STC
.result
;
2360 auto decl
= new VarDeclaration(rloc
, null, r
.id
, init
, stc);
2361 auto sdecl
= new ExpStatement(rloc
, decl
);
2362 s
.push(new ScopeStatement(rloc
, new CompoundStatement(rloc
, sdecl
, r
.ensure
), rloc
));
2369 fensure
= new CompoundStatement(loc
, s
);
2375 /* Rewrite contracts as nested functions, then call them. Doing it as nested
2376 * functions means that overriding functions can call them.
2378 TypeFunction f
= cast(TypeFunction
) type
;
2380 /* Make a copy of the parameters and make them all ref */
2381 static Parameters
* toRefCopy(ParameterList parameterList
)
2383 auto result
= new Parameters();
2385 foreach (n
, p
; parameterList
)
2388 if (!(p
.storageClass
& STC
.lazy_
))
2389 p
.storageClass
= (p
.storageClass | STC
.ref_
) & ~STC
.out_
;
2390 p
.defaultArg
= null; // won't be the same with ref
2401 * void __require(ref params) { ... }
2402 * __require(params);
2404 Loc loc
= frequire
.loc
;
2405 fdrequireParams
= new Expressions();
2408 foreach (vd
; *parameters
)
2409 fdrequireParams
.push(new VarExp(loc
, vd
));
2411 auto fo
= cast(TypeFunction
)(originalType ? originalType
: f
);
2412 auto fparams
= toRefCopy(fo
.parameterList
);
2413 auto tf
= new TypeFunction(ParameterList(fparams
), Type
.tvoid
, LINK
.d
);
2414 tf
.isnothrow
= f
.isnothrow
;
2415 tf
.isnogc
= f
.isnogc
;
2416 tf
.purity
= f
.purity
;
2418 auto fd
= new FuncDeclaration(loc
, loc
, Id
.require
, STC
.undefined_
, tf
);
2419 fd
.fbody
= frequire
;
2420 Statement s1
= new ExpStatement(loc
, fd
);
2421 Expression e
= new CallExp(loc
, new VarExp(loc
, fd
, false), fdrequireParams
);
2422 Statement s2
= new ExpStatement(loc
, e
);
2423 frequire
= new CompoundStatement(loc
, s1
, s2
);
2427 /* We need to set fdensureParams here and not in the block below to
2428 * have the parameters available when calling a base class ensure(),
2429 * even if this function doesn't have an out contract.
2431 fdensureParams
= new Expressions();
2432 if (canBuildResultVar())
2433 fdensureParams
.push(new IdentifierExp(loc
, Id
.result
));
2436 foreach (vd
; *parameters
)
2437 fdensureParams
.push(new VarExp(loc
, vd
));
2442 /* out (result) { ... }
2444 * void __ensure(ref tret result, ref params) { ... }
2445 * __ensure(result, params);
2447 Loc loc
= fensure
.loc
;
2448 auto fparams
= new Parameters();
2449 if (canBuildResultVar())
2451 Parameter p
= new Parameter(STC
.ref_ | STC
.const_
, f
.nextOf(), Id
.result
, null, null);
2454 auto fo
= cast(TypeFunction
)(originalType ? originalType
: f
);
2455 fparams
.pushSlice((*toRefCopy(fo
.parameterList
))[]);
2456 auto tf
= new TypeFunction(ParameterList(fparams
), Type
.tvoid
, LINK
.d
);
2457 tf
.isnothrow
= f
.isnothrow
;
2458 tf
.isnogc
= f
.isnogc
;
2459 tf
.purity
= f
.purity
;
2461 auto fd
= new FuncDeclaration(loc
, loc
, Id
.ensure
, STC
.undefined_
, tf
);
2463 Statement s1
= new ExpStatement(loc
, fd
);
2464 Expression e
= new CallExp(loc
, new VarExp(loc
, fd
, false), fdensureParams
);
2465 Statement s2
= new ExpStatement(loc
, e
);
2466 fensure
= new CompoundStatement(loc
, s1
, s2
);
2471 /****************************************************
2472 * Merge into this function the 'out' contracts of all it overrides.
2473 * 'out's are AND'd together, i.e. all of them need to pass.
2475 extern (D
) final Statement
mergeFensure(Statement sf
, Identifier oid
, Expressions
* params
)
2477 /* Same comments as for mergeFrequire(), except that we take care
2478 * of generating a consistent reference to the 'result' local by
2479 * explicitly passing 'result' to the nested function as a reference
2481 * This won't work for the 'this' parameter as it would require changing
2482 * the semantic code for the nested function so that it looks on the parameter
2483 * list for the 'this' pointer, something that would need an unknown amount
2484 * of tweaking of various parts of the compiler that I'd rather leave alone.
2486 foreach (fdv
; foverrides
)
2488 /* The semantic pass on the contracts of the overridden functions must
2489 * be completed before code generation occurs.
2490 * https://issues.dlang.org/show_bug.cgi?id=3602 and
2491 * https://issues.dlang.org/show_bug.cgi?id=5230
2493 if (needsFensure(fdv
) && fdv
.semanticRun
!= PASS
.semantic3done
)
2496 Scope
* sc
= fdv
._scope
.push();
2497 sc
.stc &= ~STC
.override_
;
2502 sf
= fdv
.mergeFensure(sf
, oid
, params
);
2505 //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
2506 // Make the call: __ensure(result, params)
2507 params
= Expression
.arraySyntaxCopy(params
);
2508 if (canBuildResultVar())
2510 Type t1
= fdv
.type
.nextOf().toBasetype();
2511 Type t2
= this.type
.nextOf().toBasetype();
2512 if (t1
.isBaseOf(t2
, null))
2514 /* Making temporary reference variable is necessary
2515 * in covariant return.
2516 * https://issues.dlang.org/show_bug.cgi?id=5204
2517 * https://issues.dlang.org/show_bug.cgi?id=10479
2519 Expression
* eresult
= &(*params
)[0];
2520 auto ei
= new ExpInitializer(Loc
.initial
, *eresult
);
2521 auto v
= new VarDeclaration(Loc
.initial
, t1
, Identifier
.generateId("__covres"), ei
);
2522 v
.storage_class |
= STC
.temp
;
2523 auto de = new DeclarationExp(Loc
.initial
, v
);
2524 auto ve
= new VarExp(Loc
.initial
, v
);
2525 *eresult
= new CommaExp(Loc
.initial
, de, ve
);
2528 Expression e
= new CallExp(loc
, new VarExp(loc
, fdv
.fdensure
, false), params
);
2529 Statement s2
= new ExpStatement(loc
, e
);
2533 sf
= new CompoundStatement(sf
.loc
, s2
, sf
);
2542 /*********************************************
2543 * Returns: the function's parameter list, and whether
2544 * it is variadic or not.
2546 final ParameterList
getParameterList()
2550 TypeFunction fdtype
= type
.isTypeFunction();
2551 if (fdtype
) // Could also be TypeError
2552 return fdtype
.parameterList
;
2555 return ParameterList(null, VarArg
.none
);
2558 /**********************************
2559 * Generate a FuncDeclaration for a runtime library function.
2561 static FuncDeclaration
genCfunc(Parameters
* fparams
, Type treturn
, const(char)* name
, StorageClass
stc = 0)
2563 return genCfunc(fparams
, treturn
, Identifier
.idPool(name
, cast(uint)strlen(name
)), stc);
2566 static FuncDeclaration
genCfunc(Parameters
* fparams
, Type treturn
, Identifier id
, StorageClass
stc = 0)
2571 __gshared DsymbolTable st
= null;
2573 //printf("genCfunc(name = '%s')\n", id.toChars());
2574 //printf("treturn\n\t"); treturn.print();
2576 // See if already in table
2578 st
= new DsymbolTable();
2582 fd
= s
.isFuncDeclaration();
2584 assert(fd
.type
.nextOf().equals(treturn
));
2588 tf
= new TypeFunction(ParameterList(fparams
), treturn
, LINK
.c
, stc);
2589 fd
= new FuncDeclaration(Loc
.initial
, Loc
.initial
, id
, STC
.static_
, tf
);
2590 fd
.visibility
= Visibility(Visibility
.Kind
.public_
);
2591 fd
.linkage
= LINK
.c
;
2599 * Check parameters and return type of D main() function.
2600 * Issue error messages.
2602 extern (D
) final void checkDmain()
2604 TypeFunction tf
= type
.toTypeFunction();
2605 const nparams
= tf
.parameterList
.length
;
2609 auto fparam0
= tf
.parameterList
[0];
2610 auto t
= fparam0
.type
.toBasetype();
2611 if (t
.ty
!= Tarray ||
2612 t
.nextOf().ty
!= Tarray ||
2613 t
.nextOf().nextOf().ty
!= Tchar ||
2614 fparam0
.storageClass
& (STC
.out_ | STC
.ref_ | STC
.lazy_
))
2621 // auto main(), check after semantic
2622 assert(this.inferRetType
);
2623 else if (tf
.nextOf().ty
!= Tint32
&& tf
.nextOf().ty
!= Tvoid
&& tf
.nextOf().ty
!= Tnoreturn
)
2624 error("must return `int`, `void` or `noreturn`, not `%s`", tf
.nextOf().toChars());
2625 else if (tf
.parameterList
.varargs || nparams
>= 2 || argerr
)
2626 error("parameters must be `main()` or `main(string[] args)`");
2629 /***********************************************
2630 * Check all return statements for a function to verify that returning
2631 * using NRVO is possible.
2634 * `false` if the result cannot be returned by hidden reference.
2636 final bool checkNRVO()
2638 if (!nrvo_can || returns
is null)
2641 auto tf
= type
.toTypeFunction();
2645 foreach (rs
; *returns
)
2647 if (auto ve
= rs
.exp
.isVarExp())
2649 auto v
= ve
.var
.isVarDeclaration();
2650 if (!v || v
.isOut() || v
.isRef())
2652 else if (nrvo_var
is null)
2654 // Variables in the data segment (e.g. globals, TLS or not),
2655 // parameters and closure variables cannot be NRVOed.
2656 if (v
.isDataseg() || v
.isParameter() || v
.toParent2() != this)
2658 // The variable type needs to be equivalent to the return type.
2659 if (!v
.type
.equivalent(tf
.next
))
2661 //printf("Setting nrvo to %s\n", v.toChars());
2664 else if (nrvo_var
!= v
)
2667 else //if (!exp.isLvalue()) // keep NRVO-ability
2673 override final inout(FuncDeclaration
) isFuncDeclaration() inout
2678 inout(FuncDeclaration
) toAliasFunc() inout
2683 override void accept(Visitor v
)
2689 /********************************************************
2690 * Generate Expression to call the invariant.
2692 * ad aggregate with the invariant
2693 * vthis variable with 'this'
2695 * void expression that calls the invariant
2697 Expression
addInvariant(AggregateDeclaration ad
, VarDeclaration vthis
)
2699 Expression e
= null;
2700 // Call invariant directly only if it exists
2701 FuncDeclaration inv
= ad
.inv
;
2702 ClassDeclaration cd
= ad
.isClassDeclaration();
2715 // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
2716 // For the correct mangling,
2717 // run attribute inference on inv if needed.
2718 inv
.functionSemantic();
2721 //e = new DsymbolExp(Loc.initial, inv);
2722 //e = new CallExp(Loc.initial, e);
2723 //e = e.semantic(sc2);
2725 /* https://issues.dlang.org/show_bug.cgi?id=13113
2726 * Currently virtual invariant calls completely
2727 * bypass attribute enforcement.
2728 * Change the behavior of pre-invariant call by following it.
2730 e
= new ThisExp(Loc
.initial
);
2731 e
.type
= ad
.type
.addMod(vthis
.type
.mod
);
2732 e
= new DotVarExp(Loc
.initial
, e
, inv
, false);
2734 e
= new CallExp(Loc
.initial
, e
);
2735 e
.type
= Type
.tvoid
;
2740 /***************************************************
2741 * Visit each overloaded function/template in turn, and call dg(s) on it.
2742 * Exit when no more, or dg(s) returns nonzero.
2745 * fstart = symbol to start from
2746 * dg = the delegate to be called on the overload
2747 * sc = context used to check if symbol is accessible (and therefore visible),
2752 * !=0 done (and the return value from the last dg() call)
2754 extern (D
) int overloadApply(Dsymbol fstart
, scope int delegate(Dsymbol
) dg
, Scope
* sc
= null)
2757 for (auto d
= fstart
; d
; d
= next
)
2759 import dmd
.access
: checkSymbolAccess
;
2760 if (auto od
= d
.isOverDeclaration())
2762 /* The scope is needed here to check whether a function in
2763 an overload set was added by means of a private alias (or a
2764 selective import). If the scope where the alias is created
2765 is imported somewhere, the overload set is visible, but the private
2770 if (checkSymbolAccess(sc
, od
))
2772 if (int r
= overloadApply(od
.aliassym
, dg
, sc
))
2776 else if (int r
= overloadApply(od
.aliassym
, dg
, sc
))
2780 else if (auto fa
= d
.isFuncAliasDeclaration())
2782 if (fa
.hasOverloads
)
2784 if (int r
= overloadApply(fa
.funcalias
, dg
, sc
))
2787 else if (auto fd
= fa
.toAliasFunc())
2794 d
.error("is aliased to a function");
2799 else if (auto ad
= d
.isAliasDeclaration())
2803 if (checkSymbolAccess(sc
, ad
))
2804 next
= ad
.toAlias();
2807 next
= ad
.toAlias();
2813 else if (auto td
= d
.isTemplateDeclaration())
2819 else if (auto fd
= d
.isFuncDeclaration())
2825 else if (auto os
= d
.isOverloadSet())
2833 d
.error("is aliased to a function");
2835 // BUG: should print error message?
2842 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
2843 mismatching modifiers to `buf`.
2845 The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
2846 lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
2849 buf = output buffer to write to
2850 lhsMod = modifier on the left-hand side
2851 lhsMod = modifier on the right-hand side
2855 A tuple with `isMutable` and `isNotShared` set
2856 if the `lhsMod` is missing those modifiers (compared to rhs).
2858 auto MODMatchToBuffer(OutBuffer
* buf
, ubyte lhsMod
, ubyte rhsMod
)
2860 static struct Mismatches
2866 Mismatches mismatches
;
2868 bool bothMutable
= ((lhsMod
& rhsMod
) == 0);
2869 bool sharedMismatch
= ((lhsMod ^ rhsMod
) & MODFlags
.shared_
) != 0;
2870 bool sharedMismatchOnly
= ((lhsMod ^ rhsMod
) == MODFlags
.shared_
);
2872 if (lhsMod
& MODFlags
.shared_
)
2873 buf
.writestring("`shared` ");
2874 else if (sharedMismatch
&& !(lhsMod
& MODFlags
.immutable_
))
2876 buf
.writestring("non-shared ");
2877 mismatches
.isNotShared
= true;
2880 if (bothMutable
&& sharedMismatchOnly
)
2883 else if (lhsMod
& MODFlags
.immutable_
)
2884 buf
.writestring("`immutable` ");
2885 else if (lhsMod
& MODFlags
.const_
)
2886 buf
.writestring("`const` ");
2887 else if (lhsMod
& MODFlags
.wild
)
2888 buf
.writestring("`inout` ");
2891 buf
.writestring("mutable ");
2892 mismatches
.isMutable
= true;
2902 auto mismatches
= MODMatchToBuffer(&buf
, MODFlags
.shared_
, 0);
2903 assert(buf
[] == "`shared` ");
2904 assert(!mismatches
.isNotShared
);
2907 mismatches
= MODMatchToBuffer(&buf
, 0, MODFlags
.shared_
);
2908 assert(buf
[] == "non-shared ");
2909 assert(mismatches
.isNotShared
);
2912 mismatches
= MODMatchToBuffer(&buf
, MODFlags
.const_
, 0);
2913 assert(buf
[] == "`const` ");
2914 assert(!mismatches
.isMutable
);
2917 mismatches
= MODMatchToBuffer(&buf
, 0, MODFlags
.const_
);
2918 assert(buf
[] == "mutable ");
2919 assert(mismatches
.isMutable
);
2922 private const(char)* prependSpace(const(char)* str)
2924 if (!str ||
!*str) return "";
2926 return (" " ~ str.toDString() ~ "\0").ptr
;
2929 /// Flag used by $(LREF resolveFuncCall).
2930 enum FuncResolveFlag
: ubyte
2932 standard
= 0, /// issue error messages, solve the call.
2933 quiet
= 1, /// do not issue error message on no match, just return `null`.
2934 overloadOnly
= 2, /// only resolve overloads, i.e. do not issue error on ambiguous
2935 /// matches and need explicit this.
2938 /*******************************************
2939 * Given a symbol that could be either a FuncDeclaration or
2940 * a function template, resolve it to a function symbol.
2942 * loc = instantiation location
2943 * sc = instantiation scope
2944 * s = instantiation symbol
2945 * tiargs = initial list of template arguments
2946 * tthis = if !NULL, the `this` argument type
2947 * fargs = arguments to function
2948 * flags = see $(LREF FuncResolveFlag).
2950 * if match is found, then function symbol, else null
2952 FuncDeclaration
resolveFuncCall(const ref Loc loc
, Scope
* sc
, Dsymbol s
,
2953 Objects
* tiargs
, Type tthis
, Expressions
* fargs
, FuncResolveFlag flags
)
2956 return null; // no match
2960 printf("resolveFuncCall('%s')\n", s
.toChars());
2962 printf("\tthis: %s\n", tthis
.toChars());
2965 for (size_t i
= 0; i
< fargs
.dim
; i
++)
2967 Expression arg
= (*fargs
)[i
];
2969 printf("\t%s: %s\n", arg
.toChars(), arg
.type
.toChars());
2974 if (tiargs
&& arrayObjectIsError(tiargs
) ||
2975 fargs
&& arrayObjectIsError(cast(Objects
*)fargs
))
2981 functionResolve(m
, s
, loc
, sc
, tiargs
, tthis
, fargs
, null);
2984 if (m
.last
> MATCH
.nomatch
&& m
.lastf
)
2986 if (m
.count
== 1) // exactly one match
2988 if (!(flags
& FuncResolveFlag
.quiet
))
2989 m
.lastf
.functionSemantic();
2992 if ((flags
& FuncResolveFlag
.overloadOnly
) && !tthis
&& m
.lastf
.needThis())
2998 /* Failed to find a best match.
2999 * Do nothing or print error.
3001 if (m
.last
== MATCH
.nomatch
)
3003 // error was caused on matched function, not on the matching itself,
3004 // so return the function to produce a better diagnostic
3009 // We are done at this point, as the rest of this function generate
3010 // a diagnostic on invalid match
3011 if (flags
& FuncResolveFlag
.quiet
)
3014 auto fd
= s
.isFuncDeclaration();
3015 auto od
= s
.isOverDeclaration();
3016 auto td
= s
.isTemplateDeclaration();
3017 if (td
&& td
.funcroot
)
3018 s
= fd
= td
.funcroot
;
3020 OutBuffer tiargsBuf
;
3021 arrayObjectsToBuffer(&tiargsBuf
, tiargs
);
3024 fargsBuf
.writeByte('(');
3025 argExpTypesToCBuffer(&fargsBuf
, fargs
);
3026 fargsBuf
.writeByte(')');
3028 tthis
.modToBuffer(&fargsBuf
);
3030 // The call is ambiguous
3031 if (m
.lastf
&& m
.nextf
)
3033 TypeFunction tf1
= m
.lastf
.type
.toTypeFunction();
3034 TypeFunction tf2
= m
.nextf
.type
.toTypeFunction();
3035 const(char)* lastprms
= parametersTypeToChars(tf1
.parameterList
);
3036 const(char)* nextprms
= parametersTypeToChars(tf2
.parameterList
);
3038 const(char)* mod1
= prependSpace(MODtoChars(tf1
.mod
));
3039 const(char)* mod2
= prependSpace(MODtoChars(tf2
.mod
));
3041 .error(loc
, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
3042 s
.parent
.toPrettyChars(), s
.ident
.toChars(),
3043 fargsBuf
.peekChars(),
3044 m
.lastf
.loc
.toChars(), m
.lastf
.toPrettyChars(), lastprms
, mod1
,
3045 m
.nextf
.loc
.toChars(), m
.nextf
.toPrettyChars(), nextprms
, mod2
);
3049 // no match, generate an error messages
3052 // all of overloads are templates
3055 .error(loc
, "%s `%s.%s` cannot deduce function from argument types `!(%s)%s`",
3056 td
.kind(), td
.parent
.toPrettyChars(), td
.ident
.toChars(),
3057 tiargsBuf
.peekChars(), fargsBuf
.peekChars());
3059 printCandidates(loc
, td
, sc
.isDeprecated());
3062 /* This case used to happen when several ctors are mixed in an agregate.
3063 A (bad) error message is already generated in overloadApply().
3064 see https://issues.dlang.org/show_bug.cgi?id=19729
3065 and https://issues.dlang.org/show_bug.cgi?id=17259
3073 .error(loc
, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
3074 od
.ident
.toChars(), tiargsBuf
.peekChars(), fargsBuf
.peekChars());
3078 // remove when deprecation period of class allocators and deallocators is over
3079 if (fd
.isNewDeclaration() && fd
.checkDisabled(loc
, sc
))
3082 bool hasOverloads
= fd
.overnext
!is null;
3083 auto tf
= fd
.type
.isTypeFunction();
3084 // if type is an error, the original type should be there for better diagnostics
3086 tf
= fd
.originalType
.toTypeFunction();
3088 if (tthis
&& !MODimplicitConv(tthis
.mod
, tf
.mod
)) // modifier mismatch
3090 OutBuffer thisBuf
, funcBuf
;
3091 MODMatchToBuffer(&thisBuf
, tthis
.mod
, tf
.mod
);
3092 auto mismatches
= MODMatchToBuffer(&funcBuf
, tf
.mod
, tthis
.mod
);
3095 .error(loc
, "none of the overloads of `%s` are callable using a %sobject",
3096 fd
.ident
.toChars(), thisBuf
.peekChars());
3097 printCandidates(loc
, fd
, sc
.isDeprecated());
3101 const(char)* failMessage
;
3102 functionResolve(m
, orig_s
, loc
, sc
, tiargs
, tthis
, fargs
, &failMessage
);
3105 .error(loc
, "%s `%s%s%s` is not callable using argument types `%s`",
3106 fd
.kind(), fd
.toPrettyChars(), parametersTypeToChars(tf
.parameterList
),
3107 tf
.modToChars(), fargsBuf
.peekChars());
3108 errorSupplemental(loc
, failMessage
);
3112 .error(loc
, "%smethod `%s` is not callable using a %sobject",
3113 funcBuf
.peekChars(), fd
.toPrettyChars(), thisBuf
.peekChars());
3115 if (mismatches
.isNotShared
)
3116 .errorSupplemental(fd
.loc
, "Consider adding `shared` here");
3117 else if (mismatches
.isMutable
)
3118 .errorSupplemental(fd
.loc
, "Consider adding `const` or `inout` here");
3122 //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
3125 .error(loc
, "none of the overloads of `%s` are callable using argument types `%s`",
3126 fd
.toChars(), fargsBuf
.peekChars());
3127 printCandidates(loc
, fd
, sc
.isDeprecated());
3131 .error(loc
, "%s `%s%s%s` is not callable using argument types `%s`",
3132 fd
.kind(), fd
.toPrettyChars(), parametersTypeToChars(tf
.parameterList
),
3133 tf
.modToChars(), fargsBuf
.peekChars());
3134 // re-resolve to check for supplemental message
3135 const(char)* failMessage
;
3136 functionResolve(m
, orig_s
, loc
, sc
, tiargs
, tthis
, fargs
, &failMessage
);
3138 errorSupplemental(loc
, failMessage
);
3142 /*******************************************
3143 * Prints template and function overload candidates as supplemental errors.
3145 * loc = instantiation location
3146 * declaration = the declaration to print overload candidates for
3147 * showDeprecated = If `false`, `deprecated` function won't be shown
3149 private void printCandidates(Decl
)(const ref Loc loc
, Decl declaration
, bool showDeprecated
)
3150 if (is(Decl
== TemplateDeclaration
) ||
is(Decl
== FuncDeclaration
))
3152 // max num of overloads to print (-v overrides this).
3153 enum int DisplayLimit
= 5;
3155 const(char)* constraintsTip
;
3157 // determine if the first candidate was printed
3158 bool printed
= false;
3160 overloadApply(declaration
, (Dsymbol s
)
3162 Dsymbol nextOverload
;
3164 if (auto fd
= s
.isFuncDeclaration())
3166 // Don't print overloads which have errors.
3167 // Not that if the whole overload set has errors, we'll never reach
3168 // this point so there's no risk of printing no candidate
3169 if (fd
.errors || fd
.type
.ty
== Terror
)
3171 // Don't print disabled functions, or `deprecated` outside of deprecated scope
3172 if (fd
.storage_class
& STC
.disable ||
(fd
.isDeprecated() && !showDeprecated
))
3175 const single_candidate
= fd
.overnext
is null;
3176 auto tf
= cast(TypeFunction
) fd
.type
;
3177 .errorSupplemental(fd
.loc
,
3178 printed ?
" `%s%s`" :
3179 single_candidate ?
"Candidate is: `%s%s`" : "Candidates are: `%s%s`",
3181 parametersTypeToChars(tf
.parameterList
));
3183 nextOverload
= fd
.overnext
;
3185 else if (auto td
= s
.isTemplateDeclaration())
3187 import dmd
.staticcond
;
3189 const tmsg
= td
.toCharsNoConstraints();
3190 const cmsg
= td
.getConstraintEvalError(constraintsTip
);
3192 const single_candidate
= td
.overnext
is null;
3194 // add blank space if there are multiple candidates
3195 // the length of the blank space is `strlen("Candidates are: ")`
3199 .errorSupplemental(td
.loc
,
3200 printed ?
" `%s`\n%s" :
3201 single_candidate ?
"Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
3207 .errorSupplemental(td
.loc
,
3209 single_candidate ?
"Candidate is: `%s`" : "Candidates are: `%s`",
3213 nextOverload
= td
.overnext
;
3216 if (global
.params
.verbose ||
++displayed
< DisplayLimit
)
3219 // Too many overloads to sensibly display.
3220 // Just show count of remaining overloads.
3222 overloadApply(nextOverload
, (s
) { ++num
; return 0; });
3225 .errorSupplemental(loc
, "... (%d more, -v to show) ...", num
);
3226 return 1; // stop iterating
3229 // Nothing was displayed, all overloads are either disabled or deprecated
3231 .errorSupplemental(loc
, "All possible candidates are marked as `deprecated` or `@disable`");
3232 // should be only in verbose mode
3234 .tip(constraintsTip
);
3237 /**************************************
3238 * Returns an indirect type one step from t.
3240 Type
getIndirection(Type t
)
3243 if (t
.ty
== Tarray || t
.ty
== Tpointer
)
3244 return t
.nextOf().toBasetype();
3245 if (t
.ty
== Taarray || t
.ty
== Tclass
)
3247 if (t
.ty
== Tstruct
)
3248 return t
.hasPointers() ? t
: null; // TODO
3250 // should consider TypeDelegate?
3254 /**************************************
3255 * Performs type-based alias analysis between a newly created value and a pre-
3256 * existing memory reference:
3258 * Assuming that a reference A to a value of type `ta` was available to the code
3259 * that created a reference B to a value of type `tb`, it returns whether B
3260 * might alias memory reachable from A based on the types involved (either
3261 * directly or via any number of indirections in either A or B).
3263 * This relation is not symmetric in the two arguments. For example, a
3264 * a `const(int)` reference can point to a pre-existing `int`, but not the other
3270 * `const(int)`, `int`, `false`
3271 * `int`, `const(int)`, `true`
3272 * `int`, `immutable(int)`, `false`
3273 * const(immutable(int)*), immutable(int)*, false // BUG: returns true
3276 * ta = value type being referred to
3277 * tb = referred to value type that could be constructed from ta
3280 * true if reference to `tb` is isolated from reference to `ta`
3282 private bool traverseIndirections(Type ta
, Type tb
)
3284 //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
3286 static bool traverse(Type ta
, Type tb
, ref scope AssocArray
!(const(char)*, bool) table
, bool reversePass
)
3288 //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
3289 ta
= ta
.baseElemOf();
3290 tb
= tb
.baseElemOf();
3292 // First, check if the pointed-to types are convertible to each other such
3293 // that they might alias directly.
3294 static bool mayAliasDirect(Type source
, Type target
)
3297 // if source is the same as target or can be const-converted to target
3298 source
.constConv(target
) != MATCH
.nomatch ||
3299 // if target is void and source can be const-converted to target
3300 (target
.ty
== Tvoid
&& MODimplicitConv(source
.mod
, target
.mod
));
3303 if (mayAliasDirect(reversePass ? tb
: ta
, reversePass ? ta
: tb
))
3305 //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3308 if (ta
.nextOf() && ta
.nextOf() == tb
.nextOf())
3310 //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
3314 if (tb
.ty
== Tclass || tb
.ty
== Tstruct
)
3316 /* Traverse the type of each field of the aggregate
3318 bool* found
= table
.getLvalue(tb
.deco
);
3320 return true; // We have already seen this symbol, break the cycle
3324 AggregateDeclaration sym
= tb
.toDsymbol(null).isAggregateDeclaration();
3325 foreach (v
; sym
.fields
)
3327 Type tprmi
= v
.type
.addMod(tb
.mod
);
3328 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
3329 if (!traverse(ta
, tprmi
, table
, reversePass
))
3333 else if (tb
.ty
== Tarray || tb
.ty
== Taarray || tb
.ty
== Tpointer
)
3335 Type tind
= tb
.nextOf();
3336 if (!traverse(ta
, tind
, table
, reversePass
))
3339 else if (tb
.hasPointers())
3341 // BUG: consider the context pointer of delegate types
3345 // Still no match, so try breaking up ta if we have not done so yet.
3348 scope newTable
= AssocArray
!(const(char)*, bool)();
3349 return traverse(tb
, ta
, newTable
, true);
3355 // To handle arbitrary levels of indirections in both parameters, we
3356 // recursively descend into aggregate members/levels of indirection in both
3357 // `ta` and `tb` while avoiding cycles. Start with the original types.
3358 scope table
= AssocArray
!(const(char)*, bool)();
3359 const result
= traverse(ta
, tb
, table
, false);
3360 //printf(" returns %d\n", result);
3364 /* For all functions between outerFunc and f, mark them as needing
3367 private void markAsNeedingClosure(Dsymbol f
, FuncDeclaration outerFunc
)
3369 for (Dsymbol sx
= f
; sx
&& sx
!= outerFunc
; sx
= sx
.toParentP(outerFunc
))
3371 FuncDeclaration fy
= sx
.isFuncDeclaration();
3372 if (fy
&& fy
.closureVars
.dim
)
3374 /* fy needs a closure if it has closureVars[],
3375 * because the frame pointer in the closure will be accessed.
3377 fy
.requiresClosure
= true;
3383 * Given a nested function f inside a function outerFunc, check
3384 * if any sibling callers of f have escaped. If so, mark
3385 * all the enclosing functions as needing closures.
3386 * This is recursive: we need to check the callers of our siblings.
3387 * Note that nested functions can only call lexically earlier nested
3388 * functions, so loops are impossible.
3390 * f = inner function (nested within outerFunc)
3391 * outerFunc = outer function
3392 * p = for internal recursion use
3394 * true if any closures were needed
3396 private bool checkEscapingSiblings(FuncDeclaration f
, FuncDeclaration outerFunc
, void* p
= null)
3398 static struct PrevSibling
3405 ps
.p
= cast(PrevSibling
*)p
;
3408 //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
3409 bool bAnyClosures
= false;
3410 for (size_t i
= 0; i
< f
.siblingCallers
.dim
; ++i
)
3412 FuncDeclaration g
= f
.siblingCallers
[i
];
3413 if (g
.isThis() || g
.tookAddressOf
)
3415 markAsNeedingClosure(g
, outerFunc
);
3416 bAnyClosures
= true;
3419 for (auto parent
= g
.toParentP(outerFunc
); parent
&& parent
!is outerFunc
; parent
= parent
.toParentP(outerFunc
))
3421 // A parent of the sibling had its address taken.
3422 // Assume escaping of parent affects its children, so needs propagating.
3423 // see https://issues.dlang.org/show_bug.cgi?id=19679
3424 FuncDeclaration parentFunc
= parent
.isFuncDeclaration
;
3425 if (parentFunc
&& parentFunc
.tookAddressOf
)
3427 markAsNeedingClosure(parentFunc
, outerFunc
);
3428 bAnyClosures
= true;
3432 PrevSibling
* prev
= cast(PrevSibling
*)p
;
3437 bAnyClosures |
= checkEscapingSiblings(g
, outerFunc
, &ps
);
3445 //printf("\t%d\n", bAnyClosures);
3446 return bAnyClosures
;
3449 /***********************************************************
3450 * Used as a way to import a set of functions from another scope into this one.
3452 extern (C
++) final class FuncAliasDeclaration
: FuncDeclaration
3454 FuncDeclaration funcalias
;
3457 extern (D
) this(Identifier ident
, FuncDeclaration funcalias
, bool hasOverloads
= true)
3459 super(funcalias
.loc
, funcalias
.endloc
, ident
, funcalias
.storage_class
, funcalias
.type
);
3460 assert(funcalias
!= this);
3461 this.funcalias
= funcalias
;
3463 this.hasOverloads
= hasOverloads
;
3466 if (FuncAliasDeclaration fad
= funcalias
.isFuncAliasDeclaration())
3467 this.hasOverloads
= fad
.hasOverloads
;
3472 assert(!funcalias
.isFuncAliasDeclaration());
3473 this.hasOverloads
= false;
3475 userAttribDecl
= funcalias
.userAttribDecl
;
3478 override inout(FuncAliasDeclaration
) isFuncAliasDeclaration() inout
3483 override const(char)* kind() const
3485 return "function alias";
3488 override inout(FuncDeclaration
) toAliasFunc() inout
3490 return funcalias
.toAliasFunc();
3493 override void accept(Visitor v
)
3499 /***********************************************************
3501 extern (C
++) final class FuncLiteralDeclaration
: FuncDeclaration
3503 TOK tok
; // TOK.function_ or TOK.delegate_
3504 Type treq
; // target of return type inference
3509 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, Type type
, TOK tok
, ForeachStatement fes
, Identifier id
= null)
3511 super(loc
, endloc
, null, STC
.undefined_
, type
);
3512 this.ident
= id ? id
: Id
.empty
;
3515 // Always infer scope for function literals
3516 // See https://issues.dlang.org/show_bug.cgi?id=20362
3517 this.flags |
= FUNCFLAG
.inferScope
;
3518 //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
3521 override FuncLiteralDeclaration
syntaxCopy(Dsymbol s
)
3523 //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
3525 auto f
= new FuncLiteralDeclaration(loc
, endloc
, type
.syntaxCopy(), tok
, fes
, ident
);
3526 f
.treq
= treq
; // don't need to copy
3527 FuncDeclaration
.syntaxCopy(f
);
3531 override bool isNested() const
3533 //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
3534 return (tok
!= TOK
.function_
) && !isThis();
3537 override inout(AggregateDeclaration
) isThis() inout
3539 return tok
== TOK
.delegate_ ?
super.isThis() : null;
3542 override bool isVirtual() const
3547 override bool addPreInvariant()
3552 override bool addPostInvariant()
3557 /*******************************
3558 * Modify all expression type of return statements to tret.
3560 * On function literals, return type may be modified based on the context type
3561 * after its semantic3 is done, in FuncExp::implicitCastTo.
3563 * A function() dg = (){ return new B(); } // OK if is(B : A) == true
3565 * If B to A conversion is convariant that requires offseet adjusting,
3566 * all return statements should be adjusted to return expressions typed A.
3568 void modifyReturns(Scope
* sc
, Type tret
)
3570 import dmd
.statement_rewrite_walker
;
3572 extern (C
++) final class RetWalker
: StatementRewriteWalker
3574 alias visit
= typeof(super).visit
;
3578 FuncLiteralDeclaration
fld;
3580 override void visit(ReturnStatement s
)
3582 Expression exp
= s
.exp
;
3583 if (exp
&& !exp
.type
.equals(tret
))
3585 s
.exp
= exp
.castTo(sc
, tret
);
3590 if (semanticRun
< PASS
.semantic3done
)
3596 scope RetWalker w
= new RetWalker();
3602 // Also update the inferred function type to match the new return type.
3603 // This is required so the code generator does not try to cast the
3604 // modified returns back to the original type.
3605 if (inferRetType
&& type
.nextOf() != tret
)
3606 type
.toTypeFunction().next
= tret
;
3609 override inout(FuncLiteralDeclaration
) isFuncLiteralDeclaration() inout
3614 override const(char)* kind() const
3616 // GCC requires the (char*) casts
3617 return (tok
!= TOK
.function_
) ?
"delegate" : "function";
3620 override const(char)* toPrettyChars(bool QualifyTypes
= false)
3624 TemplateInstance ti
= parent
.isTemplateInstance();
3626 return ti
.tempdecl
.toPrettyChars(QualifyTypes
);
3628 return Dsymbol
.toPrettyChars(QualifyTypes
);
3631 override void accept(Visitor v
)
3637 /***********************************************************
3639 extern (C
++) final class CtorDeclaration
: FuncDeclaration
3642 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc, Type type
, bool isCpCtor
= false)
3644 super(loc
, endloc
, Id
.ctor
, stc, type
);
3645 this.isCpCtor
= isCpCtor
;
3646 //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars());
3649 override CtorDeclaration
syntaxCopy(Dsymbol s
)
3652 auto f
= new CtorDeclaration(loc
, endloc
, storage_class
, type
.syntaxCopy());
3653 FuncDeclaration
.syntaxCopy(f
);
3657 override const(char)* kind() const
3659 return isCpCtor ?
"copy constructor" : "constructor";
3662 override const(char)* toChars() const
3667 override bool isVirtual() const
3672 override bool addPreInvariant()
3677 override bool addPostInvariant()
3679 return (isThis() && vthis
&& global
.params
.useInvariants
== CHECKENABLE
.on
);
3682 override inout(CtorDeclaration
) isCtorDeclaration() inout
3687 override void accept(Visitor v
)
3693 /***********************************************************
3695 extern (C
++) final class PostBlitDeclaration
: FuncDeclaration
3697 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc, Identifier id
)
3699 super(loc
, endloc
, id
, stc, null);
3702 override PostBlitDeclaration
syntaxCopy(Dsymbol s
)
3705 auto dd = new PostBlitDeclaration(loc
, endloc
, storage_class
, ident
);
3706 FuncDeclaration
.syntaxCopy(dd);
3710 override bool isVirtual() const
3715 override bool addPreInvariant()
3720 override bool addPostInvariant()
3722 return (isThis() && vthis
&& global
.params
.useInvariants
== CHECKENABLE
.on
);
3725 override bool overloadInsert(Dsymbol s
)
3727 return false; // cannot overload postblits
3730 override inout(PostBlitDeclaration
) isPostBlitDeclaration() inout
3735 override void accept(Visitor v
)
3741 /***********************************************************
3743 extern (C
++) final class DtorDeclaration
: FuncDeclaration
3745 extern (D
) this(const ref Loc loc
, const ref Loc endloc
)
3747 super(loc
, endloc
, Id
.dtor
, STC
.undefined_
, null);
3750 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc, Identifier id
)
3752 super(loc
, endloc
, id
, stc, null);
3755 override DtorDeclaration
syntaxCopy(Dsymbol s
)
3758 auto dd = new DtorDeclaration(loc
, endloc
, storage_class
, ident
);
3759 FuncDeclaration
.syntaxCopy(dd);
3763 override const(char)* kind() const
3765 return "destructor";
3768 override const(char)* toChars() const
3773 override bool isVirtual() const
3775 // D dtor's don't get put into the vtbl[]
3776 // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
3777 return vtblIndex
!= -1;
3780 override bool addPreInvariant()
3782 return (isThis() && vthis
&& global
.params
.useInvariants
== CHECKENABLE
.on
);
3785 override bool addPostInvariant()
3790 override bool overloadInsert(Dsymbol s
)
3792 return false; // cannot overload destructors
3795 override inout(DtorDeclaration
) isDtorDeclaration() inout
3800 override void accept(Visitor v
)
3806 /***********************************************************
3808 extern (C
++) class StaticCtorDeclaration
: FuncDeclaration
3810 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc)
3812 super(loc
, endloc
, Identifier
.generateIdWithLoc("_staticCtor", loc
), STC
.static_ |
stc, null);
3815 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, string name
, StorageClass
stc)
3817 super(loc
, endloc
, Identifier
.generateIdWithLoc(name
, loc
), STC
.static_ |
stc, null);
3820 override StaticCtorDeclaration
syntaxCopy(Dsymbol s
)
3823 auto scd
= new StaticCtorDeclaration(loc
, endloc
, storage_class
);
3824 FuncDeclaration
.syntaxCopy(scd
);
3828 override final inout(AggregateDeclaration
) isThis() inout @nogc nothrow pure @safe
3833 override final bool isVirtual() const @nogc nothrow pure @safe
3838 override final bool addPreInvariant() @nogc nothrow pure @safe
3843 override final bool addPostInvariant() @nogc nothrow pure @safe
3848 override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
3853 override final inout(StaticCtorDeclaration
) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
3858 override void accept(Visitor v
)
3864 /***********************************************************
3866 extern (C
++) final class SharedStaticCtorDeclaration
: StaticCtorDeclaration
3868 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc)
3870 super(loc
, endloc
, "_sharedStaticCtor", stc);
3873 override SharedStaticCtorDeclaration
syntaxCopy(Dsymbol s
)
3876 auto scd
= new SharedStaticCtorDeclaration(loc
, endloc
, storage_class
);
3877 FuncDeclaration
.syntaxCopy(scd
);
3881 override inout(SharedStaticCtorDeclaration
) isSharedStaticCtorDeclaration() inout
3886 override void accept(Visitor v
)
3892 /***********************************************************
3894 extern (C
++) class StaticDtorDeclaration
: FuncDeclaration
3896 VarDeclaration vgate
; // 'gate' variable
3898 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc)
3900 super(loc
, endloc
, Identifier
.generateIdWithLoc("_staticDtor", loc
), STC
.static_ |
stc, null);
3903 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, string name
, StorageClass
stc)
3905 super(loc
, endloc
, Identifier
.generateIdWithLoc(name
, loc
), STC
.static_ |
stc, null);
3908 override StaticDtorDeclaration
syntaxCopy(Dsymbol s
)
3911 auto sdd
= new StaticDtorDeclaration(loc
, endloc
, storage_class
);
3912 FuncDeclaration
.syntaxCopy(sdd
);
3916 override final inout(AggregateDeclaration
) isThis() inout
3921 override final bool isVirtual() const
3926 override final bool hasStaticCtorOrDtor()
3931 override final bool addPreInvariant()
3936 override final bool addPostInvariant()
3941 override final inout(StaticDtorDeclaration
) isStaticDtorDeclaration() inout
3946 override void accept(Visitor v
)
3952 /***********************************************************
3954 extern (C
++) final class SharedStaticDtorDeclaration
: StaticDtorDeclaration
3956 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc)
3958 super(loc
, endloc
, "_sharedStaticDtor", stc);
3961 override SharedStaticDtorDeclaration
syntaxCopy(Dsymbol s
)
3964 auto sdd
= new SharedStaticDtorDeclaration(loc
, endloc
, storage_class
);
3965 FuncDeclaration
.syntaxCopy(sdd
);
3969 override inout(SharedStaticDtorDeclaration
) isSharedStaticDtorDeclaration() inout
3974 override void accept(Visitor v
)
3980 /***********************************************************
3982 extern (C
++) final class InvariantDeclaration
: FuncDeclaration
3984 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc, Identifier id
, Statement fbody
)
3986 super(loc
, endloc
, id ? id
: Identifier
.generateId("__invariant"), stc, null);
3990 override InvariantDeclaration
syntaxCopy(Dsymbol s
)
3993 auto id
= new InvariantDeclaration(loc
, endloc
, storage_class
, null, null);
3994 FuncDeclaration
.syntaxCopy(id
);
3998 override bool isVirtual() const
4003 override bool addPreInvariant()
4008 override bool addPostInvariant()
4013 override inout(InvariantDeclaration
) isInvariantDeclaration() inout
4018 override void accept(Visitor v
)
4025 /***********************************************************
4027 extern (C
++) final class UnitTestDeclaration
: FuncDeclaration
4029 char* codedoc
; // for documented unittest
4031 // toObjFile() these nested functions after this one
4032 FuncDeclarations deferredNested
;
4034 extern (D
) this(const ref Loc loc
, const ref Loc endloc
, StorageClass
stc, char* codedoc
)
4036 super(loc
, endloc
, Identifier
.generateIdWithLoc("__unittest", loc
), stc, null);
4037 this.codedoc
= codedoc
;
4040 override UnitTestDeclaration
syntaxCopy(Dsymbol s
)
4043 auto utd
= new UnitTestDeclaration(loc
, endloc
, storage_class
, codedoc
);
4044 FuncDeclaration
.syntaxCopy(utd
);
4048 override inout(AggregateDeclaration
) isThis() inout
4053 override bool isVirtual() const
4058 override bool addPreInvariant()
4063 override bool addPostInvariant()
4068 override inout(UnitTestDeclaration
) isUnitTestDeclaration() inout
4073 override void accept(Visitor v
)
4079 /***********************************************************
4081 extern (C
++) final class NewDeclaration
: FuncDeclaration
4083 extern (D
) this(const ref Loc loc
, StorageClass
stc)
4085 super(loc
, Loc
.initial
, Id
.classNew
, STC
.static_ |
stc, null);
4088 override NewDeclaration
syntaxCopy(Dsymbol s
)
4091 auto f
= new NewDeclaration(loc
, storage_class
);
4092 FuncDeclaration
.syntaxCopy(f
);
4096 override const(char)* kind() const
4101 override bool isVirtual() const
4106 override bool addPreInvariant()
4111 override bool addPostInvariant()
4116 override inout(NewDeclaration
) isNewDeclaration() inout
4121 override void accept(Visitor v
)