Skip to content

Commit 82c3f0a

Browse files
committed
[dev.typeparams] cmd/compile/internal/types2: untyped shift counts must fit into uint
Updates #43697. Change-Id: If94658cb798bb0434ac3ebbf9dff504dcd59a02a Reviewed-on: https://go-review.googlesource.com/c/go/+/283872 Trust: Robert Griesemer <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent 67bf62d commit 82c3f0a

File tree

2 files changed

+26
-28
lines changed

2 files changed

+26
-28
lines changed

src/cmd/compile/internal/types2/expr.go

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -770,14 +770,14 @@ func (check *Checker) comparison(x, y *operand, op syntax.Operator) {
770770
}
771771

772772
func (check *Checker) shift(x, y *operand, e *syntax.Operation, op syntax.Operator) {
773-
untypedx := isUntyped(x.typ)
773+
// TODO(gri) This function seems overly complex. Revisit.
774774

775775
var xval constant.Value
776776
if x.mode == constant_ {
777777
xval = constant.ToInt(x.val)
778778
}
779779

780-
if isInteger(x.typ) || untypedx && xval != nil && xval.Kind() == constant.Int {
780+
if isInteger(x.typ) || isUntyped(x.typ) && xval != nil && xval.Kind() == constant.Int {
781781
// The lhs is of integer type or an untyped constant representable
782782
// as an integer. Nothing to do.
783783
} else {
@@ -789,40 +789,36 @@ func (check *Checker) shift(x, y *operand, e *syntax.Operation, op syntax.Operat
789789

790790
// spec: "The right operand in a shift expression must have integer type
791791
// or be an untyped constant representable by a value of type uint."
792-
switch {
793-
case isInteger(y.typ):
794-
// nothing to do
795-
case isUntyped(y.typ):
796-
check.convertUntyped(y, Typ[Uint])
797-
if y.mode == invalid {
792+
793+
// Provide a good error message for negative shift counts.
794+
if y.mode == constant_ {
795+
yval := constant.ToInt(y.val) // consider -1, 1.0, but not -1.1
796+
if yval.Kind() == constant.Int && constant.Sign(yval) < 0 {
797+
check.invalidOpf(y, "negative shift count %s", y)
798798
x.mode = invalid
799799
return
800800
}
801-
default:
802-
check.invalidOpf(y, "shift count %s must be integer", y)
803-
x.mode = invalid
804-
return
805801
}
806802

807-
var yval constant.Value
808-
if y.mode == constant_ {
809-
// rhs must be an integer value
810-
// (Either it was of an integer type already, or it was
811-
// untyped and successfully converted to a uint above.)
812-
yval = constant.ToInt(y.val)
813-
assert(yval.Kind() == constant.Int)
814-
if constant.Sign(yval) < 0 {
815-
check.invalidOpf(y, "negative shift count %s", y)
803+
// Caution: Check for isUntyped first because isInteger includes untyped
804+
// integers (was bug #43697).
805+
if isUntyped(y.typ) {
806+
check.convertUntyped(y, Typ[Uint])
807+
if y.mode == invalid {
816808
x.mode = invalid
817809
return
818810
}
811+
} else if !isInteger(y.typ) {
812+
check.invalidOpf(y, "shift count %s must be integer", y)
813+
x.mode = invalid
814+
return
819815
}
820816

821817
if x.mode == constant_ {
822818
if y.mode == constant_ {
823819
// rhs must be within reasonable bounds in constant shifts
824820
const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64
825-
s, ok := constant.Uint64Val(yval)
821+
s, ok := constant.Uint64Val(y.val)
826822
if !ok || s > shiftBound {
827823
check.invalidOpf(y, "invalid shift count %s", y)
828824
x.mode = invalid
@@ -849,7 +845,7 @@ func (check *Checker) shift(x, y *operand, e *syntax.Operation, op syntax.Operat
849845
}
850846

851847
// non-constant shift with constant lhs
852-
if untypedx {
848+
if isUntyped(x.typ) {
853849
// spec: "If the left operand of a non-constant shift
854850
// expression is an untyped constant, the type of the
855851
// constant is what it would be if the shift expression

src/cmd/compile/internal/types2/testdata/shifts.src

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func shifts0() {
2020
// This depends on the exact spec wording which is not
2121
// done yet.
2222
// TODO(gri) revisit and adjust when spec change is done
23-
_ = 1<<- /* ERROR "truncated to uint" */ 1.0
23+
_ = 1<<- /* ERROR "negative shift count" */ 1.0
2424
_ = 1<<1075 /* ERROR "invalid shift" */
2525
_ = 2.0<<1
2626
_ = 1<<1.0
@@ -60,11 +60,13 @@ func shifts1() {
6060
_ uint = 1 << u
6161
_ float32 = 1 /* ERROR "must be integer" */ << u
6262

63-
// for issue 14822
63+
// issue #14822
64+
_ = 1<<( /* ERROR "overflows uint" */ 1<<64)
6465
_ = 1<<( /* ERROR "invalid shift count" */ 1<<64-1)
65-
_ = 1<<( /* ERROR "invalid shift count" */ 1<<64)
66-
_ = u<<(1<<63) // valid
67-
_ = u<<(1<<64) // valid
66+
67+
// issue #43697
68+
_ = u<<( /* ERROR "overflows uint" */ 1<<64)
69+
_ = u<<(1<<64-1)
6870
)
6971
}
7072

0 commit comments

Comments
 (0)