From 343b34a2184ef67d653af106bdfb1bdabfb75f34 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 1 Mar 2026 15:02:58 -0500 Subject: [PATCH 01/10] Support checked user-defined operators --- standard/conversions.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/standard/conversions.md b/standard/conversions.md index 132a04873..24b0c65ad 100644 --- a/standard/conversions.md +++ b/standard/conversions.md @@ -789,7 +789,10 @@ A user-defined explicit conversion from an expression `E` to a type `T` is pro - If `E` has a type, let `S` be that type. - If `S` or `T` are nullable value types, let `Sᵢ` and `Tᵢ` be their underlying types, otherwise let `Sᵢ` and `Tᵢ` be `S` and `T`, respectively. - If `Sᵢ` or `Tᵢ` are type parameters, let `S₀` and `T₀` be their effective base classes, otherwise let `S₀` and `T₀` be `Sᵢ` and `Tᵢ`, respectively. -- Find the set of types, `D`, from which user-defined conversion operators will be considered. This set consists of `S₀` (if `S₀` exists and is a class or struct), the base classes of `S₀` (if `S₀` exists and is a class), `T₀` (if `T₀` is a class or struct), and the base classes of `T₀` (if `T₀` is a class). A type is added to the set `D` only if an identity conversion to another type already included in the set does not exist. +- Find the set of types, `D`, from which user-defined conversion operators will be considered. This set consists of `S₀` (if `S₀` exists and is a class or struct), the base classes of `S₀` (if `S₀` exists and is a class), `T₀` (if `T₀` is a class or struct), and the base classes of `T₀` (if `T₀` is a class). A type is added to the set `D` only if an identity conversion to another type already included in the set doesn’t exist. +- Find the set of conversion operators, `U₀`. This set consists of: + - In an `unchecked` evaluation context, the user-defined implicit or regular explicit conversion operators declared by the classes or structs in `D`. + - In a `checked` evaluation context, the user-defined implicit or regular/checked explicit conversion operators declared by the classes or structs in `D` except for regular explicit conversion operators that have a pair-wise matching checked operator declaration within the same declaring type. - Find the set of applicable user-defined and lifted conversion operators, `U`. This set consists of the user-defined and lifted implicit or explicit conversion operators declared by the classes or structs in `D` that convert from a type encompassing `E` or encompassed by `S` (if it exists) to a type encompassing or encompassed by `T`. If `U` is empty, the conversion is undefined and a compile-time error occurs. - Find the most-specific source type, `Sₓ`, of the operators in `U`: - If `S` exists and any of the operators in `U` convert from `S`, then `Sₓ` is `S`. @@ -1079,6 +1082,10 @@ Not every lambda expression can be converted to expression tree types. The conve > > *end note* +The addition of support for checked operators resulted in the addition of the following factory methods to `System.Linq.Expressions.Expression`: `NegateChecked`, `AddChecked`, `SubtractChecked`, `MultiplyChecked`, and `ConvertChecked`. (There is no factory method for checked division.) + +> *Note*: As assignment is not supported in an expression tree, there are no such factory methods for checked increment or checked decrement. *end note* + ## 10.8 Method group conversions An implicit conversion exists from a method group ([§12.2](expressions.md#122-expression-classifications)) to a compatible delegate type ([§21.4](delegates.md#214-delegate-compatibility)). If `D` is a delegate type, and `E` is an expression that is classified as a method group, then `D` is compatible with `E` if and only if `E` contains at least one method that is applicable in its normal form ([§12.6.4.2](expressions.md#12642-applicable-function-member)) to any argument list ([§12.6.2](expressions.md#1262-argument-lists)) having types and modifiers matching the parameter types and modifiers of `D`, as described in the following. From 8a6b68f08b53ca7d5b7abd4ba8b1e8c8652824a6 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 1 Mar 2026 15:06:45 -0500 Subject: [PATCH 02/10] Support checked user-defined operators --- standard/expressions.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/standard/expressions.md b/standard/expressions.md index 2066e33ff..fca37bd7d 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -264,6 +264,9 @@ An operation of the form `x «op» y`, where «op» is an overloadable binary Given a type `T` and an operation `operator «op»(A)`, where «op» is an overloadable operator and `A` is an argument list, the set of candidate user-defined operators provided by `T` for operator `«op»(A)` is determined as follows: - Determine the type `T₀`. If `T` is a nullable value type, `T₀` is its underlying type; otherwise, `T₀` is equal to `T`. +- Find the set of user-defined operators, `U`. This set consists of: + - In an `unchecked` evaluation context, all regular `operator «op»` declarations in `T₀`. + - In a `checked` evaluation context, all checked and non-checked `operator «op»` declarations in `T₀` except regular declarations that have a pair-wise matching checked operator declaration. - For all `operator «op»` declarations in `T₀` and all lifted forms of such operators, if at least one operator is applicable ([§12.6.4.2](expressions.md#12642-applicable-function-member)) with respect to the argument list `A`, then the set of candidate operators consists of all such applicable operators in `T₀`. - Otherwise, if `T₀` is `object`, the set of candidate operators is empty. - Otherwise, the set of candidate operators provided by `T₀` is the set of candidate operators provided by the direct base class of `T₀`, or the effective base class of `T₀` if `T₀` is a type parameter. @@ -3358,7 +3361,7 @@ For an enum type `T`, the result of the expression `sizeof(T)` is a constant va ### 12.8.20 The checked and unchecked operators -The `checked` and `unchecked` operators are used to control the overflow-checking context for integral-type arithmetic operations and conversions. +The `checked` and `unchecked` operators are used to control the overflow-checking context for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general) and [§15.10.4](15104-conversion-operators)). ```ANTLR checked_expression From c0ba24faa09f6d0616a0d701d258abb731001076 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 1 Mar 2026 15:08:56 -0500 Subject: [PATCH 03/10] support checked user-defined operators --- standard/statements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/statements.md b/standard/statements.md index 220c789ac..95b1f5083 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -1976,7 +1976,7 @@ The end point of a `try` statement is reachable if both of the following are tru ## 13.12 The checked and unchecked statements -The `checked` and `unchecked` statements are used to control the ***overflow-checking context*** for integral-type arithmetic operations and conversions. +The `checked` and `unchecked` statements are used to control the ***overflow-checking context*** for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general) and [§15.10.4](15104-conversion-operators)). ```ANTLR checked_statement From dc2e06aaaaa5ee090a3eda760875079f80bbd5f8 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 1 Mar 2026 15:18:50 -0500 Subject: [PATCH 04/10] support checked user-defined operators --- standard/classes.md | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index ba26b5c0d..0370667fd 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -1531,14 +1531,14 @@ The following method names are reserved. While many have corresponding operators | `op_BitwiseAndAssignment` | (reserved) | | `op_BitwiseOr` | `\|` | | `op_BitwiseOrAssignment` | (reserved) | -| `op_CheckedAddition` | (reserved for future use) | -| `op_CheckedDecrement` | (reserved for future use) | -| `op_CheckedDivision` | (reserved for future use) | -| `op_CheckedExplicit` | (reserved for future use) | -| `op_CheckedIncrement` | (reserved for future use) | -| `op_CheckedMultiply` | (reserved for future use) | -| `op_CheckedSubtraction` | (reserved for future use) | -| `op_CheckedUnaryNegation` | (reserved for future use) | +| `op_CheckedAddition` | checked addition `+` | +| `op_CheckedDecrement` | checked decrement `--` | +| `op_CheckedDivision` | checked division `/` | +| `op_CheckedExplicit` | checked explicit (narrowing) coercion | +| `op_CheckedIncrement` | checked increment `++` | +| `op_CheckedMultiply` | checked multiply `*` | +| `op_CheckedSubtraction` | checked subtraction `-` | +| `op_CheckedUnaryNegation` | checked unary negation `-` | | `op_Comma` | (reserved) | | `op_Decrement` | `--` (prefix and postfix) | | `op_Division` | `/` | @@ -4959,7 +4959,7 @@ logical_negation_operator ; overloadable_unary_operator - : '+' | '-' | logical_negation_operator | '~' | '++' | '--' | 'true' | 'false' + : '+' | 'checked'? '-' | '!' | '~' | 'checked'? '++' | 'checked'? '--' | 'true' | 'false' ; binary_operator_declarator @@ -4968,13 +4968,13 @@ binary_operator_declarator ; overloadable_binary_operator - : '+' | '-' | '*' | '/' | '%' | '&' | '|' | '^' | '<<' - | right_shift | '==' | '!=' | '>' | '<' | '>=' | '<=' + : 'checked'? '+' | 'checked'? '-' | 'checked'? '*' | 'checked'? '/' | '%' | '&' | '|' | '^' | '<<' + | right_shift | '==' | '!=' | '>' | '<' | '>=' | '<=' ; conversion_operator_declarator : 'implicit' 'operator' type '(' fixed_parameter ')' - | 'explicit' 'operator' type '(' fixed_parameter ')' + | 'explicit' 'operator' 'checked'? type '(' fixed_parameter ')' ; operator_body @@ -5010,6 +5010,17 @@ Additional information on unary and binary operators can be found in [§12.4](e Additional information on conversion operators can be found in [§10.5](conversions.md#105-user-defined-conversions). +An *operator_declaration* containing `checked` declares a ***checked operator***. For each checked operator in that type there shall be a corresponding ***regular operator*** having the same signature, but without `checked`, and return type. + +> *Note*: The opposite is not required. Specifically, an *operator_declaration* without `checked` need not have a matching checked operator. When this is the case, the operator is neither a checked operator nor a regular operator. *end note* + +It is suggested that a user-defined checked operator throw an exception (such as `System.OverflowException`) when the result of an operation is too large to represent in the destination type, whatever that might mean for that type. + +It is suggested that a user-defined regular operator not throw an exception when the result of an operation is too large to represent in the destination type, whatever that might mean for that type. Instead, it should return an instance representing a truncated result, whatever that might mean for that type. + +A checked operator does not implement a regular operator, and vice versa. +The presence of `checked` in a checked operator declaration has no effect on the checked context of that operator’s *operator_body*. That is controlled by the `checked` and `unchecked` operators or statements present in that *operator_body*, or by the default checking context provided by the runtime environment. + ### 15.10.2 Unary operators The following rules apply to unary operator declarations, where `T` denotes the instance type of the class or struct that contains the operator declaration: @@ -5174,7 +5185,7 @@ For all types but `object`, the operators declared by the `Convertible` type User-defined conversions are not allowed to convert from or to *interface_type*s. In particular, this restriction ensures that no user-defined transformations occur when converting to an *interface_type*, and that a conversion to an *interface_type* succeeds only if the `object` being converted actually implements the specified *interface_type*. -The signature of a conversion operator consists of the source type and the target type. (This is the only form of member for which the return type participates in the signature.) The implicit or explicit classification of a conversion operator is not part of the operator’s signature. Thus, a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types. +The signature of a conversion operator consists of the source type and the target type. (This is the only form of member for which the return type participates in the signature.) To allow a type to have both checked and regular operators with the same source- and target-type combination, the signature of a checked conversion operator also includes the fact that it is checked. The implicit or explicit classification of a conversion operator is not part of the operator’s signature. Thus, a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types. > *Note*: In general, user-defined implicit conversions should be designed to never throw exceptions and never lose information. If a user-defined conversion can give rise to exceptions (for example, because the source argument is out of range) or loss of information (such as discarding high-order bits), then that conversion should be defined as an explicit conversion. *end note* From 966e77ff973a40a5c53356dff96ccd9b7845508d Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 1 Mar 2026 15:20:39 -0500 Subject: [PATCH 05/10] support checked user-defined operators --- standard/standard-library.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/standard/standard-library.md b/standard/standard-library.md index 5f42ac8ac..7e6368f4e 100644 --- a/standard/standard-library.md +++ b/standard/standard-library.md @@ -774,6 +774,16 @@ namespace System.Linq.Expressions public sealed class Expression { public TDelegate Compile(); + public static UnaryExpression NegateChecked(Expression expression, + MethodInfo? method); + public static BinaryExpression AddChecked(Expression left, + Expression right, MethodInfo? method); + public static BinaryExpression SubtractChecked(Expression left, + Expression right, MethodInfo? method); + public static BinaryExpression MultiplyChecked(Expression left, + Expression right, MethodInfo? method); + public static UnaryExpression ConvertChecked(Expression expression, + Type type, MethodInfo? method); } } From 7e72600abfe2413e6cedd60dc95a76ed3d35b1c3 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 1 Mar 2026 15:24:11 -0500 Subject: [PATCH 06/10] support checked user-defined operators --- standard/documentation-comments.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/standard/documentation-comments.md b/standard/documentation-comments.md index a6dbfbde9..f08b75313 100644 --- a/standard/documentation-comments.md +++ b/standard/documentation-comments.md @@ -963,7 +963,7 @@ IDs: "M:Acme.Widget.op_UnaryPlus(Acme.Widget)" ``` -The complete set of unary operator function names used is as follows: `op_UnaryPlus`, `op_UnaryNegation`, `op_LogicalNot`, `op_OnesComplement`, `op_Increment`, `op_Decrement`, `op_True`, and `op_False`. +The complete set of unary operator function names used is as follows: `op_UnaryPlus`, `op_UnaryNegation`, `op_CheckedUnaryNegation`, `op_LogicalNot`, `op_OnesComplement`, `op_Increment`, `op_CheckedIncrement`, `op_Decrement`, `op_CheckedDecrement`, `op_True`, and `op_False`. **Binary operators** @@ -984,10 +984,12 @@ IDs: "M:Acme.Widget.op_Addition(Acme.Widget,Acme.Widget)" ``` -The complete set of binary operator function names used is as follows: `op_Addition`, `op_Subtraction`, `op_Multiply`, `op_Division`, `op_Modulus`, `op_BitwiseAnd`, `op_BitwiseOr`, `op_ExclusiveOr`, `op_LeftShift`, `op_RightShift`, `op_Equality`, `op_Inequality`, `op_LessThan`, `op_LessThanOrEqual`, `op_GreaterThan`, and `op_GreaterThanOrEqual`. +The complete set of binary operator function names used is as follows: `op_Addition`, `op_CheckedAddition`, `op_Subtraction`, `op_CheckedSubtraction`, `op_Multiply`, `op_CheckedMultiply`, `op_Division`, `op_CheckedDivision`, `op_Modulus`, `op_BitwiseAnd`, `op_BitwiseOr`, `op_ExclusiveOr`, `op_LeftShift`, `op_RightShift`, `op_Equality`, `op_Inequality`, `op_LessThan`, `op_LessThanOrEqual`, `op_GreaterThan`, and `op_GreaterThanOrEqual`. **Conversion operators** have a trailing “`~`” followed by the return type. When either the source or destination of a conversion operator is a generic type, the “`<`” and “`">`” characters are replaced by the “`{`” and “`}`” characters, respectively. +The complete set of conversion operator function names used is as follows: `op_Explicit`, `op_CheckedExplicit`, and `op_Implicit`. + ```csharp namespace Acme From f6e0eb6731e5f7043d43ce9e251366aa0d52f742 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 1 Mar 2026 15:36:21 -0500 Subject: [PATCH 07/10] fix md --- standard/classes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/classes.md b/standard/classes.md index 0370667fd..ed4adef9d 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -5014,7 +5014,7 @@ An *operator_declaration* containing `checked` declares a ***checked operator*** > *Note*: The opposite is not required. Specifically, an *operator_declaration* without `checked` need not have a matching checked operator. When this is the case, the operator is neither a checked operator nor a regular operator. *end note* -It is suggested that a user-defined checked operator throw an exception (such as `System.OverflowException`) when the result of an operation is too large to represent in the destination type, whatever that might mean for that type. +It is suggested that a user-defined checked operator throw an exception (such as `System.OverflowException`) when the result of an operation is too large to represent in the destination type, whatever that might mean for that type. It is suggested that a user-defined regular operator not throw an exception when the result of an operation is too large to represent in the destination type, whatever that might mean for that type. Instead, it should return an instance representing a truncated result, whatever that might mean for that type. From 887d998ebf817bbb3bb1b2812ee170363dec1b18 Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 1 Mar 2026 15:37:16 -0500 Subject: [PATCH 08/10] fix link --- standard/expressions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/expressions.md b/standard/expressions.md index fca37bd7d..ed4c9daa3 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -3361,7 +3361,7 @@ For an enum type `T`, the result of the expression `sizeof(T)` is a constant va ### 12.8.20 The checked and unchecked operators -The `checked` and `unchecked` operators are used to control the overflow-checking context for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general) and [§15.10.4](15104-conversion-operators)). +The `checked` and `unchecked` operators are used to control the overflow-checking context for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general) and [§15.10.4](classes.md#15104-conversion-operators)). ```ANTLR checked_expression From 1fbe99890d9146dbdd795ce799649558a4255eec Mon Sep 17 00:00:00 2001 From: Rex Jaeschke Date: Sun, 1 Mar 2026 15:38:15 -0500 Subject: [PATCH 09/10] fix link --- standard/statements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standard/statements.md b/standard/statements.md index 95b1f5083..094184002 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -1976,7 +1976,7 @@ The end point of a `try` statement is reachable if both of the following are tru ## 13.12 The checked and unchecked statements -The `checked` and `unchecked` statements are used to control the ***overflow-checking context*** for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general) and [§15.10.4](15104-conversion-operators)). +The `checked` and `unchecked` statements are used to control the ***overflow-checking context*** for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general) and [§15.10.4](classes.md#15104-conversion-operators)). ```ANTLR checked_statement From c210eb9428112e48adcc5b070764ce84774b84c3 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 1 May 2026 16:06:54 -0400 Subject: [PATCH 10/10] Address several omissions Thiese are primarily omissions that ripple from the changes already described in this PR. --- standard/classes.md | 11 ++++++++--- standard/conversions.md | 4 ++-- standard/expressions.md | 6 ++++-- standard/statements.md | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/standard/classes.md b/standard/classes.md index ed4adef9d..fa437fc3b 100644 --- a/standard/classes.md +++ b/standard/classes.md @@ -4959,7 +4959,7 @@ logical_negation_operator ; overloadable_unary_operator - : '+' | 'checked'? '-' | '!' | '~' | 'checked'? '++' | 'checked'? '--' | 'true' | 'false' + : '+' | 'checked'? '-' | logical_negation_operator | '~' | 'checked'? '++' | 'checked'? '--' | 'true' | 'false' ; binary_operator_declarator @@ -5010,7 +5010,7 @@ Additional information on unary and binary operators can be found in [§12.4](e Additional information on conversion operators can be found in [§10.5](conversions.md#105-user-defined-conversions). -An *operator_declaration* containing `checked` declares a ***checked operator***. For each checked operator in that type there shall be a corresponding ***regular operator*** having the same signature, but without `checked`, and return type. +An *operator_declaration* containing `checked` declares a ***checked operator***. For each checked operator declared in a type there shall be a corresponding declaration of a ***regular operator*** in that same type whose signature differs only by the absence of `checked`, and whose return type is the same. > *Note*: The opposite is not required. Specifically, an *operator_declaration* without `checked` need not have a matching checked operator. When this is the case, the operator is neither a checked operator nor a regular operator. *end note* @@ -5019,6 +5019,7 @@ It is suggested that a user-defined checked operator throw an exception (such as It is suggested that a user-defined regular operator not throw an exception when the result of an operation is too large to represent in the destination type, whatever that might mean for that type. Instead, it should return an instance representing a truncated result, whatever that might mean for that type. A checked operator does not implement a regular operator, and vice versa. + The presence of `checked` in a checked operator declaration has no effect on the checked context of that operator’s *operator_body*. That is controlled by the `checked` and `unchecked` operators or statements present in that *operator_body*, or by the default checking context provided by the runtime environment. ### 15.10.2 Unary operators @@ -5033,6 +5034,8 @@ The signature of a unary operator consists of the operator token (`+`, `-`, `!`, The `true` and `false` unary operators require pair-wise declaration. A compile-time error occurs if a class declares one of these operators without also declaring the other. The `true` and `false` operators are described further in [§12.27](expressions.md#1227-boolean-expressions). +> *Note*: A unary `++`, `--`, or `-` operator may have a checked form (see [§15.10.1](classes.md#15101-general)). *end note* + > *Example*: The following example shows an implementation and subsequent usage of operator++ for an integer vector class: > > @@ -5085,6 +5088,8 @@ Certain binary operators require pair-wise declaration. For every declaration of - operator `>` and operator `<` - operator `>=` and operator `<=` +> *Note*: A binary `+`, `-`, `*`, or `/` operator may have a checked form (see [§15.10.1](classes.md#15101-general)). *end note* + ### 15.10.4 Conversion operators A conversion operator declaration introduces a ***user-defined conversion*** ([§10.5](conversions.md#105-user-defined-conversions)), which augments the pre-defined implicit and explicit conversions. @@ -5185,7 +5190,7 @@ For all types but `object`, the operators declared by the `Convertible` type User-defined conversions are not allowed to convert from or to *interface_type*s. In particular, this restriction ensures that no user-defined transformations occur when converting to an *interface_type*, and that a conversion to an *interface_type* succeeds only if the `object` being converted actually implements the specified *interface_type*. -The signature of a conversion operator consists of the source type and the target type. (This is the only form of member for which the return type participates in the signature.) To allow a type to have both checked and regular operators with the same source- and target-type combination, the signature of a checked conversion operator also includes the fact that it is checked. The implicit or explicit classification of a conversion operator is not part of the operator’s signature. Thus, a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types. +The signature of a conversion operator consists of the source type and the target type. (This is the only form of member for which the return type participates in the signature.) To allow a type to have both checked and regular operators with the same source- and target-type combination, the signature of a checked conversion operator also includes the fact that it is checked. The implicit or explicit classification of a conversion operator is not part of the operator’s signature. Thus, a class or struct cannot declare both an implicit and an explicit conversion operator with the same source and target types. (This restriction applies to both regular and checked explicit conversion operators.) > *Note*: In general, user-defined implicit conversions should be designed to never throw exceptions and never lose information. If a user-defined conversion can give rise to exceptions (for example, because the source argument is out of range) or loss of information (such as discarding high-order bits), then that conversion should be defined as an explicit conversion. *end note* diff --git a/standard/conversions.md b/standard/conversions.md index 24b0c65ad..df5d72a21 100644 --- a/standard/conversions.md +++ b/standard/conversions.md @@ -790,9 +790,9 @@ A user-defined explicit conversion from an expression `E` to a type `T` is pro - If `S` or `T` are nullable value types, let `Sᵢ` and `Tᵢ` be their underlying types, otherwise let `Sᵢ` and `Tᵢ` be `S` and `T`, respectively. - If `Sᵢ` or `Tᵢ` are type parameters, let `S₀` and `T₀` be their effective base classes, otherwise let `S₀` and `T₀` be `Sᵢ` and `Tᵢ`, respectively. - Find the set of types, `D`, from which user-defined conversion operators will be considered. This set consists of `S₀` (if `S₀` exists and is a class or struct), the base classes of `S₀` (if `S₀` exists and is a class), `T₀` (if `T₀` is a class or struct), and the base classes of `T₀` (if `T₀` is a class). A type is added to the set `D` only if an identity conversion to another type already included in the set doesn’t exist. -- Find the set of conversion operators, `U₀`. This set consists of: +- Find the set of conversion operators, `U₀` (see [§15.10.1](classes.md#15101-general), [§15.10.4](classes.md#15104-conversion-operators)). This set consists of: - In an `unchecked` evaluation context, the user-defined implicit or regular explicit conversion operators declared by the classes or structs in `D`. - - In a `checked` evaluation context, the user-defined implicit or regular/checked explicit conversion operators declared by the classes or structs in `D` except for regular explicit conversion operators that have a pair-wise matching checked operator declaration within the same declaring type. + - In a `checked` evaluation context, the user-defined implicit conversion operators and the checked and regular explicit conversion operators declared by the classes or structs in `D`, except for regular explicit conversion operators that have a pair-wise matching checked operator declaration within the same declaring type. - Find the set of applicable user-defined and lifted conversion operators, `U`. This set consists of the user-defined and lifted implicit or explicit conversion operators declared by the classes or structs in `D` that convert from a type encompassing `E` or encompassed by `S` (if it exists) to a type encompassing or encompassed by `T`. If `U` is empty, the conversion is undefined and a compile-time error occurs. - Find the most-specific source type, `Sₓ`, of the operators in `U`: - If `S` exists and any of the operators in `U` convert from `S`, then `Sₓ` is `S`. diff --git a/standard/expressions.md b/standard/expressions.md index ed4c9daa3..3382ab032 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -266,7 +266,7 @@ Given a type `T` and an operation `operator «op»(A)`, where «op» is an ove - Determine the type `T₀`. If `T` is a nullable value type, `T₀` is its underlying type; otherwise, `T₀` is equal to `T`. - Find the set of user-defined operators, `U`. This set consists of: - In an `unchecked` evaluation context, all regular `operator «op»` declarations in `T₀`. - - In a `checked` evaluation context, all checked and non-checked `operator «op»` declarations in `T₀` except regular declarations that have a pair-wise matching checked operator declaration. + - In a `checked` evaluation context, all checked and regular `operator «op»` declarations in `T₀` (see [§15.10.1](classes.md#15101-general)) except regular declarations that have a pair-wise matching checked operator declaration. - For all `operator «op»` declarations in `T₀` and all lifted forms of such operators, if at least one operator is applicable ([§12.6.4.2](expressions.md#12642-applicable-function-member)) with respect to the argument list `A`, then the set of candidate operators consists of all such applicable operators in `T₀`. - Otherwise, if `T₀` is `object`, the set of candidate operators is empty. - Otherwise, the set of candidate operators provided by `T₀` is the set of candidate operators provided by the direct base class of `T₀`, or the effective base class of `T₀` if `T₀` is a type parameter. @@ -3361,7 +3361,7 @@ For an enum type `T`, the result of the expression `sizeof(T)` is a constant va ### 12.8.20 The checked and unchecked operators -The `checked` and `unchecked` operators are used to control the overflow-checking context for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general) and [§15.10.4](classes.md#15104-conversion-operators)). +The `checked` and `unchecked` operators are used to control the overflow-checking context for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general)). ```ANTLR checked_expression @@ -3383,6 +3383,8 @@ The following operations are affected by the overflow checking context establish - The predefined `-` unary operator ([§12.9.3](expressions.md#1293-unary-minus-operator)), when the operand is of an integral type. - The predefined `+`, `-`, `*`, and `/` binary operators ([§12.13](expressions.md#1213-arithmetic-operators)), when both operands are of integral or enum types. - Explicit numeric conversions ([§10.3.2](conversions.md#1032-explicit-numeric-conversions)) from one integral or enum type to another integral or enum type, or from `float` or `double` to an integral or enum type. +- User-defined `++`, `--`, unary `-`, and binary `+`, `-`, `*`, and `/` operators ([§15.10.1](classes.md#15101-general)), when a checked form of the operator is declared on the operand type. +- User-defined explicit conversion operators ([§15.10.4](classes.md#15104-conversion-operators)), when a checked form of the conversion operator is declared. When one of the above operations produces a result that is too large to represent in the destination type, the context in which the operation is performed controls the resulting behavior: diff --git a/standard/statements.md b/standard/statements.md index 094184002..232f9009b 100644 --- a/standard/statements.md +++ b/standard/statements.md @@ -1976,7 +1976,7 @@ The end point of a `try` statement is reachable if both of the following are tru ## 13.12 The checked and unchecked statements -The `checked` and `unchecked` statements are used to control the ***overflow-checking context*** for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general) and [§15.10.4](classes.md#15104-conversion-operators)). +The `checked` and `unchecked` statements are used to control the ***overflow-checking context*** for integral-type arithmetic operations and conversions. They may also be used to control the overflow-checking context for various operations and conversions involving user-defined types ([§15.10.1](classes.md#15101-general)). ```ANTLR checked_statement