diff options
author | Ayke van Laethem <[email protected]> | 2020-07-26 21:28:48 +0200 |
---|---|---|
committer | Ron Evans <[email protected]> | 2020-08-25 16:16:35 +0200 |
commit | 4fa1fc6e7215a53baf73b552a714ce8241a8da11 (patch) | |
tree | a2a789c29dfb97197e07cc68709b4442317c566f /interp | |
parent | ccb803e35d8377264831f4be7b11e34cf855a741 (diff) | |
download | tinygo-4fa1fc6e7215a53baf73b552a714ce8241a8da11.tar.gz tinygo-4fa1fc6e7215a53baf73b552a714ce8241a8da11.zip |
interp: don't panic in the Store method
Instead return an error, which indicates where it goes wrong. That's
less user unfriendly than panicking.
Diffstat (limited to 'interp')
-rw-r--r-- | interp/frame.go | 10 | ||||
-rw-r--r-- | interp/values.go | 27 |
2 files changed, 22 insertions, 15 deletions
diff --git a/interp/frame.go b/interp/frame.go index 28e610958..16984f93f 100644 --- a/interp/frame.go +++ b/interp/frame.go @@ -111,7 +111,10 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re if inst.IsVolatile() { fr.builder.CreateStore(value.Value(), ptr.Value()) } else { - ptr.Store(value.Value()) + err := ptr.Store(value.Value()) + if err != nil { + return nil, nil, fr.errorAt(inst, err) + } } case !inst.IsAGetElementPtrInst().IsNil(): value := fr.getLocal(inst.Operand(0)) @@ -422,7 +425,10 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re if err != nil { return nil, nil, fr.errorAt(inst, err) } - dstArray.Store(val) + err = dstArray.Store(val) + if err != nil { + return nil, nil, fr.errorAt(inst, err) + } // dst++ dstArrayValue, err := dstArray.GetElementPtr([]uint32{1}) if err != nil { diff --git a/interp/values.go b/interp/values.go index dba81fcef..ae29bf99d 100644 --- a/interp/values.go +++ b/interp/values.go @@ -16,7 +16,7 @@ type Value interface { Type() llvm.Type // equal to Value().Type() IsConstant() bool // returns true if this value is a constant value Load() (llvm.Value, error) // dereference a pointer - Store(llvm.Value) // store to a pointer + Store(llvm.Value) error // store to a pointer GetElementPtr([]uint32) (Value, error) // returns an interior pointer String() string // string representation, for debugging } @@ -68,8 +68,8 @@ func (v *LocalValue) Load() (llvm.Value, error) { } // Store stores to the underlying value if the value type is a pointer type, -// otherwise it panics. -func (v *LocalValue) Store(value llvm.Value) { +// otherwise it returns an error. +func (v *LocalValue) Store(value llvm.Value) error { if !v.Underlying.IsAGlobalVariable().IsNil() { if !value.IsConstant() { v.MarkDirty() @@ -77,29 +77,28 @@ func (v *LocalValue) Store(value llvm.Value) { } else { v.Underlying.SetInitializer(value) } - return + return nil } if !value.IsConstant() { v.MarkDirty() v.Eval.builder.CreateStore(value, v.Underlying) - return + return nil } switch v.Underlying.Opcode() { case llvm.GetElementPtr: indices := v.getConstGEPIndices() if indices[0] != 0 { - panic("invalid GEP") + return errors.New("invalid GEP") } global := &LocalValue{v.Eval, v.Underlying.Operand(0)} agg, err := global.Load() if err != nil { - panic(err) // TODO + return err } agg = llvm.ConstInsertValue(agg, value, indices[1:]) - global.Store(agg) - return + return global.Store(agg) default: - panic("interp: store on a constant") + return errors.New("interp: store on a constant") } } @@ -313,9 +312,11 @@ func (v *MapValue) Load() (llvm.Value, error) { panic("interp: load from a map") } -// Store panics: maps are of reference type so cannot be stored to. -func (v *MapValue) Store(value llvm.Value) { - panic("interp: store on a map") +// Store returns an error: maps are of reference type so cannot be stored to. +func (v *MapValue) Store(value llvm.Value) error { + // This must be a bug, but it might be helpful to indicate the location + // anyway. + return errors.New("interp: store on a map") } // GetElementPtr panics: maps are of reference type so their (interior) |