Swift silently truncates integer literals on 32-bit builds
| Originator: | pyry.jahkola | ||
| Number: | rdar://19547450 | Date Originated: | 2015-01-21 |
| Status: | Duplicate of 17604532 (Closed) | Resolved: | |
| Product: | Developer Tools | Product Version: | 6.1.1 (6A2006) |
| Classification: | Other Bug | Reproducible: | Always |
Summary:
In general, integer initialisation from integer literals is guarded by a compile-time range check—trying to fit e.g. 0xf000 into an Int16 correctly gives a compiler error telling there's an overflow:
"Integer literal overflows when stored into 'Int16'"
But somehow, this logic goes wrong when building for a 32-bit target, possibly incorrectly behaving as if Int could fit 64 bits:
// Results from a 32-bit build shown in comments.
let i = 3_000_000_000 //=> i: Int = -1294967296
let j = Int64(10_000_000_000) //=> j: Int64 = 1410065408
assert(j == 10_000_000_000) // assertion fails!
Neither of these should pass the compiler without a notice. And I think they should both cause a compiler error when built for a 32-bit target. (Built in 64-bit mode, both lines behave as could be expected because Int is able to fit both literals.)
Steps to Reproduce:
Try to compile these following three functions one at a time, first for a 64-bit target and then a 32-bit target.
func worksAsExpected() {
let x1 = 0x7fffffff //=> x1: Int = 2147483647
let x2 = 0x7fffffff as Int32 //=> x2: Int32 = 2147483647
let x3 = 0x7fff as Int16 //=> x3: Int16 = 32767
let x4 = 0x7f as Int8 //=> x4: Int8 = 127
let x5 = 10_000_000_000 as Int64 //=> x5: Int64 = 10000000000
println("\(x1), \(x2), \(x3), \(x4), \(x5)")
}
func failsAsExpected() {
let _ = 0x8000000000000000 // error: Integer literal overflows when stored into 'Int'
let _ = 0x80000000 as Int32 // error: Integer literal overflows when stored into 'Int32'
let _ = 0x8000 as Int16 // error: Integer literal overflows when stored into 'Int16'
let _ = 0x80 as Int8 // error: Integer literal overflows when stored into 'Int8'
let _ = Int16(0x8000) // error: Integer overflows when converted from 'Int' to 'Int16'
let _ = Int8(0x80) // error: Integer overflows when converted from 'Int' to 'Int8'
}
func worksUnexpectedly() {
// Expecting error: Integer literal overflows when stored into 'Int'
let e1 = Int32(0x80000000) //=> e1: Int32 = -2147483648
let e2 = Int32(0xffffffff) //=> e2: Int32 = -1
let e3 = 0xffffffff //=> e3: Int = -1
let e4 = 0x100000000 //=> e4: Int = 0
let e5 = 10_000_000_000 //=> e5: Int = 1410065408
let e6 = Int64(10_000_000_000) //=> e6: Int64 = 1410065408
}
Expected Results:
1) The function worksAsExpected() should compile and run, printing:
2147483647, 2147483647, 32767, 127, 10000000000
2) The function failsAsExpected() should fail to compile, with the errors as marked in comments.
3) The function worksUnexpectedly() should fail to compile for 32-bit, probably with the following error from every statement:
Integer literal overflows when stored into 'Int'
For 64-bit builds, the lines declaring e1 and e2 should give an error.
Actual Results:
1) Works as expected
2) Fails as expected
3) For 32-bit, unexpectedly compiles and runs printing:
-2147483648, -1, -1, 0, 1410065408, 1410065408
For 64-bit, expectedly gives errors from the lines declaring e1 and e2.
Version:
6.1.1 (6A2006)
Notes:
This behaviour is very surprising when using the constructor-like syntax to define Int64 values:
let i = Int64(10_000_000_000)
Currently, my best advice is to do either of these instead:
let j = 10_000_000_000 as Int64
let k: Int64 = 10_000_000_000
Configuration:
Attachments:
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!