diff --git a/ssa/type.go b/ssa/type.go index e9f3aab4f2..506aa76536 100644 --- a/ssa/type.go +++ b/ssa/type.go @@ -388,8 +388,10 @@ func (p Program) toType(raw types.Type) Type { return &aType{p.tyVoidPtr(), typ, vkPtr} } case *types.Pointer: - elem := p.rawType(t.Elem()) - return &aType{llvm.PointerType(elem.ll, 0), typ, vkPtr} + // LLVM pointers are opaque, so the element LLVM type is not needed here. + // Avoid expanding it eagerly: legal Go recursive types often close their + // cycle through a pointer. + return &aType{p.tyVoidPtr(), typ, vkPtr} case *types.Interface: if t.Empty() { return &aType{p.rtEface(), typ, vkEface} diff --git a/ssa/type_patch_test.go b/ssa/type_patch_test.go index 93b25371c5..cf8b33b98e 100644 --- a/ssa/type_patch_test.go +++ b/ssa/type_patch_test.go @@ -119,6 +119,29 @@ func TestToLLVMFuncPtrUsesVoidPtr(t *testing.T) { } } +func TestPointerTypeDoesNotExpandRecursiveNamedElement(t *testing.T) { + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, "recursive.go", `package p + +type T18 *[10]T19 +type T19 T18 +`, 0) + if err != nil { + t.Fatal(err) + } + pkg := types.NewPackage("example.com/p", "p") + if err := types.NewChecker(&types.Config{}, fset, pkg, nil).Files([]*ast.File{f}); err != nil { + t.Fatal(err) + } + + prog := NewProgram(nil) + prog.TypeSizes(types.SizesFor("gc", runtime.GOARCH)) + t18 := pkg.Scope().Lookup("T18").Type() + if got, want := prog.Type(t18, InGo).ll.String(), prog.tyVoidPtr().String(); got != want { + t.Fatalf("recursive named pointer LLVM type = %q, want %q", got, want) + } +} + func TestNamedStructLayoutEquivalent(t *testing.T) { prog := NewProgram(nil) prog.TypeSizes(types.SizesFor("gc", runtime.GOARCH)) diff --git a/test/go/recursive_named_types_test.go b/test/go/recursive_named_types_test.go new file mode 100644 index 0000000000..5159bd30ff --- /dev/null +++ b/test/go/recursive_named_types_test.go @@ -0,0 +1,91 @@ +package gotest + +import "testing" + +type recursiveNamedT1 struct { + Next *recursiveNamedT2 +} + +type recursiveNamedT2 recursiveNamedT1 + +type recursiveNamedT3 struct { + Next *recursiveNamedT4 +} + +type recursiveNamedT4 recursiveNamedT5 +type recursiveNamedT5 recursiveNamedT6 +type recursiveNamedT6 recursiveNamedT7 +type recursiveNamedT7 recursiveNamedT8 +type recursiveNamedT8 recursiveNamedT9 +type recursiveNamedT9 recursiveNamedT3 + +type recursiveNamedT10 struct { + x struct { + y ***struct { + z *struct { + Next *recursiveNamedT11 + } + } + } +} + +type recursiveNamedT11 recursiveNamedT10 + +type recursiveNamedT12 struct { + F1 *recursiveNamedT15 + F2 *recursiveNamedT13 + F3 *recursiveNamedT16 +} + +type recursiveNamedT13 recursiveNamedT14 +type recursiveNamedT14 recursiveNamedT15 +type recursiveNamedT15 recursiveNamedT16 +type recursiveNamedT16 recursiveNamedT17 +type recursiveNamedT17 recursiveNamedT12 + +type recursiveNamedT18 *[10]recursiveNamedT19 +type recursiveNamedT19 recursiveNamedT18 + +func TestRecursiveNamedTypeLiterals(t *testing.T) { + _ = &recursiveNamedT1{&recursiveNamedT2{}} + _ = &recursiveNamedT2{&recursiveNamedT2{}} + _ = &recursiveNamedT3{&recursiveNamedT4{}} + _ = &recursiveNamedT4{&recursiveNamedT4{}} + _ = &recursiveNamedT5{&recursiveNamedT4{}} + _ = &recursiveNamedT6{&recursiveNamedT4{}} + _ = &recursiveNamedT7{&recursiveNamedT4{}} + _ = &recursiveNamedT8{&recursiveNamedT4{}} + _ = &recursiveNamedT9{&recursiveNamedT4{}} + _ = &recursiveNamedT12{&recursiveNamedT15{}, &recursiveNamedT13{}, &recursiveNamedT16{}} + + var ( + tn struct{ Next *recursiveNamedT11 } + tz struct { + z *struct{ Next *recursiveNamedT11 } + } + tpz *struct { + z *struct{ Next *recursiveNamedT11 } + } + tppz **struct { + z *struct{ Next *recursiveNamedT11 } + } + tpppz ***struct { + z *struct{ Next *recursiveNamedT11 } + } + ty struct { + y ***struct { + z *struct{ Next *recursiveNamedT11 } + } + } + ) + tn.Next = &recursiveNamedT11{} + tz.z = &tn + tpz = &tz + tppz = &tpz + tpppz = &tppz + ty.y = tpppz + _ = &recursiveNamedT10{ty} + + t19s := &[10]recursiveNamedT19{} + _ = recursiveNamedT18(t19s) +} diff --git a/test/goroot/xfail.yaml b/test/goroot/xfail.yaml index a5a66d10b4..1131db0156 100644 --- a/test/goroot/xfail.yaml +++ b/test/goroot/xfail.yaml @@ -1826,10 +1826,6 @@ xfails: directive: run case: zerodivide.go reason: current main goroot run failure on darwin/arm64 - - platform: darwin/arm64 - directive: run - case: fixedbugs/bug336.go - reason: current main goroot run failure on darwin/arm64 - platform: darwin/arm64 directive: run case: fixedbugs/issue16130.go @@ -1957,11 +1953,6 @@ xfails: directive: run case: zerodivide.go reason: go1.24 goroot run failure on linux/amd64 - - version: go1.24 - platform: linux/amd64 - directive: run - case: fixedbugs/bug336.go - reason: go1.24 goroot run failure on linux/amd64 - version: go1.24 platform: linux/amd64 directive: run @@ -2067,11 +2058,6 @@ xfails: directive: run case: zerodivide.go reason: go1.25 goroot run failure on linux/amd64 - - version: go1.25 - platform: linux/amd64 - directive: run - case: fixedbugs/bug336.go - reason: go1.25 goroot run failure on linux/amd64 - version: go1.25 platform: linux/amd64 directive: run @@ -2182,11 +2168,6 @@ xfails: directive: run case: zerodivide.go reason: go1.26 goroot run failure on linux/amd64 - - version: go1.26 - platform: linux/amd64 - directive: run - case: fixedbugs/bug336.go - reason: go1.26 goroot run failure on linux/amd64 - version: go1.26 platform: linux/amd64 directive: run