// valPos tries to find a position for the given value // even if the value doesn't have one. func valPos(val ssa.Value) token.Pos { if pos := val.Pos(); pos.IsValid() { return pos } instr, ok := val.(ssa.Instruction) if !ok { return token.NoPos } for _, op := range instr.Operands(nil) { if pos := (*op).Pos(); pos.IsValid() { return pos } } return token.NoPos }
// declare creates an llvm.dbg.declare call for the specified function // parameter or local variable. func (d *debugInfo) declare(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) { tag := tagAutoVariable if paramIndex >= 0 { tag = tagArgVariable } ld := debug.NewLocalVariableDescriptor(tag) ld.Argument = uint32(paramIndex + 1) ld.Name = llv.Name() if file := d.Fset.File(v.Pos()); file != nil { ld.Line = uint32(file.Position(v.Pos()).Line) ld.File = &d.getCompileUnit(file).Path } ld.Type = d.TypeDebugDescriptor(deref(v.Type())) ld.Context = d.context() b.InsertDeclare(d.module, llvm.MDNode([]llvm.Value{llv}), d.MDNode(ld)) }
func (ctxt *context) getErrorInfo(v ssa.Value, member int, enclosingPos token.Pos, seen map[ssa.Value]bool) (result *errorInfo) { if !enclosingPos.IsValid() { panicf("getErrorInfo with invalid pos; %T %s", v, v) } // log.Printf("getErrorInfo[%d] %T %v {", member, v, v) // defer func() { // log.Printf("} -> %+v", result) // }() if seen[v] { return &errorInfo{} } seen[v] = true defer delete(seen, v) if pos := v.Pos(); pos.IsValid() { enclosingPos = pos } terminate := func() []errorTermination { return []errorTermination{{ val: v, pos: enclosingPos, }} } switch v := v.(type) { case *ssa.Call: if member > 0 && member != v.Type().(*types.Tuple).Len()-1 { log.Printf("error from non-final member of function") return &errorInfo{unknown: terminate()} } return &errorInfo{nested: []*ssa.Call{v}} case *ssa.ChangeInterface: return ctxt.getErrorInfo(v.X, 0, enclosingPos, seen) case *ssa.Extract: return ctxt.getErrorInfo(v.Tuple, v.Index, enclosingPos, seen) case *ssa.Field: return &errorInfo{unknown: terminate()} case *ssa.Index: return &errorInfo{unknown: terminate()} case *ssa.Lookup: return &errorInfo{unknown: terminate()} case *ssa.Const: if v.Value != nil { panicf("non-nil constant cannot make error, surely?") } return &errorInfo{} case *ssa.MakeInterface: // TODO look into components of v.X return &errorInfo{nonNil: terminate()} case *ssa.Next: return &errorInfo{unknown: terminate()} case *ssa.Parameter: return &errorInfo{unknown: terminate()} case *ssa.Phi: var info errorInfo for _, edge := range v.Edges { info.add(ctxt.getErrorInfo(edge, member, enclosingPos, seen)) } return &info case *ssa.Select: return &errorInfo{unknown: terminate()} case *ssa.TypeAssert: if v.CommaOk { return &errorInfo{unknown: terminate()} } return ctxt.getErrorInfo(v.X, 0, enclosingPos, seen) case *ssa.UnOp: switch v.Op { case token.ARROW: return &errorInfo{unknown: terminate()} case token.MUL: if _, isGlobal := v.X.(*ssa.Global); isGlobal { // Assume that if we're returning a global variable, it's a // global non-nil error, such as os.ErrInvalid. return &errorInfo{nonNil: terminate()} } return &errorInfo{unknown: terminate()} default: panicf("unexpected unary operator %s at %s", v, ctxt.lprog.Fset.Position(enclosingPos)) } } panicf("unexpected value found for error: %T; %v", v, v) panic("not reached") }