Skip to content

Commit f651344

Browse files
committed
Add additional examples.
Add three more examples to illustrate the ref safety rules for scoped ref. These highlight the potential issues with an unscoped ref.
1 parent 08bba1a commit f651344

2 files changed

Lines changed: 82 additions & 0 deletions

File tree

standard/structs.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,6 +1150,37 @@ The safe-context of an object initializer expression is the narrowest of:
11501150
11511151
> *Note*: Another way of modeling this is to consider any argument to a member initializer that can be assigned to the receiver as being an argument to the constructor. *end note*
11521152
1153+
> *Example*: The following illustrates how an object initializer narrows the safe-context of the resulting value:
1154+
>
1155+
> <!-- Example: {template:"standalone-lib-without-using", name:"ObjectInitializerSafeContext", expectedErrors:["CS8352"]} -->
1156+
> ```csharp
1157+
> using System;
1158+
>
1159+
> ref struct S
1160+
> {
1161+
> public Span<int> Field;
1162+
> public S(ref int i) { }
1163+
> }
1164+
>
1165+
> class C
1166+
> {
1167+
> static S Example()
1168+
> {
1169+
> Span<int> stackSpan = stackalloc int[42];
1170+
> int i = 0;
1171+
>
1172+
> // safe-context is narrowest of:
1173+
> // constructor safe-context (caller-context) and
1174+
> // RHS of Field assignment (stackSpan: function-member)
1175+
> // = function-member
1176+
> var x = new S(ref i) { Field = stackSpan };
1177+
> return x; // Error: x has safe-context of function-member
1178+
> }
1179+
> }
1180+
> ```
1181+
>
1182+
> *end example*
1183+
11531184
#### 16.5.15.7 stackalloc
11541185
11551186
The result of a stackalloc expression has safe-context of function-member.

standard/variables.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,31 @@ For a parameter `p`:
13641364
13651365
When a parameter is annotated with `[UnscopedRef]` ([§UnscopedRefAttribute](attributes.md#unscopedrefattribute-the-unscopedref-attribute)), its ref-safe-context is widened by one level from its default: function-member becomes return-only, and return-only becomes caller-context.
13661366
1367+
> *Example*: The following illustrates how the implicit `this` parameter of a struct instance method is `scoped ref` (ref-safe-context of *function-member*), and how `[UnscopedRef]` widens it to *return-only*, enabling ref returns of fields:
1368+
>
1369+
> <!-- Example: {template:"standalone-lib-without-using", name:"ParameterRefSafeContext", expectedErrors:["CS8170"]} -->
1370+
> ```csharp
1371+
> using System.Diagnostics.CodeAnalysis;
1372+
>
1373+
> struct S
1374+
> {
1375+
> private int _field;
1376+
>
1377+
> // Error: ref-safe-context of `this` is function-member,
1378+
> // so ref-safe-context of `_field` is also function-member,
1379+
> // which does not satisfy the return-only requirement.
1380+
> public ref int Bad() => ref _field;
1381+
>
1382+
> // OK: [UnscopedRef] widens `this` from function-member to
1383+
> // return-only, so `_field` also has ref-safe-context of
1384+
> // return-only, satisfying the ref return requirement.
1385+
> [UnscopedRef]
1386+
> public ref int Good() => ref _field;
1387+
> }
1388+
> ```
1389+
>
1390+
> *end example*
1391+
13671392
#### 9.7.2.4 Field ref safe context
13681393
13691394
For a variable designating a reference to a field, `e.F`:
@@ -1481,3 +1506,29 @@ Any other difference with respect to `scoped` or `[UnscopedRef]` between the bas
14811506
The `scoped` modifier and `[UnscopedRef]` attribute do not affect hiding.
14821507
14831508
Overloads shall not differ only on `scoped` or `[UnscopedRef]`.
1509+
1510+
> *Example*: The following illustrates valid and invalid scope variance in overrides:
1511+
>
1512+
> <!-- Example: {template:"standalone-lib-without-using", name:"ParameterScopeVariance", expectedErrors:["CS0111"]} -->
1513+
> ```csharp
1514+
> using System;
1515+
>
1516+
> class Base
1517+
> {
1518+
> public virtual void M(ref Span<int> x) { }
1519+
> }
1520+
>
1521+
> class Derived : Base
1522+
> {
1523+
> // OK: adds scoped to a ref parameter
1524+
> public override void M(scoped ref Span<int> x) { }
1525+
> }
1526+
>
1527+
> class C
1528+
> {
1529+
> void N(Span<int> x) { }
1530+
> void N(scoped Span<int> x) { } // Error: overloads differ only on scoped
1531+
> }
1532+
> ```
1533+
>
1534+
> *end example*

0 commit comments

Comments
 (0)