From b680614e571c52b45cef9288e15ec3df601828a3 Mon Sep 17 00:00:00 2001 From: "H. S. Teoh" Date: Thu, 22 Aug 2013 18:07:36 -0700 Subject: [PATCH 1/3] Add unittest for issue 6893. --- std/format.d | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/std/format.d b/std/format.d index e5c1417e2c9..fc80fd2f2e0 100644 --- a/std/format.d +++ b/std/format.d @@ -5929,3 +5929,12 @@ unittest formattedWrite(stream, "%2$.*1$d", 12, 10); assert(stream.data == "000000000010", stream.data); } + +unittest +{ + // bug 6893 + enum E : ulong { A, B, C } + auto stream = appender!(char[])(); + formattedWrite(stream, "%s", E.C); + assert(stream.data == "C"); +} From 8f8587f677ff00b3261a87c96e9f6353051fac15 Mon Sep 17 00:00:00 2001 From: "H. S. Teoh" Date: Fri, 23 Aug 2013 10:32:52 -0700 Subject: [PATCH 2/3] Allow narrowing conversions of enum -> integral (int, short, etc.). It will just throw at runtime if the value of the enum is too large. --- std/conv.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/conv.d b/std/conv.d index 9318f6fba5b..d3c66ce6b37 100644 --- a/std/conv.d +++ b/std/conv.d @@ -1308,7 +1308,7 @@ fit in the narrower type. */ T toImpl(T, S)(S value) if (!isImplicitlyConvertible!(S, T) && - (isNumeric!S || isSomeChar!S) && !is(S == enum) && + (isNumeric!S || isSomeChar!S) && (isNumeric!T || isSomeChar!T) && !is(T == enum)) { enum sSmallest = mostNegative!S; From d42e0eddecbf047074319222825b11865f303d7a Mon Sep 17 00:00:00 2001 From: "H. S. Teoh" Date: Fri, 23 Aug 2013 11:01:34 -0700 Subject: [PATCH 3/3] Add unittest for narrowing enum -> integral conversions. --- std/conv.d | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/std/conv.d b/std/conv.d index d3c66ce6b37..94014eaf62f 100644 --- a/std/conv.d +++ b/std/conv.d @@ -1360,6 +1360,29 @@ T toImpl(T, S)(S value) dchar to4 = to!dchar(from4); } +unittest +{ + // Narrowing conversions from enum -> integral should be allowed, but they + // should throw at runtime if the enum value doesn't fit in the target + // type. + enum E1 : ulong { A = 1, B = 1UL<<48 } + assert(to!int(E1.A) == 1); + assertThrown!ConvOverflowException(to!int(E1.B)); // E1.B overflows int + + enum E2 : long { A = -1L<<48, B = -1<<31, C = 1<<31 } + assertThrown!ConvOverflowException(to!int(E2.A)); // E2.A overflows int + assertThrown!ConvOverflowException(to!uint(E2.B)); // E2.B overflows uint + assert(to!int(E2.B) == -1<<31); // but does not overflow int + assert(to!int(E2.C) == 1<<31); // E2.C does not overflow int + + enum E3 : int { A = -1, B = 1, C = 255 } + assertThrown!ConvOverflowException(to!ubyte(E3.A)); + assert(to!byte(E3.A) == -1); + assert(to!byte(E3.B) == 1); + assert(to!ubyte(E3.C) == 255); + assertThrown!ConvOverflowException(to!byte(E3.C)); +} + /** Array-to-array conversion (except when target is a string type) converts each element in turn by using $(D to).