compiler,transform: fix for pointer-to-pointer type switches from @aykevl

Этот коммит содержится в:
Damian Gryski 2023-06-01 10:41:36 -07:00 коммит произвёл Ron Evans
родитель 62fb386d57
коммит f5f4751088
4 изменённых файлов: 44 добавлений и 6 удалений

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

@ -683,11 +683,8 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
} else {
assertedTypeGlobal := b.getTypeCode(expr.AssertedType)
if !assertedTypeGlobal.IsAConstantExpr().IsNil() {
assertedTypeGlobal = assertedTypeGlobal.Operand(0) // resolve the GEP operation
}
globalName := "reflect/types.typeid:" + strings.TrimPrefix(assertedTypeGlobal.Name(), "reflect/types.type:")
name, _ := getTypeCodeName(expr.AssertedType)
globalName := "reflect/types.typeid:" + name
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
if assertedTypeCodeGlobal.IsNil() {
// Create a new typecode global.

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

@ -113,6 +113,9 @@ func main() {
println("slept 1ms")
blockStatic(SleepBlocker(time.Millisecond))
println("slept 1ms")
// check that pointer-to-pointer type switches work
ptrptrswitch()
}
func printItf(val interface{}) {
@ -312,3 +315,22 @@ func namedptr2() interface{} {
type Test byte
return (*Test)(nil)
}
func ptrptrswitch() {
identify(0)
identify(new(int))
identify(new(*int))
}
func identify(itf any) {
switch itf.(type) {
case int:
println("type is int")
case *int:
println("type is *int")
case **int:
println("type is **int")
default:
println("other type??")
}
}

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

@ -24,3 +24,6 @@ Byte(): 3
non-blocking call on sometimes-blocking interface
slept 1ms
slept 1ms
type is int
type is *int
type is **int

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

@ -285,11 +285,27 @@ func (p *lowerInterfacesPass) run() error {
for _, use := range getUses(p.mod.NamedFunction("runtime.typeAssert")) {
actualType := use.Operand(0)
name := strings.TrimPrefix(use.Operand(1).Name(), "reflect/types.typeid:")
gepOffset := uint64(0)
for strings.HasPrefix(name, "pointer:pointer:") {
// This is a type like **int, which has the name pointer:pointer:int
// but is encoded using pointer tagging.
// Calculate the pointer tag, which is emitted as a GEP instruction.
name = name[len("pointer:"):]
gepOffset++
}
if t, ok := p.types[name]; ok {
// The type exists in the program, so lower to a regular pointer
// comparison.
p.builder.SetInsertPointBefore(use)
commaOk := p.builder.CreateICmp(llvm.IntEQ, t.typecodeGEP, actualType, "typeassert.ok")
typecodeGEP := t.typecodeGEP
if gepOffset != 0 {
// This is a tagged pointer.
typecodeGEP = llvm.ConstInBoundsGEP(p.ctx.Int8Type(), typecodeGEP, []llvm.Value{
llvm.ConstInt(p.ctx.Int64Type(), gepOffset, false),
})
}
commaOk := p.builder.CreateICmp(llvm.IntEQ, typecodeGEP, actualType, "typeassert.ok")
use.ReplaceAllUsesWith(commaOk)
} else {
// The type does not exist in the program, so lower to a constant