]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types: preserve untyped constants on the RHS of a shift expression
authorRob Findley <rfindley@google.com>
Mon, 26 Jul 2021 20:33:44 +0000 (16:33 -0400)
committerRobert Findley <rfindley@google.com>
Tue, 27 Jul 2021 00:15:55 +0000 (00:15 +0000)
CL 291316 fixed go/types to verify that untyped shift counts are
representable by uint, but as a side effect also converted their types
to uint.

Rearrange the logic to keep the check for representability, but not
actually convert untyped integer constants. Untyped non-integer
constants are still converted, to preserve the behavior of 1.16. This
behavior for non-integer types is a bug, filed as #47410.

Updates #47410
Fixes #47243

Change-Id: I5eab4aab35b97f932fccdee2d4a18623ee2ccad5
Reviewed-on: https://go-review.googlesource.com/c/go/+/337529
Trust: Robert Findley <rfindley@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/go/types/api_test.go
src/go/types/check_test.go
src/go/types/expr.go

index f37b91d5a4eba5f6fae7ebe26b5bb3415e4fa9d7..f964c656f93f9dc97cfdf3ae8ac4e80c93aaced5 100644 (file)
@@ -322,6 +322,18 @@ func TestTypesInfo(t *testing.T) {
                        `[][]struct{}`,
                },
 
+               // issue 47243
+               {`package issue47243_a; var x int32; var _ = x << 3`, `3`, `untyped int`},
+               {`package issue47243_b; var x int32; var _ = x << 3.`, `3.`, `uint`}, // issue 47410: should be untyped float
+               {`package issue47243_c; var x int32; var _ = 1 << x`, `1 << x`, `int`},
+               {`package issue47243_d; var x int32; var _ = 1 << x`, `1`, `int`},
+               {`package issue47243_e; var x int32; var _ = 1 << 2`, `1`, `untyped int`},
+               {`package issue47243_f; var x int32; var _ = 1 << 2`, `2`, `untyped int`},
+               {`package issue47243_g; var x int32; var _ = int(1) << 2`, `2`, `untyped int`},
+               {`package issue47243_h; var x int32; var _ = 1 << (2 << x)`, `1`, `int`},
+               {`package issue47243_i; var x int32; var _ = 1 << (2 << x)`, `(2 << x)`, `untyped int`},
+               {`package issue47243_j; var x int32; var _ = 1 << (2 << x)`, `2`, `untyped int`},
+
                // tests for broken code that doesn't parse or type-check
                {broken + `x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
                {broken + `x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
index c85a8e46fbb6f9fb01f29f915641d9dcdfaf9632..f83abf11ce2e22623cb1ff266ec0b2c4a2f6557f 100644 (file)
@@ -344,6 +344,13 @@ func TestIssue46453(t *testing.T) {
        checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false, nil)
 }
 
+func TestIssue47243_TypedRHS(t *testing.T) {
+       // The RHS of the shift expression below overflows uint on 32bit platforms,
+       // but this is OK as it is explicitly typed.
+       const src = "package issue47243\n\nvar a uint64; var _ = a << uint64(4294967296)" // uint64(1<<32)
+       checkFiles(t, &StdSizes{4, 4}, "", []string{"p.go"}, [][]byte{[]byte(src)}, false, nil)
+}
+
 func TestCheck(t *testing.T)     { DefPredeclaredTestFuncs(); testDir(t, "check") }
 func TestExamples(t *testing.T)  { testDir(t, "examples") }
 func TestFixedbugs(t *testing.T) { testDir(t, "fixedbugs") }
index 5c65fad44799897e0f4c807d6cdff51ee4f50bce..58962e777bc9541ec549a0c0de0035187f0331ac 100644 (file)
@@ -778,32 +778,48 @@ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) {
        // spec: "The right operand in a shift expression must have integer type
        // or be an untyped constant representable by a value of type uint."
 
-       // Provide a good error message for negative shift counts.
+       // Check that constants are representable by uint, but do not convert them
+       // (see also issue #47243).
        if y.mode == constant_ {
+               // Provide a good error message for negative shift counts.
                yval := constant.ToInt(y.val) // consider -1, 1.0, but not -1.1
                if yval.Kind() == constant.Int && constant.Sign(yval) < 0 {
                        check.invalidOp(y, _InvalidShiftCount, "negative shift count %s", y)
                        x.mode = invalid
                        return
                }
+
+               if isUntyped(y.typ) {
+                       // Caution: Check for representability here, rather than in the switch
+                       // below, because isInteger includes untyped integers (was bug #43697).
+                       check.representable(y, Typ[Uint])
+                       if y.mode == invalid {
+                               x.mode = invalid
+                               return
+                       }
+               }
        }
 
-       // Caution: Check for isUntyped first because isInteger includes untyped
-       //          integers (was bug #43697).
-       if isUntyped(y.typ) {
+       // Check that RHS is otherwise at least of integer type.
+       switch {
+       case isInteger(y.typ):
+               if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
+                       check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y)
+                       x.mode = invalid
+                       return
+               }
+       case isUntyped(y.typ):
+               // This is incorrect, but preserves pre-existing behavior.
+               // See also bug #47410.
                check.convertUntyped(y, Typ[Uint])
                if y.mode == invalid {
                        x.mode = invalid
                        return
                }
-       } else if !isInteger(y.typ) {
+       default:
                check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", y)
                x.mode = invalid
                return
-       } else if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
-               check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y)
-               x.mode = invalid
-               return
        }
 
        if x.mode == constant_ {