interp: report 'unreachable' instruction as an error
This instruction should never be hit in real programs, but the interpreter may hit it after a call to panic(). This would always be a runtime error.
Этот коммит содержится в:
родитель
cea0a5977a
коммит
469193735a
2 изменённых файлов: 12 добавлений и 5 удалений
|
@ -17,6 +17,8 @@ type frame struct {
|
||||||
locals map[llvm.Value]Value
|
locals map[llvm.Value]Value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrUnreachable = errors.New("interp: unreachable executed")
|
||||||
|
|
||||||
// evalBasicBlock evaluates a single basic block, returning the return value (if
|
// evalBasicBlock evaluates a single basic block, returning the return value (if
|
||||||
// ending with a ret instruction), a list of outgoing basic blocks (if not
|
// ending with a ret instruction), a list of outgoing basic blocks (if not
|
||||||
// ending with a ret instruction), or an error on failure.
|
// ending with a ret instruction), or an error on failure.
|
||||||
|
@ -303,8 +305,10 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||||
case callee.Name() == "runtime.makeInterface":
|
case callee.Name() == "runtime.makeInterface":
|
||||||
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstPtrToInt(inst.Operand(0), fr.TargetData.IntPtrType())}
|
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstPtrToInt(inst.Operand(0), fr.TargetData.IntPtrType())}
|
||||||
case strings.HasPrefix(callee.Name(), "runtime.print") || callee.Name() == "runtime._panic":
|
case strings.HasPrefix(callee.Name(), "runtime.print") || callee.Name() == "runtime._panic":
|
||||||
// all print instructions, which necessarily have side
|
// This are all print instructions, which necessarily have side
|
||||||
// effects but no results
|
// effects but no results.
|
||||||
|
// TODO: print an error when executing runtime._panic (with the
|
||||||
|
// exact error message it would print at runtime).
|
||||||
var params []llvm.Value
|
var params []llvm.Value
|
||||||
for i := 0; i < inst.OperandsCount()-1; i++ {
|
for i := 0; i < inst.OperandsCount()-1; i++ {
|
||||||
operand := fr.getLocal(inst.Operand(i)).Value()
|
operand := fr.getLocal(inst.Operand(i)).Value()
|
||||||
|
@ -428,9 +432,9 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||||
// unconditional branch (goto)
|
// unconditional branch (goto)
|
||||||
return nil, []llvm.Value{inst.Operand(0)}, nil
|
return nil, []llvm.Value{inst.Operand(0)}, nil
|
||||||
case !inst.IsAUnreachableInst().IsNil():
|
case !inst.IsAUnreachableInst().IsNil():
|
||||||
// unreachable was reached (e.g. after a call to panic())
|
// Unreachable was reached (e.g. after a call to panic()).
|
||||||
// assume this is actually unreachable when running
|
// Report this as an error, as it is not supposed to happen.
|
||||||
return &LocalValue{fr.Eval, llvm.Undef(fr.fn.Type())}, nil, nil
|
return nil, nil, ErrUnreachable
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, nil, &Unsupported{inst}
|
return nil, nil, &Unsupported{inst}
|
||||||
|
|
|
@ -63,6 +63,9 @@ func Run(mod llvm.Module, targetData llvm.TargetData, debug bool) error {
|
||||||
}
|
}
|
||||||
pkgName := initName[:len(initName)-5]
|
pkgName := initName[:len(initName)-5]
|
||||||
_, err := e.Function(call.CalledValue(), nil, pkgName)
|
_, err := e.Function(call.CalledValue(), nil, pkgName)
|
||||||
|
if err == ErrUnreachable {
|
||||||
|
break
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче