// genConv generates constraints for the conversion operation conv. func (a *analysis) genConv(conv *ssa.Convert, cgn *cgnode) { res := a.valueNode(conv) if res == 0 { return // result is non-pointerlike } tSrc := conv.X.Type() tDst := conv.Type() switch utSrc := tSrc.Underlying().(type) { case *types.Slice: // []byte/[]rune -> string? return case *types.Pointer: // *T -> unsafe.Pointer? if tDst.Underlying() == tUnsafePtr { return // we don't model unsafe aliasing (unsound) } case *types.Basic: switch tDst.Underlying().(type) { case *types.Pointer: // Treat unsafe.Pointer->*T conversions like // new(T) and create an unaliased object. if utSrc == tUnsafePtr { obj := a.addNodes(mustDeref(tDst), "unsafe.Pointer conversion") a.endObject(obj, cgn, conv) a.addressOf(tDst, res, obj) return } case *types.Slice: // string -> []byte/[]rune (or named aliases)? if utSrc.Info()&types.IsString != 0 { obj := a.addNodes(sliceToArray(tDst), "convert") a.endObject(obj, cgn, conv) a.addressOf(tDst, res, obj) return } case *types.Basic: // All basic-to-basic type conversions are no-ops. // This includes uintptr<->unsafe.Pointer conversions, // which we (unsoundly) ignore. return } } panic(fmt.Sprintf("illegal *ssa.Convert %s -> %s: %s", tSrc, tDst, conv.Parent())) }