Skip to content

Commit 7e6c011

Browse files
committed
Review and update ref fields
Add attribite, update examples, add a few prose areas.
1 parent ca88c28 commit 7e6c011

4 files changed

Lines changed: 66 additions & 2 deletions

File tree

standard/attributes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,10 @@ It is an error to use `[UnscopedRef]` on
12581258
12591259
See §scoped-modifier for more information.
12601260
1261+
### §ScopedRefAttribute The ScopedRef attribute
1262+
1263+
The name `System.Runtime.CompilerServices.ScopedRefAttribute` is reserved for compiler use. The compiler emits this attribute on a parameter when the parameter's `scoped` annotation differs from its default state, in order to encode the `scoped` modifier (§scoped-modifier) in metadata. This attribute is not permitted in source.
1264+
12611265
### 23.5.8 The EnumeratorCancellation attribute
12621266
12631267
Specifies the parameter representing the `CancellationToken` for an asynchronous iterator ([§15.15](classes.md#1515-synchronous-and-asynchronous-iterators)). The argument for this parameter shall be combined with the argument passed to `IAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken)`. This combined token shall be polled by `IAsyncEnumerator<T>.MoveNextAsync()` ([§15.15.5.2](classes.md#151552-advance-the-enumerator)). The tokens shall be combined into a single token as if by `CancellationToken.CreateLinkedTokenSource` and its `Token` property. The combined token will be canceled if either of the two source tokens are canceled. The combined token is seen as the argument to the asynchronous iterator method ([§15.15](classes.md#1515-synchronous-and-asynchronous-iterators)) in the body of that method.

standard/classes.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1715,6 +1715,8 @@ The value of a field is obtained in an expression using a *simple_name* ([§12.8
17151715

17161716
A field declaration that declares multiple fields is equivalent to multiple declarations of single fields with the same attributes, modifiers, and type.
17171717

1718+
> *Note*: Inside a `ref struct`, a field may also be declared as a reference variable; see §Ref-Fields. *end note*
1719+
17181720
> *Example*:
17191721
>
17201722
> <!-- Example: {template:"standalone-lib-without-using", name:"Fields1", ignoredWarnings:["CS0649"]} -->
@@ -2374,6 +2376,8 @@ It is a compile-time error to modify the value of an input parameter.
23742376
23752377
> *Note*: The primary purpose of input parameters is for efficiency. When the type of a method parameter is a large struct (in terms of memory requirements), it is useful to be able to avoid copying the whole value of the argument when calling the method. Input parameters allow methods to refer to existing values in memory, while providing protection against unwanted changes to those values. *end note*
23762378
2379+
An input parameter may carry the `scoped` modifierscoped-modifier) or the `[UnscopedRef]` attributeUnscopedRefAttribute).
2380+
23772381
##### 15.6.2.3.3 Reference parameters
23782382
23792383
A parameter declared with a `ref` modifier is a ***reference parameter***. For definite-assignment rules, see [§9.2.6](variables.md#926-reference-parameters).
@@ -2437,14 +2441,18 @@ A parameter declared with a `ref` modifier is a ***reference parameter***. For d
24372441
>
24382442
> *end example*
24392443
2440-
For a `struct` type, within an instance method, instance accessor ([§12.2.1](expressions.md#1221-general)), or instance constructor with a constructor initializer, the `this` keyword behaves exactly as a reference parameter of the struct type ([§12.8.14](expressions.md#12814-this-access)).
2444+
For a `struct` type, within an instance method, instance accessor ([§12.2.1](expressions.md#1221-general)), or instance constructor with a constructor initializer, the `this` keyword behaves exactly as a reference parameter of the struct type ([§12.8.14](expressions.md#12814-this-access)). The `this` parameter of a struct instance method is implicitly `scoped ref` (§scoped-modifier).
2445+
2446+
A reference parameter may carry the `scoped` modifier (§scoped-modifier) or the `[UnscopedRef]` attribute (§UnscopedRefAttribute).
24412447
24422448
##### 15.6.2.3.4 Output parameters
24432449
24442450
A parameter declared with an `out` modifier is an ***output parameter***. For definite-assignment rules, see [§9.2.7](variables.md#927-output-parameters).
24452451
24462452
A method declared as an optional partial method ([§15.6.9.2](classes.md#15692-optional-partial-methods)) shall not have output parameters.
24472453
2454+
An output parameter is implicitly `scoped` (§scoped-modifier); the `[UnscopedRef]` attributeUnscopedRefAttribute) may be applied to widen its ref-safe-context.
2455+
24482456
> *Note*: Output parameters are typically used in methods that produce multiple return values. *end note*
24492457
<!-- markdownlint-disable MD028 -->
24502458

standard/structs.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,12 @@ struct_field_declaration
754754

755755
A *struct_field_declaration* without `ref`, `readonly ref`, or `ref readonly` is as described in [§15.5](classes.md#155-fields).
756756

757-
A `ref` or `readonly ref` field is a reference variable and shall only be declared in a `ref` struct.
757+
A `ref` or `readonly ref` field is a reference variable and is subject to the following constraints:
758+
759+
- It shall only be declared in a `ref struct`.
760+
- It shall not be declared `static`, `volatile`, or `const`.
761+
- Its type shall not itself be a `ref struct` type.
762+
- In a `readonly ref struct`, every `ref` field shall be declared `readonly ref` (it may additionally be declared `readonly ref readonly`).
758763

759764
Consider the following ref struct declaration:
760765

standard/variables.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,6 +1498,53 @@ Consider the following declarations and their safe contexts:
14981498
14991499
In this relationship the *ref-safe-context* of a value can never be wider than the *safe-context*.
15001500
1501+
> *Example*: The following illustrates how `scoped` restricts the lifetime of a local and prevents it from escaping its enclosing function:
1502+
>
1503+
> <!-- Example: {template:"standalone-lib-without-using", name:"ScopedLocalCannotEscape", expectedErrors:["CS8352"]} -->
1504+
> ```csharp
1505+
> using System;
1506+
>
1507+
> class C
1508+
> {
1509+
> static Span<int> Bad()
1510+
> {
1511+
> // Without `scoped`, the safe-context of `s` would be caller-context
1512+
> // because the right-hand side has safe-context of caller-context.
1513+
> // The `scoped` modifier forces the safe-context to function-member,
1514+
> // so `s` cannot be returned.
1515+
> scoped Span<int> s = default;
1516+
> return s; // Error: s has safe-context of function-member
1517+
> }
1518+
> }
1519+
> ```
1520+
>
1521+
> *end example*
1522+
1523+
> *Example*: The following illustrates how `scoped ref` on a parameter prevents the parameter from being captured by a constructed `ref struct` value that the method returns:
1524+
>
1525+
> <!-- Example: {template:"standalone-lib-without-using", name:"ScopedRefParameter", expectedErrors:["CS8347","CS8166"]} -->
1526+
> ```csharp
1527+
> ref struct RS
1528+
> {
1529+
> public ref int RefField;
1530+
> public RS(ref int i) { RefField = ref i; }
1531+
> }
1532+
>
1533+
> class C
1534+
> {
1535+
> // `scoped ref` means `value` does not contribute ref-safe-context
1536+
> // to the return value. The `RS` constructor requires a ref argument
1537+
> // with ref-safe-context of caller-context, but `value` only contributes
1538+
> // function-member, so the call is rejected.
1539+
> static RS CreateWithoutCapture(scoped ref int value)
1540+
> => new RS(ref value);
1541+
> }
1542+
> ```
1543+
>
1544+
> *end example*
1545+
1546+
In summary, two `ref` locations are implicitly `scoped`: the `this` parameter of a struct instance method, and every `out` parameter. See §9.7.2.3.
1547+
15011548
### §parameter-scope-variance Parameter scope variance
15021549
15031550
The `scoped` modifier (§scoped-modifier) and `[UnscopedRef]` attribute (§UnscopedRefAttribute) on parameters affect overriding, interface implementation, and `delegate` conversion. The signature for an override, interface implementation, or `delegate` conversion may:

0 commit comments

Comments
 (0)