go/types: don't report errors for untyped int shifts on Go < 1.13

CL 337529 introduced upfront type-checking of constant shift operands,
to avoid converting their type to uint (per the spec). However, it
had an oversight in that the checks intended for non-constant operands
still ran after the explicit checking of constant operands. As a
result, there are at least two bugs:
 - When GoVersion is < 1.13, we report spurious errors for untyped
   constant shift operands.
 - When the operand is an untyped float constant, we still convert to
   uint (this was a known bug reported in #47410).

Looking at this now, it seems clear that we can avoid both of these bugs
by simply not running the additional checks in the case of a constant
operand. However, this should be considered with some care, as shifts
are notoriously tricky.

Updates #47410
Fixes #52031

Change-Id: Ia489cc5470b92a8187d3de0423d05b309daf47bb
Reviewed-on: https://go-review.googlesource.com/c/go/+/396775
Reviewed-by: Robert Griesemer <gri@golang.org>
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Robert Findley 2022-03-30 09:56:13 -04:00
parent f8e70fc9a6
commit 8a816d5efc
4 changed files with 58 additions and 20 deletions

View File

@ -330,7 +330,7 @@ func TestTypesInfo(t *testing.T) {
// 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_b; var x int32; var _ = x << 3.`, `3.`, `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`},

View File

@ -235,6 +235,11 @@ func testFiles(t *testing.T, sizes Sizes, filenames []string, srcs [][]byte, man
t.Fatal(err)
}
if manual && *goVersion != "" {
// goVersion overrides -lang for manual tests.
conf.GoVersion = *goVersion
}
// TODO(gri) remove this or use flag mechanism to set mode if still needed
if strings.HasSuffix(filenames[0], ".go1") {
// TODO(rfindley): re-enable this test by using GoVersion.

View File

@ -934,28 +934,28 @@ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) {
return
}
}
}
// Check that RHS is otherwise at least of integer type.
switch {
case allInteger(y.typ):
if !allUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y)
} else {
// Check that RHS is otherwise at least of integer type.
switch {
case allInteger(y.typ):
if !allUnsigned(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
}
default:
check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", 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
}
default:
check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", y)
x.mode = invalid
return
}
if x.mode == constant_ {

View File

@ -0,0 +1,33 @@
// -lang=go1.12
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p
type resultFlags uint
// Example from #52031.
//
// The following shifts should not produce errors on Go < 1.13, as their
// untyped constant operands are representable by type uint.
const (
_ resultFlags = (1 << iota) / 2
reportEqual
reportUnequal
reportByIgnore
reportByMethod
reportByFunc
reportByCycle
)
// Invalid cases.
var x int = 1
var _ = (8 << x /* ERROR "signed shift count .* requires go1.13 or later" */)
const _ = (1 << 1.2 /* ERROR "truncated to uint" */)
var y float64
var _ = (1 << y /* ERROR "must be integer" */)