Most of the logic to implement scoped pointers and scoped references is here.
Groups global state for escape checking together
Called byinitDMD /deinitializeDMD to reset global state
bool
checkMutableArguments(ref Scope
sc, FuncDeclaration
fd, TypeFunction
tf, Expression
ethis, Expressions*
arguments, bool
gag);
Checks memory objects passed to a function. Checks that if a memory object is passed by ref or by pointer, all of the refs or pointers are const, or there is only one mutable ref or pointer to it.
Parameters:Scopesc | used to determine current function and module |
FuncDeclarationfd | function being called |
TypeFunctiontf | fd's type |
Expressionethis | if not null, thethis pointer |
Expressions*arguments | actual arguments to function |
boolgag | do not print error messages |
bool
checkArrayLiteralEscape(ref Scope
sc, ArrayLiteralExp
ae, bool
gag);
Array literal is going to be allocated on the GC heap. Check its elements to see if any would escape by going on the heap.
Parameters:Scopesc | used to determine current function and module |
ArrayLiteralExpae | array literal expression |
boolgag | do not print error messages |
Returns:true if any elements escaped
bool
checkAssocArrayLiteralEscape(ref Scope
sc, AssocArrayLiteralExp
ae, bool
gag);
Associative array literal is going to be allocated on the GC heap. Check its elements to see if any would escape by going on the heap.
Parameters:Scopesc | used to determine current function and module |
AssocArrayLiteralExpae | associative array literal expression |
boolgag | do not print error messages |
Returns:true if any elements escaped
bool
checkParamArgumentEscape(ref Scope
sc, FuncDeclaration
fdc, Identifier
parId, VarDeclaration
vPar, STC
parStc, Expression
arg, bool
assertmsg, bool
gag);
Function parameterpar is being initialized toarg, andpar may escape. Detect if scoped values can escape this way. Print error messages when these are detected.
Parameters:Scopesc | used to determine current function and module |
FuncDeclarationfdc | function being called,null if called indirectly |
IdentifierparId | name of function parameter for error messages |
VarDeclarationvPar | VarDeclaration corresponding topar |
STCparStc | storage classes of function parameter (may have addedscope frompure) |
Expressionarg | initializer for param |
boolassertmsg | true if the parameter is the msg argument to assert(bool, msg). |
boolgag | do not print error messages |
Returns:true if pointers to the stack can escape via assignment
bool
checkParamArgumentReturn(ref Scope
sc, Expression
firstArg, Expression
arg, Parameter
param, bool
gag);
Function argument initializes areturn parameter, and that parameter gets assigned tofirstArg. Essentially, treat asfirstArg =arg;
Parameters:Scopesc | used to determine current function and module |
ExpressionfirstArg | ref argument through whicharg may be assigned |
Expressionarg | initializer for parameter |
Parameterparam | parameter declaration corresponding toarg |
boolgag | do not print error messages |
Returns:true if assignment tofirstArg would cause an error
bool
checkConstructorEscape(ref Scope
sc, CallExp
ce, bool
gag);
Check struct constructor of the forms.this(args), by checking eachreturn parameter to see if it gets assigned tos.
Parameters:Scopesc | used to determine current function and module |
CallExpce | constructor call of the forms.this(args) |
boolgag | do not print error messages |
Returns:true if construction would cause an escaping reference error
enum
ReturnParamDest: int;
How areturn parameter escapes its pointer value
through return statement:return x
assigned to a struct instance:this.x = x
assigned to first argument:firstArg = x
ReturnParamDest
returnParamDest(TypeFunction
tf, Type
tthis);
Find out if instead of returning areturn parameter via a return statement, it is returned via assignment to eitherthis or the first parameter.
This works the same as returning the value via a return statement. Although the first argument must beref, it is not regarded as returning byref.
Parameters:TypeFunctiontf | function type |
Typetthis | type ofthis parameter, ornull if none |
Returns:What areturn parameter should transfer the lifetime of the argument to
bool
checkAssignEscape(ref Scope
sc, Expression
e, bool
gag, bool
byRef);
Given anAssignExp, determine if the lvalue will cause the contents of the rvalue to escape. Print error messages when these are detected. Inferscope attribute for the lvalue where possible, in order to eliminate the error.
Parameters:Scopesc | used to determine current function and module |
Expressione | AssignExp orCatAssignExp to check for any pointers to the stack |
boolgag | do not print error messages |
boolbyRef | set totrue ife1 ofe gets assigned a reference toe2 |
Returns:true if pointers to the stack can escape via assignment
bool
checkThrowEscape(ref Scope
sc, Expression
e, bool
gag);
Detect cases where pointers to the stack can escape the lifetime of the stack frame when throwinge. Print error messages when these are detected.
Parameters:Scopesc | used to determine current function and module |
Expressione | expression to check for any pointers to the stack |
boolgag | do not print error messages |
Returns:true if pointers to the stack can escape
bool
checkNewEscape(ref Scope
sc, Expression
e, bool
gag);
Detect cases where pointers to the stack can escape the lifetime of the stack frame by being placed into a GC allocated object. Print error messages when these are detected.
Parameters:Scopesc | used to determine current function and module |
Expressione | expression to check for any pointers to the stack |
boolgag | do not print error messages |
Returns:true if pointers to the stack can escape
bool
checkReturnEscape(ref Scope
sc, Expression
e, bool
gag);
Detect cases where pointers to the stack can escape the lifetime of the stack frame by returninge by value. Print error messages when these are detected.
Parameters:Scopesc | used to determine current function and module |
Expressione | expression to check for any pointers to the stack |
boolgag | do not print error messages |
Returns:true if pointers to the stack can escape
bool
checkReturnEscapeRef(ref Scope
sc, Expression
e, bool
gag);
Detect cases where returninge byref can result in a reference to the stack being returned. Print error messages when these are detected.
Parameters:Scopesc | used to determine current function and module |
Expressione | expression to check |
boolgag | do not print error messages |
Returns:true if references to the stack can escape
void
escapeByValue(Expression
e, ref scope EscapeByResults
er);
e is an expression to be returned by value, and that value contains pointers. Walk e to determine which variables are possibly being returned by value, such as: int* function(int* p) { return p; } If e is a form of &p, determine which variables have content which is being returned as ref, such as: int* function(int i) { return &i; } Multiple variables can be inserted, because of expressions like this: int function(bool b, int i, int* p) { return b ? &i : p; }
No side effects.
Parameters:Expressione | expression to be returned by value |
EscapeByResultser | where to place collected data |
Aggregate the data collected by the escapeBy??() functions.
void delegate(VarDeclaration, bool retRefTransition)
byRef;
called on variables being returned by ref / address
void delegate(VarDeclaration)
byValue;
called on variables with values containing pointers
void delegate(FuncDeclaration, bool called)
byFunc;
called on nested functions that are turned into delegatesWhencalled is true, it means the delegate escapes variablesfrom the closure through a call to it, whilefalse means thedelegate itself escapes.
void delegate(Expression, bool retRefTransition)
byExp;
called when expression temporaries are being returned by ref / address
if @live semantics apply, i.e. expressionsp,*p,**p, etc., all returnp.
void
findAllOuterAccessedVariables(FuncDeclaration
fd, VarDeclarations*
vars);
Find all variables accessed by this delegate that are in functions enclosing it.
Parameters:FuncDeclarationfd | function |
VarDeclarations*vars | array to append found variables to |
void
finishScopeParamInference(FuncDeclaration
funcdecl, ref TypeFunction
f);
After semantic analysis of the function body, try to inferscope /return on the parameters
Parameters:FuncDeclarationfuncdecl | function declaration that was analyzed |
TypeFunctionf | final function type.funcdecl.type started as the 'premature type' before attribute inference, then its inferred attributes are copied over to final typef |