argument(e.discardHole(), &call.Args[i])
}
- case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
+ case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
call := call.(*ir.UnaryExpr)
argument(e.discardHole(), &call.X)
- case ir.OUNSAFEADD, ir.OUNSAFESLICE:
+ case ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
call := call.(*ir.BinaryExpr)
argument(ks[0], &call.X)
argument(e.discardHole(), &call.Y)
n := n.(*ir.UnaryExpr)
e.discard(n.X)
- case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OINLCALL, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.ORECOVER, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+ case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OINLCALL,
+ ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.ORECOVER,
+ ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
e.call([]hole{k}, n)
case ir.ONEW:
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,
+ OCOPY, OCOMPLEX, OUNSAFEADD, OUNSAFESLICE, OUNSAFESTRING,
OEFACE:
n.op = op
}
return n
}
+// A StringHeaderExpr expression constructs a string header from its parts.
+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
+}
+
// A StarExpr is a dereference expression *X.
// It may end up being a value or a type.
type StarExpr struct {
case OBITNOT, ONEG, ONOT, OPLUS, ORECV,
OALIGNOF, OCAP, OCLOSE, OIMAG, OLEN, ONEW,
OOFFSETOF, OPANIC, OREAL, OSIZEOF,
- OCHECKNIL, OCFUNC, OIDATA, OITAB, OSPTR:
+ OCHECKNIL, OCFUNC, OIDATA, OITAB, OSPTR,
+ OUNSAFESTRINGDATA, OUNSAFESLICEDATA:
n.op = op
}
}
// Op
var OpNames = []string{
- OADDR: "&",
- OADD: "+",
- OADDSTR: "+",
- OALIGNOF: "unsafe.Alignof",
- OANDAND: "&&",
- OANDNOT: "&^",
- OAND: "&",
- OAPPEND: "append",
- OAS: "=",
- OAS2: "=",
- OBREAK: "break",
- OCALL: "function call", // not actual syntax
- OCAP: "cap",
- OCASE: "case",
- OCLOSE: "close",
- OCOMPLEX: "complex",
- OBITNOT: "^",
- OCONTINUE: "continue",
- OCOPY: "copy",
- ODELETE: "delete",
- ODEFER: "defer",
- ODIV: "/",
- OEQ: "==",
- OFALL: "fallthrough",
- OFOR: "for",
- OGE: ">=",
- OGOTO: "goto",
- OGT: ">",
- OIF: "if",
- OIMAG: "imag",
- OINLMARK: "inlmark",
- ODEREF: "*",
- OLEN: "len",
- OLE: "<=",
- OLSH: "<<",
- OLT: "<",
- OMAKE: "make",
- ONEG: "-",
- OMOD: "%",
- OMUL: "*",
- ONEW: "new",
- ONE: "!=",
- ONOT: "!",
- OOFFSETOF: "unsafe.Offsetof",
- OOROR: "||",
- OOR: "|",
- OPANIC: "panic",
- OPLUS: "+",
- OPRINTN: "println",
- OPRINT: "print",
- ORANGE: "range",
- OREAL: "real",
- ORECV: "<-",
- ORECOVER: "recover",
- ORETURN: "return",
- ORSH: ">>",
- OSELECT: "select",
- OSEND: "<-",
- OSIZEOF: "unsafe.Sizeof",
- OSUB: "-",
- OSWITCH: "switch",
- OUNSAFEADD: "unsafe.Add",
- OUNSAFESLICE: "unsafe.Slice",
- OXOR: "^",
+ OADDR: "&",
+ OADD: "+",
+ OADDSTR: "+",
+ OALIGNOF: "unsafe.Alignof",
+ OANDAND: "&&",
+ OANDNOT: "&^",
+ OAND: "&",
+ OAPPEND: "append",
+ OAS: "=",
+ OAS2: "=",
+ OBREAK: "break",
+ OCALL: "function call", // not actual syntax
+ OCAP: "cap",
+ OCASE: "case",
+ OCLOSE: "close",
+ OCOMPLEX: "complex",
+ OBITNOT: "^",
+ OCONTINUE: "continue",
+ OCOPY: "copy",
+ ODELETE: "delete",
+ ODEFER: "defer",
+ ODIV: "/",
+ OEQ: "==",
+ OFALL: "fallthrough",
+ OFOR: "for",
+ OGE: ">=",
+ OGOTO: "goto",
+ OGT: ">",
+ OIF: "if",
+ OIMAG: "imag",
+ OINLMARK: "inlmark",
+ ODEREF: "*",
+ OLEN: "len",
+ OLE: "<=",
+ OLSH: "<<",
+ OLT: "<",
+ OMAKE: "make",
+ ONEG: "-",
+ OMOD: "%",
+ OMUL: "*",
+ ONEW: "new",
+ ONE: "!=",
+ ONOT: "!",
+ OOFFSETOF: "unsafe.Offsetof",
+ OOROR: "||",
+ OOR: "|",
+ OPANIC: "panic",
+ OPLUS: "+",
+ OPRINTN: "println",
+ OPRINT: "print",
+ ORANGE: "range",
+ OREAL: "real",
+ ORECV: "<-",
+ ORECOVER: "recover",
+ ORETURN: "return",
+ ORSH: ">>",
+ OSELECT: "select",
+ OSEND: "<-",
+ OSIZEOF: "unsafe.Sizeof",
+ OSUB: "-",
+ OSWITCH: "switch",
+ OUNSAFEADD: "unsafe.Add",
+ OUNSAFESLICE: "unsafe.Slice",
+ OUNSAFESLICEDATA: "unsafe.SliceData",
+ OUNSAFESTRING: "unsafe.String",
+ OUNSAFESTRINGDATA: "unsafe.StringData",
+ OXOR: "^",
}
// GoString returns the Go syntax for the Op, or else its name.
}
var OpPrec = []int{
- OALIGNOF: 8,
- OAPPEND: 8,
- OBYTES2STR: 8,
- OARRAYLIT: 8,
- OSLICELIT: 8,
- ORUNES2STR: 8,
- OCALLFUNC: 8,
- OCALLINTER: 8,
- OCALLMETH: 8,
- OCALL: 8,
- OCAP: 8,
- OCLOSE: 8,
- OCOMPLIT: 8,
- OCONVIFACE: 8,
- OCONVIDATA: 8,
- OCONVNOP: 8,
- OCONV: 8,
- OCOPY: 8,
- ODELETE: 8,
- OGETG: 8,
- OLEN: 8,
- OLITERAL: 8,
- OMAKESLICE: 8,
- OMAKESLICECOPY: 8,
- OMAKE: 8,
- OMAPLIT: 8,
- ONAME: 8,
- ONEW: 8,
- ONIL: 8,
- ONONAME: 8,
- OOFFSETOF: 8,
- OPANIC: 8,
- OPAREN: 8,
- OPRINTN: 8,
- OPRINT: 8,
- ORUNESTR: 8,
- OSIZEOF: 8,
- OSLICE2ARRPTR: 8,
- OSTR2BYTES: 8,
- OSTR2RUNES: 8,
- OSTRUCTLIT: 8,
- OTYPE: 8,
- OUNSAFEADD: 8,
- OUNSAFESLICE: 8,
- OINDEXMAP: 8,
- OINDEX: 8,
- OSLICE: 8,
- OSLICESTR: 8,
- OSLICEARR: 8,
- OSLICE3: 8,
- OSLICE3ARR: 8,
- OSLICEHEADER: 8,
- ODOTINTER: 8,
- ODOTMETH: 8,
- ODOTPTR: 8,
- ODOTTYPE2: 8,
- ODOTTYPE: 8,
- ODOT: 8,
- OXDOT: 8,
- OMETHVALUE: 8,
- OMETHEXPR: 8,
- OPLUS: 7,
- ONOT: 7,
- OBITNOT: 7,
- ONEG: 7,
- OADDR: 7,
- ODEREF: 7,
- ORECV: 7,
- OMUL: 6,
- ODIV: 6,
- OMOD: 6,
- OLSH: 6,
- ORSH: 6,
- OAND: 6,
- OANDNOT: 6,
- OADD: 5,
- OSUB: 5,
- OOR: 5,
- OXOR: 5,
- OEQ: 4,
- OLT: 4,
- OLE: 4,
- OGE: 4,
- OGT: 4,
- ONE: 4,
- OSEND: 3,
- OANDAND: 2,
- OOROR: 1,
+ OALIGNOF: 8,
+ OAPPEND: 8,
+ OBYTES2STR: 8,
+ OARRAYLIT: 8,
+ OSLICELIT: 8,
+ ORUNES2STR: 8,
+ OCALLFUNC: 8,
+ OCALLINTER: 8,
+ OCALLMETH: 8,
+ OCALL: 8,
+ OCAP: 8,
+ OCLOSE: 8,
+ OCOMPLIT: 8,
+ OCONVIFACE: 8,
+ OCONVIDATA: 8,
+ OCONVNOP: 8,
+ OCONV: 8,
+ OCOPY: 8,
+ ODELETE: 8,
+ OGETG: 8,
+ OLEN: 8,
+ OLITERAL: 8,
+ OMAKESLICE: 8,
+ OMAKESLICECOPY: 8,
+ OMAKE: 8,
+ OMAPLIT: 8,
+ ONAME: 8,
+ ONEW: 8,
+ ONIL: 8,
+ ONONAME: 8,
+ OOFFSETOF: 8,
+ OPANIC: 8,
+ OPAREN: 8,
+ OPRINTN: 8,
+ OPRINT: 8,
+ ORUNESTR: 8,
+ OSIZEOF: 8,
+ OSLICE2ARRPTR: 8,
+ OSTR2BYTES: 8,
+ OSTR2RUNES: 8,
+ OSTRUCTLIT: 8,
+ OTYPE: 8,
+ OUNSAFEADD: 8,
+ OUNSAFESLICE: 8,
+ OUNSAFESLICEDATA: 8,
+ OUNSAFESTRING: 8,
+ OUNSAFESTRINGDATA: 8,
+ OINDEXMAP: 8,
+ OINDEX: 8,
+ OSLICE: 8,
+ OSLICESTR: 8,
+ OSLICEARR: 8,
+ OSLICE3: 8,
+ OSLICE3ARR: 8,
+ OSLICEHEADER: 8,
+ OSTRINGHEADER: 8,
+ ODOTINTER: 8,
+ ODOTMETH: 8,
+ ODOTPTR: 8,
+ ODOTTYPE2: 8,
+ ODOTTYPE: 8,
+ ODOT: 8,
+ OXDOT: 8,
+ OMETHVALUE: 8,
+ OMETHEXPR: 8,
+ OPLUS: 7,
+ ONOT: 7,
+ OBITNOT: 7,
+ ONEG: 7,
+ OADDR: 7,
+ ODEREF: 7,
+ ORECV: 7,
+ OMUL: 6,
+ ODIV: 6,
+ OMOD: 6,
+ OLSH: 6,
+ ORSH: 6,
+ OAND: 6,
+ OANDNOT: 6,
+ OADD: 5,
+ OSUB: 5,
+ OOR: 5,
+ OXOR: 5,
+ OEQ: 4,
+ OLT: 4,
+ OLE: 4,
+ OGE: 4,
+ OGT: 4,
+ ONE: 4,
+ OSEND: 3,
+ OANDAND: 2,
+ OOROR: 1,
// Statements handled by stmtfmt
OAS: -1,
//
// This node is created so the walk pass can optimize this pattern which would
// otherwise be hard to detect after the order pass.
- OMUL // X * Y
- ODIV // X / Y
- OMOD // X % Y
- OLSH // X << Y
- ORSH // X >> Y
- OAND // X & Y
- OANDNOT // X &^ Y
- ONEW // new(X); corresponds to calls to new in source code
- ONOT // !X
- OBITNOT // ^X
- OPLUS // +X
- ONEG // -X
- OOROR // X || Y
- OPANIC // panic(X)
- OPRINT // print(List)
- OPRINTN // println(List)
- OPAREN // (X)
- OSEND // Chan <- Value
- OSLICE // X[Low : High] (X is untypechecked or slice)
- OSLICEARR // X[Low : High] (X is pointer to array)
- OSLICESTR // X[Low : High] (X is string)
- OSLICE3 // X[Low : High : Max] (X is untypedchecked or slice)
- OSLICE3ARR // X[Low : High : Max] (X is pointer to array)
- OSLICEHEADER // sliceheader{Ptr, Len, Cap} (Ptr is unsafe.Pointer, Len is length, Cap is capacity)
- ORECOVER // recover()
- ORECOVERFP // recover(Args) w/ explicit FP argument
- ORECV // <-X
- ORUNESTR // Type(X) (Type is string, X is rune)
- OSELRECV2 // like OAS2: Lhs = Rhs where len(Lhs)=2, len(Rhs)=1, Rhs[0].Op = ORECV (appears as .Var of OCASE)
- OREAL // real(X)
- OIMAG // imag(X)
- OCOMPLEX // complex(X, Y)
- OALIGNOF // unsafe.Alignof(X)
- OOFFSETOF // unsafe.Offsetof(X)
- OSIZEOF // unsafe.Sizeof(X)
- OUNSAFEADD // unsafe.Add(X, Y)
- OUNSAFESLICE // unsafe.Slice(X, Y)
- OMETHEXPR // X(Args) (method expression T.Method(args), first argument is the method receiver)
- OMETHVALUE // X.Sel (method expression t.Method, not called)
+ OMUL // X * Y
+ ODIV // X / Y
+ OMOD // X % Y
+ OLSH // X << Y
+ ORSH // X >> Y
+ OAND // X & Y
+ OANDNOT // X &^ Y
+ ONEW // new(X); corresponds to calls to new in source code
+ ONOT // !X
+ OBITNOT // ^X
+ OPLUS // +X
+ ONEG // -X
+ OOROR // X || Y
+ OPANIC // panic(X)
+ OPRINT // print(List)
+ OPRINTN // println(List)
+ OPAREN // (X)
+ OSEND // Chan <- Value
+ OSLICE // X[Low : High] (X is untypechecked or slice)
+ OSLICEARR // X[Low : High] (X is pointer to array)
+ OSLICESTR // X[Low : High] (X is string)
+ OSLICE3 // X[Low : High : Max] (X is untypedchecked or slice)
+ OSLICE3ARR // X[Low : High : Max] (X is pointer to array)
+ OSLICEHEADER // sliceheader{Ptr, Len, Cap} (Ptr is unsafe.Pointer, Len is length, Cap is capacity)
+ OSTRINGHEADER // stringheader{Ptr, Len} (Ptr is unsafe.Pointer, Len is length)
+ ORECOVER // recover()
+ ORECOVERFP // recover(Args) w/ explicit FP argument
+ ORECV // <-X
+ ORUNESTR // Type(X) (Type is string, X is rune)
+ OSELRECV2 // like OAS2: Lhs = Rhs where len(Lhs)=2, len(Rhs)=1, Rhs[0].Op = ORECV (appears as .Var of OCASE)
+ OREAL // real(X)
+ OIMAG // imag(X)
+ OCOMPLEX // complex(X, Y)
+ OALIGNOF // unsafe.Alignof(X)
+ OOFFSETOF // unsafe.Offsetof(X)
+ OSIZEOF // unsafe.Sizeof(X)
+ OUNSAFEADD // unsafe.Add(X, Y)
+ OUNSAFESLICE // unsafe.Slice(X, Y)
+ OUNSAFESLICEDATA // unsafe.SliceData(X)
+ OUNSAFESTRING // unsafe.String(X, Y)
+ OUNSAFESTRINGDATA // unsafe.StringData(X)
+ OMETHEXPR // X(Args) (method expression T.Method(args), first argument is the method receiver)
+ OMETHVALUE // X.Sel (method expression t.Method, not called)
// statements
OBLOCK // { List } (block of code)
}
}
+func (n *StringHeaderExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
+func (n *StringHeaderExpr) copy() Node {
+ c := *n
+ c.init = copyNodes(c.init)
+ return &c
+}
+func (n *StringHeaderExpr) doChildren(do func(Node) bool) bool {
+ if doNodes(n.init, do) {
+ return true
+ }
+ if n.Ptr != nil && do(n.Ptr) {
+ return true
+ }
+ if n.Len != nil && do(n.Len) {
+ return true
+ }
+ return false
+}
+func (n *StringHeaderExpr) editChildren(edit func(Node) Node) {
+ editNodes(n.init, edit)
+ if n.Ptr != nil {
+ n.Ptr = edit(n.Ptr).(Node)
+ }
+ if n.Len != nil {
+ n.Len = edit(n.Len).(Node)
+ }
+}
+
func (n *StructKeyExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
func (n *StructKeyExpr) copy() Node {
c := *n
_ = x[OSLICE3-96]
_ = x[OSLICE3ARR-97]
_ = x[OSLICEHEADER-98]
- _ = x[ORECOVER-99]
- _ = x[ORECOVERFP-100]
- _ = x[ORECV-101]
- _ = x[ORUNESTR-102]
- _ = x[OSELRECV2-103]
- _ = x[OREAL-104]
- _ = x[OIMAG-105]
- _ = x[OCOMPLEX-106]
- _ = x[OALIGNOF-107]
- _ = x[OOFFSETOF-108]
- _ = x[OSIZEOF-109]
- _ = x[OUNSAFEADD-110]
- _ = x[OUNSAFESLICE-111]
- _ = x[OMETHEXPR-112]
- _ = x[OMETHVALUE-113]
- _ = x[OBLOCK-114]
- _ = x[OBREAK-115]
- _ = x[OCASE-116]
- _ = x[OCONTINUE-117]
- _ = x[ODEFER-118]
- _ = x[OFALL-119]
- _ = x[OFOR-120]
- _ = x[OGOTO-121]
- _ = x[OIF-122]
- _ = x[OLABEL-123]
- _ = x[OGO-124]
- _ = x[ORANGE-125]
- _ = x[ORETURN-126]
- _ = x[OSELECT-127]
- _ = x[OSWITCH-128]
- _ = x[OTYPESW-129]
- _ = x[OFUNCINST-130]
- _ = x[OINLCALL-131]
- _ = x[OEFACE-132]
- _ = x[OITAB-133]
- _ = x[OIDATA-134]
- _ = x[OSPTR-135]
- _ = x[OCFUNC-136]
- _ = x[OCHECKNIL-137]
- _ = x[ORESULT-138]
- _ = x[OINLMARK-139]
- _ = x[OLINKSYMOFFSET-140]
- _ = x[OJUMPTABLE-141]
- _ = x[ODYNAMICDOTTYPE-142]
- _ = x[ODYNAMICDOTTYPE2-143]
- _ = x[ODYNAMICTYPE-144]
- _ = x[OTAILCALL-145]
- _ = x[OGETG-146]
- _ = x[OGETCALLERPC-147]
- _ = x[OGETCALLERSP-148]
- _ = x[OEND-149]
+ _ = x[OSTRINGHEADER-99]
+ _ = x[ORECOVER-100]
+ _ = x[ORECOVERFP-101]
+ _ = x[ORECV-102]
+ _ = x[ORUNESTR-103]
+ _ = x[OSELRECV2-104]
+ _ = x[OREAL-105]
+ _ = x[OIMAG-106]
+ _ = x[OCOMPLEX-107]
+ _ = x[OALIGNOF-108]
+ _ = x[OOFFSETOF-109]
+ _ = x[OSIZEOF-110]
+ _ = x[OUNSAFEADD-111]
+ _ = x[OUNSAFESLICE-112]
+ _ = x[OUNSAFESLICEDATA-113]
+ _ = x[OUNSAFESTRING-114]
+ _ = x[OUNSAFESTRINGDATA-115]
+ _ = x[OMETHEXPR-116]
+ _ = x[OMETHVALUE-117]
+ _ = x[OBLOCK-118]
+ _ = x[OBREAK-119]
+ _ = x[OCASE-120]
+ _ = x[OCONTINUE-121]
+ _ = x[ODEFER-122]
+ _ = x[OFALL-123]
+ _ = x[OFOR-124]
+ _ = x[OGOTO-125]
+ _ = x[OIF-126]
+ _ = x[OLABEL-127]
+ _ = x[OGO-128]
+ _ = x[ORANGE-129]
+ _ = x[ORETURN-130]
+ _ = x[OSELECT-131]
+ _ = x[OSWITCH-132]
+ _ = x[OTYPESW-133]
+ _ = x[OFUNCINST-134]
+ _ = x[OINLCALL-135]
+ _ = x[OEFACE-136]
+ _ = x[OITAB-137]
+ _ = x[OIDATA-138]
+ _ = x[OSPTR-139]
+ _ = x[OCFUNC-140]
+ _ = x[OCHECKNIL-141]
+ _ = x[ORESULT-142]
+ _ = x[OINLMARK-143]
+ _ = x[OLINKSYMOFFSET-144]
+ _ = x[OJUMPTABLE-145]
+ _ = x[ODYNAMICDOTTYPE-146]
+ _ = x[ODYNAMICDOTTYPE2-147]
+ _ = x[ODYNAMICTYPE-148]
+ _ = x[OTAILCALL-149]
+ _ = x[OGETG-150]
+ _ = x[OGETCALLERPC-151]
+ _ = x[OGETCALLERSP-152]
+ _ = x[OEND-153]
}
-const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2REALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTINLCALLEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND"
+const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERSTRINGHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2REALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEUNSAFESLICEDATAUNSAFESTRINGUNSAFESTRINGDATAMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTINLCALLEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND"
-var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 132, 134, 137, 147, 154, 161, 168, 172, 176, 184, 192, 201, 204, 209, 216, 223, 229, 238, 246, 254, 260, 264, 273, 282, 289, 293, 296, 303, 311, 318, 324, 327, 333, 340, 348, 352, 359, 367, 369, 371, 373, 375, 377, 379, 384, 389, 397, 400, 409, 412, 416, 424, 431, 440, 453, 456, 459, 462, 465, 468, 471, 477, 480, 483, 489, 493, 496, 500, 505, 510, 516, 521, 525, 530, 538, 546, 552, 561, 572, 579, 588, 592, 599, 607, 611, 615, 622, 629, 637, 643, 652, 663, 671, 680, 685, 690, 694, 702, 707, 711, 714, 718, 720, 725, 727, 732, 738, 744, 750, 756, 764, 771, 776, 780, 785, 789, 794, 802, 808, 815, 828, 837, 851, 866, 877, 885, 889, 900, 911, 914}
+var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 132, 134, 137, 147, 154, 161, 168, 172, 176, 184, 192, 201, 204, 209, 216, 223, 229, 238, 246, 254, 260, 264, 273, 282, 289, 293, 296, 303, 311, 318, 324, 327, 333, 340, 348, 352, 359, 367, 369, 371, 373, 375, 377, 379, 384, 389, 397, 400, 409, 412, 416, 424, 431, 440, 453, 456, 459, 462, 465, 468, 471, 477, 480, 483, 489, 493, 496, 500, 505, 510, 516, 521, 525, 530, 538, 546, 552, 561, 572, 584, 591, 600, 604, 611, 619, 623, 627, 634, 641, 649, 655, 664, 675, 690, 702, 718, 726, 735, 740, 745, 749, 757, 762, 766, 769, 773, 775, 780, 782, 787, 793, 799, 805, 811, 819, 826, 831, 835, 840, 844, 849, 857, 863, 870, 883, 892, 906, 921, 932, 940, 944, 955, 966, 969}
func (i Op) String() string {
if i >= Op(len(_Op_index)-1) {
transformArgs(n)
fallthrough
- case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
+ case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF, ir.OUNSAFESLICEDATA, ir.OUNSAFESTRINGDATA:
u := ir.NewUnaryExpr(n.Pos(), op, n.Args[0])
u1 := typed(n.Type(), ir.InitExpr(n.Init(), u)) // typecheckargs can add to old.Init
switch op {
case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
// This corresponds to the EvalConst() call near end of typecheck().
return typecheck.EvalConst(u1)
- case ir.OCLOSE, ir.ONEW:
+ case ir.OCLOSE, ir.ONEW, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
// nothing more to do
return u1
}
- case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+ case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
transformArgs(n)
b := ir.NewBinaryExpr(n.Pos(), op, n.Args[0], n.Args[1])
n1 := typed(n.Type(), ir.InitExpr(n.Init(), b))
s.callResult(n, callNormal)
if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class == ir.PFUNC {
if fn := n.X.Sym().Name; base.Flag.CompilingRuntime && fn == "throw" ||
- n.X.Sym().Pkg == ir.Pkgs.Runtime && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap" || fn == "panicunsafeslicelen" || fn == "panicunsafeslicenilptr") {
+ n.X.Sym().Pkg == ir.Pkgs.Runtime && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap" || fn == "panicunsafeslicelen" || fn == "panicunsafeslicenilptr" || fn == "panicunsafestringlen" || fn == "panicunsafestringnilptr") {
m := s.mem()
b := s.endBlock()
b.Kind = ssa.BlockExit
c := s.expr(n.Cap)
return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
+ case ir.OSTRINGHEADER:
+ n := n.(*ir.StringHeaderExpr)
+ p := s.expr(n.Ptr)
+ l := s.expr(n.Len)
+ return s.newValue2(ssa.OpStringMake, n.Type(), p, l)
+
case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
n := n.(*ir.SliceExpr)
check := s.checkPtrEnabled && n.Op() == ir.OSLICE3ARR && n.X.Op() == ir.OCONVNOP && n.X.(*ir.ConvExpr).X.Type().IsUnsafePtr()
{"unsafeslicecheckptr", funcTag, 118},
{"panicunsafeslicelen", funcTag, 9},
{"panicunsafeslicenilptr", funcTag, 9},
- {"mulUintptr", funcTag, 119},
- {"memmove", funcTag, 120},
- {"memclrNoHeapPointers", funcTag, 121},
- {"memclrHasPointers", funcTag, 121},
- {"memequal", funcTag, 122},
- {"memequal0", funcTag, 123},
- {"memequal8", funcTag, 123},
- {"memequal16", funcTag, 123},
- {"memequal32", funcTag, 123},
- {"memequal64", funcTag, 123},
- {"memequal128", funcTag, 123},
- {"f32equal", funcTag, 124},
- {"f64equal", funcTag, 124},
- {"c64equal", funcTag, 124},
- {"c128equal", funcTag, 124},
- {"strequal", funcTag, 124},
- {"interequal", funcTag, 124},
- {"nilinterequal", funcTag, 124},
- {"memhash", funcTag, 125},
- {"memhash0", funcTag, 126},
- {"memhash8", funcTag, 126},
- {"memhash16", funcTag, 126},
- {"memhash32", funcTag, 126},
- {"memhash64", funcTag, 126},
- {"memhash128", funcTag, 126},
- {"f32hash", funcTag, 126},
- {"f64hash", funcTag, 126},
- {"c64hash", funcTag, 126},
- {"c128hash", funcTag, 126},
- {"strhash", funcTag, 126},
- {"interhash", funcTag, 126},
- {"nilinterhash", funcTag, 126},
- {"int64div", funcTag, 127},
- {"uint64div", funcTag, 128},
- {"int64mod", funcTag, 127},
- {"uint64mod", funcTag, 128},
- {"float64toint64", funcTag, 129},
- {"float64touint64", funcTag, 130},
- {"float64touint32", funcTag, 131},
- {"int64tofloat64", funcTag, 132},
- {"int64tofloat32", funcTag, 134},
- {"uint64tofloat64", funcTag, 135},
- {"uint64tofloat32", funcTag, 136},
- {"uint32tofloat64", funcTag, 137},
- {"complex128div", funcTag, 138},
- {"getcallerpc", funcTag, 139},
- {"getcallersp", funcTag, 139},
+ {"unsafestringcheckptr", funcTag, 119},
+ {"panicunsafestringlen", funcTag, 9},
+ {"panicunsafestringnilptr", funcTag, 9},
+ {"mulUintptr", funcTag, 120},
+ {"memmove", funcTag, 121},
+ {"memclrNoHeapPointers", funcTag, 122},
+ {"memclrHasPointers", funcTag, 122},
+ {"memequal", funcTag, 123},
+ {"memequal0", funcTag, 124},
+ {"memequal8", funcTag, 124},
+ {"memequal16", funcTag, 124},
+ {"memequal32", funcTag, 124},
+ {"memequal64", funcTag, 124},
+ {"memequal128", funcTag, 124},
+ {"f32equal", funcTag, 125},
+ {"f64equal", funcTag, 125},
+ {"c64equal", funcTag, 125},
+ {"c128equal", funcTag, 125},
+ {"strequal", funcTag, 125},
+ {"interequal", funcTag, 125},
+ {"nilinterequal", funcTag, 125},
+ {"memhash", funcTag, 126},
+ {"memhash0", funcTag, 127},
+ {"memhash8", funcTag, 127},
+ {"memhash16", funcTag, 127},
+ {"memhash32", funcTag, 127},
+ {"memhash64", funcTag, 127},
+ {"memhash128", funcTag, 127},
+ {"f32hash", funcTag, 127},
+ {"f64hash", funcTag, 127},
+ {"c64hash", funcTag, 127},
+ {"c128hash", funcTag, 127},
+ {"strhash", funcTag, 127},
+ {"interhash", funcTag, 127},
+ {"nilinterhash", funcTag, 127},
+ {"int64div", funcTag, 128},
+ {"uint64div", funcTag, 129},
+ {"int64mod", funcTag, 128},
+ {"uint64mod", funcTag, 129},
+ {"float64toint64", funcTag, 130},
+ {"float64touint64", funcTag, 131},
+ {"float64touint32", funcTag, 132},
+ {"int64tofloat64", funcTag, 133},
+ {"int64tofloat32", funcTag, 135},
+ {"uint64tofloat64", funcTag, 136},
+ {"uint64tofloat32", funcTag, 137},
+ {"uint32tofloat64", funcTag, 138},
+ {"complex128div", funcTag, 139},
+ {"getcallerpc", funcTag, 140},
+ {"getcallersp", funcTag, 140},
{"racefuncenter", funcTag, 31},
{"racefuncexit", funcTag, 9},
{"raceread", funcTag, 31},
{"racewrite", funcTag, 31},
- {"racereadrange", funcTag, 140},
- {"racewriterange", funcTag, 140},
- {"msanread", funcTag, 140},
- {"msanwrite", funcTag, 140},
- {"msanmove", funcTag, 141},
- {"asanread", funcTag, 140},
- {"asanwrite", funcTag, 140},
- {"checkptrAlignment", funcTag, 142},
- {"checkptrArithmetic", funcTag, 144},
- {"libfuzzerTraceCmp1", funcTag, 145},
- {"libfuzzerTraceCmp2", funcTag, 146},
- {"libfuzzerTraceCmp4", funcTag, 147},
- {"libfuzzerTraceCmp8", funcTag, 148},
- {"libfuzzerTraceConstCmp1", funcTag, 145},
- {"libfuzzerTraceConstCmp2", funcTag, 146},
- {"libfuzzerTraceConstCmp4", funcTag, 147},
- {"libfuzzerTraceConstCmp8", funcTag, 148},
- {"libfuzzerHookStrCmp", funcTag, 149},
- {"libfuzzerHookEqualFold", funcTag, 149},
+ {"racereadrange", funcTag, 141},
+ {"racewriterange", funcTag, 141},
+ {"msanread", funcTag, 141},
+ {"msanwrite", funcTag, 141},
+ {"msanmove", funcTag, 142},
+ {"asanread", funcTag, 141},
+ {"asanwrite", funcTag, 141},
+ {"checkptrAlignment", funcTag, 143},
+ {"checkptrArithmetic", funcTag, 145},
+ {"libfuzzerTraceCmp1", funcTag, 146},
+ {"libfuzzerTraceCmp2", funcTag, 147},
+ {"libfuzzerTraceCmp4", funcTag, 148},
+ {"libfuzzerTraceCmp8", funcTag, 149},
+ {"libfuzzerTraceConstCmp1", funcTag, 146},
+ {"libfuzzerTraceConstCmp2", funcTag, 147},
+ {"libfuzzerTraceConstCmp4", funcTag, 148},
+ {"libfuzzerTraceConstCmp8", funcTag, 149},
+ {"libfuzzerHookStrCmp", funcTag, 150},
+ {"libfuzzerHookEqualFold", funcTag, 150},
{"x86HasPOPCNT", varTag, 6},
{"x86HasSSE41", varTag, 6},
{"x86HasFMA", varTag, 6},
}
func runtimeTypes() []*types.Type {
- var typs [150]*types.Type
+ var typs [151]*types.Type
typs[0] = types.ByteType
typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[types.TANY]
typs[116] = types.NewSlice(typs[2])
typs[117] = newSig(params(typs[1], typs[116], typs[15]), params(typs[116]))
typs[118] = newSig(params(typs[1], typs[7], typs[22]), nil)
- typs[119] = newSig(params(typs[5], typs[5]), params(typs[5], typs[6]))
- typs[120] = newSig(params(typs[3], typs[3], typs[5]), nil)
- typs[121] = newSig(params(typs[7], typs[5]), nil)
- typs[122] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
- typs[123] = newSig(params(typs[3], typs[3]), params(typs[6]))
- typs[124] = newSig(params(typs[7], typs[7]), params(typs[6]))
- typs[125] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5]))
- typs[126] = newSig(params(typs[7], typs[5]), params(typs[5]))
- typs[127] = newSig(params(typs[22], typs[22]), params(typs[22]))
- typs[128] = newSig(params(typs[24], typs[24]), params(typs[24]))
- typs[129] = newSig(params(typs[20]), params(typs[22]))
- typs[130] = newSig(params(typs[20]), params(typs[24]))
- typs[131] = newSig(params(typs[20]), params(typs[62]))
- typs[132] = newSig(params(typs[22]), params(typs[20]))
- typs[133] = types.Types[types.TFLOAT32]
- typs[134] = newSig(params(typs[22]), params(typs[133]))
- typs[135] = newSig(params(typs[24]), params(typs[20]))
- typs[136] = newSig(params(typs[24]), params(typs[133]))
- typs[137] = newSig(params(typs[62]), params(typs[20]))
- typs[138] = newSig(params(typs[26], typs[26]), params(typs[26]))
- typs[139] = newSig(nil, params(typs[5]))
- typs[140] = newSig(params(typs[5], typs[5]), nil)
- typs[141] = newSig(params(typs[5], typs[5], typs[5]), nil)
- typs[142] = newSig(params(typs[7], typs[1], typs[5]), nil)
- typs[143] = types.NewSlice(typs[7])
- typs[144] = newSig(params(typs[7], typs[143]), nil)
- typs[145] = newSig(params(typs[66], typs[66], typs[15]), nil)
- typs[146] = newSig(params(typs[60], typs[60], typs[15]), nil)
- typs[147] = newSig(params(typs[62], typs[62], typs[15]), nil)
- typs[148] = newSig(params(typs[24], typs[24], typs[15]), nil)
- typs[149] = newSig(params(typs[28], typs[28], typs[15]), nil)
+ typs[119] = newSig(params(typs[7], typs[22]), nil)
+ typs[120] = newSig(params(typs[5], typs[5]), params(typs[5], typs[6]))
+ typs[121] = newSig(params(typs[3], typs[3], typs[5]), nil)
+ typs[122] = newSig(params(typs[7], typs[5]), nil)
+ typs[123] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
+ typs[124] = newSig(params(typs[3], typs[3]), params(typs[6]))
+ typs[125] = newSig(params(typs[7], typs[7]), params(typs[6]))
+ typs[126] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5]))
+ typs[127] = newSig(params(typs[7], typs[5]), params(typs[5]))
+ typs[128] = newSig(params(typs[22], typs[22]), params(typs[22]))
+ typs[129] = newSig(params(typs[24], typs[24]), params(typs[24]))
+ typs[130] = newSig(params(typs[20]), params(typs[22]))
+ typs[131] = newSig(params(typs[20]), params(typs[24]))
+ typs[132] = newSig(params(typs[20]), params(typs[62]))
+ typs[133] = newSig(params(typs[22]), params(typs[20]))
+ typs[134] = types.Types[types.TFLOAT32]
+ typs[135] = newSig(params(typs[22]), params(typs[134]))
+ typs[136] = newSig(params(typs[24]), params(typs[20]))
+ typs[137] = newSig(params(typs[24]), params(typs[134]))
+ typs[138] = newSig(params(typs[62]), params(typs[20]))
+ typs[139] = newSig(params(typs[26], typs[26]), params(typs[26]))
+ typs[140] = newSig(nil, params(typs[5]))
+ typs[141] = newSig(params(typs[5], typs[5]), nil)
+ typs[142] = newSig(params(typs[5], typs[5], typs[5]), nil)
+ typs[143] = newSig(params(typs[7], typs[1], typs[5]), nil)
+ typs[144] = types.NewSlice(typs[7])
+ typs[145] = newSig(params(typs[7], typs[144]), nil)
+ typs[146] = newSig(params(typs[66], typs[66], typs[15]), nil)
+ typs[147] = newSig(params(typs[60], typs[60], typs[15]), nil)
+ typs[148] = newSig(params(typs[62], typs[62], typs[15]), nil)
+ typs[149] = newSig(params(typs[24], typs[24], typs[15]), nil)
+ typs[150] = newSig(params(typs[28], typs[28], typs[15]), nil)
return typs[:]
}
func unsafeslicecheckptr(typ *byte, ptr unsafe.Pointer, len int64)
func panicunsafeslicelen()
func panicunsafeslicenilptr()
+func unsafestringcheckptr(ptr unsafe.Pointer, len int64)
+func panicunsafestringlen()
+func panicunsafestringnilptr()
func mulUintptr(x, y uintptr) (uintptr, bool)
ir.ORECOVER,
ir.ORECV,
ir.OUNSAFEADD,
- ir.OUNSAFESLICE:
+ ir.OUNSAFESLICE,
+ ir.OUNSAFESLICEDATA,
+ ir.OUNSAFESTRING,
+ ir.OUNSAFESTRINGDATA:
return true
}
return false
return n
}
+// tcUnsafeData typechecks an OUNSAFESLICEDATA or OUNSAFESTRINGDATA node.
+func tcUnsafeData(n *ir.UnaryExpr) ir.Node {
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
+ l := n.X
+ t := l.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+
+ var kind types.Kind
+ if n.Op() == ir.OUNSAFESLICEDATA {
+ kind = types.TSLICE
+ } else {
+ /* kind is string */
+ kind = types.TSTRING
+ }
+
+ if t.Kind() != kind {
+ base.Errorf("invalid argument %L for %v", l, n.Op())
+ n.SetType(nil)
+ return n
+ }
+
+ if kind == types.TSTRING {
+ t = types.ByteType
+ } else {
+ t = t.Elem()
+ }
+ n.SetType(types.NewPtr(t))
+ return n
+}
+
// tcRecv typechecks an ORECV node.
func tcRecv(n *ir.UnaryExpr) ir.Node {
n.X = Expr(n.X)
return n
}
+// tcStringHeader typechecks an OSTRINGHEADER node.
+func tcStringHeader(n *ir.StringHeaderExpr) ir.Node {
+ t := n.Type()
+ if t == nil {
+ base.Fatalf("no type specified for OSTRINGHEADER")
+ }
+
+ if !t.IsString() {
+ base.Fatalf("invalid type %v for OSTRINGHEADER", n.Type())
+ }
+
+ if n.Ptr == nil || n.Ptr.Type() == nil || !n.Ptr.Type().IsUnsafePtr() {
+ base.Fatalf("need unsafe.Pointer for OSTRINGHEADER")
+ }
+
+ n.Ptr = Expr(n.Ptr)
+ n.Len = DefaultLit(Expr(n.Len), types.Types[types.TINT])
+
+ if ir.IsConst(n.Len, constant.Int) && ir.Int64Val(n.Len) < 0 {
+ base.Fatalf("len for OSTRINGHEADER must be non-negative")
+ }
+
+ return n
+}
+
// tcStar typechecks an ODEREF node, which may be an expression or a type.
func tcStar(n *ir.StarExpr, top int) ir.Node {
n.X = typecheck(n.X, ctxExpr|ctxType)
n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
return typecheck(n, top)
- case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
+ case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
typecheckargs(n)
fallthrough
case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
u := ir.NewUnaryExpr(n.Pos(), l.BuiltinOp, arg)
return typecheck(ir.InitExpr(n.Init(), u), top) // typecheckargs can add to old.Init
- case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+ case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
typecheckargs(n)
arg1, arg2, ok := needTwoArgs(n)
if !ok {
base.Errorf("unsafe.Slice of incomplete (or unallocatable) type not allowed")
}
- if !checkunsafeslice(&n.Y) {
+ if !checkunsafesliceorstring(n.Op(), &n.Y) {
n.SetType(nil)
return n
}
n.SetType(types.NewSlice(t.Elem()))
return n
}
+
+// tcUnsafeString typechecks an OUNSAFESTRING node.
+func tcUnsafeString(n *ir.BinaryExpr) *ir.BinaryExpr {
+ n.X = Expr(n.X)
+ n.Y = Expr(n.Y)
+ if n.X.Type() == nil || n.Y.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ t := n.X.Type()
+ if !t.IsPtr() || !types.Identical(t.Elem(), types.Types[types.TUINT8]) {
+ base.Errorf("first argument to unsafe.String must be *byte; have %L", t)
+ }
+
+ if !checkunsafesliceorstring(n.Op(), &n.Y) {
+ n.SetType(nil)
+ return n
+ }
+ n.SetType(types.Types[types.TSTRING])
+ return n
+}
w.expr(n.Max)
w.typ(n.Type())
- case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+ case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
// treated like other builtin calls (see e.g., OREAL)
n := n.(*ir.BinaryExpr)
w.op(n.Op())
w.expr(n.X)
w.bool(n.Implicit())
- case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
+ case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
n := n.(*ir.UnaryExpr)
w.op(n.Op())
w.pos(n.Pos())
n.SetImplicit(r.bool())
return n
- case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+ case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE,
+ ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN,
+ ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESLICEDATA, ir.OUNSAFESTRING, ir.OUNSAFESTRINGDATA:
pos := r.pos()
switch op {
- case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE:
+ case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
init := r.stmtList()
n := ir.NewBinaryExpr(pos, op, r.expr(), r.expr())
n.SetInit(init)
n.SetType(r.typ())
return n
- case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
+ case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
n := ir.NewUnaryExpr(pos, op, r.expr())
if op != ir.OPANIC {
n.SetType(r.typ())
n := n.(*ir.SliceHeaderExpr)
return tcSliceHeader(n)
+ case ir.OSTRINGHEADER:
+ n := n.(*ir.StringHeaderExpr)
+ return tcStringHeader(n)
+
case ir.OMAKESLICECOPY:
n := n.(*ir.MakeExpr)
return tcMakeSliceCopy(n)
n := n.(*ir.BinaryExpr)
return tcUnsafeSlice(n)
+ case ir.OUNSAFESLICEDATA:
+ n := n.(*ir.UnaryExpr)
+ return tcUnsafeData(n)
+
+ case ir.OUNSAFESTRING:
+ n := n.(*ir.BinaryExpr)
+ return tcUnsafeString(n)
+
+ case ir.OUNSAFESTRINGDATA:
+ n := n.(*ir.UnaryExpr)
+ return tcUnsafeData(n)
+
case ir.OCLOSURE:
n := n.(*ir.ClosureExpr)
return tcClosure(n, top)
return true
}
-// checkunsafeslice is like checkmake but for unsafe.Slice.
-func checkunsafeslice(np *ir.Node) bool {
+// checkunsafesliceorstring is like checkmake but for unsafe.{Slice,String}.
+func checkunsafesliceorstring(op ir.Op, np *ir.Node) bool {
n := *np
if !n.Type().IsInteger() && n.Type().Kind() != types.TIDEAL {
- base.Errorf("non-integer len argument in unsafe.Slice - %v", n.Type())
+ base.Errorf("non-integer len argument in %v - %v", op, n.Type())
return false
}
if n.Op() == ir.OLITERAL {
v := toint(n.Val())
if constant.Sign(v) < 0 {
- base.Errorf("negative len argument in unsafe.Slice")
+ base.Errorf("negative len argument in %v", op)
return false
}
if ir.ConstOverflow(v, types.Types[types.TINT]) {
- base.Errorf("len argument too large in unsafe.Slice")
+ base.Errorf("len argument too large in %v", op)
return false
}
}
{"Offsetof", ir.OOFFSETOF},
{"Sizeof", ir.OSIZEOF},
{"Slice", ir.OUNSAFESLICE},
+ {"SliceData", ir.OUNSAFESLICEDATA},
+ {"String", ir.OUNSAFESTRING},
+ {"StringData", ir.OUNSAFESTRINGDATA},
}
// InitUniverse initializes the universe block.
return mkcall("gorecover", nn.Type(), init, walkExpr(nn.Args[0], init))
}
+// walkUnsafeData walks an OUNSAFESLICEDATA or OUNSAFESTRINGDATA expression.
+func walkUnsafeData(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
+ slice := walkExpr(n.X, init)
+ res := typecheck.Expr(ir.NewUnaryExpr(n.Pos(), ir.OSPTR, slice))
+ res.SetType(n.Type())
+ return walkExpr(res, init)
+}
+
func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
ptr := safeExpr(n.X, init)
len := safeExpr(n.Y, init)
return walkExpr(typecheck.Expr(h), init)
}
+func walkUnsafeString(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
+ ptr := safeExpr(n.X, init)
+ len := safeExpr(n.Y, init)
+
+ lenType := types.Types[types.TINT64]
+ unsafePtr := typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR])
+
+ // If checkptr enabled, call runtime.unsafestringcheckptr to check ptr and len.
+ // for simplicity, unsafestringcheckptr always uses int64.
+ // Type checking guarantees that TIDEAL len are positive and fit in an int.
+ if ir.ShouldCheckPtr(ir.CurFunc, 1) {
+ fnname := "unsafestringcheckptr"
+ fn := typecheck.LookupRuntime(fnname)
+ init.Append(mkcall1(fn, nil, init, unsafePtr, typecheck.Conv(len, lenType)))
+ } else {
+ // Otherwise, open code unsafe.String to prevent runtime call overhead.
+ // Keep this code in sync with runtime.unsafestring{,64}
+ if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() {
+ lenType = types.Types[types.TINT]
+ } else {
+ // len64 := int64(len)
+ // if int64(int(len64)) != len64 {
+ // panicunsafestringlen()
+ // }
+ len64 := typecheck.Conv(len, lenType)
+ nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
+ nif.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, typecheck.Conv(typecheck.Conv(len64, types.Types[types.TINT]), lenType), len64)
+ nif.Body.Append(mkcall("panicunsafestringlen", nil, &nif.Body))
+ appendWalkStmt(init, nif)
+ }
+
+ // if len < 0 { panicunsafestringlen() }
+ nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
+ nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, typecheck.Conv(len, lenType), ir.NewInt(0))
+ nif.Body.Append(mkcall("panicunsafestringlen", nil, &nif.Body))
+ appendWalkStmt(init, nif)
+
+ // if uintpr(len) > -uintptr(ptr) {
+ // if ptr == nil {
+ // panicunsafestringnilptr()
+ // }
+ // panicunsafeslicelen()
+ // }
+ nifLen := ir.NewIfStmt(base.Pos, nil, nil, nil)
+ nifLen.Cond = ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(len, types.Types[types.TUINTPTR]), ir.NewUnaryExpr(base.Pos, ir.ONEG, typecheck.Conv(unsafePtr, types.Types[types.TUINTPTR])))
+ nifPtr := ir.NewIfStmt(base.Pos, nil, nil, nil)
+ nifPtr.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, unsafePtr, typecheck.NodNil())
+ nifPtr.Body.Append(mkcall("panicunsafestringnilptr", nil, &nifPtr.Body))
+ nifLen.Body.Append(nifPtr, mkcall("panicunsafestringlen", nil, &nifLen.Body))
+ appendWalkStmt(init, nifLen)
+ }
+ h := ir.NewStringHeaderExpr(n.Pos(),
+ typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]),
+ typecheck.Conv(len, types.Types[types.TINT]),
+ )
+ return walkExpr(typecheck.Expr(h), init)
+}
+
func badtype(op ir.Op, tl, tr *types.Type) {
var s string
if tl != nil {
n := n.(*ir.BinaryExpr)
return walkUnsafeSlice(n, init)
+ case ir.OUNSAFESTRING:
+ n := n.(*ir.BinaryExpr)
+ return walkUnsafeString(n, init)
+
+ case ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
+ n := n.(*ir.UnaryExpr)
+ return walkUnsafeData(n, init)
+
case ir.ODOT, ir.ODOTPTR:
n := n.(*ir.SelectorExpr)
return walkDot(n, init)
n := n.(*ir.SliceHeaderExpr)
return walkSliceHeader(n, init)
+ case ir.OSTRINGHEADER:
+ n := n.(*ir.StringHeaderExpr)
+ return walkStringHeader(n, init)
+
case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
n := n.(*ir.SliceExpr)
return walkSlice(n, init)
return n
}
+// walkStringHeader walks an OSTRINGHEADER node.
+func walkStringHeader(n *ir.StringHeaderExpr, init *ir.Nodes) ir.Node {
+ n.Ptr = walkExpr(n.Ptr, init)
+ n.Len = walkExpr(n.Len, init)
+ return n
+}
+
// TODO(josharian): combine this with its caller and simplify
func reduceSlice(n *ir.SliceExpr) ir.Node {
if n.High != nil && n.High.Op() == ir.OLEN && ir.SameSafeExpr(n.X, n.High.(*ir.UnaryExpr).X) {
ir.OCAP, ir.OIMAG, ir.OLEN, ir.OREAL,
ir.OCONVNOP, ir.ODOT,
ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.OSPTR,
- ir.OBYTES2STRTMP, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OSLICEHEADER:
+ ir.OBYTES2STRTMP, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OSLICEHEADER, ir.OSTRINGHEADER:
// ok: operations that don't require function calls.
// Expand as needed.
}
{"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"},
{"CheckPtrSliceOK", ""},
{"CheckPtrSliceFail", "fatal error: checkptr: unsafe.Slice result straddles multiple allocations\n"},
+ {"CheckPtrStringOK", ""},
+ {"CheckPtrStringFail", "fatal error: checkptr: unsafe.String result straddles multiple allocations\n"},
}
for _, tc := range testCases {
return math.MulUintptr(a, b)
}
-// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
-func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
- if len < 0 {
- panicunsafeslicelen()
- }
-
- if et.size == 0 {
- if ptr == nil && len > 0 {
- panicunsafeslicenilptr()
- }
- }
-
- mem, overflow := math.MulUintptr(et.size, uintptr(len))
- if overflow || mem > -uintptr(ptr) {
- if ptr == nil {
- panicunsafeslicenilptr()
- }
- panicunsafeslicelen()
- }
-}
-
-// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
-func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
- len := int(len64)
- if int64(len) != len64 {
- panicunsafeslicelen()
- }
- unsafeslice(et, ptr, len)
-}
-
-func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) {
- unsafeslice64(et, ptr, len64)
-
- // Check that underlying array doesn't straddle multiple heap objects.
- // unsafeslice64 has already checked for overflow.
- if checkptrStraddles(ptr, uintptr(len64)*et.size) {
- throw("checkptr: unsafe.Slice result straddles multiple allocations")
- }
-}
-
-func panicunsafeslicelen() {
- panic(errorString("unsafe.Slice: len out of range"))
-}
-
-func panicunsafeslicenilptr() {
- panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
-}
-
// growslice handles slice growth during append.
// It is passed the slice element type, the old slice, and the desired new minimum capacity,
// and it returns a new slice with at least that capacity, with the old data
register("CheckPtrSmall", CheckPtrSmall)
register("CheckPtrSliceOK", CheckPtrSliceOK)
register("CheckPtrSliceFail", CheckPtrSliceFail)
+ register("CheckPtrStringOK", CheckPtrStringOK)
+ register("CheckPtrStringFail", CheckPtrStringFail)
register("CheckPtrAlignmentNested", CheckPtrAlignmentNested)
}
sink2 = unsafe.Slice(p, 100)
}
+func CheckPtrStringOK() {
+ p := new([4]byte)
+ sink2 = unsafe.String(&p[1], 3)
+}
+
+func CheckPtrStringFail() {
+ p := new(byte)
+ sink2 = p
+ sink2 = unsafe.String(p, 100)
+}
+
func CheckPtrAlignmentNested() {
s := make([]int8, 100)
p := unsafe.Pointer(&s[0])
--- /dev/null
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/math"
+ "unsafe"
+)
+
+func unsafestring(ptr unsafe.Pointer, len int) {
+ if len < 0 {
+ panicunsafestringlen()
+ }
+
+ if uintptr(len) > -uintptr(ptr) {
+ if ptr == nil {
+ panicunsafestringnilptr()
+ }
+ panicunsafestringlen()
+ }
+}
+
+// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeString
+func unsafestring64(ptr unsafe.Pointer, len64 int64) {
+ len := int(len64)
+ if int64(len) != len64 {
+ panicunsafestringlen()
+ }
+ unsafestring(ptr, len)
+}
+
+func unsafestringcheckptr(ptr unsafe.Pointer, len64 int64) {
+ unsafestring64(ptr, len64)
+
+ // Check that underlying array doesn't straddle multiple heap objects.
+ // unsafestring64 has already checked for overflow.
+ if checkptrStraddles(ptr, uintptr(len64)) {
+ throw("checkptr: unsafe.String result straddles multiple allocations")
+ }
+}
+
+func panicunsafestringlen() {
+ panic(errorString("unsafe.String: len out of range"))
+}
+
+func panicunsafestringnilptr() {
+ panic(errorString("unsafe.String: ptr is nil and len is not zero"))
+}
+
+// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
+func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
+ if len < 0 {
+ panicunsafeslicelen()
+ }
+
+ if et.size == 0 {
+ if ptr == nil && len > 0 {
+ panicunsafeslicenilptr()
+ }
+ }
+
+ mem, overflow := math.MulUintptr(et.size, uintptr(len))
+ if overflow || mem > -uintptr(ptr) {
+ if ptr == nil {
+ panicunsafeslicenilptr()
+ }
+ panicunsafeslicelen()
+ }
+}
+
+// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
+func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
+ len := int(len64)
+ if int64(len) != len64 {
+ panicunsafeslicelen()
+ }
+ unsafeslice(et, ptr, len)
+}
+
+func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) {
+ unsafeslice64(et, ptr, len64)
+
+ // Check that underlying array doesn't straddle multiple heap objects.
+ // unsafeslice64 has already checked for overflow.
+ if checkptrStraddles(ptr, uintptr(len64)*et.size) {
+ throw("checkptr: unsafe.Slice result straddles multiple allocations")
+ }
+}
+
+func panicunsafeslicelen() {
+ panic(errorString("unsafe.Slice: len out of range"))
+}
+
+func panicunsafeslicenilptr() {
+ panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
+}
--- /dev/null
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+ "unsafe"
+)
+
+func main() {
+ var s = []byte("abc")
+ sh1 := *(*reflect.SliceHeader)(unsafe.Pointer(&s))
+ ptr2 := unsafe.Pointer(unsafe.SliceData(s))
+ if ptr2 != unsafe.Pointer(sh1.Data) {
+ panic(fmt.Errorf("unsafe.SliceData %p != %p", ptr2, unsafe.Pointer(sh1.Data)))
+ }
+}
--- /dev/null
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "unsafe"
+)
+
+func main() {
+ hello := [5]byte{'m', 'o', 's', 'h', 'i'}
+ if unsafe.String(&hello[0], uint64(len(hello))) != "moshi" {
+ panic("unsafe.String convert error")
+ }
+}
--- /dev/null
+// run
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+ "unsafe"
+)
+
+func main() {
+ var s = "abc"
+ sh1 := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ ptr2 := unsafe.Pointer(unsafe.StringData(s))
+ if ptr2 != unsafe.Pointer(sh1.Data) {
+ panic(fmt.Errorf("unsafe.StringData ret %p != %p", ptr2, unsafe.Pointer(sh1.Data)))
+ }
+}
_ = unsafe.Slice(last, 1)
mustPanic(func() { _ = unsafe.Slice(last, 2) })
}
+
+ // unsafe.String
+ {
+ s := unsafe.String(&p[0], len(p))
+ assert(s == string(p[:]))
+ assert(len(s) == len(p))
+
+ // the empty string
+ assert(unsafe.String(nil, 0) == "")
+
+ // nil pointer with positive length panics
+ mustPanic(func() { _ = unsafe.String(nil, 1) })
+
+ // negative length
+ var neg int = -1
+ mustPanic(func() { _ = unsafe.String(new(byte), neg) })
+
+ // length too large
+ var tooBig uint64 = math.MaxUint64
+ mustPanic(func() { _ = unsafe.String(new(byte), tooBig) })
+
+ // string memory overflows address space
+ last := (*byte)(unsafe.Pointer(^uintptr(0)))
+ _ = unsafe.String(last, 1)
+ mustPanic(func() { _ = unsafe.String(last, 2) })
+ }
+
+ // unsafe.StringData
+ {
+ var s = "string"
+ assert(string(unsafe.Slice(unsafe.StringData(s), len(s))) == s)
+ }
+
+ //unsafe.SliceData
+ {
+ var s = []byte("slice")
+ assert(unsafe.String(unsafe.SliceData(s), len(s)) == string(s))
+ }
}
func assert(ok bool) {