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