diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs index 970a1c13a1824..fd250070ce6a1 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs @@ -541,7 +541,8 @@ private BoundExpression BindSimpleBinaryOperator(BinaryExpressionSyntax node, Bi && left is BoundUnconvertedInterpolatedString or BoundBinaryOperator { IsUnconvertedInterpolatedStringAddition: true } && right is BoundUnconvertedInterpolatedString) { - var stringConstant = FoldBinaryOperator(node, BinaryOperatorKind.StringConcatenation, left, right, SpecialType.System_String, diagnostics); + Debug.Assert(right.Type.SpecialType == SpecialType.System_String); + var stringConstant = FoldBinaryOperator(node, BinaryOperatorKind.StringConcatenation, left, right, right.Type, diagnostics); return new BoundBinaryOperator(node, BinaryOperatorKind.StringConcatenation, BoundBinaryOperator.UncommonData.UnconvertedInterpolatedStringAddition(stringConstant), LookupResultKind.Empty, left, right, right.Type); } @@ -621,7 +622,7 @@ private BoundExpression BindSimpleBinaryOperator(BinaryExpressionSyntax node, Bi resultLeft = CreateConversion(left, best.LeftConversion, signature.LeftType, diagnostics); resultRight = CreateConversion(right, best.RightConversion, signature.RightType, diagnostics); - resultConstant = FoldBinaryOperator(node, resultOperatorKind, resultLeft, resultRight, resultType.SpecialType, diagnostics); + resultConstant = FoldBinaryOperator(node, resultOperatorKind, resultLeft, resultRight, resultType, diagnostics); } else { @@ -856,7 +857,7 @@ private BoundExpression BindConditionalLogicalOperator(BinaryExpressionSyntax no if ((object)left.Type != null && left.Type.SpecialType == SpecialType.System_Boolean && (object)right.Type != null && right.Type.SpecialType == SpecialType.System_Boolean) { - var constantValue = FoldBinaryOperator(node, kind | BinaryOperatorKind.Bool, left, right, SpecialType.System_Boolean, diagnostics); + var constantValue = FoldBinaryOperator(node, kind | BinaryOperatorKind.Bool, left, right, left.Type, diagnostics); // NOTE: no candidate user-defined operators. return new BoundBinaryOperator(node, kind | BinaryOperatorKind.Bool, constantValue, methodOpt: null, constrainedToTypeOpt: null, @@ -1596,6 +1597,7 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType) BinaryOperatorKind kind, BoundExpression left, BoundExpression right, + TypeSymbol resultTypeSymbol, BindingDiagnosticBag diagnostics) { Debug.Assert(left != null); @@ -1628,8 +1630,6 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType) BinaryOperatorKind newKind = kind.Operator().WithType(newLeftOperand.Type!.SpecialType); - SpecialType operatorType = SpecialType.None; - switch (newKind.Operator()) { case BinaryOperatorKind.Addition: @@ -1637,7 +1637,7 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType) case BinaryOperatorKind.And: case BinaryOperatorKind.Or: case BinaryOperatorKind.Xor: - operatorType = operandType.SpecialType; + resultTypeSymbol = operandType; break; case BinaryOperatorKind.LessThan: @@ -1646,16 +1646,16 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType) case BinaryOperatorKind.GreaterThanOrEqual: case BinaryOperatorKind.Equal: case BinaryOperatorKind.NotEqual: - operatorType = SpecialType.System_Boolean; + Debug.Assert(resultTypeSymbol.SpecialType == SpecialType.System_Boolean); break; default: throw ExceptionUtilities.UnexpectedValue(newKind.Operator()); } - var constantValue = FoldBinaryOperator(syntax, newKind, newLeftOperand, newRightOperand, operatorType, diagnostics); + var constantValue = FoldBinaryOperator(syntax, newKind, newLeftOperand, newRightOperand, resultTypeSymbol, diagnostics); - if (operatorType != SpecialType.System_Boolean && constantValue != null && !constantValue.IsBad) + if (resultTypeSymbol.SpecialType != SpecialType.System_Boolean && constantValue != null && !constantValue.IsBad) { TypeSymbol resultType = kind == BinaryOperatorKind.EnumSubtraction ? underlyingType : enumType; @@ -1672,7 +1672,7 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType) BinaryOperatorKind kind, BoundExpression left, BoundExpression right, - SpecialType resultType, + TypeSymbol resultTypeSymbol, BindingDiagnosticBag diagnostics) { Debug.Assert(left != null); @@ -1704,7 +1704,7 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType) if (kind.IsEnum() && !kind.IsLifted()) { - return FoldEnumBinaryOperator(syntax, kind, left, right, diagnostics); + return FoldEnumBinaryOperator(syntax, kind, left, right, resultTypeSymbol, diagnostics); } // Divisions by zero on integral types and decimal always fail even in an unchecked context. @@ -1715,6 +1715,7 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType) } object? newValue = null; + SpecialType resultType = resultTypeSymbol.SpecialType; // Certain binary operations never fail; bool & bool, for example. If we are in one of those // cases, simply fold the operation and return. @@ -1765,13 +1766,10 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType) { if (CheckOverflowAtCompileTime) { - Error(diagnostics, ErrorCode.ERR_CheckedOverflow, syntax); - return ConstantValue.Bad; - } - else - { - return null; + Error(diagnostics, ErrorCode.WRN_CompileTimeCheckedOverflow, syntax, resultTypeSymbol); } + + return null; } if (newValue != null) @@ -2616,7 +2614,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper var resultOperand = CreateConversion(operand.Syntax, operand, best.Conversion, isCast: false, conversionGroupOpt: null, signature.OperandType, diagnostics); var resultType = signature.ReturnType; UnaryOperatorKind resultOperatorKind = signature.Kind; - var resultConstant = FoldUnaryOperator(node, resultOperatorKind, resultOperand, resultType.SpecialType, diagnostics); + var resultConstant = FoldUnaryOperator(node, resultOperatorKind, resultOperand, resultType, diagnostics); CheckNativeIntegerFeatureAvailability(resultOperatorKind, node, diagnostics); CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, signature.ConstrainedToTypeOpt, diagnostics); @@ -2653,7 +2651,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper UnaryOperatorKind newKind = kind.Operator().WithType(upconvertSpecialType); - var constantValue = FoldUnaryOperator(syntax, newKind, operand, upconvertType.SpecialType, diagnostics); + var constantValue = FoldUnaryOperator(syntax, newKind, operand, upconvertType, diagnostics); // Convert back to the underlying type if (constantValue != null && !constantValue.IsBad) @@ -2671,7 +2669,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper CSharpSyntaxNode syntax, UnaryOperatorKind kind, BoundExpression operand, - SpecialType resultType, + TypeSymbol resultTypeSymbol, BindingDiagnosticBag diagnostics) { Debug.Assert(operand != null); @@ -2693,6 +2691,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper return FoldEnumUnaryOperator(syntax, kind, operand, diagnostics); } + SpecialType resultType = resultTypeSymbol.SpecialType; var newValue = FoldNeverOverflowUnaryOperator(kind, value); if (newValue != null) { @@ -2707,13 +2706,10 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper { if (CheckOverflowAtCompileTime) { - Error(diagnostics, ErrorCode.ERR_CheckedOverflow, syntax); - return ConstantValue.Bad; - } - else - { - return null; + Error(diagnostics, ErrorCode.WRN_CompileTimeCheckedOverflow, syntax, resultTypeSymbol); } + + return null; } if (newValue != null) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 3a29c639d314a..b186b2df08d31 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6860,4 +6860,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ A lambda expression with attributes cannot be converted to an expression tree + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs index e5cd11ad517a7..4888c6ab400cf 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs @@ -517,7 +517,7 @@ private void EmitUnaryCheckedOperatorExpression(BoundUnaryOperator expression, b // then the mathematical negation of x is not representable within the operand type. If this occurs within a checked context, // a System.OverflowException is thrown; if it occurs within an unchecked context, // the result is the value of the operand and the overflow is not reported. - Debug.Assert(type == UnaryOperatorKind.Int || type == UnaryOperatorKind.Long); + Debug.Assert(type == UnaryOperatorKind.Int || type == UnaryOperatorKind.Long || type == UnaryOperatorKind.NInt); // ldc.i4.0 // conv.i8 (when the operand is 64bit) @@ -530,6 +530,10 @@ private void EmitUnaryCheckedOperatorExpression(BoundUnaryOperator expression, b { _builder.EmitOpCode(ILOpCode.Conv_i8); } + else if (type == UnaryOperatorKind.NInt) + { + _builder.EmitOpCode(ILOpCode.Conv_i); + } EmitExpression(expression.Operand, used: true); _builder.EmitOpCode(ILOpCode.Sub_ovf); diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 8bd7a092336be..a0103bb4d352a 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1997,6 +1997,8 @@ internal enum ErrorCode WRN_InterpolatedStringHandlerArgumentAttributeIgnoredOnLambdaParameters = 8971, ERR_LambdaWithAttributesToExpressionTree = 8972, + WRN_CompileTimeCheckedOverflow = 8973, + #endregion // Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index a8f8d47fbbf08..30b9687ba8906 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -484,6 +484,7 @@ internal static int GetWarningLevel(ErrorCode code) case ErrorCode.WRN_CallerArgumentExpressionAttributeSelfReferential: case ErrorCode.WRN_ParameterOccursAfterInterpolatedStringHandlerParameter: case ErrorCode.WRN_InterpolatedStringHandlerArgumentAttributeIgnoredOnLambdaParameters: + case ErrorCode.WRN_CompileTimeCheckedOverflow: return 1; default: return 0; diff --git a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs index f3b671b3148e1..c2f678f8ff2d5 100644 --- a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs @@ -277,6 +277,7 @@ public static bool IsWarning(ErrorCode code) case ErrorCode.WRN_CallerArgumentExpressionAttributeSelfReferential: case ErrorCode.WRN_CallerArgumentExpressionParamForUnconsumedLocation: case ErrorCode.WRN_InterpolatedStringHandlerArgumentAttributeIgnoredOnLambdaParameters: + case ErrorCode.WRN_CompileTimeCheckedOverflow: return true; default: return false; diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 62621c35981c6..c0856c0163acb 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. Porovnání ukazatelů funkcí může přinést neočekávaný výsledek, protože ukazatele na stejnou funkci můžou být rozdílné. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 8ac9b80f5a419..c40e645012109 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. Der Vergleich von Funktionszeigern kann zu einem unerwarteten Ergebnis führen, weil Zeiger auf dieselbe Funktion möglicherweise unterschiedlich sind. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 6997d732e38b1..99fcadfceefa5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. La comparación de los punteros de función puede proporcionar resultados inesperados, ya que los punteros a la misma función pueden ser distintos. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 763cb30922adf..f7537e0ac08ad 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. La comparaison des pointeurs de fonction peut donner un résultat inattendu, car les pointeurs vers la même fonction peuvent être distincts. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 8d9ac38b5fee6..a41ec2b9b41d9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. Il confronto dei puntatori a funzione potrebbe produrre un risultato imprevisto perché i puntatori alla stessa funzione possono essere distinti. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 62be3ce3e759b..e505b9a14b045 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. 同じ関数へのポインターがそれぞれ異なっている可能性があるため、関数ポインターの比較によって予期しない結果が生成されるおそれがあります。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 5ee5afe82c4f6..d3caf58be831a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. 같은 함수에 대한 포인터가 다를 수 있으므로 함수 포인터를 비교하면 예기치 않은 결과가 발생할 수 있습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 95a5326dc2140..ed9ef53a248a6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. Porównanie wskaźników funkcji może zwrócić nieoczekiwany wynik, ponieważ wskaźniki do tej samej funkcji mogą być różne. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index a38e72c62fdde..be49626f6292c 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. A comparação de ponteiros de função pode gerar um resultado inesperado, pois os ponteiros para a mesma função podem ser diferentes. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index ade4a67d82dd7..4fd115083cf9b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. Сравнение указателей на функции может привести к непредвиденному результату, так как указатели на одну и ту же функцию могут быть разными. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index dee46f104703d..3e5f565c7d42d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. Aynı işleve yönelik işaretçiler birbirinden farklı olabileceğinden işlev işaretçilerinin karşılaştırılması beklenmeyen bir sonuç verebilir. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 89b4cfb75a1af..4c03064611b52 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. 函数指针比较可能产生意外的结果,因为指向同一函数的指针可能是不同的。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 7058d02508bb0..343ad5a2a74de 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1407,6 +1407,16 @@ The CallerArgumentExpressionAttribute will have no effect; it is overridden by the CallerMemberNameAttribute + + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override) + + + + The operation may overflow at runtime (use 'unchecked' syntax to override) + The operation may overflow at runtime (use 'unchecked' syntax to override) + + Comparison of function pointers might yield an unexpected result, since pointers to the same function may be distinct. 因為同一個函式的指標可能截然不同,所以比較函式指標可能會產生非預期的結果。 diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs index 0f44ddb4e1309..3e8b2c8c4e03e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NativeIntegerTests.cs @@ -12515,7 +12515,7 @@ .maxstack 2 } [Fact] - public void ConstantFolding() + public void ConstantFolding_01() { const string intMinValue = "-2147483648"; const string intMaxValue = "2147483647"; @@ -12528,7 +12528,7 @@ public void ConstantFolding() unaryOperator("nuint", "+", uintMaxValue, uintMaxValue); unaryOperator("nint", "-", "-1", "1"); - unaryOperatorCheckedOverflow("nint", "-", intMinValue, IntPtr.Size == 4 ? "-2147483648" : "2147483648"); + unaryOperatorCheckedOverflow("nint", "-", intMinValue, IntPtr.Size == 4 ? "-2147483648" : "2147483648", IntPtr.Size == 4 ? "System.OverflowException" : "2147483648"); unaryOperator("nint", "-", "-2147483647", intMaxValue); unaryOperator("nint", "-", intMaxValue, "-2147483647"); unaryOperator("nuint", "-", "0", null, getBadUnaryOpDiagnostics); @@ -12542,29 +12542,29 @@ public void ConstantFolding() unaryOperatorNotConstant("nuint", "~", "0", IntPtr.Size == 4 ? uintMaxValue : ulongMaxValue); unaryOperatorNotConstant("nuint", "~", uintMaxValue, IntPtr.Size == 4 ? "0" : "18446744069414584320"); - binaryOperatorCheckedOverflow("nint", "+", "nint", intMinValue, "nint", "-1", IntPtr.Size == 4 ? "2147483647" : "-2147483649"); + binaryOperatorCheckedOverflow("nint", "+", "nint", intMinValue, "nint", "-1", IntPtr.Size == 4 ? "2147483647" : "-2147483649", IntPtr.Size == 4 ? "System.OverflowException" : "-2147483649"); binaryOperator("nint", "+", "nint", "-2147483647", "nint", "-1", intMinValue); - binaryOperatorCheckedOverflow("nint", "+", "nint", "1", "nint", intMaxValue, IntPtr.Size == 4 ? "-2147483648" : "2147483648"); + binaryOperatorCheckedOverflow("nint", "+", "nint", "1", "nint", intMaxValue, IntPtr.Size == 4 ? "-2147483648" : "2147483648", IntPtr.Size == 4 ? "System.OverflowException" : "2147483648"); binaryOperator("nint", "+", "nint", "1", "nint", "2147483646", intMaxValue); - binaryOperatorCheckedOverflow("nuint", "+", "nuint", "1", "nuint", uintMaxValue, IntPtr.Size == 4 ? "0" : "4294967296"); + binaryOperatorCheckedOverflow("nuint", "+", "nuint", "1", "nuint", uintMaxValue, IntPtr.Size == 4 ? "0" : "4294967296", IntPtr.Size == 4 ? "System.OverflowException" : "4294967296"); binaryOperator("nuint", "+", "nuint", "1", "nuint", "4294967294", uintMaxValue); - binaryOperatorCheckedOverflow("nint", "-", "nint", intMinValue, "nint", "1", IntPtr.Size == 4 ? "2147483647" : "-2147483649"); + binaryOperatorCheckedOverflow("nint", "-", "nint", intMinValue, "nint", "1", IntPtr.Size == 4 ? "2147483647" : "-2147483649", IntPtr.Size == 4 ? "System.OverflowException" : "-2147483649"); binaryOperator("nint", "-", "nint", intMinValue, "nint", "-1", "-2147483647"); binaryOperator("nint", "-", "nint", "-1", "nint", intMaxValue, intMinValue); - binaryOperatorCheckedOverflow("nint", "-", "nint", "-2", "nint", intMaxValue, IntPtr.Size == 4 ? "2147483647" : "-2147483649"); - binaryOperatorCheckedOverflow("nuint", "-", "nuint", "0", "nuint", "1", IntPtr.Size == 4 ? uintMaxValue : ulongMaxValue); + binaryOperatorCheckedOverflow("nint", "-", "nint", "-2", "nint", intMaxValue, IntPtr.Size == 4 ? "2147483647" : "-2147483649", IntPtr.Size == 4 ? "System.OverflowException" : "-2147483649"); + binaryOperatorCheckedOverflow("nuint", "-", "nuint", "0", "nuint", "1", IntPtr.Size == 4 ? uintMaxValue : ulongMaxValue, "System.OverflowException"); binaryOperator("nuint", "-", "nuint", uintMaxValue, "nuint", uintMaxValue, "0"); - binaryOperatorCheckedOverflow("nint", "*", "nint", intMinValue, "nint", "2", IntPtr.Size == 4 ? "0" : "-4294967296"); - binaryOperatorCheckedOverflow("nint", "*", "nint", intMinValue, "nint", "-1", IntPtr.Size == 4 ? "-2147483648" : "2147483648"); + binaryOperatorCheckedOverflow("nint", "*", "nint", intMinValue, "nint", "2", IntPtr.Size == 4 ? "0" : "-4294967296", IntPtr.Size == 4 ? "System.OverflowException" : "-4294967296"); + binaryOperatorCheckedOverflow("nint", "*", "nint", intMinValue, "nint", "-1", IntPtr.Size == 4 ? "-2147483648" : "2147483648", IntPtr.Size == 4 ? "System.OverflowException" : "2147483648"); binaryOperator("nint", "*", "nint", "-1", "nint", intMaxValue, "-2147483647"); - binaryOperatorCheckedOverflow("nint", "*", "nint", "2", "nint", intMaxValue, IntPtr.Size == 4 ? "-2" : "4294967294"); - binaryOperatorCheckedOverflow("nuint", "*", "nuint", uintMaxValue, "nuint", "2", IntPtr.Size == 4 ? "4294967294" : "8589934590"); + binaryOperatorCheckedOverflow("nint", "*", "nint", "2", "nint", intMaxValue, IntPtr.Size == 4 ? "-2" : "4294967294", IntPtr.Size == 4 ? "System.OverflowException" : "4294967294"); + binaryOperatorCheckedOverflow("nuint", "*", "nuint", uintMaxValue, "nuint", "2", IntPtr.Size == 4 ? "4294967294" : "8589934590", IntPtr.Size == 4 ? "System.OverflowException" : "8589934590"); binaryOperator("nuint", "*", "nuint", intMaxValue, "nuint", "2", "4294967294"); binaryOperator("nint", "/", "nint", intMinValue, "nint", "1", intMinValue); - binaryOperatorCheckedOverflow("nint", "/", "nint", intMinValue, "nint", "-1", IntPtr.Size == 4 ? "System.OverflowException" : "2147483648"); + binaryOperatorCheckedOverflow("nint", "/", "nint", intMinValue, "nint", "-1", IntPtr.Size == 4 ? "System.OverflowException" : "2147483648", IntPtr.Size == 4 ? "System.OverflowException" : "2147483648"); binaryOperator("nint", "/", "nint", "1", "nint", "0", null, getIntDivByZeroDiagnostics); binaryOperator("nint", "/", "nint", "0", "nint", "0", null, getIntDivByZeroDiagnostics); binaryOperator("nuint", "/", "nuint", uintMaxValue, "nuint", "1", uintMaxValue); @@ -12574,7 +12574,7 @@ public void ConstantFolding() binaryOperator("nint", "%", "nint", intMinValue, "nint", "2", "0"); binaryOperator("nint", "%", "nint", intMinValue, "nint", "-2", "0"); - binaryOperatorCheckedOverflow("nint", "%", "nint", intMinValue, "nint", "-1", IntPtr.Size == 4 ? "System.OverflowException" : "0"); + binaryOperatorCheckedOverflow("nint", "%", "nint", intMinValue, "nint", "-1", IntPtr.Size == 4 ? "System.OverflowException" : "0", IntPtr.Size == 4 ? "System.OverflowException" : "0"); binaryOperator("nint", "%", "nint", "1", "nint", "0", null, getIntDivByZeroDiagnostics); binaryOperator("nint", "%", "nint", "0", "nint", "0", null, getIntDivByZeroDiagnostics); binaryOperator("nuint", "%", "nuint", uintMaxValue, "nuint", "1", "0"); @@ -12686,18 +12686,26 @@ void unaryOperator(string opType, string op, string operand, string expectedResu constantExpression(opType, $"unchecked({expr})", expectedResult, diagnostics); } - void unaryOperatorCheckedOverflow(string opType, string op, string operand, string expectedResult) + void unaryOperatorCheckedOverflow(string opType, string op, string operand, string expectedResultUnchecked, string expectedResultChecked) { var declarations = $"const {opType} A = {operand};"; var expr = $"{op}A"; - constantDeclaration(opType, declarations, expr, null, new[] { Diagnostic(ErrorCode.ERR_CheckedOverflow, expr) }); - constantDeclaration(opType, declarations, $"checked({expr})", null, new[] { Diagnostic(ErrorCode.ERR_CheckedOverflow, expr) }); + constantDeclaration(opType, declarations, expr, null, + new[] { + Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, expr).WithArguments(opType), + Diagnostic(ErrorCode.ERR_NotConstantExpression, expr).WithArguments("Library.F") + }); + constantDeclaration(opType, declarations, $"checked({expr})", null, + new[] { + Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, expr).WithArguments(opType), + Diagnostic(ErrorCode.ERR_NotConstantExpression, $"checked({expr})").WithArguments("Library.F") + }); constantDeclaration(opType, declarations, $"unchecked({expr})", null, new[] { Diagnostic(ErrorCode.ERR_NotConstantExpression, $"unchecked({expr})").WithArguments("Library.F") }); expr = $"{op}({opType})({operand})"; - constantExpression(opType, expr, null, new[] { Diagnostic(ErrorCode.ERR_CheckedOverflow, expr) }); - constantExpression(opType, $"checked({expr})", null, new[] { Diagnostic(ErrorCode.ERR_CheckedOverflow, expr) }); - constantExpression(opType, $"unchecked({expr})", expectedResult, Array.Empty()); + constantExpression(opType, expr, expectedResultUnchecked, new[] { Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, expr).WithArguments(opType) }); + constantExpression(opType, $"checked({expr})", expectedResultChecked, new[] { Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, expr).WithArguments(opType) }); + constantExpression(opType, $"unchecked({expr})", expectedResultUnchecked, Array.Empty()); } void unaryOperatorNotConstant(string opType, string op, string operand, string expectedResult) @@ -12732,18 +12740,26 @@ void binaryOperator(string opType, string op, string leftType, string leftOperan constantExpression(opType, $"unchecked({expr})", expectedResult, diagnostics); } - void binaryOperatorCheckedOverflow(string opType, string op, string leftType, string leftOperand, string rightType, string rightOperand, string expectedResult) + void binaryOperatorCheckedOverflow(string opType, string op, string leftType, string leftOperand, string rightType, string rightOperand, string expectedResultUnchecked, string expectedResultChecked) { var declarations = $"const {leftType} A = {leftOperand}; const {rightType} B = {rightOperand};"; var expr = $"A {op} B"; - constantDeclaration(opType, declarations, expr, null, new[] { Diagnostic(ErrorCode.ERR_CheckedOverflow, expr) }); - constantDeclaration(opType, declarations, $"checked({expr})", null, new[] { Diagnostic(ErrorCode.ERR_CheckedOverflow, expr) }); + constantDeclaration(opType, declarations, expr, null, + new[] { + Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, expr).WithArguments(opType), + Diagnostic(ErrorCode.ERR_NotConstantExpression, expr).WithArguments("Library.F") + }); + constantDeclaration(opType, declarations, $"checked({expr})", null, + new[] { + Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, expr).WithArguments(opType), + Diagnostic(ErrorCode.ERR_NotConstantExpression, $"checked({expr})").WithArguments("Library.F") + }); constantDeclaration(opType, declarations, $"unchecked({expr})", null, new[] { Diagnostic(ErrorCode.ERR_NotConstantExpression, $"unchecked({expr})").WithArguments("Library.F") }); expr = $"(({leftType})({leftOperand})) {op} (({rightType})({rightOperand}))"; - constantExpression(opType, expr, null, new[] { Diagnostic(ErrorCode.ERR_CheckedOverflow, expr) }); - constantExpression(opType, $"checked({expr})", null, new[] { Diagnostic(ErrorCode.ERR_CheckedOverflow, expr) }); - constantExpression(opType, $"unchecked({expr})", expectedResult, Array.Empty()); + constantExpression(opType, expr, expectedResultUnchecked, new[] { Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, expr).WithArguments(opType) }); + constantExpression(opType, $"checked({expr})", expectedResultChecked, new[] { Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, expr).WithArguments(opType) }); + constantExpression(opType, $"unchecked({expr})", expectedResultUnchecked, Array.Empty()); } void binaryOperatorNotConstant(string opType, string op, string leftType, string leftOperand, string rightType, string rightOperand, string expectedResult) @@ -12771,7 +12787,11 @@ void constantDeclaration(string opType, string declarations, string expr, string var comp = CreateCompilation(sourceA, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(expectedDiagnostics); - if (expectedDiagnostics.Length > 0) return; + if (expectedDiagnostics.Any(d => ErrorFacts.GetSeverity((ErrorCode)d.Code) == DiagnosticSeverity.Error)) + { + Assert.Null(expectedResult); + return; + } string sourceB = @"class Program @@ -12784,10 +12804,9 @@ static void Main() var refA = comp.EmitToImageReference(); comp = CreateCompilation(sourceB, references: new[] { refA }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); CompileAndVerify(comp, expectedOutput: expectedResult); + Assert.NotNull(expectedResult); } - // https://github.com/dotnet/csharplang/issues/3259: Should ERR_CheckedOverflow cases be evaluated - // at runtime rather than compile time to allow operations to succeed on 64-bit platforms? void constantExpression(string opType, string expr, string expectedResult, DiagnosticDescription[] expectedDiagnostics) { string source = @@ -12810,14 +12829,149 @@ static void Main() }} }}"; var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.Regular9); - comp.VerifyDiagnostics(expectedDiagnostics); - if (expectedDiagnostics.Length > 0) return; + if (expectedDiagnostics.Any(d => ErrorFacts.GetSeverity((ErrorCode)d.Code) == DiagnosticSeverity.Error)) + { + comp.VerifyDiagnostics(expectedDiagnostics); + Assert.Null(expectedResult); + return; + } - CompileAndVerify(comp, expectedOutput: expectedResult); + CompileAndVerify(comp, expectedOutput: expectedResult).VerifyDiagnostics(expectedDiagnostics); + Assert.NotNull(expectedResult); } } + [Fact] + [WorkItem(51714, "https://github.com/dotnet/roslyn/issues/51714")] + public void ConstantFolding_02() + { + var source = +@" +class Program +{ + static void Main() + { + const nuint x = unchecked(uint.MaxValue + (nuint)42); + const nuint y = checked(uint.MaxValue + (nuint)42); + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics( + // (6,25): error CS0133: The expression being assigned to 'x' must be constant + // const nuint x = unchecked(uint.MaxValue + (nuint)42); + Diagnostic(ErrorCode.ERR_NotConstantExpression, "unchecked(uint.MaxValue + (nuint)42)").WithArguments("x").WithLocation(6, 25), + // (7,25): error CS0133: The expression being assigned to 'y' must be constant + // const nuint y = checked(uint.MaxValue + (nuint)42); + Diagnostic(ErrorCode.ERR_NotConstantExpression, "checked(uint.MaxValue + (nuint)42)").WithArguments("y").WithLocation(7, 25), + // (7,33): warning CS8973: The operation may overflow 'nuint' at runtime (use 'unchecked' syntax to override) + // const nuint y = checked(uint.MaxValue + (nuint)42); + Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, "uint.MaxValue + (nuint)42").WithArguments("nuint").WithLocation(7, 33) + ); + + source = +@" +class Program +{ + static void Main() + { + try + { + var y = checked(uint.MaxValue + (nuint)42); + System.Console.WriteLine(y); + } + catch (System.Exception e) + { + System.Console.WriteLine(e.GetType()); + } + } +}"; + comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: IntPtr.Size == 4 ? "System.OverflowException" : "4294967337").VerifyDiagnostics( + // (8,29): warning CS8973: The operation may overflow 'nuint' at runtime (use 'unchecked' syntax to override) + // var y = checked(uint.MaxValue + (nuint)42); + Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, "uint.MaxValue + (nuint)42").WithArguments("nuint").WithLocation(8, 29) + ); + + source = +@" +class Program +{ + static void Main() + { + var y = unchecked(uint.MaxValue + (nuint)42); + System.Console.WriteLine(y); + } +}"; + comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: IntPtr.Size == 4 ? "41" : "4294967337").VerifyDiagnostics(); + } + + [Fact] + [WorkItem(51714, "https://github.com/dotnet/roslyn/issues/51714")] + public void ConstantFolding_03() + { + var source = +@" +class Program +{ + static void Main() + { + const nint x = unchecked(-(nint)int.MinValue); + const nint y = checked(-(nint)int.MinValue); + } +}"; + var comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + comp.VerifyDiagnostics( + // (6,24): error CS0133: The expression being assigned to 'x' must be constant + // const nint x = unchecked(-(nint)int.MinValue); + Diagnostic(ErrorCode.ERR_NotConstantExpression, "unchecked(-(nint)int.MinValue)").WithArguments("x").WithLocation(6, 24), + // (7,24): error CS0133: The expression being assigned to 'y' must be constant + // const nint y = checked(-(nint)int.MinValue); + Diagnostic(ErrorCode.ERR_NotConstantExpression, "checked(-(nint)int.MinValue)").WithArguments("y").WithLocation(7, 24), + // (7,32): warning CS8973: The operation may overflow 'nint' at runtime (use 'unchecked' syntax to override) + // const nint y = checked(-(nint)int.MinValue); + Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, "-(nint)int.MinValue").WithArguments("nint").WithLocation(7, 32) + ); + + source = +@" +class Program +{ + static void Main() + { + try + { + var y = checked(-(nint)int.MinValue); + System.Console.WriteLine(y); + } + catch (System.Exception e) + { + System.Console.WriteLine(e.GetType()); + } + } +}"; + comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: IntPtr.Size == 4 ? "System.OverflowException" : "2147483648").VerifyDiagnostics( + // (8,29): warning CS8973: The operation may overflow 'nint' at runtime (use 'unchecked' syntax to override) + // var y = checked(-(nint)int.MinValue); + Diagnostic(ErrorCode.WRN_CompileTimeCheckedOverflow, "-(nint)int.MinValue").WithArguments("nint").WithLocation(8, 29) + ); + + source = +@" +class Program +{ + static void Main() + { + var y = unchecked(-(nint)int.MinValue); + System.Console.WriteLine(y); + } +}"; + comp = CreateCompilation(source, options: TestOptions.ReleaseExe); + CompileAndVerify(comp, expectedOutput: IntPtr.Size == 4 ? "-2147483648" : "2147483648").VerifyDiagnostics(); + } + // OverflowException behavior is consistent with unchecked int division. [Fact] public void UncheckedIntegerDivision() diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs index 8e3997638658b..c746dbf998e96 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs @@ -345,6 +345,7 @@ public void WarningLevel_2() case ErrorCode.WRN_IsPatternAlways: case ErrorCode.WRN_AnalyzerReferencesFramework: case ErrorCode.WRN_InterpolatedStringHandlerArgumentAttributeIgnoredOnLambdaParameters: + case ErrorCode.WRN_CompileTimeCheckedOverflow: Assert.Equal(1, ErrorFacts.GetWarningLevel(errorCode)); break; case ErrorCode.WRN_InvalidVersionFormat: