compiler: support all kinds of recursive types

Previously we only supported recursive types in structs. But there can
be other kinds of recursive types, like slices:

    type RecursiveSlice []RecursiveSlice

This doesn't involve structs, so it led to infinite recursion in the
compiler. This fix avoids recursion at the proper level: at the place
where the named type is defined.
Этот коммит содержится в:
Ayke van Laethem 2023-03-16 23:48:50 +01:00 коммит произвёл Ron Evans
родитель c5598630c9
коммит 5b42871baa
3 изменённых файлов: 17 добавлений и 9 удалений

Просмотреть файл

@ -569,10 +569,19 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
case *types.Map: case *types.Map:
return c.getDIType(types.NewPointer(c.program.ImportedPackage("runtime").Members["hashmap"].(*ssa.Type).Type())) return c.getDIType(types.NewPointer(c.program.ImportedPackage("runtime").Members["hashmap"].(*ssa.Type).Type()))
case *types.Named: case *types.Named:
return c.dibuilder.CreateTypedef(llvm.DITypedef{ // Placeholder metadata node, to be replaced afterwards.
temporaryMDNode := c.dibuilder.CreateReplaceableCompositeType(llvm.Metadata{}, llvm.DIReplaceableCompositeType{
Tag: dwarf.TagTypedef,
SizeInBits: sizeInBytes * 8,
AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
})
c.ditypes[typ] = temporaryMDNode
md := c.dibuilder.CreateTypedef(llvm.DITypedef{
Type: c.getDIType(typ.Underlying()), Type: c.getDIType(typ.Underlying()),
Name: typ.String(), Name: typ.String(),
}) })
temporaryMDNode.ReplaceAllUsesWith(md)
return md
case *types.Pointer: case *types.Pointer:
return c.dibuilder.CreatePointerType(llvm.DIPointerType{ return c.dibuilder.CreatePointerType(llvm.DIPointerType{
Pointee: c.getDIType(typ.Elem()), Pointee: c.getDIType(typ.Elem()),
@ -634,13 +643,6 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
}, },
}) })
case *types.Struct: case *types.Struct:
// Placeholder metadata node, to be replaced afterwards.
temporaryMDNode := c.dibuilder.CreateReplaceableCompositeType(llvm.Metadata{}, llvm.DIReplaceableCompositeType{
Tag: dwarf.TagStructType,
SizeInBits: sizeInBytes * 8,
AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
})
c.ditypes[typ] = temporaryMDNode
elements := make([]llvm.Metadata, typ.NumFields()) elements := make([]llvm.Metadata, typ.NumFields())
for i := range elements { for i := range elements {
field := typ.Field(i) field := typ.Field(i)
@ -659,7 +661,6 @@ func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata {
AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8, AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8,
Elements: elements, Elements: elements,
}) })
temporaryMDNode.ReplaceAllUsesWith(md)
return md return md
case *types.TypeParam: case *types.TypeParam:
return c.getDIType(typ.Underlying()) return c.getDIType(typ.Underlying())

6
testdata/slice.go предоставленный
Просмотреть файл

@ -6,6 +6,8 @@ type MySlice [32]byte
type myUint8 uint8 type myUint8 uint8
type RecursiveSlice []RecursiveSlice
// Indexing into slice with named type (regression test). // Indexing into slice with named type (regression test).
var array = [4]int{ var array = [4]int{
myUint8(2): 3, myUint8(2): 3,
@ -160,6 +162,10 @@ func main() {
for _, c := range named { for _, c := range named {
assert(c == 0) assert(c == 0)
} }
// Test recursive slices.
rs := []RecursiveSlice(nil)
println("len:", len(rs))
} }
func printslice(name string, s []int) { func printslice(name string, s []int) {

1
testdata/slice.txt предоставленный
Просмотреть файл

@ -16,3 +16,4 @@ bytes: len=6 cap=6 data: 1 2 3 102 111 111
slice to array pointer: 1 -2 20 4 slice to array pointer: 1 -2 20 4
unsafe.Add array: 1 5 8 4 unsafe.Add array: 1 5 8 4
unsafe.Slice array: 3 3 9 15 4 unsafe.Slice array: 3 3 9 15 4
len: 0