]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: remove implicit deref from len(p) where p is ptr-to-array
authorKeith Randall <khr@golang.org>
Fri, 14 Mar 2025 20:19:18 +0000 (13:19 -0700)
committerKeith Randall <khr@golang.org>
Wed, 19 Mar 2025 16:55:46 +0000 (09:55 -0700)
func f() *[4]int { return nil }
_ = len(f())

should not panic. We evaluate f, but there isn't a dereference
according to the spec (just "arg is evaluated").

Update #72844

Change-Id: Ia32cefc1b7aa091cd1c13016e015842b4d12d5b4
Reviewed-on: https://go-review.googlesource.com/c/go/+/658096
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Keith Randall <khr@google.com>
src/cmd/compile/internal/typecheck/expr.go
test/fixedbugs/issue72844.go [new file with mode: 0644]

index 2eec8d41ad18567f1fa0b4a1cb8dd802f83166c2..44a69f03320efd74605dcff119b5cd1d665346ae 100644 (file)
@@ -634,16 +634,16 @@ func tcIndex(n *ir.IndexExpr) ir.Node {
 func tcLenCap(n *ir.UnaryExpr) ir.Node {
        n.X = Expr(n.X)
        n.X = DefaultLit(n.X, nil)
-       n.X = implicitstar(n.X)
        l := n.X
        t := l.Type()
        if t == nil {
                n.SetType(nil)
                return n
        }
-
        var ok bool
-       if n.Op() == ir.OLEN {
+       if t.IsPtr() && t.Elem().IsArray() {
+               ok = true
+       } else if n.Op() == ir.OLEN {
                ok = okforlen[t.Kind()]
        } else {
                ok = okforcap[t.Kind()]
diff --git a/test/fixedbugs/issue72844.go b/test/fixedbugs/issue72844.go
new file mode 100644 (file)
index 0000000..0322841
--- /dev/null
@@ -0,0 +1,70 @@
+// run
+
+// Copyright 2025 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 main
+
+//go:noinline
+func nilPtrFunc() *[4]int {
+       return nil
+}
+
+var nilPtrVar *[4]int
+
+func testLen1() {
+       _ = len(*nilPtrFunc())
+}
+
+func testLen2() {
+       _ = len(nilPtrFunc())
+}
+
+func testLen3() {
+       _ = len(*nilPtrVar)
+}
+
+func testLen4() {
+       _ = len(nilPtrVar)
+}
+
+func testRange1() {
+       for range *nilPtrFunc() {
+       }
+}
+func testRange2() {
+       for range nilPtrFunc() {
+       }
+}
+func testRange3() {
+       for range *nilPtrVar {
+       }
+}
+func testRange4() {
+       for range nilPtrVar {
+       }
+}
+
+func main() {
+       //shouldPanic(testLen1)
+       shouldNotPanic(testLen2)
+       shouldNotPanic(testLen3)
+       shouldNotPanic(testLen4)
+       //shouldPanic(testRange1)
+       shouldNotPanic(testRange2)
+       shouldNotPanic(testRange3)
+       shouldNotPanic(testRange4)
+}
+
+func shouldPanic(f func()) {
+       defer func() {
+               if e := recover(); e == nil {
+                       panic("should have panicked")
+               }
+       }()
+       f()
+}
+func shouldNotPanic(f func()) {
+       f()
+}