Skip to content

Commit f1dd653

Browse files
gafterRexJaeschkeBillWagner
authored
Remove constraints on stackalloc (support new locations) (#1211)
* add implicit conversion of T* to Span<T> * Remove constraints on location of stackalloc expressions * Support stackalloc expressions anywhere for C# 8. * Remove incorrect conversions. * Update standard/expressions.md Co-authored-by: Bill Wagner <[email protected]> * Update standard/unsafe-code.md Co-authored-by: Bill Wagner <[email protected]> --------- Co-authored-by: Rex Jaeschke <[email protected]> Co-authored-by: Bill Wagner <[email protected]>
1 parent 31e02af commit f1dd653

File tree

2 files changed

+3
-20
lines changed

2 files changed

+3
-20
lines changed

standard/expressions.md

+2-17
Original file line numberDiff line numberDiff line change
@@ -3275,8 +3275,7 @@ The safe context rules for a stack allocation expression are described in [§16.
32753275
```ANTLR
32763276
stackalloc_expression
32773277
: 'stackalloc' unmanaged_type '[' expression ']'
3278-
| 'stackalloc' unmanaged_type? '[' constant_expression? ']'
3279-
stackalloc_initializer
3278+
| 'stackalloc' unmanaged_type? '[' constant_expression? ']' stackalloc_initializer
32803279
;
32813280
32823281
stackalloc_initializer
@@ -3292,18 +3291,6 @@ stackalloc_element_initializer
32923291
;
32933292
```
32943293

3295-
<!-- The following restrictions apply to C# 7.3, they are relaxed in C# 8 -->
3296-
A *stackalloc_expression* is only permitted in two contexts:
3297-
3298-
1. The initializing *expression*, `E`, of a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)); and
3299-
2. The right operand *expression*, `E`, of a simple assignment ([§12.21.2](expressions.md#12212-simple-assignment)) which itself occurs as a *expression_statement* ([§13.7](statements.md#137-expression-statements))
3300-
3301-
In both contexts the *stackalloc_expression* is only permitted to occur as:
3302-
3303-
- The whole of `E`; or
3304-
- The second and/or third operands of a *conditional_expression* ([§12.18](expressions.md#1218-conditional-operator)) which is itself the whole of `E`.
3305-
<!-- End of C# 7.3 restrictions -->
3306-
33073294
The *unmanaged_type* ([§8.8](types.md#88-unmanaged-types)) indicates the type of the items that will be stored in the newly allocated location, and the *expression* indicates the number of these items. Taken together, these specify the required allocation size. The type of *expression* shall be implicitly convertible to the type `int`.
33083295

33093296
As the size of a stack allocation cannot be negative, it is a compile-time error to specify the number of items as a *constant_expression* that evaluates to a negative value.
@@ -3318,14 +3305,12 @@ When a *stackalloc_initializer* is present:
33183305

33193306
Each *stackalloc_element_initializer* shall have an implicit conversion to *unmanaged_type* ([§10.2](conversions.md#102-implicit-conversions)). The *stackalloc_element_initializer*s initialize elements in the allocated memory in increasing order, starting with the element at index zero. In the absence of a *stackalloc_initializer*, the content of the newly allocated memory is undefined.
33203307

3321-
The result of a *stackalloc_expression* is an instance of type `Span<T>`, where `T` is the *unmanaged_type*:
3308+
If a *stackalloc_expression* occurs directly as the initializing expression of a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)), where the *local_variable_type* is either a pointer type ([§23.3](unsafe-code.md#233-pointer-types)) or inferred (`var`), then the result of the *stackalloc_expression* is a pointer of type `T*` (§23.9). In this case the *stackalloc_expression* must appear in unsafe code. Otherwise the result of a *stackalloc_expression* is an instance of type `Span<T>`, where `T` is the *unmanaged_type*:
33223309

33233310
- `Span<T>` ([§C.3](standard-library.md#c3-standard-library-types-not-defined-in-isoiec-23271)) is a ref struct type ([§16.2.3](structs.md#1623-ref-modifier)), which presents a block of memory, here the block allocated by the *stackalloc_expression*, as an indexable collection of typed (`T`) items.
33243311
- The result’s `Length` property returns the number of items allocated.
33253312
- The result’s indexer ([§15.9](classes.md#159-indexers)) returns a *variable_reference* ([§9.5](variables.md#95-variable-references)) to an item of the allocated block and is range checked.
33263313

3327-
> *Note*: When occurring in unsafe code the result of a *stackalloc_expression* may be of a different type, see ([§23.9](unsafe-code.md#239-stack-allocation)). *end note*
3328-
33293314
Stack allocation initializers are not permitted in `catch` or `finally` blocks ([§13.11](statements.md#1311-the-try-statement)).
33303315

33313316
> *Note*: There is no way to explicitly free memory allocated using `stackalloc`. *end note*

standard/unsafe-code.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -1049,9 +1049,7 @@ When the outermost containing struct variable of a fixed-size buffer member is a
10491049
10501050
See [§12.8.22](expressions.md#12822-stack-allocation) for general information about the operator `stackalloc`. Here, the ability of that operator to result in a pointer is discussed.
10511051
1052-
In an unsafe context if a *stackalloc_expression* ([§12.8.22](expressions.md#12822-stack-allocation)) occurs as the initializing expression of a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)), where the *local_variable_type* is either a pointer type ([§23.3](unsafe-code.md#233-pointer-types)) or inferred (`var`), then the result of the *stackalloc_expression* is a pointer of type `T *` to be beginning of the allocated block, where `T` is the *unmanaged_type* of the *stackalloc_expression*.
1053-
1054-
In all other respects the semantics of *local_variable_declaration*s ([§13.6.2](statements.md#1362-local-variable-declarations)) and *stackalloc_expression*s ([§12.8.22](expressions.md#12822-stack-allocation)) in unsafe contexts follow those defined for safe contexts.
1052+
When a *stackalloc_expression* occurs as the initializing expression of a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)), where the *local_variable_type* is either a pointer type ([§23.3](unsafe-code.md#233-pointer-types)) or inferred (`var`), the result of the *stackalloc_expression* is a pointer of type `T*`, where `T` is the *unmanaged_type* of the *stackalloc_expression*. In this case the result is a pointer to be beginning of the allocated block.
10551053
10561054
> *Example*:
10571055
>

0 commit comments

Comments
 (0)