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 448ec0708f014..30daf67e4d644 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,26 +28,19 @@ f1_keywords: - "CS8332" - "CS8337" - "CS8338" - - "CS8351" - "CS8373" - - "CS8374" - "CS8388" - "CS8977" + - "CS8986" + - "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" @@ -85,10 +74,6 @@ helpviewer_keywords: - "CS1939" - "CS1988" - "CS7084" - - "CS8166" - - "CS8167" - - "CS8168" - - "CS8169" - "CS8196" - "CS8325" - "CS8326" @@ -99,26 +84,19 @@ helpviewer_keywords: - "CS8332" - "CS8337" - "CS8338" - - "CS8351" - "CS8373" - - "CS8374" - "CS8388" - "CS8977" + - "CS8986" + - "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" @@ -135,7 +113,8 @@ helpviewer_keywords: - "CS9201" - "CS9205" - "CS9265" -ms.date: 11/06/2024 +ai-usage: ai-assisted +ms.date: 11/21/2025 --- # Errors and warnings associated with reference parameters, variables, and returns @@ -160,10 +139,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 +149,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 +168,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 +188,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*. @@ -233,12 +200,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#97-reference-variables-and-returns). ## Reference variable restrictions @@ -271,31 +240,41 @@ 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 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**). +- 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#97-reference-variables-and-returns). ## `unscoped ref` restrictions 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: + +- 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**). -You must remove the `unscoped` modifier on the parameter declaration that caused the error. +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 @@ -311,7 +290,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 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). ## Writable reference variables require a writable referent @@ -329,43 +314,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: - -- [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. +To correct these errors: -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: +- 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**). -- **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). +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). 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..93d5741e6492d --- /dev/null +++ b/docs/csharp/language-reference/compiler-messages/ref-safety-errors.md @@ -0,0 +1,211 @@ +--- +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" + - "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: + - "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" +ai-usage: ai-assisted +ms.date: 11/21/2025 +--- +# Errors and warnings related to ref safety + +The following errors can be generated when reference variable safety rules are violated: + + +- [**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**](#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 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: + +- **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](../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 + +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 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). + +## 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](../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 + +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 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 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). 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" ---