cmd/compile: add clear(x) builtin

To clear map, and zero content of slice.

Updates #56351

Change-Id: I5f81dfbc465500f5acadaf2c6beb9b5f0d2c4045
Reviewed-on: https://go-review.googlesource.com/c/go/+/453395
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
Cuong Manh Le 2022-11-25 16:11:45 +07:00 committed by Gopher Robot
parent bb4ea80bef
commit b89a840d65
17 changed files with 256 additions and 142 deletions

View File

@ -179,7 +179,7 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
argument(e.discardHole(), &call.Args[i]) 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.OCLEAR:
call := call.(*ir.UnaryExpr) call := call.(*ir.UnaryExpr)
argument(e.discardHole(), &call.X) argument(e.discardHole(), &call.X)

View File

@ -180,7 +180,7 @@ func (e *escape) stmt(n ir.Node) {
dsts[i] = res.Nname.(*ir.Name) dsts[i] = res.Nname.(*ir.Name)
} }
e.assignList(dsts, n.Results, "return", n) e.assignList(dsts, n.Results, "return", n)
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OINLCALL, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER: case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER, ir.OINLCALL, ir.OCLEAR, ir.OCLOSE, ir.OCOPY, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
e.call(nil, n) e.call(nil, n)
case ir.OGO, ir.ODEFER: case ir.OGO, ir.ODEFER:
n := n.(*ir.GoDeferStmt) n := n.(*ir.GoDeferStmt)

View File

@ -747,7 +747,7 @@ func (n *UnaryExpr) SetOp(op Op) {
default: default:
panic(n.no("SetOp " + op.String())) panic(n.no("SetOp " + op.String()))
case OBITNOT, ONEG, ONOT, OPLUS, ORECV, case OBITNOT, ONEG, ONOT, OPLUS, ORECV,
OALIGNOF, OCAP, OCLOSE, OIMAG, OLEN, ONEW, OALIGNOF, OCAP, OCLEAR, OCLOSE, OIMAG, OLEN, ONEW,
OOFFSETOF, OPANIC, OREAL, OSIZEOF, OOFFSETOF, OPANIC, OREAL, OSIZEOF,
OCHECKNIL, OCFUNC, OIDATA, OITAB, OSPTR, OCHECKNIL, OCFUNC, OIDATA, OITAB, OSPTR,
OUNSAFESTRINGDATA, OUNSAFESLICEDATA: OUNSAFESTRINGDATA, OUNSAFESLICEDATA:

View File

@ -39,6 +39,7 @@ var OpNames = []string{
OCALL: "function call", // not actual syntax OCALL: "function call", // not actual syntax
OCAP: "cap", OCAP: "cap",
OCASE: "case", OCASE: "case",
OCLEAR: "clear",
OCLOSE: "close", OCLOSE: "close",
OCOMPLEX: "complex", OCOMPLEX: "complex",
OBITNOT: "^", OBITNOT: "^",
@ -182,6 +183,7 @@ var OpPrec = []int{
OCALLMETH: 8, OCALLMETH: 8,
OCALL: 8, OCALL: 8,
OCAP: 8, OCAP: 8,
OCLEAR: 8,
OCLOSE: 8, OCLOSE: 8,
OCOMPLIT: 8, OCOMPLIT: 8,
OCONVIFACE: 8, OCONVIFACE: 8,
@ -767,6 +769,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
case OREAL, case OREAL,
OIMAG, OIMAG,
OCAP, OCAP,
OCLEAR,
OCLOSE, OCLOSE,
OLEN, OLEN,
ONEW, ONEW,

View File

@ -159,6 +159,7 @@ const (
OCALLMETH // X(Args) (direct method call x.Method(args)) OCALLMETH // X(Args) (direct method call x.Method(args))
OCALLINTER // X(Args) (interface method call x.Method(args)) OCALLINTER // X(Args) (interface method call x.Method(args))
OCAP // cap(X) OCAP // cap(X)
OCLEAR // clear(X)
OCLOSE // close(X) OCLOSE // close(X)
OCLOSURE // func Type { Func.Closure.Body } (func literal) OCLOSURE // func Type { Func.Closure.Body } (func literal)
OCOMPLIT // Type{List} (composite literal, not yet lowered to specific form) OCOMPLIT // Type{List} (composite literal, not yet lowered to specific form)

View File

@ -42,132 +42,133 @@ func _() {
_ = x[OCALLMETH-31] _ = x[OCALLMETH-31]
_ = x[OCALLINTER-32] _ = x[OCALLINTER-32]
_ = x[OCAP-33] _ = x[OCAP-33]
_ = x[OCLOSE-34] _ = x[OCLEAR-34]
_ = x[OCLOSURE-35] _ = x[OCLOSE-35]
_ = x[OCOMPLIT-36] _ = x[OCLOSURE-36]
_ = x[OMAPLIT-37] _ = x[OCOMPLIT-37]
_ = x[OSTRUCTLIT-38] _ = x[OMAPLIT-38]
_ = x[OARRAYLIT-39] _ = x[OSTRUCTLIT-39]
_ = x[OSLICELIT-40] _ = x[OARRAYLIT-40]
_ = x[OPTRLIT-41] _ = x[OSLICELIT-41]
_ = x[OCONV-42] _ = x[OPTRLIT-42]
_ = x[OCONVIFACE-43] _ = x[OCONV-43]
_ = x[OCONVIDATA-44] _ = x[OCONVIFACE-44]
_ = x[OCONVNOP-45] _ = x[OCONVIDATA-45]
_ = x[OCOPY-46] _ = x[OCONVNOP-46]
_ = x[ODCL-47] _ = x[OCOPY-47]
_ = x[ODCLFUNC-48] _ = x[ODCL-48]
_ = x[ODCLCONST-49] _ = x[ODCLFUNC-49]
_ = x[ODCLTYPE-50] _ = x[ODCLCONST-50]
_ = x[ODELETE-51] _ = x[ODCLTYPE-51]
_ = x[ODOT-52] _ = x[ODELETE-52]
_ = x[ODOTPTR-53] _ = x[ODOT-53]
_ = x[ODOTMETH-54] _ = x[ODOTPTR-54]
_ = x[ODOTINTER-55] _ = x[ODOTMETH-55]
_ = x[OXDOT-56] _ = x[ODOTINTER-56]
_ = x[ODOTTYPE-57] _ = x[OXDOT-57]
_ = x[ODOTTYPE2-58] _ = x[ODOTTYPE-58]
_ = x[OEQ-59] _ = x[ODOTTYPE2-59]
_ = x[ONE-60] _ = x[OEQ-60]
_ = x[OLT-61] _ = x[ONE-61]
_ = x[OLE-62] _ = x[OLT-62]
_ = x[OGE-63] _ = x[OLE-63]
_ = x[OGT-64] _ = x[OGE-64]
_ = x[ODEREF-65] _ = x[OGT-65]
_ = x[OINDEX-66] _ = x[ODEREF-66]
_ = x[OINDEXMAP-67] _ = x[OINDEX-67]
_ = x[OKEY-68] _ = x[OINDEXMAP-68]
_ = x[OSTRUCTKEY-69] _ = x[OKEY-69]
_ = x[OLEN-70] _ = x[OSTRUCTKEY-70]
_ = x[OMAKE-71] _ = x[OLEN-71]
_ = x[OMAKECHAN-72] _ = x[OMAKE-72]
_ = x[OMAKEMAP-73] _ = x[OMAKECHAN-73]
_ = x[OMAKESLICE-74] _ = x[OMAKEMAP-74]
_ = x[OMAKESLICECOPY-75] _ = x[OMAKESLICE-75]
_ = x[OMUL-76] _ = x[OMAKESLICECOPY-76]
_ = x[ODIV-77] _ = x[OMUL-77]
_ = x[OMOD-78] _ = x[ODIV-78]
_ = x[OLSH-79] _ = x[OMOD-79]
_ = x[ORSH-80] _ = x[OLSH-80]
_ = x[OAND-81] _ = x[ORSH-81]
_ = x[OANDNOT-82] _ = x[OAND-82]
_ = x[ONEW-83] _ = x[OANDNOT-83]
_ = x[ONOT-84] _ = x[ONEW-84]
_ = x[OBITNOT-85] _ = x[ONOT-85]
_ = x[OPLUS-86] _ = x[OBITNOT-86]
_ = x[ONEG-87] _ = x[OPLUS-87]
_ = x[OOROR-88] _ = x[ONEG-88]
_ = x[OPANIC-89] _ = x[OOROR-89]
_ = x[OPRINT-90] _ = x[OPANIC-90]
_ = x[OPRINTN-91] _ = x[OPRINT-91]
_ = x[OPAREN-92] _ = x[OPRINTN-92]
_ = x[OSEND-93] _ = x[OPAREN-93]
_ = x[OSLICE-94] _ = x[OSEND-94]
_ = x[OSLICEARR-95] _ = x[OSLICE-95]
_ = x[OSLICESTR-96] _ = x[OSLICEARR-96]
_ = x[OSLICE3-97] _ = x[OSLICESTR-97]
_ = x[OSLICE3ARR-98] _ = x[OSLICE3-98]
_ = x[OSLICEHEADER-99] _ = x[OSLICE3ARR-99]
_ = x[OSTRINGHEADER-100] _ = x[OSLICEHEADER-100]
_ = x[ORECOVER-101] _ = x[OSTRINGHEADER-101]
_ = x[ORECOVERFP-102] _ = x[ORECOVER-102]
_ = x[ORECV-103] _ = x[ORECOVERFP-103]
_ = x[ORUNESTR-104] _ = x[ORECV-104]
_ = x[OSELRECV2-105] _ = x[ORUNESTR-105]
_ = x[OREAL-106] _ = x[OSELRECV2-106]
_ = x[OIMAG-107] _ = x[OREAL-107]
_ = x[OCOMPLEX-108] _ = x[OIMAG-108]
_ = x[OALIGNOF-109] _ = x[OCOMPLEX-109]
_ = x[OOFFSETOF-110] _ = x[OALIGNOF-110]
_ = x[OSIZEOF-111] _ = x[OOFFSETOF-111]
_ = x[OUNSAFEADD-112] _ = x[OSIZEOF-112]
_ = x[OUNSAFESLICE-113] _ = x[OUNSAFEADD-113]
_ = x[OUNSAFESLICEDATA-114] _ = x[OUNSAFESLICE-114]
_ = x[OUNSAFESTRING-115] _ = x[OUNSAFESLICEDATA-115]
_ = x[OUNSAFESTRINGDATA-116] _ = x[OUNSAFESTRING-116]
_ = x[OMETHEXPR-117] _ = x[OUNSAFESTRINGDATA-117]
_ = x[OMETHVALUE-118] _ = x[OMETHEXPR-118]
_ = x[OBLOCK-119] _ = x[OMETHVALUE-119]
_ = x[OBREAK-120] _ = x[OBLOCK-120]
_ = x[OCASE-121] _ = x[OBREAK-121]
_ = x[OCONTINUE-122] _ = x[OCASE-122]
_ = x[ODEFER-123] _ = x[OCONTINUE-123]
_ = x[OFALL-124] _ = x[ODEFER-124]
_ = x[OFOR-125] _ = x[OFALL-125]
_ = x[OGOTO-126] _ = x[OFOR-126]
_ = x[OIF-127] _ = x[OGOTO-127]
_ = x[OLABEL-128] _ = x[OIF-128]
_ = x[OGO-129] _ = x[OLABEL-129]
_ = x[ORANGE-130] _ = x[OGO-130]
_ = x[ORETURN-131] _ = x[ORANGE-131]
_ = x[OSELECT-132] _ = x[ORETURN-132]
_ = x[OSWITCH-133] _ = x[OSELECT-133]
_ = x[OTYPESW-134] _ = x[OSWITCH-134]
_ = x[OFUNCINST-135] _ = x[OTYPESW-135]
_ = x[OINLCALL-136] _ = x[OFUNCINST-136]
_ = x[OEFACE-137] _ = x[OINLCALL-137]
_ = x[OITAB-138] _ = x[OEFACE-138]
_ = x[OIDATA-139] _ = x[OITAB-139]
_ = x[OSPTR-140] _ = x[OIDATA-140]
_ = x[OCFUNC-141] _ = x[OSPTR-141]
_ = x[OCHECKNIL-142] _ = x[OCFUNC-142]
_ = x[ORESULT-143] _ = x[OCHECKNIL-143]
_ = x[OINLMARK-144] _ = x[ORESULT-144]
_ = x[OLINKSYMOFFSET-145] _ = x[OINLMARK-145]
_ = x[OJUMPTABLE-146] _ = x[OLINKSYMOFFSET-146]
_ = x[ODYNAMICDOTTYPE-147] _ = x[OJUMPTABLE-147]
_ = x[ODYNAMICDOTTYPE2-148] _ = x[ODYNAMICDOTTYPE-148]
_ = x[ODYNAMICTYPE-149] _ = x[ODYNAMICDOTTYPE2-149]
_ = x[OTAILCALL-150] _ = x[ODYNAMICTYPE-150]
_ = x[OGETG-151] _ = x[OTAILCALL-151]
_ = x[OGETCALLERPC-152] _ = x[OGETG-152]
_ = x[OGETCALLERSP-153] _ = x[OGETCALLERPC-153]
_ = x[OEND-154] _ = x[OGETCALLERSP-154]
_ = x[OEND-155]
} }
const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERSTRINGHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2REALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEUNSAFESLICEDATAUNSAFESTRINGUNSAFESTRINGDATAMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTINLCALLEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND" const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLEARCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERSTRINGHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2REALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEUNSAFESLICEDATAUNSAFESTRINGUNSAFESTRINGDATAMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTINLCALLEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND"
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, 129, 141, 143, 146, 156, 163, 170, 177, 181, 185, 193, 201, 210, 213, 218, 225, 232, 238, 247, 255, 263, 269, 273, 282, 291, 298, 302, 305, 312, 320, 327, 333, 336, 342, 349, 357, 361, 368, 376, 378, 380, 382, 384, 386, 388, 393, 398, 406, 409, 418, 421, 425, 433, 440, 449, 462, 465, 468, 471, 474, 477, 480, 486, 489, 492, 498, 502, 505, 509, 514, 519, 525, 530, 534, 539, 547, 555, 561, 570, 581, 593, 600, 609, 613, 620, 628, 632, 636, 643, 650, 658, 664, 673, 684, 699, 711, 727, 735, 744, 749, 754, 758, 766, 771, 775, 778, 782, 784, 789, 791, 796, 802, 808, 814, 820, 828, 835, 840, 844, 849, 853, 858, 866, 872, 879, 892, 901, 915, 930, 941, 949, 953, 964, 975, 978} 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, 129, 141, 143, 146, 156, 163, 170, 177, 181, 185, 193, 201, 210, 213, 218, 223, 230, 237, 243, 252, 260, 268, 274, 278, 287, 296, 303, 307, 310, 317, 325, 332, 338, 341, 347, 354, 362, 366, 373, 381, 383, 385, 387, 389, 391, 393, 398, 403, 411, 414, 423, 426, 430, 438, 445, 454, 467, 470, 473, 476, 479, 482, 485, 491, 494, 497, 503, 507, 510, 514, 519, 524, 530, 535, 539, 544, 552, 560, 566, 575, 586, 598, 605, 614, 618, 625, 633, 637, 641, 648, 655, 663, 669, 678, 689, 704, 716, 732, 740, 749, 754, 759, 763, 771, 776, 780, 783, 787, 789, 794, 796, 801, 807, 813, 819, 825, 833, 840, 845, 849, 854, 858, 863, 871, 877, 884, 897, 906, 920, 935, 946, 954, 958, 969, 980, 983}
func (i Op) String() string { func (i Op) String() string {
if i >= Op(len(_Op_index)-1) { if i >= Op(len(_Op_index)-1) {

View File

@ -743,6 +743,7 @@ func callOrChan(n ir.Node) bool {
ir.OCALLINTER, ir.OCALLINTER,
ir.OCALLMETH, ir.OCALLMETH,
ir.OCAP, ir.OCAP,
ir.OCLEAR,
ir.OCLOSE, ir.OCLOSE,
ir.OCOMPLEX, ir.OCOMPLEX,
ir.OCOPY, ir.OCOPY,

View File

@ -260,7 +260,7 @@ func tcCall(n *ir.CallExpr, top int) ir.Node {
n.SetTypecheck(0) // re-typechecking new op is OK, not a loop n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
return typecheck(n, top) return typecheck(n, top)
case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA: case ir.OCAP, ir.OCLEAR, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
typecheckargs(n) typecheckargs(n)
fallthrough fallthrough
case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
@ -441,6 +441,28 @@ func tcAppend(n *ir.CallExpr) ir.Node {
return n return n
} }
// tcClear typechecks an OCLEAR node.
func tcClear(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
}
switch {
case t.IsMap(), t.IsSlice():
default:
base.Errorf("invalid operation: %v (argument must be a map or slice)", n)
n.SetType(nil)
return n
}
return n
}
// tcClose typechecks an OCLOSE node. // tcClose typechecks an OCLOSE node.
func tcClose(n *ir.UnaryExpr) ir.Node { func tcClose(n *ir.UnaryExpr) ir.Node {
n.X = Expr(n.X) n.X = Expr(n.X)

View File

@ -273,6 +273,7 @@ func tcGoDefer(n *ir.GoDeferStmt) {
case ir.OCALLINTER, case ir.OCALLINTER,
ir.OCALLMETH, ir.OCALLMETH,
ir.OCALLFUNC, ir.OCALLFUNC,
ir.OCLEAR,
ir.OCLOSE, ir.OCLOSE,
ir.OCOPY, ir.OCOPY,
ir.ODELETE, ir.ODELETE,

View File

@ -336,7 +336,7 @@ func typecheck(n ir.Node, top int) (res ir.Node) {
case ir.OAPPEND: case ir.OAPPEND:
// Must be used (and not BinaryExpr/UnaryExpr). // Must be used (and not BinaryExpr/UnaryExpr).
isStmt = false isStmt = false
case ir.OCLOSE, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN: case ir.OCLEAR, ir.OCLOSE, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN:
// Must not be used. // Must not be used.
isExpr = false isExpr = false
isStmt = true isStmt = true
@ -621,6 +621,10 @@ func typecheck1(n ir.Node, top int) ir.Node {
n := n.(*ir.BinaryExpr) n := n.(*ir.BinaryExpr)
return tcComplex(n) return tcComplex(n)
case ir.OCLEAR:
n := n.(*ir.UnaryExpr)
return tcClear(n)
case ir.OCLOSE: case ir.OCLOSE:
n := n.(*ir.UnaryExpr) n := n.(*ir.UnaryExpr)
return tcClose(n) return tcClose(n)

View File

@ -34,6 +34,7 @@ var builtinFuncs = [...]struct {
}{ }{
{"append", ir.OAPPEND}, {"append", ir.OAPPEND},
{"cap", ir.OCAP}, {"cap", ir.OCAP},
{"clear", ir.OCLEAR},
{"close", ir.OCLOSE}, {"close", ir.OCLOSE},
{"complex", ir.OCOMPLEX}, {"complex", ir.OCOMPLEX},
{"copy", ir.OCOPY}, {"copy", ir.OCOPY},

View File

@ -130,6 +130,18 @@ func walkAppend(n *ir.CallExpr, init *ir.Nodes, dst ir.Node) ir.Node {
return s return s
} }
// walkClear walks an OCLEAR node.
func walkClear(n *ir.UnaryExpr) ir.Node {
typ := n.X.Type()
switch {
case typ.IsSlice():
return arrayClear(n.X.Pos(), n.X, nil)
case typ.IsMap():
return mapClear(n.X, reflectdata.TypePtrAt(n.X.Pos(), n.X.Type()))
}
panic("unreachable")
}
// walkClose walks an OCLOSE node. // walkClose walks an OCLOSE node.
func walkClose(n *ir.UnaryExpr, init *ir.Nodes) ir.Node { func walkClose(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
// cannot use chanfn - closechan takes any, not chan any // cannot use chanfn - closechan takes any, not chan any

View File

@ -279,6 +279,10 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
case ir.OCOPY: case ir.OCOPY:
return walkCopy(n.(*ir.BinaryExpr), init, base.Flag.Cfg.Instrumenting && !base.Flag.CompilingRuntime) return walkCopy(n.(*ir.BinaryExpr), init, base.Flag.Cfg.Instrumenting && !base.Flag.CompilingRuntime)
case ir.OCLEAR:
n := n.(*ir.UnaryExpr)
return walkClear(n)
case ir.OCLOSE: case ir.OCLOSE:
n := n.(*ir.UnaryExpr) n := n.(*ir.UnaryExpr)
return walkClose(n, init) return walkClose(n, init)

View File

@ -740,7 +740,7 @@ func (o *orderState) stmt(n ir.Node) {
} }
} }
case ir.OCHECKNIL, ir.OCLOSE, ir.OPANIC, ir.ORECV: case ir.OCHECKNIL, ir.OCLEAR, ir.OCLOSE, ir.OPANIC, ir.ORECV:
n := n.(*ir.UnaryExpr) n := n.(*ir.UnaryExpr)
t := o.markTemp() t := o.markTemp()
n.X = o.expr(n.X, nil) n.X = o.expr(n.X, nil)

View File

@ -13,6 +13,7 @@ import (
"cmd/compile/internal/ssagen" "cmd/compile/internal/ssagen"
"cmd/compile/internal/typecheck" "cmd/compile/internal/typecheck"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/src"
"cmd/internal/sys" "cmd/internal/sys"
) )
@ -38,7 +39,7 @@ func cheapComputableIndex(width int64) bool {
// the returned node. // the returned node.
func walkRange(nrange *ir.RangeStmt) ir.Node { func walkRange(nrange *ir.RangeStmt) ir.Node {
if isMapClear(nrange) { if isMapClear(nrange) {
return mapClear(nrange) return mapRangeClear(nrange)
} }
nfor := ir.NewForStmt(nrange.Pos(), nil, nil, nil, nil) nfor := ir.NewForStmt(nrange.Pos(), nil, nil, nil, nil)
@ -77,7 +78,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
base.Fatalf("walkRange") base.Fatalf("walkRange")
case types.TARRAY, types.TSLICE, types.TPTR: // TPTR is pointer-to-array case types.TARRAY, types.TSLICE, types.TPTR: // TPTR is pointer-to-array
if nn := arrayClear(nrange, v1, v2, a); nn != nil { if nn := arrayRangeClear(nrange, v1, v2, a); nn != nil {
base.Pos = lno base.Pos = lno
return nn return nn
} }
@ -437,18 +438,23 @@ func isMapClear(n *ir.RangeStmt) bool {
return true return true
} }
// mapClear constructs a call to runtime.mapclear for the map m. // mapRangeClear constructs a call to runtime.mapclear for the map range idiom.
func mapClear(nrange *ir.RangeStmt) ir.Node { func mapRangeClear(nrange *ir.RangeStmt) ir.Node {
m := nrange.X m := nrange.X
origPos := ir.SetPos(m) origPos := ir.SetPos(m)
defer func() { base.Pos = origPos }() defer func() { base.Pos = origPos }()
return mapClear(m, reflectdata.RangeMapRType(base.Pos, nrange))
}
// mapClear constructs a call to runtime.mapclear for the map m.
func mapClear(m, rtyp ir.Node) ir.Node {
t := m.Type() t := m.Type()
// instantiate mapclear(typ *type, hmap map[any]any) // instantiate mapclear(typ *type, hmap map[any]any)
fn := typecheck.LookupRuntime("mapclear") fn := typecheck.LookupRuntime("mapclear")
fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem()) fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
n := mkcallstmt1(fn, reflectdata.RangeMapRType(base.Pos, nrange), m) n := mkcallstmt1(fn, rtyp, m)
return walkStmt(typecheck.Stmt(n)) return walkStmt(typecheck.Stmt(n))
} }
@ -463,7 +469,7 @@ func mapClear(nrange *ir.RangeStmt) ir.Node {
// in which the evaluation of a is side-effect-free. // in which the evaluation of a is side-effect-free.
// //
// Parameters are as in walkRange: "for v1, v2 = range a". // Parameters are as in walkRange: "for v1, v2 = range a".
func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node { func arrayRangeClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
if base.Flag.N != 0 || base.Flag.Cfg.Instrumenting { if base.Flag.N != 0 || base.Flag.Cfg.Instrumenting {
return nil return nil
} }
@ -496,8 +502,17 @@ func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
return nil return nil
} }
elemsize := typecheck.RangeExprType(loop.X.Type()).Elem().Size() if !ir.IsZero(stmt.Y) {
if elemsize <= 0 || !ir.IsZero(stmt.Y) { return nil
}
return arrayClear(stmt.Pos(), a, loop)
}
// arrayClear constructs a call to runtime.memclr for fast zeroing of slices and arrays.
func arrayClear(wbPos src.XPos, a ir.Node, nrange *ir.RangeStmt) ir.Node {
elemsize := typecheck.RangeExprType(a.Type()).Elem().Size()
if elemsize <= 0 {
return nil return nil
} }
@ -527,7 +542,7 @@ func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
var fn ir.Node var fn ir.Node
if a.Type().Elem().HasPointers() { if a.Type().Elem().HasPointers() {
// memclrHasPointers(hp, hn) // memclrHasPointers(hp, hn)
ir.CurFunc.SetWBPos(stmt.Pos()) ir.CurFunc.SetWBPos(wbPos)
fn = mkcallstmt("memclrHasPointers", hp, hn) fn = mkcallstmt("memclrHasPointers", hp, hn)
} else { } else {
// memclrNoHeapPointers(hp, hn) // memclrNoHeapPointers(hp, hn)
@ -536,10 +551,11 @@ func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
n.Body.Append(fn) n.Body.Append(fn)
// i = len(a) - 1 // For array range clear, also set "i = len(a) - 1"
v1 = ir.NewAssignStmt(base.Pos, v1, ir.NewBinaryExpr(base.Pos, ir.OSUB, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(1))) if nrange != nil {
idx := ir.NewAssignStmt(base.Pos, nrange.Key, ir.NewBinaryExpr(base.Pos, ir.OSUB, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(1)))
n.Body.Append(v1) n.Body.Append(idx)
}
n.Cond = typecheck.Expr(n.Cond) n.Cond = typecheck.Expr(n.Cond)
n.Cond = typecheck.DefaultLit(n.Cond, nil) n.Cond = typecheck.DefaultLit(n.Cond, nil)

View File

@ -39,6 +39,7 @@ func walkStmt(n ir.Node) ir.Node {
ir.OAS2RECV, ir.OAS2RECV,
ir.OAS2FUNC, ir.OAS2FUNC,
ir.OAS2MAPR, ir.OAS2MAPR,
ir.OCLEAR,
ir.OCLOSE, ir.OCLOSE,
ir.OCOPY, ir.OCOPY,
ir.OCALLINTER, ir.OCALLINTER,

47
test/clear.go Normal file
View File

@ -0,0 +1,47 @@
// 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 "math"
func checkClearSlice() {
s := []int{1, 2, 3}
clear(s)
for i := range s {
if s[i] != 0 {
panic("clear not zeroing slice elem")
}
}
clear([]int{})
}
func checkClearMap() {
m1 := make(map[int]int)
m1[0] = 0
m1[1] = 1
clear(m1)
if len(m1) != 0 {
panic("m1 is not cleared")
}
// map contains NaN keys is also cleared.
m2 := make(map[float64]int)
m2[math.NaN()] = 1
m2[math.NaN()] = 1
clear(m2)
if len(m2) != 0 {
panic("m2 is not cleared")
}
clear(map[int]int{})
}
func main() {
checkClearSlice()
checkClearMap()
}