// run // 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 81266: check that we generate correct code when // using the subroutine mechanism in the equality/hash generator. package main import ( "fmt" "unsafe" ) func check(name string, got, want bool) { if got != want { panic(fmt.Sprintf("%s: got %v want %v", name, got, want)) } } // Big is large enough for subroutine treatment, and has trailing padding. type Big struct { Filler [2000]byte S string B byte } // Outer embeds Big as a non-top-level field, and has a field after // it. There is padding between the two fields. type Outer struct { Big Big X byte } // fill sets every byte of the size bytes at p to b. Used to poison // padding bytes with garbage, so that tests which pass despite // differing padding prove the padding is correctly ignored. func fill(p unsafe.Pointer, size uintptr, b byte) { buf := unsafe.Slice((*byte)(p), size) for i := range buf { buf[i] = b } } var filler [2000]byte func init() { for i := range filler { filler[i] = byte(i) } } func mkBig(s string, b byte, pad byte) Big { var x Big fill(unsafe.Pointer(&x), unsafe.Sizeof(x), pad) x.Filler = filler x.S = s x.B = b return x } func testBasic() { a := Outer{Big: mkBig("foo", 7, 0xAA), X: 1} c := Outer{Big: mkBig("foo", 7, 0x55), X: 1} check("equal despite differing padding inside Big", a == c, true) d := Outer{Big: mkBig("foo", 7, 0xAA), X: 2} check("differ in trailing field X", a == d, false) e := Outer{Big: mkBig("bar", 7, 0xAA), X: 1} check("differ in Big.S", a == e, false) g := Outer{Big: mkBig("foo", 9, 0xAA), X: 1} check("differ in Big.B", a == g, false) h := a h.Big.Filler[1000] ^= 0xFF check("differ in Big.Filler", a == h, false) } // testPadding makes sure different paddings don't prevent equality. func testPadding() { var a, c Outer fill(unsafe.Pointer(&a), unsafe.Sizeof(a), 0x11) fill(unsafe.Pointer(&c), unsafe.Sizeof(c), 0x99) a.Big.Filler = filler c.Big.Filler = filler a.Big.S = "padding-check" c.Big.S = "padding-check" a.Big.B = 42 c.Big.B = 42 a.X = 5 c.X = 5 check("equal with garbage-filled padding", a == c, true) } // testHash exercises the hash side of the subroutine mechanism. func testHash() { m := make(map[Outer]int) k1 := Outer{Big: mkBig("k1", 1, 0), X: 1} k2 := Outer{Big: mkBig("k2", 2, 0), X: 2} m[k1] = 100 m[k2] = 200 look1 := Outer{Big: mkBig("k1", 1, 0xFF), X: 1} // differing padding look2 := Outer{Big: mkBig("k2", 2, 0xFF), X: 2} v1, ok1 := m[look1] v2, ok2 := m[look2] check("map lookup k1 found", ok1, true) check("map lookup k2 found", ok2, true) if v1 != 100 { panic(fmt.Sprintf("map k1 value: got %v want 100", v1)) } if v2 != 200 { panic(fmt.Sprintf("map k2 value: got %v want 200", v2)) } notFound := Outer{Big: mkBig("k1", 1, 0), X: 99} _, ok3 := m[notFound] check("map lookup miss", ok3, false) } // testNested exercises two levels of subroutine nesting // (Outer2 -> Level1 -> Big). func testNested() { // Level1 embeds Big, so it becomes a subroutine when embedded // in Outer2. This produces two levels of subroutine nesting. type Level1 struct { B Big F2 [2000]byte T string C byte } type Outer2 struct { L1 Level1 Y byte } mkLevel1 := func(s1, s2 string, b1, b2 byte) Level1 { var l Level1 l.B = mkBig(s1, b1, 0) l.F2 = filler l.T = s2 l.C = b2 return l } a := Outer2{L1: mkLevel1("inner1", "outer1", 1, 2), Y: 9} c := Outer2{L1: mkLevel1("inner1", "outer1", 1, 2), Y: 9} check("nested equal", a == c, true) d := a d.L1.B.S = "changed" check("nested differ in deepest field", a == d, false) e := a e.L1.T = "changed" check("nested differ in Level1 field", a == e, false) g := a g.Y = 10 check("nested differ in outer field", a == g, false) mm := make(map[Outer2]string) mm[a] = "a-value" if got := mm[c]; got != "a-value" { panic(fmt.Sprintf("nested map lookup: got %q want %q", got, "a-value")) } } // testArray exercises an array of large elements, each of which uses // the subroutine mechanism. func testArray() { type BigArr struct { A [3]Big } var a, c BigArr for i := range a.A { a.A[i] = mkBig(fmt.Sprintf("elem%d", i), byte(i), byte(i)) c.A[i] = mkBig(fmt.Sprintf("elem%d", i), byte(i), byte(i+100)) // different padding } check("array equal despite differing padding", a == c, true) d := a d.A[2].S = "different" check("array differ in one element", a == d, false) } // testBoundary checks types right at the maxExpandSize (1024) cutoff, // on both sides. func testBoundary() { type Exactly1024 struct { F [1024 - 16]byte // + string(16) = 1024 exactly, on a 64-bit platform S string } type Container1024 struct { V Exactly1024 X byte } var a, c Container1024 a.V.S = "same" c.V.S = "same" a.X = 1 c.X = 1 check("boundary <=1024 equal", a == c, true) d := a d.V.S = "diff" check("boundary <=1024 differ", a == d, false) type Exactly1025 struct { F [1025 - 16]byte S string } type Container1025 struct { V Exactly1025 X byte } var e, g Container1025 e.V.S = "same" g.V.S = "same" e.X = 1 g.X = 1 check("boundary >1024 equal", e == g, true) h := e h.V.S = "diff" check("boundary >1024 differ", e == h, false) } func main() { testBasic() testPadding() testHash() testNested() testArray() testBoundary() }