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