| | |
| | |
| | |
| |
|
| | package ir |
| |
|
| | import ( |
| | "bytes" |
| | "cmd/compile/internal/base" |
| | "cmd/compile/internal/types" |
| | "cmd/internal/obj" |
| | "cmd/internal/src" |
| | "fmt" |
| | "go/constant" |
| | "go/token" |
| | ) |
| |
|
| | |
| | type Expr interface { |
| | Node |
| | isExpr() |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | type miniExpr struct { |
| | miniNode |
| | flags bitset8 |
| | typ *types.Type |
| | init Nodes |
| | } |
| |
|
| | const ( |
| | miniExprNonNil = 1 << iota |
| | miniExprTransient |
| | miniExprBounded |
| | miniExprImplicit |
| | miniExprCheckPtr |
| | ) |
| |
|
| | func (*miniExpr) isExpr() {} |
| |
|
| | func (n *miniExpr) Type() *types.Type { return n.typ } |
| | func (n *miniExpr) SetType(x *types.Type) { n.typ = x } |
| | func (n *miniExpr) NonNil() bool { return n.flags&miniExprNonNil != 0 } |
| | func (n *miniExpr) MarkNonNil() { n.flags |= miniExprNonNil } |
| | func (n *miniExpr) Transient() bool { return n.flags&miniExprTransient != 0 } |
| | func (n *miniExpr) SetTransient(b bool) { n.flags.set(miniExprTransient, b) } |
| | func (n *miniExpr) Bounded() bool { return n.flags&miniExprBounded != 0 } |
| | func (n *miniExpr) SetBounded(b bool) { n.flags.set(miniExprBounded, b) } |
| | func (n *miniExpr) Init() Nodes { return n.init } |
| | func (n *miniExpr) PtrInit() *Nodes { return &n.init } |
| | func (n *miniExpr) SetInit(x Nodes) { n.init = x } |
| |
|
| | |
| | type AddStringExpr struct { |
| | miniExpr |
| | List Nodes |
| | Prealloc *Name |
| | } |
| |
|
| | func NewAddStringExpr(pos src.XPos, list []Node) *AddStringExpr { |
| | n := &AddStringExpr{} |
| | n.pos = pos |
| | n.op = OADDSTR |
| | n.List = list |
| | return n |
| | } |
| |
|
| | |
| | |
| | type AddrExpr struct { |
| | miniExpr |
| | X Node |
| | Prealloc *Name |
| | } |
| |
|
| | func NewAddrExpr(pos src.XPos, x Node) *AddrExpr { |
| | if x == nil || x.Typecheck() != 1 { |
| | base.FatalfAt(pos, "missed typecheck: %L", x) |
| | } |
| | n := &AddrExpr{X: x} |
| | n.pos = pos |
| |
|
| | switch x.Op() { |
| | case OARRAYLIT, OMAPLIT, OSLICELIT, OSTRUCTLIT: |
| | n.op = OPTRLIT |
| |
|
| | default: |
| | n.op = OADDR |
| | if r, ok := OuterValue(x).(*Name); ok && r.Op() == ONAME { |
| | r.SetAddrtaken(true) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if r.IsClosureVar() && !r.Byval() { |
| | r.Canonical().SetAddrtaken(true) |
| | } |
| | } |
| | } |
| |
|
| | n.SetType(types.NewPtr(x.Type())) |
| | n.SetTypecheck(1) |
| |
|
| | return n |
| | } |
| |
|
| | func (n *AddrExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 } |
| | func (n *AddrExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) } |
| |
|
| | func (n *AddrExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case OADDR, OPTRLIT: |
| | n.op = op |
| | } |
| | } |
| |
|
| | |
| | type BasicLit struct { |
| | miniExpr |
| | val constant.Value |
| | } |
| |
|
| | |
| | func NewBasicLit(pos src.XPos, typ *types.Type, val constant.Value) Node { |
| | AssertValidTypeForConst(typ, val) |
| |
|
| | n := &BasicLit{val: val} |
| | n.op = OLITERAL |
| | n.pos = pos |
| | n.SetType(typ) |
| | n.SetTypecheck(1) |
| | return n |
| | } |
| |
|
| | func (n *BasicLit) Val() constant.Value { return n.val } |
| | func (n *BasicLit) SetVal(val constant.Value) { n.val = val } |
| |
|
| | |
| | |
| | func NewConstExpr(val constant.Value, orig Node) Node { |
| | return NewBasicLit(orig.Pos(), orig.Type(), val) |
| | } |
| |
|
| | |
| | |
| | type BinaryExpr struct { |
| | miniExpr |
| | X Node |
| | Y Node |
| | RType Node `mknode:"-"` |
| | } |
| |
|
| | func NewBinaryExpr(pos src.XPos, op Op, x, y Node) *BinaryExpr { |
| | n := &BinaryExpr{X: x, Y: y} |
| | n.pos = pos |
| | n.SetOp(op) |
| | return n |
| | } |
| |
|
| | func (n *BinaryExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case OADD, OADDSTR, OAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, |
| | OLSH, OLT, OMOD, OMUL, ONE, OOR, ORSH, OSUB, OXOR, |
| | OCOPY, OCOMPLEX, OUNSAFEADD, OUNSAFESLICE, OUNSAFESTRING, |
| | OMAKEFACE: |
| | n.op = op |
| | } |
| | } |
| |
|
| | |
| | type CallExpr struct { |
| | miniExpr |
| | Fun Node |
| | Args Nodes |
| | DeferAt Node |
| | RType Node `mknode:"-"` |
| | KeepAlive []*Name |
| | IsDDD bool |
| | GoDefer bool |
| | NoInline bool |
| | UseBuf bool |
| | AppendNoAlias bool |
| | |
| | |
| | IsCompilerVarLive bool |
| | } |
| |
|
| | func NewCallExpr(pos src.XPos, op Op, fun Node, args []Node) *CallExpr { |
| | n := &CallExpr{Fun: fun} |
| | n.pos = pos |
| | n.SetOp(op) |
| | n.Args = args |
| | return n |
| | } |
| |
|
| | func (*CallExpr) isStmt() {} |
| |
|
| | func (n *CallExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case OAPPEND, |
| | OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, |
| | ODELETE, |
| | OGETG, OGETCALLERSP, |
| | OMAKE, OMAX, OMIN, OPRINT, OPRINTLN, |
| | ORECOVER: |
| | n.op = op |
| | } |
| | } |
| |
|
| | |
| | type ClosureExpr struct { |
| | miniExpr |
| | Func *Func `mknode:"-"` |
| | Prealloc *Name |
| | IsGoWrap bool |
| | } |
| |
|
| | |
| | |
| | type CompLitExpr struct { |
| | miniExpr |
| | List Nodes |
| | RType Node `mknode:"-"` |
| | Prealloc *Name |
| | |
| | |
| | |
| | Len int64 |
| | } |
| |
|
| | func NewCompLitExpr(pos src.XPos, op Op, typ *types.Type, list []Node) *CompLitExpr { |
| | n := &CompLitExpr{List: list} |
| | n.pos = pos |
| | n.SetOp(op) |
| | if typ != nil { |
| | n.SetType(typ) |
| | } |
| | return n |
| | } |
| |
|
| | func (n *CompLitExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 } |
| | func (n *CompLitExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) } |
| |
|
| | func (n *CompLitExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case OARRAYLIT, OCOMPLIT, OMAPLIT, OSTRUCTLIT, OSLICELIT: |
| | n.op = op |
| | } |
| | } |
| |
|
| | |
| | |
| | type ConvExpr struct { |
| | miniExpr |
| | X Node |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | TypeWord Node `mknode:"-"` |
| | SrcRType Node `mknode:"-"` |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | ElemRType Node `mknode:"-"` |
| | ElemElemRType Node `mknode:"-"` |
| | } |
| |
|
| | func NewConvExpr(pos src.XPos, op Op, typ *types.Type, x Node) *ConvExpr { |
| | n := &ConvExpr{X: x} |
| | n.pos = pos |
| | n.typ = typ |
| | n.SetOp(op) |
| | return n |
| | } |
| |
|
| | func (n *ConvExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 } |
| | func (n *ConvExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) } |
| | func (n *ConvExpr) CheckPtr() bool { return n.flags&miniExprCheckPtr != 0 } |
| | func (n *ConvExpr) SetCheckPtr(b bool) { n.flags.set(miniExprCheckPtr, b) } |
| |
|
| | func (n *ConvExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, OBYTES2STRTMP, ORUNES2STR, OSTR2BYTES, OSTR2BYTESTMP, OSTR2RUNES, ORUNESTR, OSLICE2ARR, OSLICE2ARRPTR: |
| | n.op = op |
| | } |
| | } |
| |
|
| | |
| | type IndexExpr struct { |
| | miniExpr |
| | X Node |
| | Index Node |
| | RType Node `mknode:"-"` |
| | Assigned bool |
| | } |
| |
|
| | func NewIndexExpr(pos src.XPos, x, index Node) *IndexExpr { |
| | n := &IndexExpr{X: x, Index: index} |
| | n.pos = pos |
| | n.op = OINDEX |
| | return n |
| | } |
| |
|
| | func (n *IndexExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case OINDEX, OINDEXMAP: |
| | n.op = op |
| | } |
| | } |
| |
|
| | |
| | type KeyExpr struct { |
| | miniExpr |
| | Key Node |
| | Value Node |
| | } |
| |
|
| | func NewKeyExpr(pos src.XPos, key, value Node) *KeyExpr { |
| | n := &KeyExpr{Key: key, Value: value} |
| | n.pos = pos |
| | n.op = OKEY |
| | return n |
| | } |
| |
|
| | |
| | type StructKeyExpr struct { |
| | miniExpr |
| | Field *types.Field |
| | Value Node |
| | } |
| |
|
| | func NewStructKeyExpr(pos src.XPos, field *types.Field, value Node) *StructKeyExpr { |
| | n := &StructKeyExpr{Field: field, Value: value} |
| | n.pos = pos |
| | n.op = OSTRUCTKEY |
| | return n |
| | } |
| |
|
| | func (n *StructKeyExpr) Sym() *types.Sym { return n.Field.Sym } |
| |
|
| | |
| | type InlinedCallExpr struct { |
| | miniExpr |
| | Body Nodes |
| | ReturnVars Nodes |
| | } |
| |
|
| | func NewInlinedCallExpr(pos src.XPos, body, retvars []Node) *InlinedCallExpr { |
| | n := &InlinedCallExpr{} |
| | n.pos = pos |
| | n.op = OINLCALL |
| | n.Body = body |
| | n.ReturnVars = retvars |
| | return n |
| | } |
| |
|
| | func (n *InlinedCallExpr) SingleResult() Node { |
| | if have := len(n.ReturnVars); have != 1 { |
| | base.FatalfAt(n.Pos(), "inlined call has %v results, expected 1", have) |
| | } |
| | if !n.Type().HasShape() && n.ReturnVars[0].Type().HasShape() { |
| | |
| | |
| | |
| | r := NewConvExpr(n.Pos(), OCONVNOP, n.Type(), n.ReturnVars[0]) |
| | r.SetTypecheck(1) |
| | return r |
| | } |
| | return n.ReturnVars[0] |
| | } |
| |
|
| | |
| | |
| | |
| | type LogicalExpr struct { |
| | miniExpr |
| | X Node |
| | Y Node |
| | } |
| |
|
| | func NewLogicalExpr(pos src.XPos, op Op, x, y Node) *LogicalExpr { |
| | n := &LogicalExpr{X: x, Y: y} |
| | n.pos = pos |
| | n.SetOp(op) |
| | return n |
| | } |
| |
|
| | func (n *LogicalExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case OANDAND, OOROR: |
| | n.op = op |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | type MakeExpr struct { |
| | miniExpr |
| | RType Node `mknode:"-"` |
| | Len Node |
| | Cap Node |
| | } |
| |
|
| | func NewMakeExpr(pos src.XPos, op Op, len, cap Node) *MakeExpr { |
| | n := &MakeExpr{Len: len, Cap: cap} |
| | n.pos = pos |
| | n.SetOp(op) |
| | return n |
| | } |
| |
|
| | func (n *MakeExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case OMAKECHAN, OMAKEMAP, OMAKESLICE, OMAKESLICECOPY: |
| | n.op = op |
| | } |
| | } |
| |
|
| | |
| | type NilExpr struct { |
| | miniExpr |
| | } |
| |
|
| | func NewNilExpr(pos src.XPos, typ *types.Type) *NilExpr { |
| | if typ == nil { |
| | base.FatalfAt(pos, "missing type") |
| | } |
| | n := &NilExpr{} |
| | n.pos = pos |
| | n.op = ONIL |
| | n.SetType(typ) |
| | n.SetTypecheck(1) |
| | return n |
| | } |
| |
|
| | |
| | |
| | type ParenExpr struct { |
| | miniExpr |
| | X Node |
| | } |
| |
|
| | func NewParenExpr(pos src.XPos, x Node) *ParenExpr { |
| | n := &ParenExpr{X: x} |
| | n.op = OPAREN |
| | n.pos = pos |
| | return n |
| | } |
| |
|
| | func (n *ParenExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 } |
| | func (n *ParenExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) } |
| |
|
| | |
| | type ResultExpr struct { |
| | miniExpr |
| | Index int64 |
| | } |
| |
|
| | func NewResultExpr(pos src.XPos, typ *types.Type, index int64) *ResultExpr { |
| | n := &ResultExpr{Index: index} |
| | n.pos = pos |
| | n.op = ORESULT |
| | n.typ = typ |
| | return n |
| | } |
| |
|
| | |
| | |
| | type LinksymOffsetExpr struct { |
| | miniExpr |
| | Linksym *obj.LSym |
| | Offset_ int64 |
| | } |
| |
|
| | func NewLinksymOffsetExpr(pos src.XPos, lsym *obj.LSym, offset int64, typ *types.Type) *LinksymOffsetExpr { |
| | if typ == nil { |
| | base.FatalfAt(pos, "nil type") |
| | } |
| | n := &LinksymOffsetExpr{Linksym: lsym, Offset_: offset} |
| | n.typ = typ |
| | n.op = OLINKSYMOFFSET |
| | n.SetTypecheck(1) |
| | return n |
| | } |
| |
|
| | |
| | func NewLinksymExpr(pos src.XPos, lsym *obj.LSym, typ *types.Type) *LinksymOffsetExpr { |
| | return NewLinksymOffsetExpr(pos, lsym, 0, typ) |
| | } |
| |
|
| | |
| | |
| | func NewNameOffsetExpr(pos src.XPos, name *Name, offset int64, typ *types.Type) *LinksymOffsetExpr { |
| | if name == nil || IsBlank(name) || !(name.Op() == ONAME && name.Class == PEXTERN) { |
| | base.FatalfAt(pos, "cannot take offset of nil, blank name or non-global variable: %v", name) |
| | } |
| | return NewLinksymOffsetExpr(pos, name.Linksym(), offset, typ) |
| | } |
| |
|
| | |
| | type SelectorExpr struct { |
| | miniExpr |
| | X Node |
| | |
| | |
| | |
| | |
| | Sel *types.Sym |
| | |
| | Selection *types.Field |
| | Prealloc *Name |
| | } |
| |
|
| | func NewSelectorExpr(pos src.XPos, op Op, x Node, sel *types.Sym) *SelectorExpr { |
| | n := &SelectorExpr{X: x, Sel: sel} |
| | n.pos = pos |
| | n.SetOp(op) |
| | return n |
| | } |
| |
|
| | func (n *SelectorExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OMETHVALUE, OMETHEXPR: |
| | n.op = op |
| | } |
| | } |
| |
|
| | func (n *SelectorExpr) Sym() *types.Sym { return n.Sel } |
| | func (n *SelectorExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 } |
| | func (n *SelectorExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) } |
| | func (n *SelectorExpr) Offset() int64 { return n.Selection.Offset } |
| |
|
| | func (n *SelectorExpr) FuncName() *Name { |
| | if n.Op() != OMETHEXPR { |
| | panic(n.no("FuncName")) |
| | } |
| | fn := NewNameAt(n.Selection.Pos, MethodSym(n.X.Type(), n.Sel), n.Type()) |
| | fn.Class = PFUNC |
| | if n.Selection.Nname != nil { |
| | |
| | |
| | |
| | fn.Func = n.Selection.Nname.(*Name).Func |
| | } |
| | return fn |
| | } |
| |
|
| | |
| | type SliceExpr struct { |
| | miniExpr |
| | X Node |
| | Low Node |
| | High Node |
| | Max Node |
| | } |
| |
|
| | func NewSliceExpr(pos src.XPos, op Op, x, low, high, max Node) *SliceExpr { |
| | n := &SliceExpr{X: x, Low: low, High: high, Max: max} |
| | n.pos = pos |
| | n.op = op |
| | return n |
| | } |
| |
|
| | func (n *SliceExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: |
| | n.op = op |
| | } |
| | } |
| |
|
| | |
| | |
| | func (o Op) IsSlice3() bool { |
| | switch o { |
| | case OSLICE, OSLICEARR, OSLICESTR: |
| | return false |
| | case OSLICE3, OSLICE3ARR: |
| | return true |
| | } |
| | base.Fatalf("IsSlice3 op %v", o) |
| | return false |
| | } |
| |
|
| | |
| | type SliceHeaderExpr struct { |
| | miniExpr |
| | Ptr Node |
| | Len Node |
| | Cap Node |
| | } |
| |
|
| | func NewSliceHeaderExpr(pos src.XPos, typ *types.Type, ptr, len, cap Node) *SliceHeaderExpr { |
| | n := &SliceHeaderExpr{Ptr: ptr, Len: len, Cap: cap} |
| | n.pos = pos |
| | n.op = OSLICEHEADER |
| | n.typ = typ |
| | return n |
| | } |
| |
|
| | |
| | type StringHeaderExpr struct { |
| | miniExpr |
| | Ptr Node |
| | Len Node |
| | } |
| |
|
| | func NewStringHeaderExpr(pos src.XPos, ptr, len Node) *StringHeaderExpr { |
| | n := &StringHeaderExpr{Ptr: ptr, Len: len} |
| | n.pos = pos |
| | n.op = OSTRINGHEADER |
| | n.typ = types.Types[types.TSTRING] |
| | return n |
| | } |
| |
|
| | |
| | |
| | type StarExpr struct { |
| | miniExpr |
| | X Node |
| | } |
| |
|
| | func NewStarExpr(pos src.XPos, x Node) *StarExpr { |
| | n := &StarExpr{X: x} |
| | n.op = ODEREF |
| | n.pos = pos |
| | return n |
| | } |
| |
|
| | func (n *StarExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 } |
| | func (n *StarExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) } |
| |
|
| | |
| | |
| | type TypeAssertExpr struct { |
| | miniExpr |
| | X Node |
| |
|
| | |
| | |
| | ITab Node `mknode:"-"` |
| |
|
| | |
| | Descriptor *obj.LSym |
| |
|
| | |
| | |
| | |
| | UseNilPanic bool |
| | } |
| |
|
| | func NewTypeAssertExpr(pos src.XPos, x Node, typ *types.Type) *TypeAssertExpr { |
| | n := &TypeAssertExpr{X: x} |
| | n.pos = pos |
| | n.op = ODOTTYPE |
| | if typ != nil { |
| | n.SetType(typ) |
| | } |
| | return n |
| | } |
| |
|
| | func (n *TypeAssertExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case ODOTTYPE, ODOTTYPE2: |
| | n.op = op |
| | } |
| | } |
| |
|
| | |
| | type DynamicTypeAssertExpr struct { |
| | miniExpr |
| | X Node |
| |
|
| | |
| | |
| | |
| | SrcRType Node |
| |
|
| | |
| | |
| | |
| | |
| | RType Node |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | ITab Node |
| | } |
| |
|
| | func NewDynamicTypeAssertExpr(pos src.XPos, op Op, x, rtype Node) *DynamicTypeAssertExpr { |
| | n := &DynamicTypeAssertExpr{X: x, RType: rtype} |
| | n.pos = pos |
| | n.op = op |
| | return n |
| | } |
| |
|
| | func (n *DynamicTypeAssertExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case ODYNAMICDOTTYPE, ODYNAMICDOTTYPE2: |
| | n.op = op |
| | } |
| | } |
| |
|
| | |
| | |
| | type UnaryExpr struct { |
| | miniExpr |
| | X Node |
| | } |
| |
|
| | func NewUnaryExpr(pos src.XPos, op Op, x Node) *UnaryExpr { |
| | n := &UnaryExpr{X: x} |
| | n.pos = pos |
| | n.SetOp(op) |
| | return n |
| | } |
| |
|
| | func (n *UnaryExpr) SetOp(op Op) { |
| | switch op { |
| | default: |
| | panic(n.no("SetOp " + op.String())) |
| | case OBITNOT, ONEG, ONOT, OPLUS, ORECV, |
| | OCAP, OCLEAR, OCLOSE, OIMAG, OLEN, ONEW, OPANIC, OREAL, |
| | OCHECKNIL, OCFUNC, OIDATA, OITAB, OSPTR, |
| | OUNSAFESTRINGDATA, OUNSAFESLICEDATA: |
| | n.op = op |
| | } |
| | } |
| |
|
| | func IsZero(n Node) bool { |
| | switch n.Op() { |
| | case ONIL: |
| | return true |
| |
|
| | case OLITERAL: |
| | switch u := n.Val(); u.Kind() { |
| | case constant.String: |
| | return constant.StringVal(u) == "" |
| | case constant.Bool: |
| | return !constant.BoolVal(u) |
| | default: |
| | return constant.Sign(u) == 0 |
| | } |
| |
|
| | case OARRAYLIT: |
| | n := n.(*CompLitExpr) |
| | for _, n1 := range n.List { |
| | if n1.Op() == OKEY { |
| | n1 = n1.(*KeyExpr).Value |
| | } |
| | if !IsZero(n1) { |
| | return false |
| | } |
| | } |
| | return true |
| |
|
| | case OSTRUCTLIT: |
| | n := n.(*CompLitExpr) |
| | for _, n1 := range n.List { |
| | n1 := n1.(*StructKeyExpr) |
| | if !IsZero(n1.Value) { |
| | return false |
| | } |
| | } |
| | return true |
| | } |
| |
|
| | return false |
| | } |
| |
|
| | |
| | func IsAddressable(n Node) bool { |
| | switch n.Op() { |
| | case OINDEX: |
| | n := n.(*IndexExpr) |
| | if n.X.Type() != nil && n.X.Type().IsArray() { |
| | return IsAddressable(n.X) |
| | } |
| | if n.X.Type() != nil && n.X.Type().IsString() { |
| | return false |
| | } |
| | fallthrough |
| | case ODEREF, ODOTPTR: |
| | return true |
| |
|
| | case ODOT: |
| | n := n.(*SelectorExpr) |
| | return IsAddressable(n.X) |
| |
|
| | case ONAME: |
| | n := n.(*Name) |
| | if n.Class == PFUNC { |
| | return false |
| | } |
| | return true |
| |
|
| | case OLINKSYMOFFSET: |
| | return true |
| | } |
| |
|
| | return false |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func StaticValue(n Node) Node { |
| | for { |
| | switch n1 := n.(type) { |
| | case *ConvExpr: |
| | if n1.Op() == OCONVNOP { |
| | n = n1.X |
| | continue |
| | } |
| | case *InlinedCallExpr: |
| | if n1.Op() == OINLCALL { |
| | n = n1.SingleResult() |
| | continue |
| | } |
| | case *ParenExpr: |
| | n = n1.X |
| | continue |
| | } |
| |
|
| | n1 := staticValue1(n) |
| | if n1 == nil { |
| | return n |
| | } |
| | n = n1 |
| | } |
| | } |
| |
|
| | func staticValue1(nn Node) Node { |
| | if nn.Op() != ONAME { |
| | return nil |
| | } |
| | n := nn.(*Name).Canonical() |
| | if n.Class != PAUTO { |
| | return nil |
| | } |
| |
|
| | defn := n.Defn |
| | if defn == nil { |
| | return nil |
| | } |
| |
|
| | var rhs Node |
| | FindRHS: |
| | switch defn.Op() { |
| | case OAS: |
| | defn := defn.(*AssignStmt) |
| | rhs = defn.Y |
| | case OAS2: |
| | defn := defn.(*AssignListStmt) |
| | for i, lhs := range defn.Lhs { |
| | if lhs == n { |
| | rhs = defn.Rhs[i] |
| | break FindRHS |
| | } |
| | } |
| | base.FatalfAt(defn.Pos(), "%v missing from LHS of %v", n, defn) |
| | default: |
| | return nil |
| | } |
| | if rhs == nil { |
| | base.FatalfAt(defn.Pos(), "RHS is nil: %v", defn) |
| | } |
| |
|
| | if Reassigned(n) { |
| | return nil |
| | } |
| |
|
| | return rhs |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func Reassigned(name *Name) bool { |
| | if name.Op() != ONAME { |
| | base.Fatalf("reassigned %v", name) |
| | } |
| | |
| | if name.Curfn == nil { |
| | return true |
| | } |
| |
|
| | if name.Addrtaken() { |
| | return true |
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | isName := func(x Node) bool { |
| | if x == nil { |
| | return false |
| | } |
| | n, ok := OuterValue(x).(*Name) |
| | return ok && n.Canonical() == name |
| | } |
| |
|
| | var do func(n Node) bool |
| | do = func(n Node) bool { |
| | switch n.Op() { |
| | case OAS: |
| | n := n.(*AssignStmt) |
| | if isName(n.X) && n != name.Defn { |
| | return true |
| | } |
| | case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV, OSELRECV2: |
| | n := n.(*AssignListStmt) |
| | for _, p := range n.Lhs { |
| | if isName(p) && n != name.Defn { |
| | return true |
| | } |
| | } |
| | case OASOP: |
| | n := n.(*AssignOpStmt) |
| | if isName(n.X) { |
| | return true |
| | } |
| | case OADDR: |
| | n := n.(*AddrExpr) |
| | if isName(n.X) { |
| | base.FatalfAt(n.Pos(), "%v not marked addrtaken", name) |
| | } |
| | case ORANGE: |
| | n := n.(*RangeStmt) |
| | if isName(n.Key) || isName(n.Value) { |
| | return true |
| | } |
| | case OCLOSURE: |
| | n := n.(*ClosureExpr) |
| | if Any(n.Func, do) { |
| | return true |
| | } |
| | } |
| | return false |
| | } |
| | return Any(name.Curfn, do) |
| | } |
| |
|
| | |
| | func StaticCalleeName(n Node) *Name { |
| | switch n.Op() { |
| | case OMETHEXPR: |
| | n := n.(*SelectorExpr) |
| | return MethodExprName(n) |
| | case ONAME: |
| | n := n.(*Name) |
| | if n.Class == PFUNC { |
| | return n |
| | } |
| | case OCLOSURE: |
| | return n.(*ClosureExpr).Func.Nname |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | var IsIntrinsicCall = func(*CallExpr) bool { return false } |
| |
|
| | |
| | var IsIntrinsicSym = func(*types.Sym) bool { return false } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func SameSafeExpr(l Node, r Node) bool { |
| | for l.Op() == OCONVNOP { |
| | l = l.(*ConvExpr).X |
| | } |
| | for r.Op() == OCONVNOP { |
| | r = r.(*ConvExpr).X |
| | } |
| | if l.Op() != r.Op() || !types.Identical(l.Type(), r.Type()) { |
| | return false |
| | } |
| |
|
| | switch l.Op() { |
| | case ONAME: |
| | return l == r |
| |
|
| | case ODOT, ODOTPTR: |
| | l := l.(*SelectorExpr) |
| | r := r.(*SelectorExpr) |
| | return l.Sel != nil && r.Sel != nil && l.Sel == r.Sel && SameSafeExpr(l.X, r.X) |
| |
|
| | case ODEREF: |
| | l := l.(*StarExpr) |
| | r := r.(*StarExpr) |
| | return SameSafeExpr(l.X, r.X) |
| |
|
| | case ONOT, OBITNOT, OPLUS, ONEG: |
| | l := l.(*UnaryExpr) |
| | r := r.(*UnaryExpr) |
| | return SameSafeExpr(l.X, r.X) |
| |
|
| | case OCONV: |
| | l := l.(*ConvExpr) |
| | r := r.(*ConvExpr) |
| | |
| | |
| | return types.IsSimple[l.Type().Kind()] && SameSafeExpr(l.X, r.X) |
| |
|
| | case OINDEX, OINDEXMAP: |
| | l := l.(*IndexExpr) |
| | r := r.(*IndexExpr) |
| | return SameSafeExpr(l.X, r.X) && SameSafeExpr(l.Index, r.Index) |
| |
|
| | case OADD, OSUB, OOR, OXOR, OMUL, OLSH, ORSH, OAND, OANDNOT, ODIV, OMOD: |
| | l := l.(*BinaryExpr) |
| | r := r.(*BinaryExpr) |
| | return SameSafeExpr(l.X, r.X) && SameSafeExpr(l.Y, r.Y) |
| |
|
| | case OLITERAL: |
| | return constant.Compare(l.Val(), token.EQL, r.Val()) |
| |
|
| | case ONIL: |
| | return true |
| | } |
| |
|
| | return false |
| | } |
| |
|
| | |
| | |
| | |
| | func ShouldCheckPtr(fn *Func, level int) bool { |
| | return base.Debug.Checkptr >= level && fn.Pragma&NoCheckPtr == 0 |
| | } |
| |
|
| | |
| | |
| | func ShouldAsanCheckPtr(fn *Func) bool { |
| | return base.Flag.ASan && fn.Pragma&NoCheckPtr == 0 |
| | } |
| |
|
| | |
| | |
| | func IsReflectHeaderDataField(l Node) bool { |
| | if l.Type() != types.Types[types.TUINTPTR] { |
| | return false |
| | } |
| |
|
| | var tsym *types.Sym |
| | switch l.Op() { |
| | case ODOT: |
| | l := l.(*SelectorExpr) |
| | tsym = l.X.Type().Sym() |
| | case ODOTPTR: |
| | l := l.(*SelectorExpr) |
| | tsym = l.X.Type().Elem().Sym() |
| | default: |
| | return false |
| | } |
| |
|
| | if tsym == nil || l.Sym().Name != "Data" || tsym.Pkg.Path != "reflect" { |
| | return false |
| | } |
| | return tsym.Name == "SliceHeader" || tsym.Name == "StringHeader" |
| | } |
| |
|
| | func ParamNames(ft *types.Type) []Node { |
| | args := make([]Node, ft.NumParams()) |
| | for i, f := range ft.Params() { |
| | args[i] = f.Nname.(*Name) |
| | } |
| | return args |
| | } |
| |
|
| | func RecvParamNames(ft *types.Type) []Node { |
| | args := make([]Node, ft.NumRecvs()+ft.NumParams()) |
| | for i, f := range ft.RecvParams() { |
| | args[i] = f.Nname.(*Name) |
| | } |
| | return args |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func MethodSym(recv *types.Type, msym *types.Sym) *types.Sym { |
| | sym := MethodSymSuffix(recv, msym, "") |
| | sym.SetFunc(true) |
| | return sym |
| | } |
| |
|
| | |
| | |
| | |
| | func MethodSymSuffix(recv *types.Type, msym *types.Sym, suffix string) *types.Sym { |
| | if msym.IsBlank() { |
| | base.Fatalf("blank method name") |
| | } |
| |
|
| | rsym := recv.Sym() |
| | if recv.IsPtr() { |
| | if rsym != nil { |
| | base.Fatalf("declared pointer receiver type: %v", recv) |
| | } |
| | rsym = recv.Elem().Sym() |
| | } |
| |
|
| | |
| | |
| | |
| | rpkg := Pkgs.Go |
| | if rsym != nil { |
| | rpkg = rsym.Pkg |
| | } |
| |
|
| | var b bytes.Buffer |
| | if recv.IsPtr() { |
| | |
| | |
| | fmt.Fprintf(&b, "(%-S)", recv) |
| | } else { |
| | fmt.Fprintf(&b, "%-S", recv) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | if !types.IsExported(msym.Name) && msym.Pkg != rpkg { |
| | b.WriteString(".") |
| | b.WriteString(msym.Pkg.Prefix) |
| | } |
| |
|
| | b.WriteString(".") |
| | b.WriteString(msym.Name) |
| | b.WriteString(suffix) |
| | return rpkg.LookupBytes(b.Bytes()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func LookupMethodSelector(pkg *types.Pkg, name string) (typ, meth *types.Sym, err error) { |
| | typeName, methName := splitType(name) |
| | if typeName == "" { |
| | return nil, nil, fmt.Errorf("%s doesn't contain type split", name) |
| | } |
| |
|
| | if len(typeName) > 3 && typeName[:2] == "(*" && typeName[len(typeName)-1] == ')' { |
| | |
| | |
| | typeName = typeName[2 : len(typeName)-1] |
| | } |
| |
|
| | typ = pkg.Lookup(typeName) |
| | meth = pkg.Selector(methName) |
| | return typ, meth, nil |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func splitType(name string) (typ, fn string) { |
| | |
| | |
| | |
| | bracket := 0 |
| | for i, r := range name { |
| | if r == '.' && bracket == 0 { |
| | return name[:i], name[i+1:] |
| | } |
| | if r == '[' { |
| | bracket++ |
| | } |
| | if r == ']' { |
| | bracket-- |
| | } |
| | } |
| | return "", name |
| | } |
| |
|
| | |
| | |
| | |
| | func MethodExprName(n Node) *Name { |
| | name, _ := MethodExprFunc(n).Nname.(*Name) |
| | return name |
| | } |
| |
|
| | |
| | func MethodExprFunc(n Node) *types.Field { |
| | switch n.Op() { |
| | case ODOTMETH, OMETHEXPR, OMETHVALUE: |
| | return n.(*SelectorExpr).Selection |
| | } |
| | base.Fatalf("unexpected node: %v (%v)", n, n.Op()) |
| | panic("unreachable") |
| | } |
| |
|
| | |
| | |
| | |
| | type MoveToHeapExpr struct { |
| | miniExpr |
| | Slice Node |
| | |
| | |
| | RType Node |
| | |
| | |
| | |
| | |
| | |
| | |
| | PreserveCapacity bool |
| | } |
| |
|
| | func NewMoveToHeapExpr(pos src.XPos, slice Node) *MoveToHeapExpr { |
| | n := &MoveToHeapExpr{Slice: slice} |
| | n.pos = pos |
| | n.op = OMOVE2HEAP |
| | return n |
| | } |
| |
|