Commit 33a9a98e authored by Robert Griesemer's avatar Robert Griesemer

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/19300Reviewed-by: default avatarAlan Donovan <adonovan@google.com>
parent fa5e5478
...@@ -184,7 +184,8 @@ func roundFloat64(x constant.Value) constant.Value { ...@@ -184,7 +184,8 @@ func roundFloat64(x constant.Value) constant.Value {
// provided (only needed for int/uint sizes). // provided (only needed for int/uint sizes).
// //
// If rounded != nil, *rounded is set to the rounded value of x for // 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. // 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 { func representableConst(x constant.Value, conf *Config, typ *Basic, rounded *constant.Value) bool {
if x.Kind() == constant.Unknown { if x.Kind() == constant.Unknown {
...@@ -197,6 +198,9 @@ func representableConst(x constant.Value, conf *Config, typ *Basic, rounded *con ...@@ -197,6 +198,9 @@ func representableConst(x constant.Value, conf *Config, typ *Basic, rounded *con
if x.Kind() != constant.Int { if x.Kind() != constant.Int {
return false return false
} }
if rounded != nil {
*rounded = x
}
if x, ok := constant.Int64Val(x); ok { if x, ok := constant.Int64Val(x); ok {
switch typ.kind { switch typ.kind {
case Int: case Int:
...@@ -808,8 +812,6 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o ...@@ -808,8 +812,6 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o
typ := x.typ.Underlying().(*Basic) typ := x.typ.Underlying().(*Basic)
// force integer division of integer operands // force integer division of integer operands
if op == token.QUO && isInteger(typ) { if op == token.QUO && isInteger(typ) {
xval = constant.ToInt(xval)
yval = constant.ToInt(yval)
op = token.QUO_ASSIGN op = token.QUO_ASSIGN
} }
x.val = constant.BinaryOp(xval, op, yval) x.val = constant.BinaryOp(xval, op, yval)
......
...@@ -153,3 +153,20 @@ func issue10260() { ...@@ -153,3 +153,20 @@ func issue10260() {
make(chan I1) <- i0 /* ERROR cannot use .* in send: missing method foo */ 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 */ 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
)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment