Use of unsafe package detected; ensure it’s necessary, justified in comments, and bounds-checked to avoid memory corruption
// unsafe.Pointer to *Elem or *[Len]Elem.
1// Copyright 2020 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45package ir67import (8 "bytes"9 "cmd/compile/internal/base"10 "cmd/compile/internal/types"11 "cmd/internal/obj"12 "cmd/internal/src"13 "fmt"14 "go/constant"15 "go/token"16)1718// An Expr is a Node that can appear as an expression.19type Expr interface {20 Node21 isExpr()22}2324// A miniExpr is a miniNode with extra fields common to expressions.25// TODO(rsc): Once we are sure about the contents, compact the bools26// into a bit field and leave extra bits available for implementations27// embedding miniExpr. Right now there are ~24 unused bits sitting here.28type miniExpr struct {29 miniNode30 flags bitset831 typ *types.Type32 init Nodes // TODO(rsc): Don't require every Node to have an init33}3435const (36 miniExprNonNil = 1 << iota37 miniExprTransient38 miniExprBounded39 miniExprImplicit // for use by implementations; not supported by every Expr40 miniExprCheckPtr41)4243func (*miniExpr) isExpr() {}4445func (n *miniExpr) Type() *types.Type { return n.typ }46func (n *miniExpr) SetType(x *types.Type) { n.typ = x }47func (n *miniExpr) NonNil() bool { return n.flags&miniExprNonNil != 0 }48func (n *miniExpr) MarkNonNil() { n.flags |= miniExprNonNil }49func (n *miniExpr) Transient() bool { return n.flags&miniExprTransient != 0 }50func (n *miniExpr) SetTransient(b bool) { n.flags.set(miniExprTransient, b) }51func (n *miniExpr) Bounded() bool { return n.flags&miniExprBounded != 0 }52func (n *miniExpr) SetBounded(b bool) { n.flags.set(miniExprBounded, b) }53func (n *miniExpr) Init() Nodes { return n.init }54func (n *miniExpr) PtrInit() *Nodes { return &n.init }55func (n *miniExpr) SetInit(x Nodes) { n.init = x }5657// An AddStringExpr is a string concatenation List[0] + List[1] + ... + List[len(List)-1].58type AddStringExpr struct {59 miniExpr60 List Nodes61 Prealloc *Name62}6364func NewAddStringExpr(pos src.XPos, list []Node) *AddStringExpr {65 n := &AddStringExpr{}66 n.pos = pos67 n.op = OADDSTR68 n.List = list69 return n70}7172// An AddrExpr is an address-of expression &X.73// It may end up being a normal address-of or an allocation of a composite literal.74type AddrExpr struct {75 miniExpr76 X Node77 Prealloc *Name // preallocated storage if any78}7980func NewAddrExpr(pos src.XPos, x Node) *AddrExpr {81 if x == nil || x.Typecheck() != 1 {82 base.FatalfAt(pos, "missed typecheck: %L", x)83 }84 n := &AddrExpr{X: x}85 n.pos = pos8687 switch x.Op() {88 case OARRAYLIT, OMAPLIT, OSLICELIT, OSTRUCTLIT:89 n.op = OPTRLIT9091 default:92 n.op = OADDR93 if r, ok := OuterValue(x).(*Name); ok && r.Op() == ONAME {94 r.SetAddrtaken(true)9596 // If r is a closure variable, we need to mark its canonical97 // variable as addrtaken too, so that closure conversion98 // captures it by reference.99 //100 // Exception: if we've already marked the variable as101 // capture-by-value, then that means this variable isn't102 // logically modified, and we must be taking its address to pass103 // to a runtime function that won't mutate it. In that case, we104 // only need to make sure our own copy is addressable.105 if r.IsClosureVar() && !r.Byval() {106 r.Canonical().SetAddrtaken(true)107 }108 }109 }110111 n.SetType(types.NewPtr(x.Type()))112 n.SetTypecheck(1)113114 return n115}116117func (n *AddrExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 }118func (n *AddrExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }119120func (n *AddrExpr) SetOp(op Op) {121 switch op {122 default:123 panic(n.no("SetOp " + op.String()))124 case OADDR, OPTRLIT:125 n.op = op126 }127}128129// A BasicLit is a literal of basic type.130type BasicLit struct {131 miniExpr132 val constant.Value133}134135// NewBasicLit returns an OLITERAL representing val with the given type.136func NewBasicLit(pos src.XPos, typ *types.Type, val constant.Value) Node {137 AssertValidTypeForConst(typ, val)138139 n := &BasicLit{val: val}140 n.op = OLITERAL141 n.pos = pos142 n.SetType(typ)143 n.SetTypecheck(1)144 return n145}146147func (n *BasicLit) Val() constant.Value { return n.val }148func (n *BasicLit) SetVal(val constant.Value) { n.val = val }149150// NewConstExpr returns an OLITERAL representing val, copying the151// position and type from orig.152func NewConstExpr(val constant.Value, orig Node) Node {153 return NewBasicLit(orig.Pos(), orig.Type(), val)154}155156// A BinaryExpr is a binary expression X Op Y,157// or Op(X, Y) for builtin functions that do not become calls.158type BinaryExpr struct {159 miniExpr160 X Node161 Y Node162 RType Node `mknode:"-"` // see reflectdata/helpers.go163}164165func NewBinaryExpr(pos src.XPos, op Op, x, y Node) *BinaryExpr {166 n := &BinaryExpr{X: x, Y: y}167 n.pos = pos168 n.SetOp(op)169 return n170}171172func (n *BinaryExpr) SetOp(op Op) {173 switch op {174 default:175 panic(n.no("SetOp " + op.String()))176 case OADD, OADDSTR, OAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE,177 OLSH, OLT, OMOD, OMUL, ONE, OOR, ORSH, OSUB, OXOR,178 OCOPY, OCOMPLEX, OUNSAFEADD, OUNSAFESLICE, OUNSAFESTRING,179 OMAKEFACE:180 n.op = op181 }182}183184// A CallExpr is a function call Fun(Args).185type CallExpr struct {186 miniExpr187 Fun Node188 Args Nodes189 DeferAt Node190 RType Node `mknode:"-"` // see reflectdata/helpers.go191 KeepAlive []*Name // vars to be kept alive until call returns192 IsDDD bool193 GoDefer bool // whether this call is part of a go or defer statement194 NoInline bool // whether this call must not be inlined195 UseBuf bool // use stack buffer for backing store (OAPPEND only)196 AppendNoAlias bool // backing store proven to be unaliased (OAPPEND only)197 // whether it's a runtime.KeepAlive call the compiler generates to198 // keep a variable alive. See #73137.199 IsCompilerVarLive bool200 Reshape bool201}202203func NewCallExpr(pos src.XPos, op Op, fun Node, args []Node) *CallExpr {204 n := &CallExpr{Fun: fun}205 n.pos = pos206 n.SetOp(op)207 n.Args = args208 return n209}210211func (*CallExpr) isStmt() {}212213func (n *CallExpr) SetOp(op Op) {214 switch op {215 default:216 panic(n.no("SetOp " + op.String()))217 case OAPPEND,218 OCALL, OCALLFUNC, OCALLINTER, OCALLMETH,219 ODELETE,220 OGETG, OGETCALLERSP,221 OMAKE, OMAX, OMIN, OPRINT, OPRINTLN,222 ORECOVER:223 n.op = op224 }225}226227// A ClosureExpr is a function literal expression.228type ClosureExpr struct {229 miniExpr230 Func *Func `mknode:"-"`231 Prealloc *Name232 IsGoWrap bool // whether this is wrapper closure of a go statement233}234235// A CompLitExpr is a composite literal Type{Vals}.236// Before type-checking, the type is Ntype.237type CompLitExpr struct {238 miniExpr239 List Nodes // initialized values240 RType Node `mknode:"-"` // *runtime._type for OMAPLIT map types241 Prealloc *Name242 // For OSLICELIT, Len is the backing array length.243 // For OMAPLIT, Len is the number of entries that we've removed from List and244 // generated explicit mapassign calls for. This is used to inform the map alloc hint.245 Len int64246}247248func NewCompLitExpr(pos src.XPos, op Op, typ *types.Type, list []Node) *CompLitExpr {249 n := &CompLitExpr{List: list}250 n.pos = pos251 n.SetOp(op)252 if typ != nil {253 n.SetType(typ)254 }255 return n256}257258func (n *CompLitExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 }259func (n *CompLitExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }260261func (n *CompLitExpr) SetOp(op Op) {262 switch op {263 default:264 panic(n.no("SetOp " + op.String()))265 case OARRAYLIT, OCOMPLIT, OMAPLIT, OSTRUCTLIT, OSLICELIT:266 n.op = op267 }268}269270// A ConvExpr is a conversion Type(X).271// It may end up being a value or a type.272type ConvExpr struct {273 miniExpr274 X Node275276 // For implementing OCONVIFACE expressions.277 //278 // TypeWord is an expression yielding a *runtime._type or279 // *runtime.itab value to go in the type word of the iface/eface280 // result. See reflectdata.ConvIfaceTypeWord for further details.281 //282 // SrcRType is an expression yielding a *runtime._type value for X,283 // if it's not pointer-shaped and needs to be heap allocated.284 TypeWord Node `mknode:"-"`285 SrcRType Node `mknode:"-"`286287 // For -d=checkptr instrumentation of conversions from288 // unsafe.Pointer to *Elem or *[Len]Elem.289 //290 // TODO(mdempsky): We only ever need one of these, but currently we291 // don't decide which one until walk. Longer term, it probably makes292 // sense to have a dedicated IR op for `(*[Len]Elem)(ptr)[:n:m]`293 // expressions.294 ElemRType Node `mknode:"-"`295 ElemElemRType Node `mknode:"-"`296}297298func NewConvExpr(pos src.XPos, op Op, typ *types.Type, x Node) *ConvExpr {299 n := &ConvExpr{X: x}300 n.pos = pos301 n.typ = typ302 n.SetOp(op)303 return n304}305306func (n *ConvExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 }307func (n *ConvExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }308func (n *ConvExpr) CheckPtr() bool { return n.flags&miniExprCheckPtr != 0 }309func (n *ConvExpr) SetCheckPtr(b bool) { n.flags.set(miniExprCheckPtr, b) }310311func (n *ConvExpr) SetOp(op Op) {312 switch op {313 default:314 panic(n.no("SetOp " + op.String()))315 case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, OBYTES2STRTMP, ORUNES2STR, OSTR2BYTES, OSTR2BYTESTMP, OSTR2RUNES, ORUNESTR, OSLICE2ARR, OSLICE2ARRPTR:316 n.op = op317 }318}319320// An IndexExpr is an index expression X[Index].321type IndexExpr struct {322 miniExpr323 X Node324 Index Node325 RType Node `mknode:"-"` // see reflectdata/helpers.go326 Assigned bool327}328329func NewIndexExpr(pos src.XPos, x, index Node) *IndexExpr {330 n := &IndexExpr{X: x, Index: index}331 n.pos = pos332 n.op = OINDEX333 return n334}335336func (n *IndexExpr) SetOp(op Op) {337 switch op {338 default:339 panic(n.no("SetOp " + op.String()))340 case OINDEX, OINDEXMAP:341 n.op = op342 }343}344345// A KeyExpr is a Key: Value composite literal key.346type KeyExpr struct {347 miniExpr348 Key Node349 Value Node350}351352func NewKeyExpr(pos src.XPos, key, value Node) *KeyExpr {353 n := &KeyExpr{Key: key, Value: value}354 n.pos = pos355 n.op = OKEY356 return n357}358359// A StructKeyExpr is a Field: Value composite literal key.360type StructKeyExpr struct {361 miniExpr362 Field *types.Field363 Value Node364}365366func NewStructKeyExpr(pos src.XPos, field *types.Field, value Node) *StructKeyExpr {367 n := &StructKeyExpr{Field: field, Value: value}368 n.pos = pos369 n.op = OSTRUCTKEY370 return n371}372373func (n *StructKeyExpr) Sym() *types.Sym { return n.Field.Sym }374375// An InlinedCallExpr is an inlined function call.376type InlinedCallExpr struct {377 miniExpr378 Body Nodes379 ReturnVars Nodes // must be side-effect free380 Reshape bool381}382383func NewInlinedCallExpr(pos src.XPos, body, retvars []Node) *InlinedCallExpr {384 n := &InlinedCallExpr{}385 n.pos = pos386 n.op = OINLCALL387 n.Body = body388 n.ReturnVars = retvars389 return n390}391392func (n *InlinedCallExpr) SingleResult() Node {393 if have := len(n.ReturnVars); have != 1 {394 base.FatalfAt(n.Pos(), "inlined call has %v results, expected 1", have)395 }396397 // If the type of the call is not a shape, but the type of the return value398 // is a shape, we need to do an implicit conversion, so the real type399 // of n is maintained.400 needImplicitConv := !n.Type().HasShape() && n.ReturnVars[0].Type().HasShape()401 if n.Reshape { // or if the inlined call expr needs reshaping.402 needImplicitConv = true403 }404405 if needImplicitConv {406 r := NewConvExpr(n.Pos(), OCONVNOP, n.Type(), n.ReturnVars[0])407 r.SetTypecheck(1)408 return r409 }410 return n.ReturnVars[0]411}412413// A LogicalExpr is an expression X Op Y where Op is && or ||.414// It is separate from BinaryExpr to make room for statements415// that must be executed before Y but after X.416type LogicalExpr struct {417 miniExpr418 X Node419 Y Node420}421422func NewLogicalExpr(pos src.XPos, op Op, x, y Node) *LogicalExpr {423 n := &LogicalExpr{X: x, Y: y}424 n.pos = pos425 n.SetOp(op)426 return n427}428429func (n *LogicalExpr) SetOp(op Op) {430 switch op {431 default:432 panic(n.no("SetOp " + op.String()))433 case OANDAND, OOROR:434 n.op = op435 }436}437438// A MakeExpr is a make expression: make(Type[, Len[, Cap]]).439// Op is OMAKECHAN, OMAKEMAP, OMAKESLICE, or OMAKESLICECOPY,440// but *not* OMAKE (that's a pre-typechecking CallExpr).441type MakeExpr struct {442 miniExpr443 RType Node `mknode:"-"` // see reflectdata/helpers.go444 Len Node445 Cap Node446}447448func NewMakeExpr(pos src.XPos, op Op, len, cap Node) *MakeExpr {449 n := &MakeExpr{Len: len, Cap: cap}450 n.pos = pos451 n.SetOp(op)452 return n453}454455func (n *MakeExpr) SetOp(op Op) {456 switch op {457 default:458 panic(n.no("SetOp " + op.String()))459 case OMAKECHAN, OMAKEMAP, OMAKESLICE, OMAKESLICECOPY:460 n.op = op461 }462}463464// A NilExpr represents the predefined untyped constant nil.465type NilExpr struct {466 miniExpr467}468469func NewNilExpr(pos src.XPos, typ *types.Type) *NilExpr {470 if typ == nil {471 base.FatalfAt(pos, "missing type")472 }473 n := &NilExpr{}474 n.pos = pos475 n.op = ONIL476 n.SetType(typ)477 n.SetTypecheck(1)478 return n479}480481// A ParenExpr is a parenthesized expression (X).482// It may end up being a value or a type.483type ParenExpr struct {484 miniExpr485 X Node486}487488func NewParenExpr(pos src.XPos, x Node) *ParenExpr {489 n := &ParenExpr{X: x}490 n.op = OPAREN491 n.pos = pos492 return n493}494495func (n *ParenExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 }496func (n *ParenExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }497498// A ResultExpr represents a direct access to a result.499type ResultExpr struct {500 miniExpr501 Index int64 // index of the result expr.502}503504func NewResultExpr(pos src.XPos, typ *types.Type, index int64) *ResultExpr {505 n := &ResultExpr{Index: index}506 n.pos = pos507 n.op = ORESULT508 n.typ = typ509 return n510}511512// A LinksymOffsetExpr refers to an offset within a global variable.513// It is like a SelectorExpr but without the field name.514type LinksymOffsetExpr struct {515 miniExpr516 Linksym *obj.LSym517 Offset_ int64518}519520func NewLinksymOffsetExpr(pos src.XPos, lsym *obj.LSym, offset int64, typ *types.Type) *LinksymOffsetExpr {521 if typ == nil {522 base.FatalfAt(pos, "nil type")523 }524 n := &LinksymOffsetExpr{Linksym: lsym, Offset_: offset}525 n.typ = typ526 n.op = OLINKSYMOFFSET527 n.SetTypecheck(1)528 return n529}530531// NewLinksymExpr is NewLinksymOffsetExpr, but with offset fixed at 0.532func NewLinksymExpr(pos src.XPos, lsym *obj.LSym, typ *types.Type) *LinksymOffsetExpr {533 return NewLinksymOffsetExpr(pos, lsym, 0, typ)534}535536// NewNameOffsetExpr is NewLinksymOffsetExpr, but taking a *Name537// representing a global variable instead of an *obj.LSym directly.538func NewNameOffsetExpr(pos src.XPos, name *Name, offset int64, typ *types.Type) *LinksymOffsetExpr {539 if name == nil || IsBlank(name) || !(name.Op() == ONAME && name.Class == PEXTERN) {540 base.FatalfAt(pos, "cannot take offset of nil, blank name or non-global variable: %v", name)541 }542 return NewLinksymOffsetExpr(pos, name.Linksym(), offset, typ)543}544545// A SelectorExpr is a selector expression X.Sel.546type SelectorExpr struct {547 miniExpr548 X Node549 // Sel is the name of the field or method being selected, without (in the550 // case of methods) any preceding type specifier. If the field/method is551 // exported, than the Sym uses the local package regardless of the package552 // of the containing type.553 Sel *types.Sym554 // The actual selected field - may not be filled in until typechecking.555 Selection *types.Field556 Prealloc *Name // preallocated storage for OMETHVALUE, if any557}558559func NewSelectorExpr(pos src.XPos, op Op, x Node, sel *types.Sym) *SelectorExpr {560 n := &SelectorExpr{X: x, Sel: sel}561 n.pos = pos562 n.SetOp(op)563 return n564}565566func (n *SelectorExpr) SetOp(op Op) {567 switch op {568 default:569 panic(n.no("SetOp " + op.String()))570 case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OMETHVALUE, OMETHEXPR:571 n.op = op572 }573}574575func (n *SelectorExpr) Sym() *types.Sym { return n.Sel }576func (n *SelectorExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 }577func (n *SelectorExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }578func (n *SelectorExpr) Offset() int64 { return n.Selection.Offset }579580func (n *SelectorExpr) FuncName() *Name {581 if n.Op() != OMETHEXPR {582 panic(n.no("FuncName"))583 }584 fn := NewNameAt(n.Selection.Pos, MethodSym(n.X.Type(), n.Sel), n.Type())585 fn.Class = PFUNC586 if n.Selection.Nname != nil {587 // TODO(austin): Nname is nil for interface method588 // expressions (I.M), so we can't attach a Func to589 // those here.590 fn.Func = n.Selection.Nname.(*Name).Func591 }592 return fn593}594595// A SliceExpr is a slice expression X[Low:High] or X[Low:High:Max].596type SliceExpr struct {597 miniExpr598 X Node599 Low Node600 High Node601 Max Node602}603604func NewSliceExpr(pos src.XPos, op Op, x, low, high, max Node) *SliceExpr {605 n := &SliceExpr{X: x, Low: low, High: high, Max: max}606 n.pos = pos607 n.op = op608 return n609}610611func (n *SliceExpr) SetOp(op Op) {612 switch op {613 default:614 panic(n.no("SetOp " + op.String()))615 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:616 n.op = op617 }618}619620// IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR).621// o must be a slicing op.622func (o Op) IsSlice3() bool {623 switch o {624 case OSLICE, OSLICEARR, OSLICESTR:625 return false626 case OSLICE3, OSLICE3ARR:627 return true628 }629 base.Fatalf("IsSlice3 op %v", o)630 return false631}632633// A SliceHeaderExpr constructs a slice header from its parts.634type SliceHeaderExpr struct {635 miniExpr636 Ptr Node637 Len Node638 Cap Node639}640641func NewSliceHeaderExpr(pos src.XPos, typ *types.Type, ptr, len, cap Node) *SliceHeaderExpr {642 n := &SliceHeaderExpr{Ptr: ptr, Len: len, Cap: cap}643 n.pos = pos644 n.op = OSLICEHEADER645 n.typ = typ646 return n647}648649// A StringHeaderExpr expression constructs a string header from its parts.650type StringHeaderExpr struct {651 miniExpr652 Ptr Node653 Len Node654}655656func NewStringHeaderExpr(pos src.XPos, ptr, len Node) *StringHeaderExpr {657 n := &StringHeaderExpr{Ptr: ptr, Len: len}658 n.pos = pos659 n.op = OSTRINGHEADER660 n.typ = types.Types[types.TSTRING]661 return n662}663664// A StarExpr is a dereference expression *X.665// It may end up being a value or a type.666type StarExpr struct {667 miniExpr668 X Node669}670671func NewStarExpr(pos src.XPos, x Node) *StarExpr {672 n := &StarExpr{X: x}673 n.op = ODEREF674 n.pos = pos675 return n676}677678func (n *StarExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 }679func (n *StarExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }680681// A TypeAssertExpr is a selector expression X.(Type).682// Before type-checking, the type is Ntype.683type TypeAssertExpr struct {684 miniExpr685 X Node686687 // Runtime type information provided by walkDotType for688 // assertions from non-empty interface to concrete type.689 ITab Node `mknode:"-"` // *runtime.itab for Type implementing X's type690691 // An internal/abi.TypeAssert descriptor to pass to the runtime.692 Descriptor *obj.LSym693694 // When set to true, if this assert would panic, then use a nil pointer panic695 // instead of an interface conversion panic.696 // It must not be set for type assertions using the commaok form.697 UseNilPanic bool698}699700func NewTypeAssertExpr(pos src.XPos, x Node, typ *types.Type) *TypeAssertExpr {701 n := &TypeAssertExpr{X: x}702 n.pos = pos703 n.op = ODOTTYPE704 if typ != nil {705 n.SetType(typ)706 }707 return n708}709710func (n *TypeAssertExpr) SetOp(op Op) {711 switch op {712 default:713 panic(n.no("SetOp " + op.String()))714 case ODOTTYPE, ODOTTYPE2:715 n.op = op716 }717}718719// A DynamicTypeAssertExpr asserts that X is of dynamic type RType.720type DynamicTypeAssertExpr struct {721 miniExpr722 X Node723724 // SrcRType is an expression that yields a *runtime._type value725 // representing X's type. It's used in failed assertion panic726 // messages.727 SrcRType Node728729 // RType is an expression that yields a *runtime._type value730 // representing the asserted type.731 //732 // BUG(mdempsky): If ITab is non-nil, RType may be nil.733 RType Node734735 // ITab is an expression that yields a *runtime.itab value736 // representing the asserted type within the assertee expression's737 // original interface type.738 //739 // ITab is only used for assertions from non-empty interface type to740 // a concrete (i.e., non-interface) type. For all other assertions,741 // ITab is nil.742 ITab Node743}744745func NewDynamicTypeAssertExpr(pos src.XPos, op Op, x, rtype Node) *DynamicTypeAssertExpr {746 n := &DynamicTypeAssertExpr{X: x, RType: rtype}747 n.pos = pos748 n.op = op749 return n750}751752func (n *DynamicTypeAssertExpr) SetOp(op Op) {753 switch op {754 default:755 panic(n.no("SetOp " + op.String()))756 case ODYNAMICDOTTYPE, ODYNAMICDOTTYPE2:757 n.op = op758 }759}760761// A UnaryExpr is a unary expression Op X,762// or Op(X) for a builtin function that does not end up being a call.763type UnaryExpr struct {764 miniExpr765 X Node766}767768func NewUnaryExpr(pos src.XPos, op Op, x Node) *UnaryExpr {769 n := &UnaryExpr{X: x}770 n.pos = pos771 n.SetOp(op)772 return n773}774775func (n *UnaryExpr) SetOp(op Op) {776 switch op {777 default:778 panic(n.no("SetOp " + op.String()))779 case OBITNOT, ONEG, ONOT, OPLUS, ORECV,780 OCAP, OCLEAR, OCLOSE, OIMAG, OLEN, ONEW, OPANIC, OREAL,781 OCHECKNIL, OCFUNC, OIDATA, OITAB, OSPTR,782 OUNSAFESTRINGDATA, OUNSAFESLICEDATA:783 n.op = op784 }785}786787func IsZero(n Node) bool {788 switch n.Op() {789 case ONIL:790 return true791792 case OLITERAL:793 switch u := n.Val(); u.Kind() {794 case constant.String:795 return constant.StringVal(u) == ""796 case constant.Bool:797 return !constant.BoolVal(u)798 default:799 return constant.Sign(u) == 0800 }801802 case OARRAYLIT:803 n := n.(*CompLitExpr)804 for _, n1 := range n.List {805 if n1.Op() == OKEY {806 n1 = n1.(*KeyExpr).Value807 }808 if !IsZero(n1) {809 return false810 }811 }812 return true813814 case OSTRUCTLIT:815 n := n.(*CompLitExpr)816 for _, n1 := range n.List {817 n1 := n1.(*StructKeyExpr)818 if !IsZero(n1.Value) {819 return false820 }821 }822 return true823 }824825 return false826}827828// lvalue etc829func IsAddressable(n Node) bool {830 switch n.Op() {831 case OINDEX:832 n := n.(*IndexExpr)833 if n.X.Type() != nil && n.X.Type().IsArray() {834 return IsAddressable(n.X)835 }836 if n.X.Type() != nil && n.X.Type().IsString() {837 return false838 }839 fallthrough840 case ODEREF, ODOTPTR:841 return true842843 case ODOT:844 n := n.(*SelectorExpr)845 return IsAddressable(n.X)846847 case ONAME:848 n := n.(*Name)849 if n.Class == PFUNC {850 return false851 }852 return true853854 case OLINKSYMOFFSET:855 return true856 }857858 return false859}860861// StaticValue analyzes n to find the earliest expression that always862// evaluates to the same value as n, which might be from an enclosing863// function.864//865// For example, given:866//867// var x int = g()868// func() {869// y := x870// *p = int(y)871// }872//873// calling StaticValue on the "int(y)" expression returns the outer874// "g()" expression.875//876// NOTE: StaticValue can return a result with a different type than877// n's type because it can traverse through OCONVNOP operations.878// TODO: consider reapplying OCONVNOP operations to the result. See https://go.dev/cl/676517.879func StaticValue(n Node) Node {880 for {881 switch n1 := n.(type) {882 case *ConvExpr:883 if n1.Op() == OCONVNOP {884 n = n1.X885 continue886 }887 case *InlinedCallExpr:888 if n1.Op() == OINLCALL {889 n = n1.SingleResult()890 continue891 }892 case *ParenExpr:893 n = n1.X894 continue895 }896897 n1 := staticValue1(n)898 if n1 == nil {899 return n900 }901 n = n1902 }903}904905func staticValue1(nn Node) Node {906 if nn.Op() != ONAME {907 return nil908 }909 n := nn.(*Name).Canonical()910 if n.Class != PAUTO {911 return nil912 }913914 defn := n.Defn915 if defn == nil {916 return nil917 }918919 var rhs Node920FindRHS:921 switch defn.Op() {922 case OAS:923 defn := defn.(*AssignStmt)924 rhs = defn.Y925 case OAS2:926 defn := defn.(*AssignListStmt)927 for i, lhs := range defn.Lhs {928 if lhs == n {929 rhs = defn.Rhs[i]930 break FindRHS931 }932 }933 base.FatalfAt(defn.Pos(), "%v missing from LHS of %v", n, defn)934 default:935 return nil936 }937 if rhs == nil {938 if n.AutoTemp() {939 return nil940 }941 base.FatalfAt(defn.Pos(), "RHS is nil: %v", defn)942 }943944 if Reassigned(n) {945 return nil946 }947948 return rhs949}950951// Reassigned takes an ONAME node, walks the function in which it is952// defined, and returns a boolean indicating whether the name has any953// assignments other than its declaration.954// NB: global variables are always considered to be re-assigned.955// TODO: handle initial declaration not including an assignment and956// followed by a single assignment?957// NOTE: any changes made here should also be made in the corresponding958// code in the ReassignOracle.Init method.959func Reassigned(name *Name) bool {960 if name.Op() != ONAME {961 base.Fatalf("reassigned %v", name)962 }963 // no way to reliably check for no-reassignment of globals, assume it can be964 if name.Curfn == nil {965 return true966 }967968 if name.Addrtaken() {969 return true // conservatively assume it's reassigned indirectly970 }971972 // TODO(mdempsky): This is inefficient and becoming increasingly973 // unwieldy. Figure out a way to generalize escape analysis's974 // reassignment detection for use by inlining and devirtualization.975976 // isName reports whether n is a reference to name.977 isName := func(x Node) bool {978 if x == nil {979 return false980 }981 n, ok := OuterValue(x).(*Name)982 return ok && n.Canonical() == name983 }984985 var do func(n Node) bool986 do = func(n Node) bool {987 switch n.Op() {988 case OAS:989 n := n.(*AssignStmt)990 if isName(n.X) && n != name.Defn {991 return true992 }993 case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV, OSELRECV2:994 n := n.(*AssignListStmt)995 for _, p := range n.Lhs {996 if isName(p) && n != name.Defn {997 return true998 }999 }1000 case OASOP:1001 n := n.(*AssignOpStmt)1002 if isName(n.X) {1003 return true1004 }1005 case OADDR:1006 n := n.(*AddrExpr)1007 if isName(n.X) {1008 base.FatalfAt(n.Pos(), "%v not marked addrtaken", name)1009 }1010 case ORANGE:1011 n := n.(*RangeStmt)1012 if isName(n.Key) || isName(n.Value) {1013 return true1014 }1015 case OCLOSURE:1016 n := n.(*ClosureExpr)1017 if Any(n.Func, do) {1018 return true1019 }1020 }1021 return false1022 }1023 return Any(name.Curfn, do)1024}10251026// StaticCalleeName returns the ONAME/PFUNC for n, if known.1027func StaticCalleeName(n Node) *Name {1028 switch n.Op() {1029 case OMETHEXPR:1030 n := n.(*SelectorExpr)1031 return MethodExprName(n)1032 case ONAME:1033 n := n.(*Name)1034 if n.Class == PFUNC {1035 return n1036 }1037 case OCLOSURE:1038 return n.(*ClosureExpr).Func.Nname1039 }1040 return nil1041}10421043// IsIntrinsicCall reports whether the compiler back end will treat the call as an intrinsic operation.1044var IsIntrinsicCall = func(*CallExpr) bool { return false }10451046// IsIntrinsicSym reports whether the compiler back end will treat a call to this symbol as an intrinsic operation.1047var IsIntrinsicSym = func(*types.Sym) bool { return false }10481049// SameSafeExpr checks whether it is safe to reuse one of l and r1050// instead of computing both. SameSafeExpr assumes that l and r are1051// used in the same statement or expression. In order for it to be1052// safe to reuse l or r, they must:1053// - be the same expression1054// - not have side-effects (no function calls, no channel ops);1055// however, panics are ok1056// - not cause inappropriate aliasing; e.g. two string to []byte1057// conversions, must result in two distinct slices1058//1059// The handling of OINDEXMAP is subtle. OINDEXMAP can occur both1060// as an lvalue (map assignment) and an rvalue (map access). This is1061// currently OK, since the only place SameSafeExpr gets used on an1062// lvalue expression is for OSLICE and OAPPEND optimizations, and it1063// is correct in those settings.1064func SameSafeExpr(l Node, r Node) bool {1065 for l.Op() == OCONVNOP {1066 l = l.(*ConvExpr).X1067 }1068 for r.Op() == OCONVNOP {1069 r = r.(*ConvExpr).X1070 }1071 if l.Op() != r.Op() || !types.Identical(l.Type(), r.Type()) {1072 return false1073 }10741075 switch l.Op() {1076 case ONAME:1077 return l == r10781079 case ODOT, ODOTPTR:1080 l := l.(*SelectorExpr)1081 r := r.(*SelectorExpr)1082 return l.Sel != nil && r.Sel != nil && l.Sel == r.Sel && SameSafeExpr(l.X, r.X)10831084 case ODEREF:1085 l := l.(*StarExpr)1086 r := r.(*StarExpr)1087 return SameSafeExpr(l.X, r.X)10881089 case ONOT, OBITNOT, OPLUS, ONEG:1090 l := l.(*UnaryExpr)1091 r := r.(*UnaryExpr)1092 return SameSafeExpr(l.X, r.X)10931094 case OCONV:1095 l := l.(*ConvExpr)1096 r := r.(*ConvExpr)1097 // Some conversions can't be reused, such as []byte(str).1098 // Allow only numeric-ish types. This is a bit conservative.1099 return types.IsSimple[l.Type().Kind()] && SameSafeExpr(l.X, r.X)11001101 case OINDEX, OINDEXMAP:1102 l := l.(*IndexExpr)1103 r := r.(*IndexExpr)1104 return SameSafeExpr(l.X, r.X) && SameSafeExpr(l.Index, r.Index)11051106 case OADD, OSUB, OOR, OXOR, OMUL, OLSH, ORSH, OAND, OANDNOT, ODIV, OMOD:1107 l := l.(*BinaryExpr)1108 r := r.(*BinaryExpr)1109 return SameSafeExpr(l.X, r.X) && SameSafeExpr(l.Y, r.Y)11101111 case OLITERAL:1112 return constant.Compare(l.Val(), token.EQL, r.Val())11131114 case ONIL:1115 return true1116 }11171118 return false1119}11201121// ShouldCheckPtr reports whether pointer checking should be enabled for1122// function fn at a given level. See debugHelpFooter for defined1123// levels.1124func ShouldCheckPtr(fn *Func, level int) bool {1125 return base.Debug.Checkptr >= level && fn.Pragma&NoCheckPtr == 01126}11271128// ShouldAsanCheckPtr reports whether pointer checking should be enabled for1129// function fn when -asan is enabled.1130func ShouldAsanCheckPtr(fn *Func) bool {1131 return base.Flag.ASan && fn.Pragma&NoCheckPtr == 01132}11331134// IsReflectHeaderDataField reports whether l is an expression p.Data1135// where p has type reflect.SliceHeader or reflect.StringHeader.1136func IsReflectHeaderDataField(l Node) bool {1137 if l.Type() != types.Types[types.TUINTPTR] {1138 return false1139 }11401141 var tsym *types.Sym1142 switch l.Op() {1143 case ODOT:1144 l := l.(*SelectorExpr)1145 tsym = l.X.Type().Sym()1146 case ODOTPTR:1147 l := l.(*SelectorExpr)1148 tsym = l.X.Type().Elem().Sym()1149 default:1150 return false1151 }11521153 if tsym == nil || l.Sym().Name != "Data" || tsym.Pkg.Path != "reflect" {1154 return false1155 }1156 return tsym.Name == "SliceHeader" || tsym.Name == "StringHeader"1157}11581159func ParamNames(ft *types.Type) []Node {1160 args := make([]Node, ft.NumParams())1161 for i, f := range ft.Params() {1162 args[i] = f.Nname.(*Name)1163 }1164 return args1165}11661167func RecvParamNames(ft *types.Type) []Node {1168 args := make([]Node, ft.NumRecvs()+ft.NumParams())1169 for i, f := range ft.RecvParams() {1170 args[i] = f.Nname.(*Name)1171 }1172 return args1173}11741175// MethodSym returns the method symbol representing a method name1176// associated with a specific receiver type.1177//1178// Method symbols can be used to distinguish the same method appearing1179// in different method sets. For example, T.M and (*T).M have distinct1180// method symbols.1181//1182// The returned symbol will be marked as a function.1183func MethodSym(recv *types.Type, msym *types.Sym) *types.Sym {1184 sym := MethodSymSuffix(recv, msym, "")1185 sym.SetFunc(true)1186 return sym1187}11881189// MethodSymSuffix is like MethodSym, but allows attaching a1190// distinguisher suffix. To avoid collisions, the suffix must not1191// start with a letter, number, or period.1192func MethodSymSuffix(recv *types.Type, msym *types.Sym, suffix string) *types.Sym {1193 if msym.IsBlank() {1194 base.Fatalf("blank method name")1195 }11961197 rsym := recv.Sym()1198 if recv.IsPtr() {1199 if rsym != nil {1200 base.Fatalf("declared pointer receiver type: %v", recv)1201 }1202 rsym = recv.Elem().Sym()1203 }12041205 // Find the package the receiver type appeared in. For1206 // anonymous receiver types (i.e., anonymous structs with1207 // embedded fields), use the "go" pseudo-package instead.1208 rpkg := Pkgs.Go1209 if rsym != nil {1210 rpkg = rsym.Pkg1211 }12121213 var b bytes.Buffer1214 if recv.IsPtr() {1215 // The parentheses aren't really necessary, but1216 // they're pretty traditional at this point.1217 fmt.Fprintf(&b, "(%-S)", recv)1218 } else {1219 fmt.Fprintf(&b, "%-S", recv)1220 }12211222 // A particular receiver type may have multiple non-exported1223 // methods with the same name. To disambiguate them, include a1224 // package qualifier for names that came from a different1225 // package than the receiver type.1226 if !types.IsExported(msym.Name) && msym.Pkg != rpkg {1227 b.WriteString(".")1228 b.WriteString(msym.Pkg.Prefix)1229 }12301231 b.WriteString(".")1232 b.WriteString(msym.Name)1233 b.WriteString(suffix)1234 return rpkg.LookupBytes(b.Bytes())1235}12361237// LookupMethodSelector returns the types.Sym of the selector for a method1238// named in local symbol name, as well as the types.Sym of the receiver.1239//1240// TODO(prattmic): this does not attempt to handle method suffixes (wrappers).1241func LookupMethodSelector(pkg *types.Pkg, name string) (typ, meth *types.Sym, err error) {1242 typeName, methName := splitType(name)1243 if typeName == "" {1244 return nil, nil, fmt.Errorf("%s doesn't contain type split", name)1245 }12461247 if len(typeName) > 3 && typeName[:2] == "(*" && typeName[len(typeName)-1] == ')' {1248 // Symbol name is for a pointer receiver method. We just want1249 // the base type name.1250 typeName = typeName[2 : len(typeName)-1]1251 }12521253 typ = pkg.Lookup(typeName)1254 meth = pkg.Selector(methName)1255 return typ, meth, nil1256}12571258// splitType splits a local symbol name into type and method (fn). If this a1259// free function, typ == "".1260//1261// N.B. closures and methods can be ambiguous (e.g., bar.func1). These cases1262// are returned as methods.1263func splitType(name string) (typ, fn string) {1264 // Types are split on the first dot, ignoring everything inside1265 // brackets (instantiation of type parameter, usually including1266 // "go.shape").1267 bracket := 01268 for i, r := range name {1269 if r == '.' && bracket == 0 {1270 return name[:i], name[i+1:]1271 }1272 if r == '[' {1273 bracket++1274 }1275 if r == ']' {1276 bracket--1277 }1278 }1279 return "", name1280}12811282// MethodExprName returns the ONAME representing the method1283// referenced by expression n, which must be a method selector,1284// method expression, or method value.1285func MethodExprName(n Node) *Name {1286 name, _ := MethodExprFunc(n).Nname.(*Name)1287 return name1288}12891290// MethodExprFunc is like MethodExprName, but returns the types.Field instead.1291func MethodExprFunc(n Node) *types.Field {1292 switch n.Op() {1293 case ODOTMETH, OMETHEXPR, OMETHVALUE:1294 return n.(*SelectorExpr).Selection1295 }1296 base.Fatalf("unexpected node: %v (%v)", n, n.Op())1297 panic("unreachable")1298}12991300// A MoveToHeapExpr takes a slice as input and moves it to the1301// heap (by copying the backing store if it is not already1302// on the heap).1303type MoveToHeapExpr struct {1304 miniExpr1305 Slice Node1306 // An expression that evaluates to a *runtime._type1307 // that represents the slice element type.1308 RType Node1309 // If PreserveCapacity is true, the capacity of1310 // the resulting slice, and all of the elements in1311 // [len:cap], must be preserved.1312 // If PreserveCapacity is false, the resulting1313 // slice may have any capacity >= len, with any1314 // elements in the resulting [len:cap] range zeroed.1315 PreserveCapacity bool1316}13171318func NewMoveToHeapExpr(pos src.XPos, slice Node) *MoveToHeapExpr {1319 n := &MoveToHeapExpr{Slice: slice}1320 n.pos = pos1321 n.op = OMOVE2HEAP1322 return n1323}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.