# dmd.escape

Most of the logic to implement scoped pointers and scoped references is here.

#### Authors

Walter Bright

#### License

Boost License 1.0

Source: escape.d

Documentation: https://dlang.org/phobos/dmd_escape.html

Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/escape.d

- `EscapeState`

  #### Declaration

  `struct `EscapeState`;`

  Groups global state for escape checking together

  - `reset`

    #### Declaration

    `static void `reset`();`

    Called by `initDMD` / `deinitializeDMD` to `reset` global state

- `checkMutableArguments`

  #### Declaration

  `bool `checkMutableArguments`(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.

  References: DIP 1021

  #### Parameters

  `Scope* `sc`` | used to determine current function and module
  `FuncDeclaration `fd`` | function being called
  `TypeFunction `tf`` | `fd`'s type
  `Expression `ethis`` | if not `null`, the `this` pointer
  `Expressions* `arguments`` | actual `arguments` to function
  `bool `gag`` | do not print error messages

  #### Return Value

  `true` if error

- `checkArrayLiteralEscape`

  #### Declaration

  `bool `checkArrayLiteralEscape`(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

  `Scope* `sc`` | used to determine current function and module
  `ArrayLiteralExp `ae`` | array literal expression
  `bool `gag`` | do not print error messages

  #### Return Value

  `true` if any elements escaped

- `checkAssocArrayLiteralEscape`

  #### Declaration

  `bool `checkAssocArrayLiteralEscape`(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

  `Scope* `sc`` | used to determine current function and module
  `AssocArrayLiteralExp `ae`` | associative array literal expression
  `bool `gag`` | do not print error messages

  #### Return Value

  `true` if any elements escaped

- `printScopeFailure`

  #### Declaration

  `void `printScopeFailure`(E)(E `printFunc`, VarDeclaration `v`, int `recursionLimit`);`

  A `scope` variable was assigned to non-scope parameter ``v``. If applicable, print why the parameter was not inferred `scope`.

  #### Parameters

  `E `printFunc`` | error/deprecation print function to use
  `VarDeclaration `v`` | parameter that was not inferred
  `int `recursionLimit`` | recursion limit for printing the reason

- `checkParamArgumentEscape`

  #### Declaration

  `bool `checkParamArgumentEscape`(Scope* `sc`, FuncDeclaration `fdc`, Identifier `parId`, VarDeclaration `vPar`, STC `parStc`, Expression `arg`, bool `assertmsg`, bool `gag`);`

  Function parameter `par` is being initialized to ``arg``, and `par` may escape. Detect if scoped values can escape this way. Print error messages when these are detected.

  #### Parameters

  `Scope* `sc`` | used to determine current function and module
  `FuncDeclaration `fdc`` | function being called, `null` if called indirectly
  `Identifier `parId`` | name of function parameter for error messages
  `VarDeclaration `vPar`` | `VarDeclaration` corresponding to `par`
  `STC `parStc`` | storage classes of function parameter (may have added `scope` from `pure`)
  `Expression `arg`` | initializer for param
  `bool `assertmsg`` | `true` if the parameter is the msg argument to assert(bool, msg).
  `bool `gag`` | do not print error messages

  #### Return Value

  `true` if pointers to the stack can escape via assignment

- `checkParamArgumentReturn`

  #### Declaration

  `bool `checkParamArgumentReturn`(Scope* `sc`, Expression `firstArg`, Expression `arg`, Parameter `param`, bool `gag`);`

  Function argument initializes a `return` parameter, and that parameter gets assigned to ``firstArg``. Essentially, treat as ``firstArg` = `arg`;`

  #### Parameters

  `Scope* `sc`` | used to determine current function and module
  `Expression `firstArg`` | `ref` argument through which ``arg`` may be assigned
  `Expression `arg`` | initializer for parameter
  `Parameter `param`` | parameter declaration corresponding to ``arg``
  `bool `gag`` | do not print error messages

  #### Return Value

  `true` if assignment to ``firstArg`` would cause an error

- `checkConstructorEscape`

  #### Declaration

  `bool `checkConstructorEscape`(Scope* `sc`, CallExp `ce`, bool `gag`);`

  Check struct constructor of the form `s.this(args)`, by checking each `return` parameter to see if it gets assigned to `s`.

  #### Parameters

  `Scope* `sc`` | used to determine current function and module
  `CallExp `ce`` | constructor call of the form `s.this(args)`
  `bool `gag`` | do not print error messages

  #### Return Value

  `true` if construction would cause an escaping reference error

- `ReturnParamDest`

  #### Declaration

  `enum `ReturnParamDest`: int;`

  How a `return` parameter escapes its pointer value

  - `returnVal`

    #### Declaration

    ``returnVal``

    through return statement: `return x`

  - `this_`

    #### Declaration

    ``this_``

    assigned to a struct instance: `this.x = x`

  - `firstArg`

    #### Declaration

    ``firstArg``

    assigned to first argument: ``firstArg` = x`

- `returnParamDest`

  #### Declaration

  `ReturnParamDest `returnParamDest`(TypeFunction `tf`, Type `tthis`);`

  Find out if instead of returning a `return` parameter via a return statement, it is returned via assignment to either `this` or the first parameter.

  #### Discussion

  This works the same as returning the value via a return statement. Although the first argument must be `ref`, it is not regarded as returning by `ref`.

  #### See Also

  https://dlang.org.spec/function.html#return-ref-parameters

  #### Parameters

  `TypeFunction `tf`` | function type
  `Type `tthis`` | type of `this` parameter, or `null` if none

  #### Return Value

  What a `return` parameter should transfer the lifetime of the argument to

- `checkAssignEscape`

  #### Declaration

  `bool `checkAssignEscape`(Scope* `sc`, Expression `e`, bool `gag`, bool `byRef`);`

  Given an `AssignExp`, determine if the lvalue will cause the contents of the rvalue to escape. Print error messages when these are detected. Infer `scope` attribute for the lvalue where possible, in order to eliminate the error.

  #### Parameters

  `Scope* `sc`` | used to determine current function and module
  `Expression `e`` | `AssignExp` or `CatAssignExp` to check for any pointers to the stack
  `bool `gag`` | do not print error messages
  `bool `byRef`` | set to `true` if `e1` of ``e`` gets assigned a reference to `e2`

  #### Return Value

  `true` if pointers to the stack can escape via assignment

- `checkThrowEscape`

  #### Declaration

  `bool `checkThrowEscape`(Scope* `sc`, Expression `e`, bool `gag`);`

  Detect cases where pointers to the stack can escape the lifetime of the stack frame when throwing ``e``. Print error messages when these are detected.

  #### Parameters

  `Scope* `sc`` | used to determine current function and module
  `Expression `e`` | expression to check for any pointers to the stack
  `bool `gag`` | do not print error messages

  #### Return Value

  `true` if pointers to the stack can escape

- `checkNewEscape`

  #### Declaration

  `bool `checkNewEscape`(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

  `Scope* `sc`` | used to determine current function and module
  `Expression `e`` | expression to check for any pointers to the stack
  `bool `gag`` | do not print error messages

  #### Return Value

  `true` if pointers to the stack can escape

- `checkReturnEscape`

  #### Declaration

  `bool `checkReturnEscape`(Scope* `sc`, Expression `e`, bool `gag`);`

  Detect cases where pointers to the stack can escape the lifetime of the stack frame by returning ``e`` by value. Print error messages when these are detected.

  #### Parameters

  `Scope* `sc`` | used to determine current function and module
  `Expression `e`` | expression to check for any pointers to the stack
  `bool `gag`` | do not print error messages

  #### Return Value

  `true` if pointers to the stack can escape

- `checkReturnEscapeRef`

  #### Declaration

  `bool `checkReturnEscapeRef`(Scope* `sc`, Expression `e`, bool `gag`);`

  Detect cases where returning ``e`` by `ref` can result in a reference to the stack being returned. Print error messages when these are detected.

  #### Parameters

  `Scope* `sc`` | used to determine current function and module
  `Expression `e`` | expression to check
  `bool `gag`` | do not print error messages

  #### Return Value

  `true` if references to the stack can escape

- `inferScope`

  #### Declaration

  `bool `inferScope`(VarDeclaration `va`);`

  Infer `scope` for a variable

  #### Parameters

  `VarDeclaration `va`` | variable to infer scope for

  #### Return Value

  `true` if succesful or already `scope`

- `escapeByValue`

  #### Declaration

  `void `escapeByValue`(Expression `e`, EscapeByResults* `er`, bool `live` = false, bool `retRefTransition` = false);`

  `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; }

  #### Discussion

  No side effects.

  #### Parameters

  `Expression `e`` | expression to be returned by value
  `EscapeByResults* `er`` | where to place collected data
  `bool `live`` | if @`live` semantics apply, i.`e`. expressions `p`, `*p`, `**p`, etc., all return `p`.
  `bool `retRefTransition`` | if ``e`` is returned through a `return ref scope` function call

- `escapeByRef`

  #### Declaration

  `void `escapeByRef`(Expression `e`, EscapeByResults* `er`, bool `live` = false, bool `retRefTransition` = false);`

  `e` is an expression to be returned by 'ref'. Walk `e` to determine which variables are possibly being returned by ref, such as: ref int function(int i) { return i; } If `e` is a form of p, determine which variables have content which is being returned as ref, such as: ref int function(int) p { return p; } Multiple variables can be inserted, because of expressions like this: ref int function(bool b, int i, int) p { return b ? i : *p; }

  #### Discussion

  No side effects.

  #### Parameters

  `Expression `e`` | expression to be returned by 'ref'
  `EscapeByResults* `er`` | where to place collected data
  `bool `live`` | if @`live` semantics apply, i.`e`. expressions `p`, `*p`, `**p`, etc., all return `p`.
  `bool `retRefTransition`` | if ``e`` is returned through a `return ref scope` function call

- `EscapeByResults`

  #### Declaration

  `struct `EscapeByResults`;`

  Aggregate the data collected by the escapeBy??() functions.

  - `reset`

    #### Declaration

    `void `reset`();`

    Reset arrays so the storage can be used again

  - `pushRef`

    #### Declaration

    `void `pushRef`(VarDeclaration `v`, bool `retRefTransition`);`

    Escape variable ``v`` by reference

    #### Parameters

    `VarDeclaration `v`` | variable to escape
    `bool `retRefTransition`` | ``v`` is escaped through a `return ref scope` function call

  - `pushExp`

    #### Declaration

    `void `pushExp`(Expression `e`, bool `retRefTransition`);`

    Escape a reference to expression ``e``

    #### Parameters

    `Expression `e`` | expression to escape
    `bool `retRefTransition`` | ``e`` is escaped through a `return ref scope` function call

- `findAllOuterAccessedVariables`

  #### Declaration

  `void `findAllOuterAccessedVariables`(FuncDeclaration `fd`, VarDeclarations* `vars`);`

  Find all variables accessed by this delegate that are in functions enclosing it.

  #### Parameters

  `FuncDeclaration `fd`` | function
  `VarDeclarations* `vars`` | array to append found variables to

- `finishScopeParamInference`

  #### Declaration

  `void `finishScopeParamInference`(FuncDeclaration `funcdecl`, ref TypeFunction `f`);`

  After semantic analysis of the function body, try to infer `scope` / `return` on the parameters

  #### Parameters

  `FuncDeclaration `funcdecl`` | function declaration that was analyzed
  `TypeFunction `f`` | final function type. ``funcdecl`.type` started as the 'premature type' before attribute inference, then its inferred attributes are copied over to final type ``f``

- `isReferenceToMutable`

  #### Declaration

  `bool `isReferenceToMutable`(Type `t`);`

  Is type a reference to a mutable value?

  #### Discussion

  This is used to determine if an argument that does not have a corresponding Parameter, i.e. a variadic argument, is a pointer to mutable data.

  #### Parameters

  `Type `t`` | type of the argument

  #### Return Value

  `true` if it's a pointer (or reference) to mutable data

- `isReferenceToMutable`

  #### Declaration

  `bool `isReferenceToMutable`(Parameter `p`, Type `t`);`

  Is parameter a reference to a mutable value?

  #### Discussion

  This is used if an argument has a corresponding Parameter. The argument type is necessary if the Parameter is inout.

  #### Parameters

  `Parameter `p`` | Parameter to check
  `Type `t`` | type of corresponding argument

  #### Return Value

  `true` if it's a pointer (or reference) to mutable data