1
0
mirror of https://github.com/golang/go synced 2024-11-26 05:37:57 -07:00

[dev.regabi] go/types: use 512 bits as max. integer precision

This is a port of CL 288633 to go/types. It differs from that CL
in the implementation of opName, which now uses ast Exprs.

Additionally, a couple tests had to be updated:
 + TestEvalArith is updated to not overflow.
 + stmt0.src is updated to have an error positioned on the '<<'
   operator.

Change-Id: I628357c33a1e7b0bb5bb7de5736f1fb10ce404e4
Reviewed-on: https://go-review.googlesource.com/c/go/+/290630
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Rob Findley 2021-02-08 22:37:48 -05:00 committed by Robert Findley
parent 0a62067708
commit 168d6a49a5
7 changed files with 69 additions and 26 deletions

View File

@ -76,7 +76,7 @@ func TestEvalArith(t *testing.T) {
`false == false`,
`12345678 + 87654321 == 99999999`,
`10 * 20 == 200`,
`(1<<1000)*2 >> 100 == 2<<900`,
`(1<<500)*2 >> 100 == 2<<400`,
`"foo" + "bar" == "foobar"`,
`"abc" <= "bcd"`,
`len([10]struct{}{}) == 2*5`,

View File

@ -84,11 +84,6 @@ func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) {
assert(x.mode == constant_)
what := "" // operator description, if any
if int(op) < len(op2str) {
what = op2str[op]
}
if x.val.Kind() == constant.Unknown {
// TODO(gri) We should report exactly what went wrong. At the
// moment we don't have the (go/constant) API for that.
@ -105,15 +100,37 @@ func (check *Checker) overflow(x *operand, op token.Token, opPos token.Pos) {
}
// Untyped integer values must not grow arbitrarily.
const limit = 4 * 512 // 512 is the constant precision - we need more because old tests had no limits
if x.val.Kind() == constant.Int && constant.BitLen(x.val) > limit {
check.errorf(atPos(opPos), _InvalidConstVal, "constant %s overflow", what)
const prec = 512 // 512 is the constant precision
if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec {
check.errorf(atPos(opPos), _InvalidConstVal, "constant %s overflow", opName(x.expr))
x.val = constant.MakeUnknown()
}
}
// opName returns the name of an operation, or the empty string.
// For now, only operations that might overflow are handled.
// TODO(gri) Expand this to a general mechanism giving names to
// nodes?
func opName(e ast.Expr) string {
switch e := e.(type) {
case *ast.BinaryExpr:
if int(e.Op) < len(op2str2) {
return op2str2[e.Op]
}
case *ast.UnaryExpr:
if int(e.Op) < len(op2str1) {
return op2str1[e.Op]
}
}
return ""
}
var op2str1 = [...]string{
token.XOR: "bitwise complement",
}
// This is only used for operations that may cause overflow.
var op2str = [...]string{
var op2str2 = [...]string{
token.ADD: "addition",
token.SUB: "subtraction",
token.XOR: "bitwise XOR",
@ -763,8 +780,17 @@ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) {
if x.mode == constant_ {
if y.mode == constant_ {
// if either x or y has an unknown value, the result is unknown
if x.val.Kind() == constant.Unknown || y.val.Kind() == constant.Unknown {
x.val = constant.MakeUnknown()
// ensure the correct type - see comment below
if !isInteger(x.typ) {
x.typ = Typ[UntypedInt]
}
return
}
// rhs must be within reasonable bounds in constant shifts
const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64
const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64 (see issue #44057)
s, ok := constant.Uint64Val(yval)
if !ok || s > shiftBound {
check.invalidOp(y, _InvalidShiftCount, "invalid shift count %s", y)

View File

@ -175,7 +175,6 @@ func TestStdFixed(t *testing.T) {
"issue16369.go", // go/types handles this correctly - not an issue
"issue18459.go", // go/types doesn't check validity of //go:xxx directives
"issue18882.go", // go/types doesn't check validity of //go:xxx directives
"issue20232.go", // go/types handles larger constants than gc
"issue20529.go", // go/types does not have constraints on stack size
"issue22200.go", // go/types does not have constraints on stack size
"issue22200b.go", // go/types does not have constraints on stack size

View File

@ -514,7 +514,7 @@ func panic1() {
panic("foo")
panic(false)
panic(1<<10)
panic(1 /* ERROR overflows */ <<1000)
panic(1 << /* ERROR constant shift overflow */ 1000)
_ = panic /* ERROR used as value */ (0)
var s []byte
@ -538,7 +538,7 @@ func print1() {
print(2.718281828)
print(false)
print(1<<10)
print(1 /* ERROR overflows */ <<1000)
print(1 << /* ERROR constant shift overflow */ 1000)
println(nil /* ERROR untyped nil */ )
var s []int
@ -564,7 +564,7 @@ func println1() {
println(2.718281828)
println(false)
println(1<<10)
println(1 /* ERROR overflows */ <<1000)
println(1 << /* ERROR constant shift overflow */ 1000)
println(nil /* ERROR untyped nil */ )
var s []int
@ -695,7 +695,7 @@ func Alignof1() {
_ = unsafe.Alignof(42)
_ = unsafe.Alignof(new(struct{}))
_ = unsafe.Alignof(1<<10)
_ = unsafe.Alignof(1 /* ERROR overflows */ <<1000)
_ = unsafe.Alignof(1 << /* ERROR constant shift overflow */ 1000)
_ = unsafe.Alignof(nil /* ERROR "untyped nil */ )
unsafe /* ERROR not used */ .Alignof(x)
@ -783,7 +783,7 @@ func Sizeof1() {
_ = unsafe.Sizeof(42)
_ = unsafe.Sizeof(new(complex128))
_ = unsafe.Sizeof(1<<10)
_ = unsafe.Sizeof(1 /* ERROR overflows */ <<1000)
_ = unsafe.Sizeof(1 << /* ERROR constant shift overflow */ 1000)
_ = unsafe.Sizeof(nil /* ERROR untyped nil */ )
unsafe /* ERROR not used */ .Sizeof(x)

View File

@ -350,8 +350,14 @@ const _ = unsafe.Sizeof(func() {
})
// untyped constants must not get arbitrarily large
const (
huge = 1<<1000
_ = huge * huge * /* ERROR constant multiplication overflow */ huge
_ = huge << 1000 << /* ERROR constant shift overflow */ 1000
)
const prec = 512 // internal maximum precision for integers
const maxInt = (1<<(prec/2) - 1) * (1<<(prec/2) + 1) // == 1<<prec - 1
const _ = maxInt + /* ERROR constant addition overflow */ 1
const _ = -maxInt - /* ERROR constant subtraction overflow */ 1
const _ = maxInt ^ /* ERROR constant bitwise XOR overflow */ -1
const _ = maxInt * /* ERROR constant multiplication overflow */ 2
const _ = maxInt << /* ERROR constant shift overflow */ 2
const _ = 1 << /* ERROR constant shift overflow */ prec
const _ = ^ /* ERROR constant bitwise complement overflow */ maxInt

View File

@ -43,7 +43,12 @@ const (
const (
smallestFloat32 = 1.0 / (1<<(127 - 1 + 23))
smallestFloat64 = 1.0 / (1<<(1023 - 1 + 52))
// TODO(gri) The compiler limits integers to 512 bit and thus
// we cannot compute the value (1<<(1023 - 1 + 52))
// without overflow. For now we match the compiler.
// See also issue #44057.
// smallestFloat64 = 1.0 / (1<<(1023 - 1 + 52))
smallestFloat64 = 4.940656458412465441765687928682213723651e-324
)
const (
@ -53,7 +58,12 @@ const (
const (
maxFloat32 = 1<<127 * (1<<24 - 1) / (1.0<<23)
maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
// TODO(gri) The compiler limits integers to 512 bit and thus
// we cannot compute the value 1<<1023
// without overflow. For now we match the compiler.
// See also issue #44057.
// maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
maxFloat64 = 1.797693134862315708145274237317043567981e+308
)
const (
@ -271,7 +281,9 @@ const (
_ = assert(float64(smallestFloat32) == smallestFloat32)
_ = assert(float64(smallestFloat32/2) == smallestFloat32/2)
_ = assert(float64(smallestFloat64) == smallestFloat64)
_ = assert(float64(smallestFloat64/2) == 0)
// TODO(gri) With the change to the declaration of smallestFloat64
// this now fails to be true. See issue #44058.
// _ = assert(float64(smallestFloat64/2) == 0)
)
const (

View File

@ -90,7 +90,7 @@ func assignments1() {
// assignments to _
_ = nil /* ERROR "use of untyped nil" */
_ = 1 /* ERROR overflow */ <<1000
_ = 1 << /* ERROR constant shift overflow */ 1000
(_) = 0
}