From 370e9f58432c51bf3d95308cdc7109e25cc141f6 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 29 Jan 2021 15:29:36 -0800 Subject: [PATCH] [dev.typeparams] cmd/compile/internal/types2: use 512 bits as max. integer precision This matches the compiler's existing limitations and thus ensures that types2 reports the same errors for oversize integer constants. Change-Id: I4fb7c83f3af69098d96f7b6c53dbe3eaf6ea9ee4 Reviewed-on: https://go-review.googlesource.com/c/go/+/288633 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/typecheck/const.go | 2 +- src/cmd/compile/internal/types2/expr.go | 45 +++++++++++++++---- .../compile/internal/types2/stdlib_test.go | 1 - .../internal/types2/testdata/builtins.src | 10 ++--- .../internal/types2/testdata/const0.src | 17 ++++--- .../internal/types2/testdata/const1.src | 18 ++++++-- test/run.go | 1 - 7 files changed, 69 insertions(+), 25 deletions(-) diff --git a/src/cmd/compile/internal/typecheck/const.go b/src/cmd/compile/internal/typecheck/const.go index 1a8e58383ad..c60d36ba62f 100644 --- a/src/cmd/compile/internal/typecheck/const.go +++ b/src/cmd/compile/internal/typecheck/const.go @@ -449,7 +449,7 @@ func EvalConst(n ir.Node) ir.Node { n := n.(*ir.BinaryExpr) nl, nr := n.X, n.Y if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL { - // shiftBound from go/types; "so we can express smallestFloat64" + // shiftBound from go/types; "so we can express smallestFloat64" (see issue #44057) const shiftBound = 1023 - 1 + 52 s, ok := constant.Uint64Val(nr.Val()) if !ok || s > shiftBound { diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index a1a626fb33d..679495d3f3d 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -96,9 +96,7 @@ func (check *Checker) overflow(x *operand) { what := "" // operator description, if any if op, _ := x.expr.(*syntax.Operation); op != nil { pos = op.Pos() - if int(op.Op) < len(op2str) { - what = op2str[op.Op] - } + what = opName(op) } if x.val.Kind() == constant.Unknown { @@ -117,15 +115,37 @@ func (check *Checker) overflow(x *operand) { } // 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 { + const prec = 512 // 512 is the constant precision + if x.val.Kind() == constant.Int && constant.BitLen(x.val) > prec { check.errorf(pos, "constant %s overflow", what) x.val = constant.MakeUnknown() } } -// This is only used for operations that may cause overflow. -var op2str = [...]string{ +// 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 *syntax.Operation) string { + op := int(e.Op) + if e.Y == nil { + if op < len(op2str1) { + return op2str1[op] + } + } else { + if op < len(op2str2) { + return op2str2[op] + } + } + return "" +} + +// Entries must be "" or end with a space. +var op2str1 = [...]string{ + syntax.Xor: "bitwise complement", +} + +var op2str2 = [...]string{ syntax.Add: "addition", syntax.Sub: "subtraction", syntax.Xor: "bitwise XOR", @@ -800,8 +820,17 @@ func (check *Checker) shift(x, y *operand, e syntax.Expr, op syntax.Operator) { 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(y.val) if !ok || s > shiftBound { check.invalidOpf(y, "invalid shift count %s", y) diff --git a/src/cmd/compile/internal/types2/stdlib_test.go b/src/cmd/compile/internal/types2/stdlib_test.go index 1dd32298525..a146619d7e3 100644 --- a/src/cmd/compile/internal/types2/stdlib_test.go +++ b/src/cmd/compile/internal/types2/stdlib_test.go @@ -182,7 +182,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 diff --git a/src/cmd/compile/internal/types2/testdata/builtins.src b/src/cmd/compile/internal/types2/testdata/builtins.src index e473bd1df21..f866ef059f5 100644 --- a/src/cmd/compile/internal/types2/testdata/builtins.src +++ b/src/cmd/compile/internal/types2/testdata/builtins.src @@ -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) diff --git a/src/cmd/compile/internal/types2/testdata/const0.src b/src/cmd/compile/internal/types2/testdata/const0.src index 9e0de93d54f..5608b1549ba 100644 --- a/src/cmd/compile/internal/types2/testdata/const0.src +++ b/src/cmd/compile/internal/types2/testdata/const0.src @@ -350,9 +350,14 @@ const _ = unsafe.Sizeof(func() { }) // untyped constants must not get arbitrarily large -const ( - huge = 1<<1000 - // TODO(gri) here the errors should be at the last operator not the last operand - _ = huge * huge * huge // ERROR constant multiplication overflow - _ = huge << 1000 << 1000 // ERROR constant shift overflow -) +const prec = 512 // internal maximum precision for integers +const maxInt = (1<<(prec/2) - 1) * (1<<(prec/2) + 1) // == 1<