Skip to content

Commit fa4dada

Browse files
cmd/compile: prevent pointer shaping of array pointer shape types
CL 704095 added an exception in shapify to prevent pointer shaping of `*[]go.shape.T`, which would lose the original type by converting it to `*go.shape.uint8`. However, there is another edge case when the type argument is itself already a shape type (e.g., go.shape.*[1]uint8). This happens when a shaped pointer type from an outer generic function is used to instantiate an inner generic function with a basic interface constraint. In this case, pointer shaping converts `go.shape.*[1]uint8` to `go.shape.*uint8`, losing the array element type. Subsequent slice operations then fail with "bad ptr to array in slice" because uint8 is not an array type. This commit adds an exception to skip pointer shaping when the type argument is a pointer shape type whose element is an array, preserving the array type information needed for slice operations. Fixes #78297
1 parent c58d075 commit fa4dada

2 files changed

Lines changed: 75 additions & 0 deletions

File tree

src/cmd/compile/internal/noder/reader.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,16 @@ func shapify(targ *types.Type, basic bool) *types.Type {
941941
if pointerShaping && !targ.Elem().IsShape() && targ.Elem().HasShape() {
942942
return targ
943943
}
944+
// Another exception is when targ is a pointer shape type whose element
945+
// is an array (e.g., go.shape.*[1]uint8). This happens when a shaped
946+
// pointer type from an outer generic function is used to instantiate an
947+
// inner generic function with a basic constraint. Pointer-shaping would
948+
// change the element type (e.g., *[1]uint8 -> *uint8), losing the array
949+
// type needed for slice operations.
950+
// See issue #78297.
951+
if pointerShaping && targ.IsShape() && targ.Elem().IsArray() {
952+
return targ
953+
}
944954
under := targ.Underlying()
945955
if pointerShaping {
946956
under = types.NewPtr(types.Types[types.TUINT8])
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
go build main.go
2+
! stdout .
3+
! stderr .
4+
5+
go build variants.go
6+
! stdout .
7+
! stderr .
8+
9+
go build normalshaping.go
10+
! stdout .
11+
! stderr .
12+
13+
-- main.go --
14+
package main
15+
16+
func Z[U any]() (z U) { return }
17+
18+
func F[T ~*[1]byte]() {
19+
_ = Z[T]()[:]
20+
}
21+
22+
var _ = F[*[1]byte]
23+
24+
func main() {}
25+
26+
-- variants.go --
27+
package main
28+
29+
func identity[U any]() (z U) { return }
30+
31+
func sliceArrayPtr2[T ~*[2]byte]() {
32+
_ = identity[T]()[:]
33+
}
34+
35+
func sliceArrayPtrInt[T ~*[1]int]() {
36+
_ = identity[T]()[:]
37+
}
38+
39+
func sliceArrayPtrLarge[T ~*[100]byte]() {
40+
_ = identity[T]()[:]
41+
}
42+
43+
var _ = sliceArrayPtr2[*[2]byte]
44+
var _ = sliceArrayPtrInt[*[1]int]
45+
var _ = sliceArrayPtrLarge[*[100]byte]
46+
47+
func main() {}
48+
49+
-- normalshaping.go --
50+
package main
51+
52+
func echo[U any]() (z U) { return }
53+
54+
func usePtr[T ~*int]() {
55+
_ = echo[T]()
56+
}
57+
58+
func useBasic[T ~int]() {
59+
_ = echo[T]()
60+
}
61+
62+
var _ = usePtr[*int]
63+
var _ = useBasic[int]
64+
65+
func main() {}

0 commit comments

Comments
 (0)