Skip to content

Commit f1ed15b

Browse files
griesemernebulabox
authored andcommitted
go/types: permit signed integer shift count
Permit shifts by non-constant signed integer shift counts. Share logic for constant shift counts in non-constant shifts and improve error messages a little bit. R=Go1.13 Updates golang#19113. Change-Id: Ia01d83ca8aa60a6a3f4c49f026e0c46396f852be Reviewed-on: https://go-review.googlesource.com/c/159317 Run-TryBot: Robert Griesemer <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Alan Donovan <[email protected]>
1 parent 0aac2d9 commit f1ed15b

File tree

5 files changed

+46
-30
lines changed

5 files changed

+46
-30
lines changed

src/go/types/expr.go

+19-18
Original file line numberDiff line numberDiff line change
@@ -655,11 +655,10 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
655655
return
656656
}
657657

658-
// spec: "The right operand in a shift expression must have unsigned
659-
// integer type or be an untyped constant representable by a value of
660-
// type uint."
658+
// spec: "The right operand in a shift expression must have integer type
659+
// or be an untyped constant representable by a value of type uint."
661660
switch {
662-
case isUnsigned(y.typ):
661+
case isInteger(y.typ):
663662
// nothing to do
664663
case isUntyped(y.typ):
665664
check.convertUntyped(y, Typ[Uint])
@@ -668,21 +667,28 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
668667
return
669668
}
670669
default:
671-
check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
670+
check.invalidOp(y.pos(), "shift count %s must be integer", y)
672671
x.mode = invalid
673672
return
674673
}
675674

675+
var yval constant.Value
676+
if y.mode == constant_ {
677+
// rhs must be an integer value
678+
// (Either it was of an integer type already, or it was
679+
// untyped and successfully converted to a uint above.)
680+
yval = constant.ToInt(y.val)
681+
assert(yval.Kind() == constant.Int)
682+
if constant.Sign(yval) < 0 {
683+
check.invalidOp(y.pos(), "negative shift count %s", y)
684+
x.mode = invalid
685+
return
686+
}
687+
}
688+
676689
if x.mode == constant_ {
677690
if y.mode == constant_ {
678-
// rhs must be an integer value
679-
yval := constant.ToInt(y.val)
680-
if yval.Kind() != constant.Int {
681-
check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
682-
x.mode = invalid
683-
return
684-
}
685-
// rhs must be within reasonable bounds
691+
// rhs must be within reasonable bounds in constant shifts
686692
const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64
687693
s, ok := constant.Uint64Val(yval)
688694
if !ok || s > shiftBound {
@@ -741,11 +747,6 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
741747
}
742748
}
743749

744-
// constant rhs must be >= 0
745-
if y.mode == constant_ && constant.Sign(y.val) < 0 {
746-
check.invalidOp(y.pos(), "shift count %s must not be negative", y)
747-
}
748-
749750
// non-constant shift - lhs must be an integer
750751
if !isInteger(x.typ) {
751752
check.invalidOp(x.pos(), "shifted operand %s must be integer", x)

src/go/types/stdlib_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ func TestStdFixed(t *testing.T) {
167167
}
168168

169169
testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
170+
"bug073.go", // checks for unsigned integer shift - disabled for now
170171
"bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
171172
"issue6889.go", // gc-specific test
172173
"issue7746.go", // large constants - consumes too much memory

src/go/types/testdata/decls1.src

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ var (
4343
s11 = &v
4444
s12 = -(u + *t11) / *&v
4545
s13 = a /* ERROR "shifted operand" */ << d
46-
s14 = i << j /* ERROR "must be unsigned" */
46+
s14 = i << j
4747
s18 = math.Pi * 10.0
4848
s19 = s1 /* ERROR "cannot call" */ ()
4949
s20 = f0 /* ERROR "no value" */ ()
@@ -62,7 +62,7 @@ var (
6262
t11 *complex64 = &v
6363
t12 complex64 = -(u + *t11) / *&v
6464
t13 int = a /* ERROR "shifted operand" */ << d
65-
t14 int = i << j /* ERROR "must be unsigned" */
65+
t14 int = i << j
6666
t15 math /* ERROR "not in selector" */
6767
t16 math.xxx /* ERROR "not declared" */
6868
t17 math /* ERROR "not a type" */ .Pi

src/go/types/testdata/expr1.src

+4-4
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ func _(x, y int, z myint) {
3535
x = x * y
3636
x = x / y
3737
x = x % y
38-
x = x << y // ERROR must be unsigned integer
39-
x = x >> y // ERROR must be unsigned integer
38+
x = x << y
39+
x = x >> y
4040

4141
z = z + 1
4242
z = z + 1.0
@@ -46,8 +46,8 @@ func _(x, y int, z myint) {
4646
z = z /* ERROR mismatched types */ * y
4747
z = z /* ERROR mismatched types */ / y
4848
z = z /* ERROR mismatched types */ % y
49-
z = z << y // ERROR must be unsigned integer
50-
z = z >> y // ERROR must be unsigned integer
49+
z = z << y
50+
z = z >> y
5151
}
5252

5353
type myuint uint

src/go/types/testdata/shifts.src

+20-6
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,21 @@ func shifts0() {
1010
s = 10
1111
_ = 0<<0
1212
_ = 1<<s
13-
_ = 1<<- /* ERROR "overflows uint" */ 1
13+
_ = 1<<- /* ERROR "negative shift count" */ 1
14+
// For the test below we may decide to convert to int
15+
// rather than uint and then report a negative shift
16+
// count instead, which might be a better error. The
17+
// (minor) difference is that this would restrict the
18+
// shift count range by half (from all uint values to
19+
// the positive int values).
20+
// This depends on the exact spec wording which is not
21+
// done yet.
22+
// TODO(gri) revisit and adjust when spec change is done
23+
_ = 1<<- /* ERROR "truncated to uint" */ 1.0
1424
_ = 1<<1075 /* ERROR "invalid shift" */
1525
_ = 2.0<<1
26+
_ = 1<<1.0
27+
_ = 1<<(1+0i)
1628

1729
_ int = 2<<s
1830
_ float32 = 2<<s
@@ -35,22 +47,24 @@ func shifts1() {
3547
u uint
3648

3749
_ = 1<<0
38-
_ = 1<<i /* ERROR "must be unsigned" */
50+
_ = 1<<i
3951
_ = 1<<u
4052
_ = 1<<"foo" /* ERROR "cannot convert" */
4153
_ = i<<0
42-
_ = i<<- /* ERROR "overflows uint" */ 1
54+
_ = i<<- /* ERROR "negative shift count" */ 1
55+
_ = i<<1.0
56+
_ = 1<<(1+0i)
4357
_ = 1 /* ERROR "overflows" */ <<100
4458

4559
_ uint = 1 << 0
4660
_ uint = 1 << u
4761
_ float32 = 1 /* ERROR "must be integer" */ << u
4862

4963
// for issue 14822
50-
_ = 1<<( /* ERROR "invalid shift count" */ 1<<63)
51-
_ = 1<<( /* ERROR "overflows uint" */ 1<<64)
64+
_ = 1<<( /* ERROR "invalid shift count" */ 1<<64-1)
65+
_ = 1<<( /* ERROR "invalid shift count" */ 1<<64)
5266
_ = u<<(1<<63) // valid
53-
_ = u<<( /* ERROR "overflows uint" */ 1<<64)
67+
_ = u<<(1<<64) // valid
5468
)
5569
}
5670

0 commit comments

Comments
 (0)