提交 27bd018e 编写于 作者: L leppie 提交者: Neal Gafter

Detect invalid real literal and report it using CS0595

Fixes #6109.
上级 8dbfd942
......@@ -5281,6 +5281,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Invalid real literal..
/// </summary>
internal static string ERR_InvalidReal {
get {
return ResourceManager.GetString("ERR_InvalidReal", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid signature public key specified in AssemblySignatureKeyAttribute..
/// </summary>
......
......@@ -4666,4 +4666,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_PublicSignButNoKey" xml:space="preserve">
<value>Public signing was specified and requires a public key, but no public key was specified.</value>
</data>
</root>
\ No newline at end of file
<data name="ERR_InvalidReal" xml:space="preserve">
<value>Invalid real literal.</value>
</data>
</root>
......@@ -404,6 +404,7 @@ internal enum ErrorCode
ERR_InvalidAttributeArgument = 591,
ERR_AttributeOnBadSymbolType = 592,
ERR_FloatOverflow = 594,
ERR_InvalidReal = 595,
ERR_ComImportWithoutUuidAttribute = 596,
ERR_InvalidNamedArgument = 599,
ERR_DllImportOnInvalidMethod = 601,
......
......@@ -1029,10 +1029,20 @@ private bool ScanNumericLiteral(ref TokenInfo info)
TextWindow.AdvanceChar();
}
while ((ch = TextWindow.PeekChar()) >= '0' && ch <= '9')
if (!((ch = TextWindow.PeekChar()) >= '0' && ch <= '9'))
{
_builder.Append(ch);
TextWindow.AdvanceChar();
// use this for now (CS0595), cant use CS0594 as we dont know 'type'
this.AddError(MakeError(ErrorCode.ERR_InvalidReal));
// add dummy exponent, so parser does not blow up
_builder.Append('0');
}
else
{
while ((ch = TextWindow.PeekChar()) >= '0' && ch <= '9')
{
_builder.Append(ch);
TextWindow.AdvanceChar();
}
}
}
......
......@@ -44,6 +44,38 @@ public void CS0594ERR_FloatOverflow()
Diagnostic(ErrorCode.ERR_FloatOverflow, "3e100m").WithArguments("decimal"));
}
[Fact]
public void CS0595ERR_InvalidReal()
{
var test =
@"public class C
{
double d1 = 0e;
double d2 = .0e;
double d3 = 0.0e;
double d4 = 0e+;
double d5 = 0e-;
}";
ParserErrorMessageTests.ParseAndValidate(test,
// (3,17): error CS0595: Invalid real literal
// double d1 = 0e;
Diagnostic(ErrorCode.ERR_InvalidReal, "").WithLocation(3, 17),
// (4,17): error CS0595: Invalid real literal
// double d2 = .0e;
Diagnostic(ErrorCode.ERR_InvalidReal, "").WithLocation(4, 17),
// (5,17): error CS0595: Invalid real literal
// double d3 = 0.0e;
Diagnostic(ErrorCode.ERR_InvalidReal, "").WithLocation(5, 17),
// (6,17): error CS0595: Invalid real literal
// double d4 = 0e+;
Diagnostic(ErrorCode.ERR_InvalidReal, "").WithLocation(6, 17),
// (7,17): error CS0595: Invalid real literal
// double d5 = 0e-;
Diagnostic(ErrorCode.ERR_InvalidReal, "").WithLocation(7, 17)
);
}
[WorkItem(6079, "https://github.com/dotnet/roslyn/issues/6079")]
[Fact]
public void FloatLexicalError()
......@@ -55,18 +87,18 @@ public void FloatLexicalError()
}";
// The precise errors don't matter so much as the fact that the compiler should not crash.
ParserErrorMessageTests.ParseAndValidate(test,
// (3,23): error CS0594: Floating-point constant is outside the range of type 'double'
// const double d1 = 0endOfDirective.Span;
Diagnostic(ErrorCode.ERR_FloatOverflow, "").WithArguments("double").WithLocation(3, 23),
// (3,25): error CS1002: ; expected
// const double d1 = 0endOfDirective.Span;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "ndOfDirective").WithLocation(3, 25),
// (3,43): error CS1519: Invalid token ';' in class, struct, or interface member declaration
// const double d1 = 0endOfDirective.Span;
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 43),
// (3,43): error CS1519: Invalid token ';' in class, struct, or interface member declaration
// const double d1 = 0endOfDirective.Span;
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 43)
// (3,23): error CS0595: Invalid real literal
// const double d1 = 0endOfDirective.Span;
Diagnostic(ErrorCode.ERR_InvalidReal, "").WithLocation(3, 23),
// (3,25): error CS1002: ; expected
// const double d1 = 0endOfDirective.Span;
Diagnostic(ErrorCode.ERR_SemicolonExpected, "ndOfDirective").WithLocation(3, 25),
// (3,43): error CS1519: Invalid token ';' in class, struct, or interface member declaration
// const double d1 = 0endOfDirective.Span;
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 43),
// (3,43): error CS1519: Invalid token ';' in class, struct, or interface member declaration
// const double d1 = 0endOfDirective.Span;
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 43)
);
}
......
......@@ -1416,7 +1416,7 @@ public void TestNumericLiteralWithExponentAndDecimalSpecifier04()
Assert.Equal(SyntaxKind.NumericLiteralToken, token.Kind());
var errors = token.Errors();
Assert.Equal(1, errors.Length);
Assert.Equal((int)ErrorCode.ERR_FloatOverflow, errors[0].Code);
Assert.Equal((int)ErrorCode.ERR_InvalidReal, errors[0].Code);
Assert.Equal(text, token.Text);
}
......
......@@ -367,6 +367,10 @@ public static void TestSpecificDoubles()
"40497058210285131854513962138377228261454376934125320985913276672363" +
"28125001e-324",
0x0000000000000001);
CheckOneDouble("1.0e-99999999999999999999", 0.0);
CheckOneDouble("0e-99999999999999999999", 0.0);
CheckOneDouble("0e99999999999999999999", 0.0);
}
static void TestRoundTripDouble(ulong bits)
......
......@@ -26,24 +26,15 @@ internal static class RealParser
/// </summary>
/// <param name="s">The decimal floating-point constant's string</param>
/// <param name="d">The nearest double value, if conversion succeeds</param>
/// <returns>True of the input was converted; false if there was an overflow</returns>
/// <returns>True if the input was converted; false if there was an overflow</returns>
public static bool TryParseDouble(string s, out double d)
{
try
{
var str = DecimalFloatingPointString.FromSource(s);
var dbl = DoubleFloatingPointType.Instance;
ulong result;
var status = RealParser.ConvertDecimalToFloatingPointBits(str, dbl, out result);
d = BitConverter.Int64BitsToDouble((long)result);
return status != Status.Overflow;
}
catch (System.FormatException)
{
// this can occur when the exponent is empty (e.g. "0.0e") or too large to fit in an integer
d = 0.0;
return false;
}
var str = DecimalFloatingPointString.FromSource(s);
var dbl = DoubleFloatingPointType.Instance;
ulong result;
var status = RealParser.ConvertDecimalToFloatingPointBits(str, dbl, out result);
d = BitConverter.Int64BitsToDouble((long)result);
return status != Status.Overflow;
}
/// <summary>
......@@ -53,23 +44,15 @@ public static bool TryParseDouble(string s, out double d)
/// </summary>
/// <param name="s">The float floating-point constant's string</param>
/// <param name="f">The nearest float value, if conversion succeeds</param>
/// <returns>True of the input was converted; false if there was an overflow</returns>
/// <returns>True if the input was converted; false if there was an overflow</returns>
public static bool TryParseFloat(string s, out float f)
{
try
{
var str = DecimalFloatingPointString.FromSource(s);
var dbl = FloatFloatingPointType.Instance;
ulong result;
var status = RealParser.ConvertDecimalToFloatingPointBits(str, dbl, out result);
f = Int32BitsToFloat((uint)result);
return status != Status.Overflow;
}
catch (System.FormatException)
{
f = 0.0f;
return false;
}
var str = DecimalFloatingPointString.FromSource(s);
var dbl = FloatFloatingPointType.Instance;
ulong result;
var status = RealParser.ConvertDecimalToFloatingPointBits(str, dbl, out result);
f = Int32BitsToFloat((uint)result);
return status != Status.Overflow;
}
private readonly static BigInteger BigZero = BigInteger.Zero;
......@@ -348,6 +331,7 @@ public static DecimalFloatingPointString FromSource(string source)
result.Mantissa = mantissaBuilder.ToString();
if (i < source.Length && (source[i] == 'e' || source[i] == 'E'))
{
const int MAX_EXP = (1 << 30); // even playing ground
char exponentSign = '\0';
i++;
if (i < source.Length && (source[i] == '-' || source[i] == '+'))
......@@ -358,14 +342,24 @@ public static DecimalFloatingPointString FromSource(string source)
int firstExponent = i;
int lastExponent = i;
while (i < source.Length && source[i] >= '0' && source[i] <= '9') lastExponent = ++i;
int exponentMagnitude = int.Parse(source.Substring(firstExponent, lastExponent - firstExponent));
if (exponentSign == '-')
int exponentMagnitude = 0;
if (int.TryParse(source.Substring(firstExponent, lastExponent - firstExponent), out exponentMagnitude) &&
exponentMagnitude <= MAX_EXP)
{
exponent -= exponentMagnitude;
if (exponentSign == '-')
{
exponent -= exponentMagnitude;
}
else
{
exponent += exponentMagnitude;
}
}
else
{
exponent += exponentMagnitude;
exponent = exponentSign == '-' ? -MAX_EXP : MAX_EXP;
}
}
result.Exponent = exponent;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册