interp: handle type assertions on nil interfaces
Previously, a type assertion on a nil interface would result in an out-of-bounds operand access, as we assumed it was a ptrtoint. This would usually result in an undefined value which happens not to have the same name as the asserted type (and therefore the assertion fails as expected). However, with an LLVM build with asserts, LLVM throws an assertion error: ``` interp.test: /home/niaow/go/src/github.com/tinygo-org/tinygo/llvm-project/llvm/include/llvm/IR/User.h:170: llvm::Value* llvm::User::getOperand(unsigned int) const: Assertion `i < NumUserOperands && "getOperand() out of range!"' failed. ``` This change handles a type code of 0 specially.
Этот коммит содержится в:
родитель
5e33dccf1f
коммит
2f57e4ff6d
3 изменённых файлов: 8 добавлений и 0 удалений
|
@ -388,6 +388,10 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
if !actualTypePtrToInt.IsAConstantInt().IsNil() && actualTypePtrToInt.ZExtValue() == 0 {
|
||||
locals[inst.localIndex] = literalValue{uint8(0)}
|
||||
break
|
||||
}
|
||||
actualType := actualTypePtrToInt.Operand(0)
|
||||
if strings.TrimPrefix(actualType.Name(), "reflect/types.type:") == strings.TrimPrefix(assertedType.Name(), "reflect/types.typeid:") {
|
||||
locals[inst.localIndex] = literalValue{uint8(1)}
|
||||
|
|
3
interp/testdata/interface.ll
предоставленный
3
interp/testdata/interface.ll
предоставленный
|
@ -5,6 +5,7 @@ target triple = "x86_64--linux"
|
|||
%runtime.interfaceMethodInfo = type { i8*, i64 }
|
||||
|
||||
@main.v1 = global i1 0
|
||||
@main.v2 = global i1 0
|
||||
@"reflect/types.type:named:main.foo" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i64 0, %runtime.interfaceMethodInfo* null }
|
||||
@"reflect/types.typeid:named:main.foo" = external constant i8
|
||||
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
|
||||
|
@ -23,5 +24,7 @@ entry:
|
|||
; Test type asserts.
|
||||
%typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typecodeID* @"reflect/types.type:named:main.foo" to i64), i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
|
||||
store i1 %typecode, i1* @main.v1
|
||||
%typecode2 = call i1 @runtime.typeAssert(i64 0, i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
|
||||
store i1 %typecode2, i1* @main.v2
|
||||
ret void
|
||||
}
|
||||
|
|
1
interp/testdata/interface.out.ll
предоставленный
1
interp/testdata/interface.out.ll
предоставленный
|
@ -2,6 +2,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
|||
target triple = "x86_64--linux"
|
||||
|
||||
@main.v1 = local_unnamed_addr global i1 true
|
||||
@main.v2 = local_unnamed_addr global i1 false
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
entry:
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче