Go spec say on unsigned integer overflow:
For unsigned integer values, the operations +, -, *, and << are computed modulo 2n, where n is the bit width of the unsigned integer's type. Loosely speaking, these unsigned integer operations discard high bits upon overflow, and programs may rely on ''wrap around''.
I try to test it, but get inconsistent result - http://play.golang.org/p/sJxtSHbigT:
package main
import "fmt"
func main() {
fmt.Println("test")
var num uint32 = 1 << 35
}
This give error:
prog.go:7: constant 34359738368 overflows uint32
[process exited with non-zero status]
But according to spec should be no error but rather I should seen 0.
The specification you quote refers specifically to the results of "the operations +, -, *, and <<". You're trying to define a constant, not looking at the result of one of those operations.
You also can't use those over-sized values for the input of those operations. The compiler won't wrap any values for you; that's just the runtime behaviour of those operations.
package main
import "fmt"
func main() {
var num uint32 = 1 + 1 << 35
fmt.Printf("num = %v
", num)
}
prog.go:6: constant 34359738369 overflows uint32
[process exited with non-zero status]
Here's an interesting example.
var num uint32 = (1 << 31) + (1 << 31)
fmt.Printf("num = %v
", num)
prog.go:6: constant 4294967296 overflows uint32
[process exited with non-zero status]
In this case, the compiler attempts to evaluate (1 << 31) + (1 << 31)
at compile-time, producing the constant value 4294967296
, which is too large to fit.
var num uint32 = (1 << 31)
num += (1 << 31)
fmt.Printf("num = %v
", num)
num = 0
In this case, the addition is performed at run-time, and the value wraps around as you'd expect.
That's because 1 << 35
is an untyped constant expression (it only involves numerical constants). It doesn't become an uint32
until you assign it. Go prohibits you to assign to a variable a constant expression that would overflow it as stuff like that is almost certainly unintentional.