From 778880b00888066212864f95877c0febbebf7e69 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Thu, 5 Oct 2023 11:11:51 +0700 Subject: [PATCH] cmd/compile: fix typecheck range over negative integer Before range over integer, types2 leaves constant expression in RHS of non-constant shift untyped, so idealType do the validation to ensure that constant value must be an int >= 0. With range over int, the range expression can also be left untyped, and can be an negative integer, causing the validation false. Fixing this by relaxing the validation in idealType, and moving the check to Unified IR reader. Fixes #63378 Change-Id: I43042536c09afd98d52c5981adff5dbc5e7d882a Reviewed-on: https://go-review.googlesource.com/c/go/+/532835 Auto-Submit: Cuong Manh Le Reviewed-by: Keith Randall Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall --- src/cmd/compile/internal/noder/helpers.go | 9 +++++---- src/cmd/compile/internal/noder/reader.go | 7 +++++++ test/range3.go | 9 +++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go index 117abe603d..1f7b497599 100644 --- a/src/cmd/compile/internal/noder/helpers.go +++ b/src/cmd/compile/internal/noder/helpers.go @@ -87,13 +87,14 @@ func idealType(tv syntax.TypeAndValue) types2.Type { // ok; can appear in type switch case clauses // TODO(mdempsky): Handle as part of type switches instead? case types2.UntypedInt, types2.UntypedFloat, types2.UntypedComplex: - // Untyped rhs of non-constant shift, e.g. x << 1.0. - // If we have a constant value, it must be an int >= 0. + typ = types2.Typ[types2.Uint] if tv.Value != nil { s := constant.ToInt(tv.Value) - assert(s.Kind() == constant.Int && constant.Sign(s) >= 0) + assert(s.Kind() == constant.Int) + if constant.Sign(s) < 0 { + typ = types2.Typ[types2.Int] + } } - typ = types2.Typ[types2.Uint] case types2.UntypedBool: typ = types2.Typ[types2.Bool] // expression in "if" or "for" condition case types2.UntypedString: diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 1c0d0a9acc..3cd7b7c683 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -2233,6 +2233,13 @@ func (r *reader) expr() (res ir.Node) { switch op { case ir.OANDAND, ir.OOROR: return typecheck.Expr(ir.NewLogicalExpr(pos, op, x, y)) + case ir.OLSH, ir.ORSH: + // Untyped rhs of non-constant shift, e.g. x << 1.0. + // If we have a constant value, it must be an int >= 0. + if ir.IsConstNode(y) { + val := constant.ToInt(y.Val()) + assert(val.Kind() == constant.Int && constant.Sign(val) >= 0) + } } return typecheck.Expr(ir.NewBinaryExpr(pos, op, x, y)) diff --git a/test/range3.go b/test/range3.go index 613d7a53f6..51ed2eeb78 100644 --- a/test/range3.go +++ b/test/range3.go @@ -68,6 +68,14 @@ func testint3() { } } +// Issue #63378. +func testint4() { + for i := range -1 { + _ = i + panic("must not be executed") + } +} + // test range over functions var gj int @@ -377,6 +385,7 @@ func main() { testint1() testint2() testint3() + testint4() testfunc0() testfunc1() testfunc2()