From b0f45dc3b320cbb01daa2c7a7c4e1efabca70cbe Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Tue, 12 Mar 2024 12:07:43 -0400 Subject: [PATCH 1/6] add implicit conversion of T* to Span --- standard/unsafe-code.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/standard/unsafe-code.md b/standard/unsafe-code.md index b18ec8b51..c2f075613 100644 --- a/standard/unsafe-code.md +++ b/standard/unsafe-code.md @@ -277,6 +277,7 @@ In an unsafe context, the set of available implicit conversions ([§10.2](conver - From any *pointer_type* to the type `void*`. - From the `null` literal ([§6.4.5.7](lexical-structure.md#6457-the-null-literal)) to any *pointer_type*. +- From any *pointer_type* to the type `System.Span`, where `T` is the referent type of *pointer_type*. Additionally, in an unsafe context, the set of available explicit conversions ([§10.3](conversions.md#103-explicit-conversions)) is extended to include the following explicit pointer conversions: @@ -288,6 +289,7 @@ Finally, in an unsafe context, the set of standard implicit conversions ([§10.4 - From any *pointer_type* to the type `void*`. - From the `null` literal to any *pointer_type*. +- From any *pointer_type* to the type `System.Span`, where `T` is the referent type of *pointer_type*. Conversions between two pointer types never change the actual pointer value. In other words, a conversion from one pointer type to another has no effect on the underlying address given by the pointer. From 3c4161a5332ca5a1f8a6d1586e812151eebee728 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Tue, 12 Mar 2024 12:05:14 -0400 Subject: [PATCH 2/6] Remove constraints on location of stackalloc expressions --- standard/expressions.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index d756d1920..f414a24bc 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -3193,18 +3193,6 @@ stackalloc_element_initializer ; ``` - -A *stackalloc_expression* is only permitted in two contexts: - -1. The initializing *expression*, `E`, of a *local_variable_declaration* ([§13.6.2](statements.md#1362-local-variable-declarations)); and -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)) - -In both contexts the *stackalloc_expression* is only permitted to occur as: - -- The whole of `E`; or -- The second and/or third operands of a *conditional_expression* ([§12.18](expressions.md#1218-conditional-operator)) which is itself the whole of `E`. - - 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`. 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. From 7209377b4921f6a997b1fae9c164d97251924a4a Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Wed, 20 Nov 2024 10:22:45 -0800 Subject: [PATCH 3/6] Support stackalloc expressions anywhere for C# 8. --- standard/expressions.md | 7 ++----- standard/unsafe-code.md | 4 +--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/standard/expressions.md b/standard/expressions.md index f414a24bc..126ed6668 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -3176,8 +3176,7 @@ The safe context rules for a stack allocation expression are described in [§16. ```ANTLR stackalloc_expression : 'stackalloc' unmanaged_type '[' expression ']' - | 'stackalloc' unmanaged_type? '[' constant_expression? ']' - stackalloc_initializer + | 'stackalloc' unmanaged_type? '[' constant_expression? ']' stackalloc_initializer ; stackalloc_initializer @@ -3207,14 +3206,12 @@ When a *stackalloc_initializer* is present: 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. -The result of a *stackalloc_expression* is an instance of type `Span`, where `T` is the *unmanaged_type*: +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`, where `T` is the *unmanaged_type*: - `Span` ([§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. - The result’s `Length` property returns the number of items allocated. - 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. -> *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* - Stack allocation initializers are not permitted in `catch` or `finally` blocks ([§13.11](statements.md#1311-the-try-statement)). > *Note*: There is no way to explicitly free memory allocated using `stackalloc`. *end note* diff --git a/standard/unsafe-code.md b/standard/unsafe-code.md index c2f075613..7978572c4 100644 --- a/standard/unsafe-code.md +++ b/standard/unsafe-code.md @@ -1051,9 +1051,7 @@ When the outermost containing struct variable of a fixed-size buffer member is a 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. -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*. - -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. +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. > *Example*: > From 16d90207358c9b74964b11f207897ca8b162df79 Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Wed, 20 Nov 2024 10:26:43 -0800 Subject: [PATCH 4/6] Remove incorrect conversions. --- standard/unsafe-code.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/standard/unsafe-code.md b/standard/unsafe-code.md index 7978572c4..08ecb5b1b 100644 --- a/standard/unsafe-code.md +++ b/standard/unsafe-code.md @@ -277,7 +277,6 @@ In an unsafe context, the set of available implicit conversions ([§10.2](conver - From any *pointer_type* to the type `void*`. - From the `null` literal ([§6.4.5.7](lexical-structure.md#6457-the-null-literal)) to any *pointer_type*. -- From any *pointer_type* to the type `System.Span`, where `T` is the referent type of *pointer_type*. Additionally, in an unsafe context, the set of available explicit conversions ([§10.3](conversions.md#103-explicit-conversions)) is extended to include the following explicit pointer conversions: @@ -289,7 +288,6 @@ Finally, in an unsafe context, the set of standard implicit conversions ([§10.4 - From any *pointer_type* to the type `void*`. - From the `null` literal to any *pointer_type*. -- From any *pointer_type* to the type `System.Span`, where `T` is the referent type of *pointer_type*. Conversions between two pointer types never change the actual pointer value. In other words, a conversion from one pointer type to another has no effect on the underlying address given by the pointer. From 6346b522fca1a92da890edebc9199d1abfc36cb6 Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Wed, 11 Dec 2024 12:54:27 -0800 Subject: [PATCH 5/6] Update standard/expressions.md Co-authored-by: Bill Wagner --- standard/expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/expressions.md b/standard/expressions.md index 126ed6668..10b467648 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -3206,7 +3206,7 @@ When a *stackalloc_initializer* is present: 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. -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`, where `T` is the *unmanaged_type*: +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`, where `T` is the *unmanaged_type*: - `Span` ([§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. - The result’s `Length` property returns the number of items allocated. From ebc6786c884d2bc0af492fc986870b192d2cf216 Mon Sep 17 00:00:00 2001 From: Neal Gafter Date: Wed, 11 Dec 2024 12:54:46 -0800 Subject: [PATCH 6/6] Update standard/unsafe-code.md Co-authored-by: Bill Wagner --- standard/unsafe-code.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/unsafe-code.md b/standard/unsafe-code.md index 08ecb5b1b..81a5a9ba2 100644 --- a/standard/unsafe-code.md +++ b/standard/unsafe-code.md @@ -1049,7 +1049,7 @@ When the outermost containing struct variable of a fixed-size buffer member is a 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. -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. +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. > *Example*: >