cmd/compile: treat all zero-sized values as SSA-able

Might as well, we don't need any registers for such values.

Fixes #77635

Change-Id: Iedc1bc3f13662b043b183228bcc1dc4e6c91da81
Reviewed-on: https://go-review.googlesource.com/c/go/+/747780
Reviewed-by: Junyang Shao <shaojunyang@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
khr@golang.org
2026-02-20 12:04:35 -08:00
committed by Keith Randall
parent b48b2002fe
commit 0886e65b11
4 changed files with 106 additions and 2 deletions

View File

@@ -616,6 +616,9 @@ func CanSSA(t *types.Type) bool {
if t.IsSIMD() {
return true
}
if t.Size() == 0 {
return true
}
sizeLimit := int64(MaxStruct * types.PtrSize)
if t.Size() > sizeLimit {
// 4*Widthptr is an arbitrary constant. We want it

View File

@@ -4529,7 +4529,15 @@ func (s *state) assignWhichMayOverlap(left ir.Node, right *ssa.Value, deref bool
return
}
if n != 1 {
s.Fatalf("assigning to non-1-length array")
// This can happen in weird, always-panics cases, like:
// var x [0][2]int
// x[i][j] = 5
// We know it always panics because the LHS is ssa-able,
// and arrays of length > 1 can't be ssa-able unless
// they are somewhere inside an outer [0].
// We can ignore the actual assignment, it is dynamically
// unreachable. See issue 77635.
return
}
if t.Size() == 0 {
return
@@ -5223,7 +5231,15 @@ func (s *state) addr(n ir.Node) *ssa.Value {
}
if s.canSSA(n) {
s.Fatalf("addr of canSSA expression: %+v", n)
// This happens in weird, always-panics cases, like:
// var x [0][2]int
// x[i][j] = 5
// The outer assignment, ...[j] = 5, is a fine
// assignment to do, but requires computing the address
// &x[i], which will always panic when evaluated.
// We just return something reasonable in this case.
// It will be dynamically unreachable. See issue 77635.
return s.newValue1A(ssa.OpAddr, n.Type().PtrTo(), ir.Syms.Zerobase, s.sb)
}
t := types.NewPtr(n.Type())

View File

@@ -0,0 +1,23 @@
// compile
// Copyright 2026 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.
// Issue 77635: test building values of zero-sized types.
package main
import "reflect"
func F[T interface{ [2][0]int }](x T) bool {
return reflect.DeepEqual(struct {
t T
c chan int
}{t: x}, 1)
}
func main() {
var t [2][0]int
F(t)
}

View File

@@ -0,0 +1,62 @@
// compile
// Copyright 2026 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.
// Issue 77635: test building values of zero-sized types.
package p
type T1 [2][0]int
type T2 [0][2]int
type T3 struct {
t T1
x *byte
}
type T4 struct {
t T2
x *byte
}
func f1(t T1) any {
return t
}
func f2(t T2) any {
return t
}
func f3(t T3) any {
return t
}
func f4(t T4) any {
return t
}
func f5(t T1) any {
return T3{t:t}
}
func f6(t T2) any {
return T4{t:t}
}
func f7(t T1) {
use(T3{t:t})
}
func f8(t T2) {
use(T4{t:t})
}
func g1(t T3, i int) {
t.t[i][i] = 1
}
func g2(t T4, i int) {
t.t[i][i] = 1
}
func g3(t *T3, i int) {
t.t[i][i] = 1
}
func g4(t *T4, i int) {
t.t[i][i] = 1
}
//go:noinline
func use(x any) {
}