From 6a3d4d532af5b366b43490428f634c3b0805b336 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 21 Nov 2025 15:35:52 -0500 Subject: [PATCH 1/9] Add errors listed in issue --- .../compiler-messages/ref-modifiers-errors.md | 122 ++++------------ .../compiler-messages/ref-safety-errors.md | 132 ++++++++++++++++++ docs/csharp/language-reference/toc.yml | 22 +-- ...n-t-have-specifics-on-this-csharp-error.md | 36 +---- 4 files changed, 175 insertions(+), 137 deletions(-) create mode 100644 docs/csharp/language-reference/compiler-messages/ref-safety-errors.md diff --git a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md index 448ec0708f014..90c06f16fd6fb 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md @@ -18,10 +18,6 @@ f1_keywords: - "CS1939" - "CS1988" - "CS7084" - - "CS8166" - - "CS8167" - - "CS8168" - - "CS8169" - "CS8196" - "CS8325" - "CS8326" @@ -32,29 +28,26 @@ f1_keywords: - "CS8332" - "CS8337" - "CS8338" - - "CS8351" - "CS8373" - - "CS8374" - "CS8388" - - "CS8977" + - "CS8987" + - "CS9061" + - "CS9062" + - "CS9063" + - "CS9065" + - "CS9066" - "CS9072" - - "CS9077" - - "CS9078" - - "CS9079" - - "CS9085" - - "CS9086" - - "CS9087" - - "CS9089" - - "CS9091" - - "CS9092" - - "CS9093" - - "CS9094" - - "CS9095" - - "CS9096" - - "CS9097" + - "CS9073" + - "CS9074" - "CS9101" - "CS9102" - "CS9104" + - "CS9104" + - "CS9104" + - "CS9104" + - "CS9104" + - "CS9104" + - "CS9104" - "CS9190" - "CS9191" - "CS9192" @@ -85,10 +78,6 @@ helpviewer_keywords: - "CS1939" - "CS1988" - "CS7084" - - "CS8166" - - "CS8167" - - "CS8168" - - "CS8169" - "CS8196" - "CS8325" - "CS8326" @@ -99,26 +88,11 @@ helpviewer_keywords: - "CS8332" - "CS8337" - "CS8338" - - "CS8351" - "CS8373" - - "CS8374" - "CS8388" - "CS8977" - - "CS9072" - - "CS9077" - - "CS9078" - - "CS9079" - - "CS9085" - - "CS9086" - - "CS9087" - - "CS9089" - - "CS9091" - - "CS9092" - - "CS9093" - - "CS9094" - - "CS9095" - - "CS9096" - - "CS9097" + - "CS9073" + - "CS9074" - "CS9101" - "CS9102" - "CS9104" @@ -135,7 +109,8 @@ helpviewer_keywords: - "CS9201" - "CS9205" - "CS9265" -ms.date: 11/06/2024 +ai-usage: ai-assisted +ms.date: 11/21/2024 --- # Errors and warnings associated with reference parameters, variables, and returns @@ -160,10 +135,6 @@ That's by design. The text closely matches the text of the compiler error / warn - [**CS1939**](#reference-variable-restrictions): *Cannot pass the range variable as an `out` or `ref` parameter* - [**CS1988**](#reference-variable-restrictions): *Async methods cannot have `ref`, `in` or `out` parameters* - [**CS7084**](#reference-variable-restrictions): *A Windows Runtime event may not be passed as an `out` or `ref` parameter.* -- [**CS8166**](#ref-safety-violations): *Cannot return a parameter by reference because it is not a `ref` parameter* -- [**CS8167**](#ref-safety-violations): *Cannot return by reference a member of parameter because it is not a `ref` or `out` parameter* -- [**CS8168**](#ref-safety-violations): *Cannot return local by reference because it is not a ref local* -- [**CS8169**](#ref-safety-violations): *Cannot return a member of local variable by reference because it is not a ref local* - [**CS8196**](#reference-variable-restrictions): *Reference to an implicitly-typed out variable is not permitted in the same argument list.* - [**CS8325**](#reference-variable-restrictions): *'`await`' cannot be used in an expression containing a `ref` conditional operator* - [**CS8326**](#reference-variable-restrictions): *Both conditional operator values must be ref values or neither may be a ref value* @@ -174,16 +145,17 @@ That's by design. The text closely matches the text of the compiler error / warn - [**CS8332**](#writable-reference-variables-require-a-writable-referent): *Cannot assign to a member of variable or use it as the right hand side of a `ref` assignment because it is a readonly variable* - [**CS8337**](#reference-variable-restrictions): *The first parameter of a '`ref`' extension method must be a value type or a generic type constrained to struct.* - [**CS8338**](#reference-variable-restrictions): *The first '`in`' or '`ref readonly`' parameter of the extension method must be a concrete (non-generic) value type.* -- [**CS8351**](#ref-safety-violations): *Branches of a `ref` conditional operator cannot refer to variables with incompatible declaration scopes* - [**CS8373**](#incorrect-syntax): *The left-hand side of a `ref` assignment must be a ref variable.* -- [**CS8374**](#ref-safety-violations): *Cannot ref-assign source has a narrower escape scope than destination.* - [**CS8388**](#incorrect-syntax): *An `out` variable cannot be declared as a ref local* - [**CS8977**](#reference-variable-restrictions): *Cannot use '`ref`', '`in`', or '`out`' in the signature of a method attributed with 'UnmanagedCallersOnly'.* +- [**CS8986**](#reference-variable-restrictions): *The 'scoped' modifier of parameter doesn't match target.* +- [**CS8987**](#reference-variable-restrictions): *The 'scoped' modifier of parameter doesn't match overridden or implemented member.* +- [**CS9061**](#incorrect-syntax): *The 'scoped' modifier cannot be used with discard.* +- [**CS9062**](#incorrect-syntax): *Types and aliases cannot be named 'scoped'.* +- [**CS9063**](#unscoped-ref-restrictions): *UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default.* +- [**CS9065**](#incorrect-syntax): *Do not use 'System.Runtime.CompilerServices.ScopedRefAttribute'. Use the 'scoped' keyword instead.* +- [**CS9066**](#unscoped-ref-restrictions): *UnscopedRefAttribute cannot be applied to parameters that have a 'scoped' modifier.* - [**CS9072**](#reference-variable-restrictions): *A deconstruction variable cannot be declared as a ref local* -- [**CS9077**](#ref-safety-violations): *Cannot return a parameter by reference through a `ref` parameter; it can only be returned in a return statement* -- [**CS9078**](#ref-safety-violations): *Cannot return by reference a member of parameter through a `ref` parameter; it can only be returned in a return statement* -- [**CS9079**](#ref-safety-violations): *Cannot ref-assign because source can only escape the current method through a return statement.* -- [**CS9096**](#ref-safety-violations): *Cannot ref-assign because source has a wider value escape scope than destination allowing assignment through source of values with narrower escapes scopes than destination.* - [**CS9101**](#unscoped-ref-restrictions): *UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members.* - [**CS9102**](#unscoped-ref-restrictions): *UnscopedRefAttribute cannot be applied to an interface implementation because implemented member doesn't have this attribute.* - [**CS9104**](#reference-variable-restrictions): *A `using` statement resource of type cannot be used in async methods or async lambda expressions.* @@ -192,16 +164,8 @@ That's by design. The text closely matches the text of the compiler error / warn The following warnings are generated when reference variables are used incorrectly: -- [**CS9085**](#ref-safety-violations): *This ref-assigns variable but destination has a narrower escape scope than source.* -- [**CS9086**](#ref-safety-violations): *The branches of the `ref` conditional operator refer to variables with incompatible declaration scopes* -- [**CS9087**](#ref-safety-violations): *This returns a parameter by reference but it is not a `ref` parameter* -- [**CS9089**](#ref-safety-violations): *This returns by reference a member of parameter that is not a `ref` or `out` parameter* -- [**CS9091**](#ref-safety-violations): *This returns local by reference but it is not a ref local* -- [**CS9092**](#ref-safety-violations): *This returns a member of local by reference but it is not a ref local* -- [**CS9093**](#ref-safety-violations): *This ref-assigns but source can only escape the current method through a return statement.* -- [**CS9094**](#ref-safety-violations): *This returns a parameter by reference through a `ref` parameter; but it can only safely be returned in a return statement* -- [**CS9095**](#ref-safety-violations): *This returns by reference a member of parameter through a `ref` parameter; but it can only safely be returned in a return statement* -- [**CS9097**](#ref-safety-violations): *This ref-assigns but source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* +- [**CS9073**](#reference-variable-restrictions): *The 'scoped' modifier of parameter doesn't match target.* +- [**CS9074**](#reference-variable-restrictions): *The 'scoped' modifier of parameter doesn't match overridden or implemented member.* - [**CS9191**](#reference-variables-require-a-referent): *The `ref` modifier for argument corresponding to `in` parameter is equivalent to `in`. Consider using `in` instead.* - [**CS9192**](#reference-variables-require-a-referent): *Argument should be passed with `ref` or `in` keyword.* - [**CS9193**](#reference-variables-require-a-referent): *Argument should be a variable because it is passed to a `ref readonly` parameter* @@ -220,7 +184,6 @@ These errors and warnings follow these themes: - ***[Language constructs where `ref` variables aren't valid](#reference-variable-restrictions)***: Some C# idioms don't allow variables. Usually this is because ref safety analysis can't be performed reliably. - ***[Value expression used where a reference variable is needed](#reference-variables-require-a-referent)***: The expression used as a reference variable must be a variable, not a value expression. - ***[Writable reference variables referring to readonly variables](#writable-reference-variables-require-a-writable-referent)***: A reference to a readonly variable can't be passed by writable reference. -- ***[violations of ref safety](#ref-safety-violations)***: A reference variable can't refer to a variable that has a narrower context. That would mean the reference variable could refer to invalid memory. This article uses the term *reference variable* as a general term for a parameter declared with one of the `in`, `ref readonly`, `ref`, or `out` modifiers, or a `ref` local variable, a `ref` field in a `ref struct`, or a `ref` return. A reference variable refers to another variable, called the *referent*. @@ -338,34 +301,3 @@ Examples of variables that aren't writable include: - A [using](../../language-reference/statements/using.md) variable, or a [fixed](../../language-reference/statements/fixed.md) variable. You must copy the value and pass a reference to the copy. - -## Ref safety violations - -The compiler tracks the safe context of referents and reference variables. The compiler issues errors, or warnings in unsafe code, when a reference variable refers to a referent variable that's no longer valid. The referent must have a safe context that is at least as wide as the ref safe context of The reference variable. Violating these safety checks means the reference variable accesses random memory instead of the referent variable. - -- **CS8166**: *Cannot return a parameter by reference because it is not a `ref` parameter* -- **CS8167**: *Cannot return by reference a member of parameter because it is not a `ref` or `out` parameter* -- **CS8168**: *Cannot return local by reference because it is not a ref local* -- **CS8169**: *Cannot return a member of local variable by reference because it is not a ref local* -- **CS8345**: *Field or auto-implemented property cannot be of type unless it is an instance member of a `ref struct`.* -- **CS8351**: *Branches of a `ref` conditional operator cannot refer to variables with incompatible declaration scopes* -- **CS8374**: *Cannot ref-assign source has a narrower escape scope than destination.* -- **CS9077**: *Cannot return a parameter by reference through a `ref` parameter; it can only be returned in a return statement* -- **CS9078**: *Cannot return by reference a member of parameter through a `ref` parameter; it can only be returned in a return statement* -- **CS9079**: *Cannot ref-assign source to destination because source can only escape the current method through a return statement.* -- **CS9096**: *Cannot ref-assign source to destination because source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* - -Warnings: - -- **CS9085**: *This ref-assigns source to destination but source has a narrower escape scope than destination.* -- **CS9086**: *The branches of the ref conditional operator refer to variables with incompatible declaration scopes* -- **CS9087**: *This returns a parameter by reference but it is not a `ref` parameter* -- **CS9089**: *This returns by reference a member of parameter that is not a `ref` or `out` parameter* -- **CS9091**: *This returns local by reference but it is not a ref local* -- **CS9092**: *This returns a member of local by reference but it is not a ref local* -- **CS9093**: *This ref-assigns source to destination but source can only escape the current method through a return statement.* -- **CS9094**: *This returns a parameter by reference through a `ref` parameter; but it can only safely be returned in a return statement* -- **CS9095**: *This returns by reference a member of parameter through a `ref` parameter; but it can only safely be returned in a return statement* -- **CS9097**: *This ref-assigns source to destination but source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* - -The compiler uses static analysis to determine if the referent is valid at all points where the reference variable can be used. You need to refactor code so that the referent remains valid at all locations where the reference variable might refer to it. For details on the rules for ref safety, see the C# standard on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). diff --git a/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md new file mode 100644 index 0000000000000..155be74f57b73 --- /dev/null +++ b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md @@ -0,0 +1,132 @@ +--- +title: Errors and warnings related to ref safety +description: The compiler issues these errors and warnings when the referent of a reference variable might not be valid. These errors prevent you from creating dangling references. +f1_keywords: + - "CS8166" + - "CS8167" + - "CS8168" + - "CS8169" + - "CS8345" + - "CS8351" + - "CS8374" + - "CS9077" + - "CS9078" + - "CS9079" + - "CS9085" + - "CS9086" + - "CS9088" + - "CS9089" + - "CS9090" + - "CS9091" + - "CS9091" + - "CS9092" + - "CS9093" + - "CS9094" + - "CS9095" + - "CS9096" + - "CS9097" +helpviewer_keywords: + - "CS8166" + - "CS8167" + - "CS8168" + - "CS8169" + - "CS8345" + - "CS8351" + - "CS8374" + - "CS9077" + - "CS9078" + - "CS9079" + - "CS9085" + - "CS9086" + - "CS9087" + - "CS9089" + - "CS9091" + - "CS9092" + - "CS9093" + - "CS9094" + - "CS9095" + - "CS9096" + - "CS9097" +ai-usage: ai-assisted +ms.date: 11/21/2024 +--- +# Errors and warnings related to ref safety + +The following errors can be generated when reference variable safety rules are violated: + + +- [**CS8166**](#ref-safety-violations): *Cannot return a parameter by reference because it is not a `ref` parameter* +- [**CS8167**](#ref-safety-violations): *Cannot return by reference a member of parameter because it is not a `ref` or `out` parameter* +- [**CS8168**](#ref-safety-violations): *Cannot return local by reference because it is not a ref local* +- [**CS8169**](#ref-safety-violations): *Cannot return a member of local variable by reference because it is not a ref local* +- [**CS8345**](#ref-safety-violations): *Field or auto-implemented property cannot be of type unless it is an instance member of a `ref struct`.* +- [**CS8351**](#ref-safety-violations): *Branches of a `ref` conditional operator cannot refer to variables with incompatible declaration scopes* +- [**CS8374**](#ref-safety-violations): *Cannot ref-assign source has a narrower escape scope than destination.* +- [**CS9075**](#ref-safety-violations): *Cannot return a parameter by reference because it is scoped to the current method* +- [**CS9076**](#ref-safety-violations): *Cannot return by reference a member of parameter because it is scoped to the current method* +- [**CS9077**](#ref-safety-violations): *Cannot return a parameter by reference through a `ref` parameter; it can only be returned in a return statement* +- [**CS9078**](#ref-safety-violations): *Cannot return by reference a member of parameter through a `ref` parameter; it can only be returned in a return statement* +- [**CS9079**](#ref-safety-violations): *Cannot ref-assign source to destination because source can only escape the current method through a return statement.* +- [**CS9096**](#ref-safety-violations): *Cannot ref-assign source to destination because source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* + +The following warnings are generated when reference variable safety rules are violated: + +- [**CS9080**](#ref-safety-violations): *Use of variable in this context may expose referenced variables outside of their declaration scope* +- [**CS9081**](#ref-safety-violations): *A result of a stackalloc expression of type in this context may be exposed outside of the containing method* +- [**CS9082**](#ref-safety-violations): *Local is returned by reference but was initialized to a value that cannot be returned by reference* +- [**CS9083**](#ref-safety-violations): *A member of is returned by reference but was initialized to a value that cannot be returned by reference* +- [**CS9084**](#ref-safety-violations): *Struct member returns 'this' or other instance members by reference* +- [**CS9085**](#ref-safety-violations): *This ref-assigns source to destination but source has a narrower escape scope than destination.* +- [**CS9086**](#ref-safety-violations): *The branches of the ref conditional operator refer to variables with incompatible declaration scopes* +- [**CS9087**](#ref-safety-violations): *This returns a parameter by reference but it is not a `ref` parameter* +- [**CS9088**](#ref-safety-violations): *This returns a parameter by reference but it is scoped to the current method* +- [**CS9089**](#ref-safety-violations): *This returns by reference a member of parameter that is not a `ref` or `out` parameter* +- [**CS9090**](#ref-safety-violations): *This returns by reference a member of parameter that is scoped to the current method* +- [**CS9091**](#ref-safety-violations): *This returns local by reference but it is not a ref local* +- [**CS9092**](#ref-safety-violations): *This returns a member of local by reference but it is not a ref local* +- [**CS9093**](#ref-safety-violations): *This ref-assigns source to destination but source can only escape the current method through a return statement.* +- [**CS9094**](#ref-safety-violations): *This returns a parameter by reference through a `ref` parameter; but it can only safely be returned in a return statement* +- [**CS9095**](#ref-safety-violations): *This returns by reference a member of parameter through a `ref` parameter; but it can only safely be returned in a return statement* +- [**CS9097**](#ref-safety-violations): *This ref-assigns source to destination but source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* + +## Ref safety violations + +The compiler tracks the safe context of referents and reference variables. The compiler issues errors, or warnings in unsafe code, when a reference variable refers to a referent variable that's no longer valid. The referent must have a safe context that is at least as wide as the ref safe context of The reference variable. Violating these safety checks means the reference variable accesses random memory instead of the referent variable. + +- **CS8166**: *Cannot return a parameter by reference because it is not a `ref` parameter* +- **CS8167**: *Cannot return by reference a member of parameter because it is not a `ref` or `out` parameter* +- **CS8168**: *Cannot return local by reference because it is not a ref local* +- **CS8169**: *Cannot return a member of local variable by reference because it is not a ref local* +- **CS8345**: *Field or auto-implemented property cannot be of type unless it is an instance member of a `ref struct`.* +- **CS8351**: *Branches of a `ref` conditional operator cannot refer to variables with incompatible declaration scopes* +- **CS8374**: *Cannot ref-assign source has a narrower escape scope than destination.* +- **CS9075**: *Cannot return a parameter by reference because it is scoped to the current method* +- **CS9076**: *Cannot return by reference a member of parameter because it is scoped to the current method* +- **CS9077**: *Cannot return a parameter by reference through a `ref` parameter; it can only be returned in a return statement* +- **CS9078**: *Cannot return by reference a member of parameter through a `ref` parameter; it can only be returned in a return statement* +- **CS9079**: *Cannot ref-assign source to destination because source can only escape the current method through a return statement.* +- **CS9096**: *Cannot ref-assign source to destination because source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* + +Warnings: + +- **CS9080**: *Use of variable in this context may expose referenced variables outside of their declaration scope* +- **CS9081**: *A result of a stackalloc expression of type in this context may be exposed outside of the containing method* +- **CS9082**: *Local is returned by reference but was initialized to a value that cannot be returned by reference* +- **CS9083**: *A member of is returned by reference but was initialized to a value that cannot be returned by reference* +- **CS9084**: *Struct member returns 'this' or other instance members by reference* +- **CS9085**: *This ref-assigns source to destination but source has a narrower escape scope than destination.* +- **CS9086**: *The branches of the ref conditional operator refer to variables with incompatible declaration scopes* +- **CS9087**: *This returns a parameter by reference but it is not a `ref` parameter* +- **CS9088**: *This returns a parameter by reference but it is scoped to the current method* +- **CS9089**: *This returns by reference a member of parameter that is not a `ref` or `out` parameter* +- **CS9090**: *This returns by reference a member of parameter that is scoped to the current method* +- **CS9091**: *This returns local by reference but it is not a ref local* +- **CS9092**: *This returns a member of local by reference but it is not a ref local* +- **CS9093**: *This ref-assigns source to destination but source can only escape the current method through a return statement.* +- **CS9094**: *This returns a parameter by reference through a `ref` parameter; but it can only safely be returned in a return statement* +- **CS9095**: *This returns by reference a member of parameter through a `ref` parameter; but it can only safely be returned in a return statement* +- **CS9097**: *This ref-assigns source to destination but source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* + +The compiler uses static analysis to determine if the referent is valid at all points where the reference variable can be used. You need to refactor code so that the referent remains valid at all locations where the reference variable might refer to it. For details on the rules for ref safety, see the C# standard on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index c183361da12fd..800bc43316d71 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -526,20 +526,26 @@ items: href: ./compiler-messages/interface-implementation-errors.md displayName: > interface, - CS0071, CS0106, CS0277, CS0425, CS0460, CS0470, CS0473, CS0531, CS0535, CS0538, CS0539, CS0540, - CS0541, CS0550, CS0551, CS0630, CS0686, CS0736, CS0737, CS0738, CS8705, CS8707, CS8711, CS8854, - CS9333, CS9334 + CS0071, CS0106, CS0277, CS0425, CS0460, CS0470, CS0473, CS0531, CS0535, CS0538, + CS0539, CS0540, CS0541, CS0550, CS0551, CS0630, CS0686, CS0736, CS0737, CS0738, + CS8705, CS8707, CS8711, CS8854, CS9333, CS9334 - name: Reference parameters href: ./compiler-messages/ref-modifiers-errors.md displayName: > - ref safety, + ref parameters, CS0192, CS0199, CS0206, CS0631, CS0767, CS1510, CS1605, CS1623, CS1649, CS1651, - CS1655, CS1657, CS1741, CS1939, CS1988, CS7084, CS8166, CS8167, CS8168, CS8169, - CS8325, CS8326, CS8327, CS8329, CS8330, CS8331, CS8332, CS8337, CS8338, CS8351, - CS8373, CS8374, CS8388, CS8977, CS9072, CS9077, CS9078, CS9079, CS9085, CS9086, - CS9087, CS9089, CS9091, CS9092, CS9093, CS9094, CS9095, CS9096, CS9097, CS9101, + CS1655, CS1657, CS1741, CS1939, CS1988, CS7084, CS8196, CS8325, CS8326, CS8327, + CS8329, CS8330, CS8331, CS8332, CS8337, CS8338, CS8373, CS8388, CS8977, CS8986, + CS8987, CS9061, CS9062, CS9063, CS9065, CS9066, CS9072, CS9073, CS9074, CS9101, CS9102, CS9104, CS9190, CS9191, CS9192, CS9193, CS9195, CS9196, CS9197, CS9198, CS9199, CS9200, CS9201, CS9205, CS9265 + - name: Ref safety + href: ./compiler-messages/ref-safety-errors.md + displayName: > + ref safety, + CS8166, CS8167, CS8168, CS8169, CS8345, CS8351, CS8374, CS9075, CS9076, CS9077, + CS9078, CS9079, CS9080, CS9081, CS9082, CS9083, CS9084, CS9085, CS9086, CS9087, + CS9088, CS9089, CS9090, CS9091, CS9092, CS9093, CS9094, CS9095, CS9096, CS9097 - name: "`ref struct` types" href: ./compiler-messages/ref-struct-errors.md displayName: > diff --git a/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md b/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md index 15c2303696612..1d541b82007d3 100644 --- a/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md +++ b/docs/csharp/misc/sorry-we-don-t-have-specifics-on-this-csharp-error.md @@ -459,8 +459,6 @@ f1_keywords: - "CS8980" - "CS8984" - "CS8985" - - "CS8986" - - "CS8987" - "CS8989" - "CS9011" - "CS9012" @@ -495,43 +493,13 @@ f1_keywords: - "CS9053" - "CS9054" - "CS9056" - - "CS9057" + - "CS9058" - "CS9060" - - "CS9061" - - "CS9062" - - "CS9063" - - "CS9065" - - "CS9066" + - "CS9064" - "CS9067" - "CS9068" - - "CS9069" - "CS9070" - "CS9071" - - "CS9073" - - "CS9074" - - "CS9075" - - "CS9076" - - "CS9077" - - "CS9078" - - "CS9079" - - "CS9080" - - "CS9081" - - "CS9082" - - "CS9083" - - "CS9084" - - "CS9085" - - "CS9086" - - "CS9087" - - "CS9088" - - "CS9089" - - "CS9090" - - "CS9091" - - "CS9092" - - "CS9093" - - "CS9094" - - "CS9095" - - "CS9096" - - "CS9097" helpviewer_keywords: - "errors [C#], additional information" --- From 837a0f659cd8a9b9770f10b54b8941f0b2b8488e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 21 Nov 2025 15:50:46 -0500 Subject: [PATCH 2/9] first edit pass --- .../compiler-messages/ref-safety-errors.md | 197 ++++++++++++------ 1 file changed, 130 insertions(+), 67 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md index 155be74f57b73..3c9d1e0698595 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md @@ -57,76 +57,139 @@ The following errors can be generated when reference variable safety rules are v -- [**CS8166**](#ref-safety-violations): *Cannot return a parameter by reference because it is not a `ref` parameter* -- [**CS8167**](#ref-safety-violations): *Cannot return by reference a member of parameter because it is not a `ref` or `out` parameter* -- [**CS8168**](#ref-safety-violations): *Cannot return local by reference because it is not a ref local* -- [**CS8169**](#ref-safety-violations): *Cannot return a member of local variable by reference because it is not a ref local* -- [**CS8345**](#ref-safety-violations): *Field or auto-implemented property cannot be of type unless it is an instance member of a `ref struct`.* -- [**CS8351**](#ref-safety-violations): *Branches of a `ref` conditional operator cannot refer to variables with incompatible declaration scopes* -- [**CS8374**](#ref-safety-violations): *Cannot ref-assign source has a narrower escape scope than destination.* -- [**CS9075**](#ref-safety-violations): *Cannot return a parameter by reference because it is scoped to the current method* -- [**CS9076**](#ref-safety-violations): *Cannot return by reference a member of parameter because it is scoped to the current method* -- [**CS9077**](#ref-safety-violations): *Cannot return a parameter by reference through a `ref` parameter; it can only be returned in a return statement* -- [**CS9078**](#ref-safety-violations): *Cannot return by reference a member of parameter through a `ref` parameter; it can only be returned in a return statement* -- [**CS9079**](#ref-safety-violations): *Cannot ref-assign source to destination because source can only escape the current method through a return statement.* -- [**CS9096**](#ref-safety-violations): *Cannot ref-assign source to destination because source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* +- [**CS8166**](#returning-references-with-incompatible-scopes): *Cannot return a parameter by reference because it is not a `ref` parameter* +- [**CS8167**](#returning-references-with-incompatible-scopes): *Cannot return by reference a member of parameter because it is not a `ref` or `out` parameter* +- [**CS8168**](#returning-references-with-incompatible-scopes): *Cannot return local by reference because it is not a ref local* +- [**CS8169**](#returning-references-with-incompatible-scopes): *Cannot return a member of local variable by reference because it is not a ref local* +- [**CS8345**](#struct-member-and-field-restrictions): *Field or auto-implemented property cannot be of type unless it is an instance member of a `ref struct`.* +- [**CS8351**](#escape-scope-violations-and-conditional-operators): *Branches of a `ref` conditional operator cannot refer to variables with incompatible declaration scopes* +- [**CS8374**](#ref-assignments-with-incompatible-scopes): *Cannot ref-assign source has a narrower escape scope than destination.* +- [**CS9075**](#returning-references-with-incompatible-scopes): *Cannot return a parameter by reference because it is scoped to the current method* +- [**CS9076**](#returning-references-with-incompatible-scopes): *Cannot return by reference a member of parameter because it is scoped to the current method* +- [**CS9077**](#returning-references-with-incompatible-scopes): *Cannot return a parameter by reference through a `ref` parameter; it can only be returned in a return statement* +- [**CS9078**](#returning-references-with-incompatible-scopes): *Cannot return by reference a member of parameter through a `ref` parameter; it can only be returned in a return statement* +- [**CS9079**](#ref-assignments-with-incompatible-scopes): *Cannot ref-assign source to destination because source can only escape the current method through a return statement.* +- [**CS9096**](#ref-assignments-with-incompatible-scopes): *Cannot ref-assign source to destination because source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* The following warnings are generated when reference variable safety rules are violated: -- [**CS9080**](#ref-safety-violations): *Use of variable in this context may expose referenced variables outside of their declaration scope* -- [**CS9081**](#ref-safety-violations): *A result of a stackalloc expression of type in this context may be exposed outside of the containing method* -- [**CS9082**](#ref-safety-violations): *Local is returned by reference but was initialized to a value that cannot be returned by reference* -- [**CS9083**](#ref-safety-violations): *A member of is returned by reference but was initialized to a value that cannot be returned by reference* -- [**CS9084**](#ref-safety-violations): *Struct member returns 'this' or other instance members by reference* -- [**CS9085**](#ref-safety-violations): *This ref-assigns source to destination but source has a narrower escape scope than destination.* -- [**CS9086**](#ref-safety-violations): *The branches of the ref conditional operator refer to variables with incompatible declaration scopes* -- [**CS9087**](#ref-safety-violations): *This returns a parameter by reference but it is not a `ref` parameter* -- [**CS9088**](#ref-safety-violations): *This returns a parameter by reference but it is scoped to the current method* -- [**CS9089**](#ref-safety-violations): *This returns by reference a member of parameter that is not a `ref` or `out` parameter* -- [**CS9090**](#ref-safety-violations): *This returns by reference a member of parameter that is scoped to the current method* -- [**CS9091**](#ref-safety-violations): *This returns local by reference but it is not a ref local* -- [**CS9092**](#ref-safety-violations): *This returns a member of local by reference but it is not a ref local* -- [**CS9093**](#ref-safety-violations): *This ref-assigns source to destination but source can only escape the current method through a return statement.* -- [**CS9094**](#ref-safety-violations): *This returns a parameter by reference through a `ref` parameter; but it can only safely be returned in a return statement* -- [**CS9095**](#ref-safety-violations): *This returns by reference a member of parameter through a `ref` parameter; but it can only safely be returned in a return statement* -- [**CS9097**](#ref-safety-violations): *This ref-assigns source to destination but source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* - -## Ref safety violations - -The compiler tracks the safe context of referents and reference variables. The compiler issues errors, or warnings in unsafe code, when a reference variable refers to a referent variable that's no longer valid. The referent must have a safe context that is at least as wide as the ref safe context of The reference variable. Violating these safety checks means the reference variable accesses random memory instead of the referent variable. - -- **CS8166**: *Cannot return a parameter by reference because it is not a `ref` parameter* -- **CS8167**: *Cannot return by reference a member of parameter because it is not a `ref` or `out` parameter* -- **CS8168**: *Cannot return local by reference because it is not a ref local* -- **CS8169**: *Cannot return a member of local variable by reference because it is not a ref local* -- **CS8345**: *Field or auto-implemented property cannot be of type unless it is an instance member of a `ref struct`.* -- **CS8351**: *Branches of a `ref` conditional operator cannot refer to variables with incompatible declaration scopes* -- **CS8374**: *Cannot ref-assign source has a narrower escape scope than destination.* -- **CS9075**: *Cannot return a parameter by reference because it is scoped to the current method* -- **CS9076**: *Cannot return by reference a member of parameter because it is scoped to the current method* -- **CS9077**: *Cannot return a parameter by reference through a `ref` parameter; it can only be returned in a return statement* -- **CS9078**: *Cannot return by reference a member of parameter through a `ref` parameter; it can only be returned in a return statement* -- **CS9079**: *Cannot ref-assign source to destination because source can only escape the current method through a return statement.* -- **CS9096**: *Cannot ref-assign source to destination because source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* +- [**CS9080**](#escape-scope-violations-and-conditional-operators): *Use of variable in this context may expose referenced variables outside of their declaration scope* +- [**CS9081**](#escape-scope-violations-and-conditional-operators): *A result of a stackalloc expression of type in this context may be exposed outside of the containing method* +- [**CS9082**](#struct-member-and-field-restrictions): *Local is returned by reference but was initialized to a value that cannot be returned by reference* +- [**CS9083**](#struct-member-and-field-restrictions): *A member of is returned by reference but was initialized to a value that cannot be returned by reference* +- [**CS9084**](#struct-member-and-field-restrictions): *Struct member returns 'this' or other instance members by reference* +- [**CS9085**](#ref-assignments-with-incompatible-scopes): *This ref-assigns source to destination but source has a narrower escape scope than destination.* +- [**CS9086**](#escape-scope-violations-and-conditional-operators): *The branches of the ref conditional operator refer to variables with incompatible declaration scopes* +- [**CS9087**](#returning-references-with-incompatible-scopes): *This returns a parameter by reference but it is not a `ref` parameter* +- [**CS9088**](#returning-references-with-incompatible-scopes): *This returns a parameter by reference but it is scoped to the current method* +- [**CS9089**](#returning-references-with-incompatible-scopes): *This returns by reference a member of parameter that is not a `ref` or `out` parameter* +- [**CS9090**](#returning-references-with-incompatible-scopes): *This returns by reference a member of parameter that is scoped to the current method* +- [**CS9091**](#returning-references-with-incompatible-scopes): *This returns local by reference but it is not a ref local* +- [**CS9092**](#returning-references-with-incompatible-scopes): *This returns a member of local by reference but it is not a ref local* +- [**CS9093**](#ref-assignments-with-incompatible-scopes): *This ref-assigns source to destination but source can only escape the current method through a return statement.* +- [**CS9094**](#returning-references-with-incompatible-scopes): *This returns a parameter by reference through a `ref` parameter; but it can only safely be returned in a return statement* +- [**CS9095**](#returning-references-with-incompatible-scopes): *This returns by reference a member of parameter through a `ref` parameter; but it can only safely be returned in a return statement* +- [**CS9097**](#ref-assignments-with-incompatible-scopes): *This ref-assigns source to destination but source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* + +## Returning references with incompatible scopes + +The compiler prevents you from returning a reference to a variable when the variable's lifetime doesn't extend beyond the method's scope. These errors occur when attempting to return by reference a parameter, local variable, or member that isn't declared with `ref` or has a scope limited to the current method. + +Errors: + +- **CS8166**: *Cannot return a parameter by reference because it is not a `ref` parameter* +- **CS8167**: *Cannot return by reference a member of parameter because it is not a `ref` or `out` parameter* +- **CS8168**: *Cannot return local by reference because it is not a ref local* +- **CS8169**: *Cannot return a member of local variable by reference because it is not a ref local* +- **CS9075**: *Cannot return a parameter by reference because it is scoped to the current method* +- **CS9076**: *Cannot return by reference a member of parameter because it is scoped to the current method* +- **CS9077**: *Cannot return a parameter by reference through a `ref` parameter; it can only be returned in a return statement* +- **CS9078**: *Cannot return by reference a member of parameter through a `ref` parameter; it can only be returned in a return statement* Warnings: -- **CS9080**: *Use of variable in this context may expose referenced variables outside of their declaration scope* -- **CS9081**: *A result of a stackalloc expression of type in this context may be exposed outside of the containing method* -- **CS9082**: *Local is returned by reference but was initialized to a value that cannot be returned by reference* -- **CS9083**: *A member of is returned by reference but was initialized to a value that cannot be returned by reference* -- **CS9084**: *Struct member returns 'this' or other instance members by reference* -- **CS9085**: *This ref-assigns source to destination but source has a narrower escape scope than destination.* -- **CS9086**: *The branches of the ref conditional operator refer to variables with incompatible declaration scopes* -- **CS9087**: *This returns a parameter by reference but it is not a `ref` parameter* -- **CS9088**: *This returns a parameter by reference but it is scoped to the current method* -- **CS9089**: *This returns by reference a member of parameter that is not a `ref` or `out` parameter* -- **CS9090**: *This returns by reference a member of parameter that is scoped to the current method* -- **CS9091**: *This returns local by reference but it is not a ref local* -- **CS9092**: *This returns a member of local by reference but it is not a ref local* -- **CS9093**: *This ref-assigns source to destination but source can only escape the current method through a return statement.* -- **CS9094**: *This returns a parameter by reference through a `ref` parameter; but it can only safely be returned in a return statement* -- **CS9095**: *This returns by reference a member of parameter through a `ref` parameter; but it can only safely be returned in a return statement* -- **CS9097**: *This ref-assigns source to destination but source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* - -The compiler uses static analysis to determine if the referent is valid at all points where the reference variable can be used. You need to refactor code so that the referent remains valid at all locations where the reference variable might refer to it. For details on the rules for ref safety, see the C# standard on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). +- **CS9087**: *This returns a parameter by reference but it is not a `ref` parameter* +- **CS9088**: *This returns a parameter by reference but it is scoped to the current method* +- **CS9089**: *This returns by reference a member of parameter that is not a `ref` or `out` parameter* +- **CS9090**: *This returns by reference a member of parameter that is scoped to the current method* +- **CS9091**: *This returns local by reference but it is not a ref local* +- **CS9092**: *This returns a member of local by reference but it is not a ref local* +- **CS9094**: *This returns a parameter by reference through a `ref` parameter; but it can only safely be returned in a return statement* +- **CS9095**: *This returns by reference a member of parameter through a `ref` parameter; but it can only safely be returned in a return statement* + +To resolve these errors: + +- Change the method signature to declare parameters with the `ref` keyword instead of passing them by value, which allows the parameter's storage location to be returned safely because the caller controls the variable's lifetime (**CS8166**, **CS8167**, **CS9087**, **CS9089**). +- For local variables, declare them as `ref` locals by assigning them from a ref-returning expression or a ref parameter, which ensures the local refers to storage with a sufficient lifetime rather than creating a new variable with method-scoped lifetime (**CS8168**, **CS8169**, **CS9091**, **CS9092**). +- When a parameter is declared with the `scoped` modifier, avoid returning it by reference because the `scoped` modifier explicitly restricts the parameter's reference from escaping the method, preventing potential dangling references (**CS9075**, **CS9076**, **CS9088**, **CS9090**). +- If you need to return a reference that comes from a `ref` parameter, use a direct `return ref` statement rather than assigning the reference to another `ref` parameter and returning that, because the compiler can only track the escape scope through direct return statements (**CS9077**, **CS9078**, **CS9094**, **CS9095**). + +For more information about ref safety rules, see the article on [ref returns and locals](../../programming-guide/classes-and-structs/ref-returns.md) and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). + +## Ref assignments with incompatible scopes + +The compiler prevents ref assignment operations where the source variable has a narrower escape scope than the destination. A ref assignment creates a reference from the destination to the source's storage location. If the source could go out of scope before the destination, the destination would refer to invalid memory. + +Errors: + +- **CS8374**: *Cannot ref-assign source has a narrower escape scope than destination.* +- **CS9079**: *Cannot ref-assign source to destination because source can only escape the current method through a return statement.* +- **CS9096**: *Cannot ref-assign source to destination because source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* + +Warnings: + +- **CS9085**: *This ref-assigns source to destination but source has a narrower escape scope than destination.* +- **CS9093**: *This ref-assigns source to destination but source can only escape the current method through a return statement.* +- **CS9097**: *This ref-assigns source to destination but source has a wider value escape scope than destination allowing assignment through destination of values with narrower escapes scopes than source.* + +To resolve these errors: + +- Restructure your code so that the source variable in a ref assignment has an escape scope at least as wide as the destination variable, which ensures the destination reference remains valid for its entire lifetime and prevents dangling references (**CS8374**, **CS9085**). +- When working with variables that can only escape the method through a return statement, avoid assigning them to ref variables that might be accessed through other means such as being stored in fields or returned through ref parameters, because this would violate the restriction that the source can only be used in return statements (**CS9079**, **CS9093**). +- For ref assignments involving value escape scopes, ensure the source's value escape scope isn't wider than the destination's, because a mismatch would allow you to assign narrower-scoped values through the destination reference, potentially creating references to short-lived values (**CS9096**, **CS9097**). + +For more information about ref safety rules, see the article on [ref returns and locals](../../programming-guide/classes-and-structs/ref-returns.md) and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). + +## Escape scope violations and conditional operators + +The compiler tracks how variables can escape their declaration scope through various operations. These errors occur when using variables in contexts that could expose referenced variables outside their valid lifetime, including ref conditional operators and stackalloc expressions. + +Errors: + +- **CS8351**: *Branches of a `ref` conditional operator cannot refer to variables with incompatible declaration scopes* + +Warnings: + +- **CS9080**: *Use of variable in this context may expose referenced variables outside of their declaration scope* +- **CS9081**: *A result of a stackalloc expression of type in this context may be exposed outside of the containing method* +- **CS9086**: *The branches of the ref conditional operator refer to variables with incompatible declaration scopes* + +To resolve these errors: + +- Modify the ref conditional operator (the `?:` operator with `ref` returns) so that both the true and false branches refer to variables that have compatible declaration scopes, which means both variables must have lifetimes that extend to at least the same scope level, preventing the conditional expression from potentially returning a reference that becomes invalid (**CS8351**, **CS9086**). +- When using variables in expressions or method calls, ensure the context doesn't allow referenced variables to escape beyond their declaration scope, which typically means avoiding passing scoped variables to methods or expressions where they might be captured or stored beyond their intended lifetime (**CS9080**). +- For stackalloc expressions, avoid assigning the result to variables or using it in contexts where the stack-allocated memory could be accessed outside the containing method, because stack-allocated memory is automatically freed when the method returns and accessing it afterward results in undefined behavior (**CS9081**). + +For more information, see the article on [ref returns and locals](../../programming-guide/classes-and-structs/ref-returns.md), the article on [stack allocation](../../../standard/memory-and-spans/memory-t-usage-guidelines.md#stack-allocated-memory), and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). + +## Struct member and field restrictions + +The compiler enforces special rules for struct members and fields to prevent dangling references. These errors occur when struct members return references to instance state or when fields have types that require special handling. + +Errors: + +- **CS8345**: *Field or auto-implemented property cannot be of type unless it is an instance member of a `ref struct`.* + +Warnings: + +- **CS9082**: *Local is returned by reference but was initialized to a value that cannot be returned by reference* +- **CS9083**: *A member of is returned by reference but was initialized to a value that cannot be returned by reference* +- **CS9084**: *Struct member returns 'this' or other instance members by reference* + +To resolve these errors: + +- Ensure that fields and auto-implemented properties with ref-like types (such as `Span` or `ref struct` types) are only declared as instance members within a ref struct rather than in regular structs or classes, because ref-like types can only safely exist on the stack and ref structs provide the necessary lifetime guarantees (**CS8345**). +- When returning a local variable by reference from a method, verify that the local was initialized from a source that has a sufficient escape scope such as a ref parameter or ref-returning method call, rather than from a value-typed expression or local-scoped variable that would create a reference to short-lived storage (**CS9082**, **CS9083**). +- In struct instance methods or properties, avoid returning `this` or any instance fields by reference, because structs are value types that are often copied, and returning a reference to an instance member could create a reference to a temporary copy that's immediately destroyed after the method returns (**CS9084**). + +For more information, see the article on [ref struct types](../../language-reference/builtin-types/ref-struct.md) and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). From 578a3c2159894775d3d7eadfb23322804df55330 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 21 Nov 2025 16:45:09 -0500 Subject: [PATCH 3/9] final proofread Give the edits a final proofread --- .github/prompts/error-consolidation.md | 2 +- .../compiler-messages/ref-modifiers-errors.md | 79 +++++++++++-------- .../compiler-messages/ref-safety-errors.md | 10 +-- 3 files changed, 54 insertions(+), 37 deletions(-) diff --git a/.github/prompts/error-consolidation.md b/.github/prompts/error-consolidation.md index aa1d4db2f7c56..6fc5e79dfadd6 100644 --- a/.github/prompts/error-consolidation.md +++ b/.github/prompts/error-consolidation.md @@ -68,7 +68,7 @@ Rework the highlighted section so the focus is on how to correct each error. Thi ## Verify error messages -For every line in this table, verify that the error message associated with this error code matches the verbatim text in CSharpResources.resx. You can find the mapping using ErrorCodes.cs: +For every line in this list, verify that the error message associated with this error code matches the verbatim text in CSharpResources.resx. You can find the mapping using ErrorCodes.cs: 1. Find that number as a constant in `ErrorCodes.cs`. 2. Locate the corresponding `data` element in CSharpResources.resx. The `name` atttribute should match the number of the constant. diff --git a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md index 90c06f16fd6fb..f37dddfb5c96b 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md @@ -110,7 +110,7 @@ helpviewer_keywords: - "CS9205" - "CS9265" ai-usage: ai-assisted -ms.date: 11/21/2024 +ms.date: 11/21/2025 --- # Errors and warnings associated with reference parameters, variables, and returns @@ -196,12 +196,14 @@ These errors indicate that you're using incorrect syntax regarding reference var - **CS9190**: *`readonly` modifier must be specified after `ref`.* - **CS9205**: *Expected interpolated string.* -You can correct the error with one of these changes: +To correct these errors: -- The left operand of an `= ref` operator must be a reference variable. For more information on the correct syntax, see [reference variables](../statements/declarations.md#reference-variables). -- The parameter modifier `ref readonly` must be in that order. `readonly ref` is not a legal parameter modifier. Switch the order of the words. -- A local variable can't be declared as `out`. To declare a local reference variable, use `ref`. -- An `out` argument can't be an interpolated string. +- Ensure the left operand of a `= ref` operator is a reference variable rather than a value expression or non-reference local. Ref assignment requires both sides to be reference variables that can create an alias to the same storage location (**CS8373**). +- When declaring reference parameters, write the modifier as `ref readonly` rather than `readonly ref`. The C# language specification requires the `ref` keyword to precede the `readonly` modifier in parameter declarations to maintain consistent syntax across all reference parameter types (**CS9190**). +- Use the `ref` keyword instead of `out` when declaring local reference variables. `out` is exclusively a parameter modifier that indicates a method must assign a value before returning, whereas `ref` is the appropriate keyword for creating local variables that alias other storage locations (**CS8388**). +- Pass a regular variable or value expression instead of an interpolated string when calling a method with an `out` parameter. Interpolated strings are immutable temporary values that can't be used as output parameters since they don't represent assignable storage locations (**CS9205**). + +For more information about reference variables and their syntax requirements, see [reference variables](../statements/declarations.md#reference-variables) and the [C# Language Specification](~/_csharpstandard/standard/variables.md#96-reference-variables-and-returns). ## Reference variable restrictions @@ -234,22 +236,27 @@ The following warnings indicate that a reference variable shouldn't be used, and - **CS9201**: *Ref field should be ref-assigned before use.* - **CS9265**: *Field is never ref-assigned to, and will always have its default value (null reference)* -To fix the error, remove the reference variable where it isn't allowed: - -- Remove `in`, `ref`, and `out` parameters from [indexers](../../programming-guide/indexers/index.md), [iterators](../../iterators.md), and [async methods](../../asynchronous-programming/index.md). -- Remove [ref conditional expressions](../operators/conditional-operator.md#conditional-ref-expression) (`? :`) that include an [await](../operators/await.md). -- Remove the `ref` modifier from the first parameter of a [extension method](../../programming-guide/classes-and-structs/extension-methods.md) where that type isn't a value type or a generic type constrained as a value type. -- Either both or neither [conditional operator expressions] must be `ref` variables. Either remove `ref` from one expression, or add it to the other. If it's a `ref` conditional expression, both expressions must be the same type. -- `ref` and `out` parameters can't have [default values](../../programming-guide/classes-and-structs/named-and-optional-arguments.md). Either remove the `ref` or `out` modifier, or remove the default value. -- An implicitly typed `out` variable declaration can't also appear elsewhere in the same argument list. -- You can't put reference variables in a `using` statement in `async` methods lambda expressions. -- The range variable in a [LINQ query expression](../../linq/get-started/query-expression-basics.md) can't be passed by reference. -- You can't deconstruct an object into reference variables. Replace the reference variables with value variables. -- You can't implement multiple interfaces where method overloads differ only on `ref` and `out`. For example, one interface declares `void M(ref int i)` and another interface declares `void M(out int i)`. A class can't implement both interfaces because the methods aren't distinguishable. You can only implement one of those interfaces. -- Methods attributed with can't use reference parameters. -- A Windows runtime event can't be passed as a reference variable. -- A `ref readonly` parameter can't have the applied to it in remoting API. -- Initialize a `ref` field in the constructor or as a field initializer. +To correct these errors: + +- Remove reference parameters from [indexers](../../programming-guide/indexers/index.md). Indexers are designed to provide array-like access syntax and the compiler can't guarantee safe lifetime tracking for references passed through indexer accessors (**CS0631**, **CS1623**). +- Remove reference parameters from [iterator methods](../../iterators.md). Iterators execute code lazily across multiple calls using state machines, and the compiler can't ensure referenced variables remain valid across yield return boundaries where execution is suspended and resumed (**CS1623**). +- Remove reference parameters from [async methods](../../asynchronous-programming/index.md). Async methods may suspend execution at await points and resume on different threads, making it impossible to guarantee that referenced variables remain valid and accessible throughout the method's execution (**CS1988**). +- Avoid using [await expressions](../operators/await.md) inside [ref conditional expressions](../operators/conditional-operator.md#conditional-ref-expression). The await operation may suspend execution and invalidate the references being selected by the conditional operator, leading to potential use of invalidated references when execution resumes (**CS8325**). +- Ensure both branches of a ref conditional operator return references or neither returns a reference, and when both are references they must be the same type. The conditional operator must produce a consistent result type that can be safely used by the calling code regardless of which branch is selected (**CS8326**, **CS8327**). +- Remove default values from `ref` and `out` parameters. Reference parameters must always be provided at the call site to establish the required aliasing relationship between the parameter and an existing variable, making default values semantically meaningless (**CS1741**). +- Avoid declaring an implicitly typed `out` variable in an argument list that also references that same variable. The compiler must infer the variable's type from the method signature while simultaneously validating uses of that variable within the same expression, creating a circular dependency (**CS8196**). +- Don't pass [LINQ query](../../linq/get-started/query-expression-basics.md) range variables as reference parameters. Range variables are compiler-generated iteration variables whose lifetime is managed by the query execution model and don't have stable memory locations that can be safely referenced (**CS1939**). +- Use regular value variables instead of ref locals when [deconstructing](../operators/patterns.md#positional-pattern) objects. Deconstruction creates new variables to receive the deconstructed values and reference variables would attempt to alias these temporary values rather than store them independently (**CS9072**). +- Avoid implementing multiple interfaces where methods differ only by `ref` versus `out` modifiers on parameters. The C# language specification treats these as distinct signatures but doesn't provide a way to disambiguate which implementation to call since both `ref` and `out` share the same calling syntax at implementation boundaries (**CS0767**). +- Remove reference parameters from methods decorated with . These methods are callable from unmanaged code that doesn't understand C#'s reference safety rules and can't guarantee proper lifetime management of referenced variables across the managed/unmanaged boundary (**CS8977**). +- Use the `ref` modifier on [extension method](../../programming-guide/classes-and-structs/extension-methods.md) first parameters only for value types or generic types constrained to value types. Reference types are already passed by reference at the CLR level and adding `ref` would create a reference to a reference, while value type extensions with `ref` enable mutation of the extended instance (**CS8337**, **CS8338**). +- Don't pass Windows Runtime events as reference parameters. These events follow the Windows Runtime type system which has different lifetime and threading semantics than .NET references and doesn't support the aliasing behavior required by C# reference parameters (**CS7084**). +- Remove the from `ref readonly` parameters. This attribute is designed for marshaling semantics in platform invoke scenarios where the parameter direction is outbound only, which conflicts with `ref readonly`'s guarantee that the parameter references existing data that won't be reassigned (**CS9199**). +- Ensure all `ref` fields in a type are assigned either in field initializers or in all constructor code paths before the constructor completes. Uninitialized ref fields would contain invalid references that could lead to memory corruption if accessed (**CS9201**, **CS9265**). +- Match the reference kind modifiers (`ref`, `in`, `out`, `ref readonly`) between a method and its overridden base method or implemented interface method. The reference modifier is part of the method signature contract that derived types must honor to maintain substitutability and caller expectations (**CS9196**, **CS9197**, **CS9198**). +- Declare parameters as `in` rather than `ref readonly` when providing default values. `ref readonly` is designed for scenarios where the caller passes a reference to an existing variable, whereas `in` parameters can accept both references and temporary copies of values, making default values meaningful (**CS9200**). + +For more information about where reference variables are allowed, see [Method parameters](../keywords/method-parameters.md), [Iterators](../../iterators.md), [Asynchronous programming patterns](../../asynchronous-programming/index.md), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#96-reference-variables-and-returns). ## `unscoped ref` restrictions @@ -258,7 +265,12 @@ The `unscoped` qualifier on `ref` parameters isn't allowed in some locations: - **CS9101**: *UnscopedRefAttribute can only be applied to struct instance or virtual interface methods and properties, and cannot be applied to constructors or or init-only members.* - **CS9102**: *UnscopedRefAttribute cannot be applied to an interface implementation because implemented member doesn't have this attribute..* -You must remove the `unscoped` modifier on the parameter declaration that caused the error. +To correct these errors: + +- Remove the `unscoped` modifier or the attribute from struct constructors and init-only members. These members have special initialization semantics where the compiler must ensure that any references don't outlive the initialization phase, and allowing unscoped references would violate the guarantee that initialization completes before the struct becomes fully accessible (**CS9101**). +- Remove the `unscoped` modifier from interface implementation methods when the corresponding interface method doesn't have it. The unscoped characteristic affects the method's contract regarding reference lifetime guarantees, and implementations must maintain the same contract as the interface they're implementing to ensure callers can rely on consistent lifetime behavior regardless of which implementation is invoked (**CS9102**). + +For more information about scoped and unscoped references, see [Method parameters](../keywords/method-parameters.md) and the [low-level struct improvements](~/_csharplang/proposals/csharp-11.0/low-level-struct-improvements.md) feature specification. ## Reference variables require a referent @@ -274,7 +286,13 @@ Warnings: - **CS9193**: *Argument should be a variable because it is passed to a `ref readonly` parameter* - **CS9195**: *Argument should be passed with the `in` keyword* -The compiler emits these errors when you use an expression that calculates a value where a variable must be used. You must store the result of that expression in a variable to use it. For example, properties and indexers return values, not variables. You must store the result in a variable and pass a reference to that variable. +To correct these errors: + +- Store the result of a property or indexer access in a local variable before passing it as a reference parameter. [Properties](../../programming-guide/classes-and-structs/properties.md) and [indexers](../../programming-guide/indexers/index.md) are methods that return values rather than providing direct access to storage locations, and reference parameters require an actual variable with a stable memory location that can be aliased (**CS0206**, **CS1510**). +- Use the `in` modifier instead of `ref` when passing arguments to `in` parameters. While `ref` technically works due to backward compatibility, the `in` modifier more clearly expresses the intent that the argument is read-only and may be passed more efficiently as a reference without copying (**CS9191**, **CS9195**). +- Add the appropriate reference modifier (`ref`, `in`, or `ref readonly`) when passing arguments to parameters that expect references. Omitting the modifier may cause the compiler to create a temporary copy of the value, which is inefficient and can lead to unexpected behavior if the calling code expects modifications to be reflected in the original variable (**CS9192**, **CS9193**). + +For more information about reference parameters and passing variables by reference, see [Method parameters](../keywords/method-parameters.md), [ref keyword](../keywords/ref.md), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#96-reference-variables-and-returns). ## Writable reference variables require a writable referent @@ -292,12 +310,11 @@ A writable reference variable requires that the referent also is writable. The f - **CS8331**: *Cannot assign to variable or use it as the right hand side of a `ref` assignment because it is a readonly variable* - **CS8332**: *Cannot assign to a member of variable or use it as the right hand side of a `ref` assignment because it is a readonly variable* -Examples of variables that aren't writable include: +To correct these errors: -- [readonly](../../language-reference/keywords/readonly.md) fields, both instance and static fields. -- Members of `readonly` fields. -- The `this` variable. -- The [foreach](../../language-reference/statements/iteration-statements.md#the-foreach-statement) iteration variable -- A [using](../../language-reference/statements/using.md) variable, or a [fixed](../../language-reference/statements/fixed.md) variable. +- Copy the value from a [readonly field](../keywords/readonly.md) to a local variable and pass the local variable as a `ref` or `out` parameter. Readonly fields are immutable after initialization (except within constructors) and allowing writable references to them would violate the immutability guarantee that readonly provides (**CS0192**, **CS0199**, **CS1649**, **CS1651**). +- Use `ref readonly` or `in` parameters instead of `ref` or `out` when you need to pass readonly variables, iteration variables, or other non-writable values by reference. These modifiers indicate that the method will only read the referenced value without attempting to modify it. That aligns with the immutability constraints of the original variable (**CS1605**, **CS1655**, **CS1657**, **CS8329**). +- Copy members of readonly variables to local variables before passing them as writable references. Even though the member itself might not be declared as readonly, it's accessed through a readonly path (via a readonly field, `in` parameter, or `ref readonly` local), and the compiler enforces transitivity of readonly-ness to prevent indirect mutation of readonly data (**CS8330**, **CS8332**). +- Avoid writable ref assignments to readonly variables, [foreach iteration variables](../statements/iteration-statements.md#the-foreach-statement), [using statement resources](../statements/using.md), or [fixed statement variables](../statements/fixed.md). These variables have special lifetime semantics managed by the compiler. The variable is automatically finalized or disposed at the end of its scope. External references create dangling references after disposal (**CS8331**). -You must copy the value and pass a reference to the copy. +For more information about readonly semantics and reference parameters, see [readonly keyword](../keywords/readonly.md), [in parameter modifier](../keywords/in-parameter-modifier.md), [ref readonly](../statements/declarations.md#ref-readonly-locals), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#96-reference-variables-and-returns). diff --git a/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md index 3c9d1e0698595..ad016e6dca783 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md @@ -48,7 +48,7 @@ helpviewer_keywords: - "CS9096" - "CS9097" ai-usage: ai-assisted -ms.date: 11/21/2024 +ms.date: 11/21/2025 --- # Errors and warnings related to ref safety @@ -76,7 +76,7 @@ The following warnings are generated when reference variable safety rules are vi - [**CS9080**](#escape-scope-violations-and-conditional-operators): *Use of variable in this context may expose referenced variables outside of their declaration scope* - [**CS9081**](#escape-scope-violations-and-conditional-operators): *A result of a stackalloc expression of type in this context may be exposed outside of the containing method* - [**CS9082**](#struct-member-and-field-restrictions): *Local is returned by reference but was initialized to a value that cannot be returned by reference* -- [**CS9083**](#struct-member-and-field-restrictions): *A member of is returned by reference but was initialized to a value that cannot be returned by reference* +- [**CS9083**](#struct-member-and-field-restrictions): *A member is returned by reference but was initialized to a value that cannot be returned by reference* - [**CS9084**](#struct-member-and-field-restrictions): *Struct member returns 'this' or other instance members by reference* - [**CS9085**](#ref-assignments-with-incompatible-scopes): *This ref-assigns source to destination but source has a narrower escape scope than destination.* - [**CS9086**](#escape-scope-violations-and-conditional-operators): *The branches of the ref conditional operator refer to variables with incompatible declaration scopes* @@ -145,7 +145,7 @@ Warnings: To resolve these errors: - Restructure your code so that the source variable in a ref assignment has an escape scope at least as wide as the destination variable, which ensures the destination reference remains valid for its entire lifetime and prevents dangling references (**CS8374**, **CS9085**). -- When working with variables that can only escape the method through a return statement, avoid assigning them to ref variables that might be accessed through other means such as being stored in fields or returned through ref parameters, because this would violate the restriction that the source can only be used in return statements (**CS9079**, **CS9093**). +- When a variable can only escape the method through a return statement, don't assign it to a `ref` variables accessed through other means. Examples include storing in fields or returning through ref parameters. Those actions violate the restriction that the source can only be used in return statements (**CS9079**, **CS9093**). - For ref assignments involving value escape scopes, ensure the source's value escape scope isn't wider than the destination's, because a mismatch would allow you to assign narrower-scoped values through the destination reference, potentially creating references to short-lived values (**CS9096**, **CS9097**). For more information about ref safety rules, see the article on [ref returns and locals](../../programming-guide/classes-and-structs/ref-returns.md) and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). @@ -183,13 +183,13 @@ Errors: Warnings: - **CS9082**: *Local is returned by reference but was initialized to a value that cannot be returned by reference* -- **CS9083**: *A member of is returned by reference but was initialized to a value that cannot be returned by reference* +- **CS9083**: *A member is returned by reference but was initialized to a value that cannot be returned by reference* - **CS9084**: *Struct member returns 'this' or other instance members by reference* To resolve these errors: - Ensure that fields and auto-implemented properties with ref-like types (such as `Span` or `ref struct` types) are only declared as instance members within a ref struct rather than in regular structs or classes, because ref-like types can only safely exist on the stack and ref structs provide the necessary lifetime guarantees (**CS8345**). - When returning a local variable by reference from a method, verify that the local was initialized from a source that has a sufficient escape scope such as a ref parameter or ref-returning method call, rather than from a value-typed expression or local-scoped variable that would create a reference to short-lived storage (**CS9082**, **CS9083**). -- In struct instance methods or properties, avoid returning `this` or any instance fields by reference, because structs are value types that are often copied, and returning a reference to an instance member could create a reference to a temporary copy that's immediately destroyed after the method returns (**CS9084**). +- In struct instance methods or properties, avoid returning `this` or any instance fields by reference, because structs are value types that are often copied, and returning a reference to an instance member could create a reference to a temporary copy destroyed after the method returns (**CS9084**). For more information, see the article on [ref struct types](../../language-reference/builtin-types/ref-struct.md) and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). From f76bf5b6f9432aa7f64eb2acc1be186fedde937e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 21 Nov 2025 17:00:10 -0500 Subject: [PATCH 4/9] fix build warnings --- .../compiler-messages/ref-modifiers-errors.md | 2 +- .../compiler-messages/ref-safety-errors.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md index f37dddfb5c96b..5dab9e516327b 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md @@ -317,4 +317,4 @@ To correct these errors: - Copy members of readonly variables to local variables before passing them as writable references. Even though the member itself might not be declared as readonly, it's accessed through a readonly path (via a readonly field, `in` parameter, or `ref readonly` local), and the compiler enforces transitivity of readonly-ness to prevent indirect mutation of readonly data (**CS8330**, **CS8332**). - Avoid writable ref assignments to readonly variables, [foreach iteration variables](../statements/iteration-statements.md#the-foreach-statement), [using statement resources](../statements/using.md), or [fixed statement variables](../statements/fixed.md). These variables have special lifetime semantics managed by the compiler. The variable is automatically finalized or disposed at the end of its scope. External references create dangling references after disposal (**CS8331**). -For more information about readonly semantics and reference parameters, see [readonly keyword](../keywords/readonly.md), [in parameter modifier](../keywords/in-parameter-modifier.md), [ref readonly](../statements/declarations.md#ref-readonly-locals), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#96-reference-variables-and-returns). +For more information about readonly semantics and reference parameters, see [readonly keyword](../keywords/readonly.md), [in parameter modifier](../keywords/method-parameters.md#in-parameter-modifier), [ref readonly](../statements/declarations.md#reference-variables), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#96-reference-variables-and-returns). diff --git a/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md index ad016e6dca783..41623a3441a31 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md @@ -124,7 +124,7 @@ To resolve these errors: - When a parameter is declared with the `scoped` modifier, avoid returning it by reference because the `scoped` modifier explicitly restricts the parameter's reference from escaping the method, preventing potential dangling references (**CS9075**, **CS9076**, **CS9088**, **CS9090**). - If you need to return a reference that comes from a `ref` parameter, use a direct `return ref` statement rather than assigning the reference to another `ref` parameter and returning that, because the compiler can only track the escape scope through direct return statements (**CS9077**, **CS9078**, **CS9094**, **CS9095**). -For more information about ref safety rules, see the article on [ref returns and locals](../../programming-guide/classes-and-structs/ref-returns.md) and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). +For more information about ref safety rules, see the article on [ref returns](../statements/jump-statements.md#ref-returns) and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). ## Ref assignments with incompatible scopes @@ -148,7 +148,7 @@ To resolve these errors: - When a variable can only escape the method through a return statement, don't assign it to a `ref` variables accessed through other means. Examples include storing in fields or returning through ref parameters. Those actions violate the restriction that the source can only be used in return statements (**CS9079**, **CS9093**). - For ref assignments involving value escape scopes, ensure the source's value escape scope isn't wider than the destination's, because a mismatch would allow you to assign narrower-scoped values through the destination reference, potentially creating references to short-lived values (**CS9096**, **CS9097**). -For more information about ref safety rules, see the article on [ref returns and locals](../../programming-guide/classes-and-structs/ref-returns.md) and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). +For more information about ref safety rules, see the article on [ref returns](../statements/jump-statements.md#ref-returns) and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). ## Escape scope violations and conditional operators @@ -170,7 +170,7 @@ To resolve these errors: - When using variables in expressions or method calls, ensure the context doesn't allow referenced variables to escape beyond their declaration scope, which typically means avoiding passing scoped variables to methods or expressions where they might be captured or stored beyond their intended lifetime (**CS9080**). - For stackalloc expressions, avoid assigning the result to variables or using it in contexts where the stack-allocated memory could be accessed outside the containing method, because stack-allocated memory is automatically freed when the method returns and accessing it afterward results in undefined behavior (**CS9081**). -For more information, see the article on [ref returns and locals](../../programming-guide/classes-and-structs/ref-returns.md), the article on [stack allocation](../../../standard/memory-and-spans/memory-t-usage-guidelines.md#stack-allocated-memory), and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). +For more information, see the article on [ref returns](../statements/jump-statements.md#ref-returns), the article on [memory usage](../../../standard/memory-and-spans/memory-t-usage-guidelines.md), and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). ## Struct member and field restrictions From 6de9966d6e84cec9c743ed4e33d0d0e7e00ecd07 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 21 Nov 2025 17:04:54 -0500 Subject: [PATCH 5/9] warnings part 2 --- .../compiler-messages/ref-modifiers-errors.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md index 5dab9e516327b..fdc3ae6c6fd9a 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md @@ -203,7 +203,7 @@ To correct these errors: - Use the `ref` keyword instead of `out` when declaring local reference variables. `out` is exclusively a parameter modifier that indicates a method must assign a value before returning, whereas `ref` is the appropriate keyword for creating local variables that alias other storage locations (**CS8388**). - Pass a regular variable or value expression instead of an interpolated string when calling a method with an `out` parameter. Interpolated strings are immutable temporary values that can't be used as output parameters since they don't represent assignable storage locations (**CS9205**). -For more information about reference variables and their syntax requirements, see [reference variables](../statements/declarations.md#reference-variables) and the [C# Language Specification](~/_csharpstandard/standard/variables.md#96-reference-variables-and-returns). +For more information about reference variables and their syntax requirements, see [reference variables](../statements/declarations.md#reference-variables) and the [C# Language Specification](~/_csharpstandard/standard/variables.md#97-reference-variables-and-returns). ## Reference variable restrictions @@ -256,7 +256,7 @@ To correct these errors: - Match the reference kind modifiers (`ref`, `in`, `out`, `ref readonly`) between a method and its overridden base method or implemented interface method. The reference modifier is part of the method signature contract that derived types must honor to maintain substitutability and caller expectations (**CS9196**, **CS9197**, **CS9198**). - Declare parameters as `in` rather than `ref readonly` when providing default values. `ref readonly` is designed for scenarios where the caller passes a reference to an existing variable, whereas `in` parameters can accept both references and temporary copies of values, making default values meaningful (**CS9200**). -For more information about where reference variables are allowed, see [Method parameters](../keywords/method-parameters.md), [Iterators](../../iterators.md), [Asynchronous programming patterns](../../asynchronous-programming/index.md), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#96-reference-variables-and-returns). +For more information about where reference variables are allowed, see [Method parameters](../keywords/method-parameters.md), [Iterators](../../iterators.md), [Asynchronous programming patterns](../../asynchronous-programming/index.md), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#97-reference-variables-and-returns). ## `unscoped ref` restrictions @@ -292,7 +292,7 @@ To correct these errors: - Use the `in` modifier instead of `ref` when passing arguments to `in` parameters. While `ref` technically works due to backward compatibility, the `in` modifier more clearly expresses the intent that the argument is read-only and may be passed more efficiently as a reference without copying (**CS9191**, **CS9195**). - Add the appropriate reference modifier (`ref`, `in`, or `ref readonly`) when passing arguments to parameters that expect references. Omitting the modifier may cause the compiler to create a temporary copy of the value, which is inefficient and can lead to unexpected behavior if the calling code expects modifications to be reflected in the original variable (**CS9192**, **CS9193**). -For more information about reference parameters and passing variables by reference, see [Method parameters](../keywords/method-parameters.md), [ref keyword](../keywords/ref.md), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#96-reference-variables-and-returns). +For more information about reference parameters and passing variables by reference, see [Method parameters](../keywords/method-parameters.md), [ref keyword](../keywords/ref.md), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#97-reference-variables-and-returns). ## Writable reference variables require a writable referent @@ -317,4 +317,4 @@ To correct these errors: - Copy members of readonly variables to local variables before passing them as writable references. Even though the member itself might not be declared as readonly, it's accessed through a readonly path (via a readonly field, `in` parameter, or `ref readonly` local), and the compiler enforces transitivity of readonly-ness to prevent indirect mutation of readonly data (**CS8330**, **CS8332**). - Avoid writable ref assignments to readonly variables, [foreach iteration variables](../statements/iteration-statements.md#the-foreach-statement), [using statement resources](../statements/using.md), or [fixed statement variables](../statements/fixed.md). These variables have special lifetime semantics managed by the compiler. The variable is automatically finalized or disposed at the end of its scope. External references create dangling references after disposal (**CS8331**). -For more information about readonly semantics and reference parameters, see [readonly keyword](../keywords/readonly.md), [in parameter modifier](../keywords/method-parameters.md#in-parameter-modifier), [ref readonly](../statements/declarations.md#reference-variables), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#96-reference-variables-and-returns). +For more information about readonly semantics and reference parameters, see [readonly keyword](../keywords/readonly.md), [in parameter modifier](../keywords/method-parameters.md#in-parameter-modifier), [ref readonly](../statements/declarations.md#reference-variables), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#97-reference-variables-and-returns). From f110c12e594e1c3a8ef086c72a9a78312364ccfb Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 24 Nov 2025 11:49:53 -0500 Subject: [PATCH 6/9] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../compiler-messages/ref-modifiers-errors.md | 4 ++-- .../language-reference/compiler-messages/ref-safety-errors.md | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md index fdc3ae6c6fd9a..538e1d370135c 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md @@ -262,8 +262,8 @@ For more information about where reference variables are allowed, see [Method pa The `unscoped` qualifier on `ref` parameters isn't allowed in some locations: -- **CS9101**: *UnscopedRefAttribute can only be applied to struct instance or virtual interface methods and properties, and cannot be applied to constructors or or init-only members.* -- **CS9102**: *UnscopedRefAttribute cannot be applied to an interface implementation because implemented member doesn't have this attribute..* +- **CS9101**: *UnscopedRefAttribute can only be applied to struct instance or virtual interface methods and properties, and cannot be applied to constructors or init-only members.* +- **CS9102**: *UnscopedRefAttribute cannot be applied to an interface implementation because implemented member doesn't have this attribute.* To correct these errors: diff --git a/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md index 41623a3441a31..a04649786f024 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md @@ -18,7 +18,6 @@ f1_keywords: - "CS9089" - "CS9090" - "CS9091" - - "CS9091" - "CS9092" - "CS9093" - "CS9094" @@ -145,7 +144,7 @@ Warnings: To resolve these errors: - Restructure your code so that the source variable in a ref assignment has an escape scope at least as wide as the destination variable, which ensures the destination reference remains valid for its entire lifetime and prevents dangling references (**CS8374**, **CS9085**). -- When a variable can only escape the method through a return statement, don't assign it to a `ref` variables accessed through other means. Examples include storing in fields or returning through ref parameters. Those actions violate the restriction that the source can only be used in return statements (**CS9079**, **CS9093**). +- When a variable can only escape the method through a return statement, don't assign it to `ref` variables accessed through other means. Examples include storing in fields or returning through ref parameters. Those actions violate the restriction that the source can only be used in return statements (**CS9079**, **CS9093**). - For ref assignments involving value escape scopes, ensure the source's value escape scope isn't wider than the destination's, because a mismatch would allow you to assign narrower-scoped values through the destination reference, potentially creating references to short-lived values (**CS9096**, **CS9097**). For more information about ref safety rules, see the article on [ref returns](../statements/jump-statements.md#ref-returns) and the C# standard section on [ref safe contexts](~/_csharpstandard/standard/variables.md#972-ref-safe-contexts). From 46aae49a32ab6e2e2fcd3d5812265803e58d39bd Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 24 Nov 2025 12:09:25 -0500 Subject: [PATCH 7/9] warnings and feedback --- .../compiler-messages/ref-modifiers-errors.md | 18 +++++++++++------- .../compiler-messages/ref-safety-errors.md | 18 +++++++++++++++++- docs/csharp/language-reference/toc.yml | 2 +- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md index fdc3ae6c6fd9a..84a92c24f3dfb 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md @@ -30,6 +30,8 @@ f1_keywords: - "CS8338" - "CS8373" - "CS8388" + - "CS8977" + - "CS8986" - "CS8987" - "CS9061" - "CS9062" @@ -42,12 +44,6 @@ f1_keywords: - "CS9101" - "CS9102" - "CS9104" - - "CS9104" - - "CS9104" - - "CS9104" - - "CS9104" - - "CS9104" - - "CS9104" - "CS9190" - "CS9191" - "CS9192" @@ -91,6 +87,14 @@ helpviewer_keywords: - "CS8373" - "CS8388" - "CS8977" + - "CS8986" + - "CS8987" + - "CS9061" + - "CS9062" + - "CS9063" + - "CS9065" + - "CS9066" + - "CS9072" - "CS9073" - "CS9074" - "CS9101" @@ -267,7 +271,7 @@ The `unscoped` qualifier on `ref` parameters isn't allowed in some locations: To correct these errors: -- Remove the `unscoped` modifier or the attribute from struct constructors and init-only members. These members have special initialization semantics where the compiler must ensure that any references don't outlive the initialization phase, and allowing unscoped references would violate the guarantee that initialization completes before the struct becomes fully accessible (**CS9101**). +- Remove the `unscoped` modifier or the attribute from struct constructors and init-only members. These members have special initialization semantics where the compiler must ensure that any references don't outlive the initialization phase, and allowing unscoped references would violate the guarantee that initialization completes before the struct becomes fully accessible (**CS9101**). - Remove the `unscoped` modifier from interface implementation methods when the corresponding interface method doesn't have it. The unscoped characteristic affects the method's contract regarding reference lifetime guarantees, and implementations must maintain the same contract as the interface they're implementing to ensure callers can rely on consistent lifetime behavior regardless of which implementation is invoked (**CS9102**). For more information about scoped and unscoped references, see [Method parameters](../keywords/method-parameters.md) and the [low-level struct improvements](~/_csharplang/proposals/csharp-11.0/low-level-struct-improvements.md) feature specification. diff --git a/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md index 41623a3441a31..e50ca96a0ab31 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md @@ -9,16 +9,23 @@ f1_keywords: - "CS8345" - "CS8351" - "CS8374" + - "CS9075" + - "CS9076" - "CS9077" - "CS9078" - "CS9079" + - "CS9080" + - "CS9081" + - "CS9082" + - "CS9083" + - "CS9084" - "CS9085" - "CS9086" + - "CS9087" - "CS9088" - "CS9089" - "CS9090" - "CS9091" - - "CS9091" - "CS9092" - "CS9093" - "CS9094" @@ -33,13 +40,22 @@ helpviewer_keywords: - "CS8345" - "CS8351" - "CS8374" + - "CS9075" + - "CS9076" - "CS9077" - "CS9078" - "CS9079" + - "CS9080" + - "CS9081" + - "CS9082" + - "CS9083" + - "CS9084" - "CS9085" - "CS9086" - "CS9087" + - "CS9088" - "CS9089" + - "CS9090" - "CS9091" - "CS9092" - "CS9093" diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index 800bc43316d71..70ce5d949bdb3 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -538,7 +538,7 @@ items: CS8329, CS8330, CS8331, CS8332, CS8337, CS8338, CS8373, CS8388, CS8977, CS8986, CS8987, CS9061, CS9062, CS9063, CS9065, CS9066, CS9072, CS9073, CS9074, CS9101, CS9102, CS9104, CS9190, CS9191, CS9192, CS9193, CS9195, CS9196, CS9197, CS9198, - CS9199, CS9200, CS9201, CS9205, CS9265 + CS9199, CS9200, CS9201, CS9205, CS9265, - name: Ref safety href: ./compiler-messages/ref-safety-errors.md displayName: > From e994f3fbb9a3c44fb9f33a351b04e2fcaebdc5ea Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Mon, 24 Nov 2025 14:22:58 -0500 Subject: [PATCH 8/9] YAML typo --- docs/csharp/language-reference/toc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/language-reference/toc.yml b/docs/csharp/language-reference/toc.yml index 70ce5d949bdb3..800bc43316d71 100644 --- a/docs/csharp/language-reference/toc.yml +++ b/docs/csharp/language-reference/toc.yml @@ -538,7 +538,7 @@ items: CS8329, CS8330, CS8331, CS8332, CS8337, CS8338, CS8373, CS8388, CS8977, CS8986, CS8987, CS9061, CS9062, CS9063, CS9065, CS9066, CS9072, CS9073, CS9074, CS9101, CS9102, CS9104, CS9190, CS9191, CS9192, CS9193, CS9195, CS9196, CS9197, CS9198, - CS9199, CS9200, CS9201, CS9205, CS9265, + CS9199, CS9200, CS9201, CS9205, CS9265 - name: Ref safety href: ./compiler-messages/ref-safety-errors.md displayName: > From 88e0feb9812a88845aa79ff3d0616096c673cdaf Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 25 Nov 2025 09:14:20 -0500 Subject: [PATCH 9/9] Apply suggestions from code review Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com> --- .../compiler-messages/ref-modifiers-errors.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md index bd90edad32488..30daf67e4d644 100644 --- a/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md +++ b/docs/csharp/language-reference/compiler-messages/ref-modifiers-errors.md @@ -244,8 +244,8 @@ To correct these errors: - Remove reference parameters from [indexers](../../programming-guide/indexers/index.md). Indexers are designed to provide array-like access syntax and the compiler can't guarantee safe lifetime tracking for references passed through indexer accessors (**CS0631**, **CS1623**). - Remove reference parameters from [iterator methods](../../iterators.md). Iterators execute code lazily across multiple calls using state machines, and the compiler can't ensure referenced variables remain valid across yield return boundaries where execution is suspended and resumed (**CS1623**). -- Remove reference parameters from [async methods](../../asynchronous-programming/index.md). Async methods may suspend execution at await points and resume on different threads, making it impossible to guarantee that referenced variables remain valid and accessible throughout the method's execution (**CS1988**). -- Avoid using [await expressions](../operators/await.md) inside [ref conditional expressions](../operators/conditional-operator.md#conditional-ref-expression). The await operation may suspend execution and invalidate the references being selected by the conditional operator, leading to potential use of invalidated references when execution resumes (**CS8325**). +- Remove reference parameters from [async methods](../../asynchronous-programming/index.md). Async methods might suspend execution at await points and resume on different threads, making it impossible to guarantee that referenced variables remain valid and accessible throughout the method's execution (**CS1988**). +- Avoid using [await expressions](../operators/await.md) inside [ref conditional expressions](../operators/conditional-operator.md#conditional-ref-expression). The await operation might suspend execution and invalidate the references being selected by the conditional operator, leading to potential use of invalidated references when execution resumes (**CS8325**). - Ensure both branches of a ref conditional operator return references or neither returns a reference, and when both are references they must be the same type. The conditional operator must produce a consistent result type that can be safely used by the calling code regardless of which branch is selected (**CS8326**, **CS8327**). - Remove default values from `ref` and `out` parameters. Reference parameters must always be provided at the call site to establish the required aliasing relationship between the parameter and an existing variable, making default values semantically meaningless (**CS1741**). - Avoid declaring an implicitly typed `out` variable in an argument list that also references that same variable. The compiler must infer the variable's type from the method signature while simultaneously validating uses of that variable within the same expression, creating a circular dependency (**CS8196**). @@ -254,7 +254,7 @@ To correct these errors: - Avoid implementing multiple interfaces where methods differ only by `ref` versus `out` modifiers on parameters. The C# language specification treats these as distinct signatures but doesn't provide a way to disambiguate which implementation to call since both `ref` and `out` share the same calling syntax at implementation boundaries (**CS0767**). - Remove reference parameters from methods decorated with . These methods are callable from unmanaged code that doesn't understand C#'s reference safety rules and can't guarantee proper lifetime management of referenced variables across the managed/unmanaged boundary (**CS8977**). - Use the `ref` modifier on [extension method](../../programming-guide/classes-and-structs/extension-methods.md) first parameters only for value types or generic types constrained to value types. Reference types are already passed by reference at the CLR level and adding `ref` would create a reference to a reference, while value type extensions with `ref` enable mutation of the extended instance (**CS8337**, **CS8338**). -- Don't pass Windows Runtime events as reference parameters. These events follow the Windows Runtime type system which has different lifetime and threading semantics than .NET references and doesn't support the aliasing behavior required by C# reference parameters (**CS7084**). +- Don't pass Windows Runtime events as reference parameters. These events follow the Windows Runtime type system, which has different lifetime and threading semantics than .NET references and doesn't support the aliasing behavior required by C# reference parameters (**CS7084**). - Remove the from `ref readonly` parameters. This attribute is designed for marshaling semantics in platform invoke scenarios where the parameter direction is outbound only, which conflicts with `ref readonly`'s guarantee that the parameter references existing data that won't be reassigned (**CS9199**). - Ensure all `ref` fields in a type are assigned either in field initializers or in all constructor code paths before the constructor completes. Uninitialized ref fields would contain invalid references that could lead to memory corruption if accessed (**CS9201**, **CS9265**). - Match the reference kind modifiers (`ref`, `in`, `out`, `ref readonly`) between a method and its overridden base method or implemented interface method. The reference modifier is part of the method signature contract that derived types must honor to maintain substitutability and caller expectations (**CS9196**, **CS9197**, **CS9198**). @@ -294,7 +294,7 @@ To correct these errors: - Store the result of a property or indexer access in a local variable before passing it as a reference parameter. [Properties](../../programming-guide/classes-and-structs/properties.md) and [indexers](../../programming-guide/indexers/index.md) are methods that return values rather than providing direct access to storage locations, and reference parameters require an actual variable with a stable memory location that can be aliased (**CS0206**, **CS1510**). - Use the `in` modifier instead of `ref` when passing arguments to `in` parameters. While `ref` technically works due to backward compatibility, the `in` modifier more clearly expresses the intent that the argument is read-only and may be passed more efficiently as a reference without copying (**CS9191**, **CS9195**). -- Add the appropriate reference modifier (`ref`, `in`, or `ref readonly`) when passing arguments to parameters that expect references. Omitting the modifier may cause the compiler to create a temporary copy of the value, which is inefficient and can lead to unexpected behavior if the calling code expects modifications to be reflected in the original variable (**CS9192**, **CS9193**). +- Add the appropriate reference modifier (`ref`, `in`, or `ref readonly`) when passing arguments to parameters that expect references. Omitting the modifier might cause the compiler to create a temporary copy of the value, which is inefficient and can lead to unexpected behavior if the calling code expects modifications to be reflected in the original variable (**CS9192**, **CS9193**). For more information about reference parameters and passing variables by reference, see [Method parameters](../keywords/method-parameters.md), [ref keyword](../keywords/ref.md), and the [C# Language Specification](~/_csharpstandard/standard/variables.md#97-reference-variables-and-returns).