From 33a9a98e4d5893699749f75334c651b2adcecfb9 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 5 Feb 2016 15:23:47 -0800 Subject: [PATCH] go/types: make sure constants valid in integer operations are in integer form The operation where this manifested in a crash was % (only defined on integers). However, the existing code was sloppy in that it didn't retain the integer form after a value (e.g., 3.0) was accepted as representable in integer form (3 for the example). We would have seen a crash in such cases for / as well except that there was code to fix it for just that case. Remove the special code for / and fix more generally by retaining the integer form for all operations if applicable. Fixes #14229. Change-Id: I8bef769e6299839fade27c6e8b5ff29ad6521d0d Reviewed-on: https://go-review.googlesource.com/19300 Reviewed-by: Alan Donovan --- src/go/types/expr.go | 8 +++++--- src/go/types/testdata/issues.src | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 942d3fd5f7..f7c4a17378 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -184,7 +184,8 @@ func roundFloat64(x constant.Value) constant.Value { // provided (only needed for int/uint sizes). // // If rounded != nil, *rounded is set to the rounded value of x for -// representable floating-point values; it is left alone otherwise. +// representable floating-point and complex values, and to an Int +// value for integer values; it is left alone otherwise. // It is ok to provide the addressof the first argument for rounded. func representableConst(x constant.Value, conf *Config, typ *Basic, rounded *constant.Value) bool { if x.Kind() == constant.Unknown { @@ -197,6 +198,9 @@ func representableConst(x constant.Value, conf *Config, typ *Basic, rounded *con if x.Kind() != constant.Int { return false } + if rounded != nil { + *rounded = x + } if x, ok := constant.Int64Val(x); ok { switch typ.kind { case Int: @@ -808,8 +812,6 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o typ := x.typ.Underlying().(*Basic) // force integer division of integer operands if op == token.QUO && isInteger(typ) { - xval = constant.ToInt(xval) - yval = constant.ToInt(yval) op = token.QUO_ASSIGN } x.val = constant.BinaryOp(xval, op, yval) diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src index 564d0649b2..4fe0c62938 100644 --- a/src/go/types/testdata/issues.src +++ b/src/go/types/testdata/issues.src @@ -153,3 +153,20 @@ func issue10260() { make(chan I1) <- i0 /* ERROR cannot use .* in send: missing method foo */ make(chan I1) <- i2 /* ERROR cannot use .* in send: wrong type for method foo */ } + +// Check that constants representable as integers are in integer form +// before being used in operations that are only defined on integers. +func issue14229() { + // from the issue + const _ = int64(-1<<63) % 1e6 + + // related + const ( + a int = 3 + b = 4.0 + _ = a / b + _ = a % b + _ = b / a + _ = b % a + ) +} -- 2.50.0