]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: add clear(x) builtin
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Fri, 25 Nov 2022 09:11:45 +0000 (16:11 +0700)
committerGopher Robot <gobot@golang.org>
Tue, 31 Jan 2023 19:43:07 +0000 (19:43 +0000)
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>

17 files changed:
src/cmd/compile/internal/escape/call.go
src/cmd/compile/internal/escape/stmt.go
src/cmd/compile/internal/ir/expr.go
src/cmd/compile/internal/ir/fmt.go
src/cmd/compile/internal/ir/node.go
src/cmd/compile/internal/ir/op_string.go
src/cmd/compile/internal/typecheck/const.go
src/cmd/compile/internal/typecheck/func.go
src/cmd/compile/internal/typecheck/stmt.go
src/cmd/compile/internal/typecheck/typecheck.go
src/cmd/compile/internal/typecheck/universe.go
src/cmd/compile/internal/walk/builtin.go
src/cmd/compile/internal/walk/expr.go
src/cmd/compile/internal/walk/order.go
src/cmd/compile/internal/walk/range.go
src/cmd/compile/internal/walk/stmt.go
test/clear.go [new file with mode: 0644]

index f1c2c306a2a4b3034a68e3f7638cadc10d6dd060..f9eced7dc0737ec9fc3e2cafa26fd2dead92b5fc 100644 (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])
                }
 
-       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)
                argument(e.discardHole(), &call.X)
 
index 90d4f2dedcde8709bcc99a32ce1bf0b4c8616f84..1ce04d98f3fd4352002d7815b29de9ce906b00ab 100644 (file)
@@ -180,7 +180,7 @@ func (e *escape) stmt(n ir.Node) {
                        dsts[i] = res.Nname.(*ir.Name)
                }
                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)
        case ir.OGO, ir.ODEFER:
                n := n.(*ir.GoDeferStmt)
index a481b14f8b94c0751aa416fe04cdb6e1077f5f3d..95c142b93d439ae6cc65251588811aea8d6be323 100644 (file)
@@ -747,7 +747,7 @@ func (n *UnaryExpr) SetOp(op Op) {
        default:
                panic(n.no("SetOp " + op.String()))
        case OBITNOT, ONEG, ONOT, OPLUS, ORECV,
-               OALIGNOF, OCAP, OCLOSE, OIMAG, OLEN, ONEW,
+               OALIGNOF, OCAP, OCLEAR, OCLOSE, OIMAG, OLEN, ONEW,
                OOFFSETOF, OPANIC, OREAL, OSIZEOF,
                OCHECKNIL, OCFUNC, OIDATA, OITAB, OSPTR,
                OUNSAFESTRINGDATA, OUNSAFESLICEDATA:
index bac172dbbd540c1c1adeea83c419647d93b3abed..ccd295d7e1b9cc66ad8acf2c0eeb4261c59e7c1f 100644 (file)
@@ -39,6 +39,7 @@ var OpNames = []string{
        OCALL:             "function call", // not actual syntax
        OCAP:              "cap",
        OCASE:             "case",
+       OCLEAR:            "clear",
        OCLOSE:            "close",
        OCOMPLEX:          "complex",
        OBITNOT:           "^",
@@ -182,6 +183,7 @@ var OpPrec = []int{
        OCALLMETH:         8,
        OCALL:             8,
        OCAP:              8,
+       OCLEAR:            8,
        OCLOSE:            8,
        OCOMPLIT:          8,
        OCONVIFACE:        8,
@@ -767,6 +769,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
        case OREAL,
                OIMAG,
                OCAP,
+               OCLEAR,
                OCLOSE,
                OLEN,
                ONEW,
index b42f914aadd8209c163c13a46441caa2ed1b09e1..ad25b9ff32d29bf95bc9f90f2f7660c9b72e53ac 100644 (file)
@@ -159,6 +159,7 @@ const (
        OCALLMETH  // X(Args) (direct method call x.Method(args))
        OCALLINTER // X(Args) (interface method call x.Method(args))
        OCAP       // cap(X)
+       OCLEAR     // clear(X)
        OCLOSE     // close(X)
        OCLOSURE   // func Type { Func.Closure.Body } (func literal)
        OCOMPLIT   // Type{List} (composite literal, not yet lowered to specific form)
index d84a08e2a1c9eb113b0e822c1a5ef8654766afb1..e0861457cb81b0758a0b1570592b9a35895b9b1f 100644 (file)
@@ -42,132 +42,133 @@ func _() {
        _ = x[OCALLMETH-31]
        _ = x[OCALLINTER-32]
        _ = x[OCAP-33]
-       _ = x[OCLOSE-34]
-       _ = x[OCLOSURE-35]
-       _ = x[OCOMPLIT-36]
-       _ = x[OMAPLIT-37]
-       _ = x[OSTRUCTLIT-38]
-       _ = x[OARRAYLIT-39]
-       _ = x[OSLICELIT-40]
-       _ = x[OPTRLIT-41]
-       _ = x[OCONV-42]
-       _ = x[OCONVIFACE-43]
-       _ = x[OCONVIDATA-44]
-       _ = x[OCONVNOP-45]
-       _ = x[OCOPY-46]
-       _ = x[ODCL-47]
-       _ = x[ODCLFUNC-48]
-       _ = x[ODCLCONST-49]
-       _ = x[ODCLTYPE-50]
-       _ = x[ODELETE-51]
-       _ = x[ODOT-52]
-       _ = x[ODOTPTR-53]
-       _ = x[ODOTMETH-54]
-       _ = x[ODOTINTER-55]
-       _ = x[OXDOT-56]
-       _ = x[ODOTTYPE-57]
-       _ = x[ODOTTYPE2-58]
-       _ = x[OEQ-59]
-       _ = x[ONE-60]
-       _ = x[OLT-61]
-       _ = x[OLE-62]
-       _ = x[OGE-63]
-       _ = x[OGT-64]
-       _ = x[ODEREF-65]
-       _ = x[OINDEX-66]
-       _ = x[OINDEXMAP-67]
-       _ = x[OKEY-68]
-       _ = x[OSTRUCTKEY-69]
-       _ = x[OLEN-70]
-       _ = x[OMAKE-71]
-       _ = x[OMAKECHAN-72]
-       _ = x[OMAKEMAP-73]
-       _ = x[OMAKESLICE-74]
-       _ = x[OMAKESLICECOPY-75]
-       _ = x[OMUL-76]
-       _ = x[ODIV-77]
-       _ = x[OMOD-78]
-       _ = x[OLSH-79]
-       _ = x[ORSH-80]
-       _ = x[OAND-81]
-       _ = x[OANDNOT-82]
-       _ = x[ONEW-83]
-       _ = x[ONOT-84]
-       _ = x[OBITNOT-85]
-       _ = x[OPLUS-86]
-       _ = x[ONEG-87]
-       _ = x[OOROR-88]
-       _ = x[OPANIC-89]
-       _ = x[OPRINT-90]
-       _ = x[OPRINTN-91]
-       _ = x[OPAREN-92]
-       _ = x[OSEND-93]
-       _ = x[OSLICE-94]
-       _ = x[OSLICEARR-95]
-       _ = x[OSLICESTR-96]
-       _ = x[OSLICE3-97]
-       _ = x[OSLICE3ARR-98]
-       _ = x[OSLICEHEADER-99]
-       _ = x[OSTRINGHEADER-100]
-       _ = x[ORECOVER-101]
-       _ = x[ORECOVERFP-102]
-       _ = x[ORECV-103]
-       _ = x[ORUNESTR-104]
-       _ = x[OSELRECV2-105]
-       _ = x[OREAL-106]
-       _ = x[OIMAG-107]
-       _ = x[OCOMPLEX-108]
-       _ = x[OALIGNOF-109]
-       _ = x[OOFFSETOF-110]
-       _ = x[OSIZEOF-111]
-       _ = x[OUNSAFEADD-112]
-       _ = x[OUNSAFESLICE-113]
-       _ = x[OUNSAFESLICEDATA-114]
-       _ = x[OUNSAFESTRING-115]
-       _ = x[OUNSAFESTRINGDATA-116]
-       _ = x[OMETHEXPR-117]
-       _ = x[OMETHVALUE-118]
-       _ = x[OBLOCK-119]
-       _ = x[OBREAK-120]
-       _ = x[OCASE-121]
-       _ = x[OCONTINUE-122]
-       _ = x[ODEFER-123]
-       _ = x[OFALL-124]
-       _ = x[OFOR-125]
-       _ = x[OGOTO-126]
-       _ = x[OIF-127]
-       _ = x[OLABEL-128]
-       _ = x[OGO-129]
-       _ = x[ORANGE-130]
-       _ = x[ORETURN-131]
-       _ = x[OSELECT-132]
-       _ = x[OSWITCH-133]
-       _ = x[OTYPESW-134]
-       _ = x[OFUNCINST-135]
-       _ = x[OINLCALL-136]
-       _ = x[OEFACE-137]
-       _ = x[OITAB-138]
-       _ = x[OIDATA-139]
-       _ = x[OSPTR-140]
-       _ = x[OCFUNC-141]
-       _ = x[OCHECKNIL-142]
-       _ = x[ORESULT-143]
-       _ = x[OINLMARK-144]
-       _ = x[OLINKSYMOFFSET-145]
-       _ = x[OJUMPTABLE-146]
-       _ = x[ODYNAMICDOTTYPE-147]
-       _ = x[ODYNAMICDOTTYPE2-148]
-       _ = x[ODYNAMICTYPE-149]
-       _ = x[OTAILCALL-150]
-       _ = x[OGETG-151]
-       _ = x[OGETCALLERPC-152]
-       _ = x[OGETCALLERSP-153]
-       _ = x[OEND-154]
+       _ = x[OCLEAR-34]
+       _ = x[OCLOSE-35]
+       _ = x[OCLOSURE-36]
+       _ = x[OCOMPLIT-37]
+       _ = x[OMAPLIT-38]
+       _ = x[OSTRUCTLIT-39]
+       _ = x[OARRAYLIT-40]
+       _ = x[OSLICELIT-41]
+       _ = x[OPTRLIT-42]
+       _ = x[OCONV-43]
+       _ = x[OCONVIFACE-44]
+       _ = x[OCONVIDATA-45]
+       _ = x[OCONVNOP-46]
+       _ = x[OCOPY-47]
+       _ = x[ODCL-48]
+       _ = x[ODCLFUNC-49]
+       _ = x[ODCLCONST-50]
+       _ = x[ODCLTYPE-51]
+       _ = x[ODELETE-52]
+       _ = x[ODOT-53]
+       _ = x[ODOTPTR-54]
+       _ = x[ODOTMETH-55]
+       _ = x[ODOTINTER-56]
+       _ = x[OXDOT-57]
+       _ = x[ODOTTYPE-58]
+       _ = x[ODOTTYPE2-59]
+       _ = x[OEQ-60]
+       _ = x[ONE-61]
+       _ = x[OLT-62]
+       _ = x[OLE-63]
+       _ = x[OGE-64]
+       _ = x[OGT-65]
+       _ = x[ODEREF-66]
+       _ = x[OINDEX-67]
+       _ = x[OINDEXMAP-68]
+       _ = x[OKEY-69]
+       _ = x[OSTRUCTKEY-70]
+       _ = x[OLEN-71]
+       _ = x[OMAKE-72]
+       _ = x[OMAKECHAN-73]
+       _ = x[OMAKEMAP-74]
+       _ = x[OMAKESLICE-75]
+       _ = x[OMAKESLICECOPY-76]
+       _ = x[OMUL-77]
+       _ = x[ODIV-78]
+       _ = x[OMOD-79]
+       _ = x[OLSH-80]
+       _ = x[ORSH-81]
+       _ = x[OAND-82]
+       _ = x[OANDNOT-83]
+       _ = x[ONEW-84]
+       _ = x[ONOT-85]
+       _ = x[OBITNOT-86]
+       _ = x[OPLUS-87]
+       _ = x[ONEG-88]
+       _ = x[OOROR-89]
+       _ = x[OPANIC-90]
+       _ = x[OPRINT-91]
+       _ = x[OPRINTN-92]
+       _ = x[OPAREN-93]
+       _ = x[OSEND-94]
+       _ = x[OSLICE-95]
+       _ = x[OSLICEARR-96]
+       _ = x[OSLICESTR-97]
+       _ = x[OSLICE3-98]
+       _ = x[OSLICE3ARR-99]
+       _ = x[OSLICEHEADER-100]
+       _ = x[OSTRINGHEADER-101]
+       _ = x[ORECOVER-102]
+       _ = x[ORECOVERFP-103]
+       _ = x[ORECV-104]
+       _ = x[ORUNESTR-105]
+       _ = x[OSELRECV2-106]
+       _ = x[OREAL-107]
+       _ = x[OIMAG-108]
+       _ = x[OCOMPLEX-109]
+       _ = x[OALIGNOF-110]
+       _ = x[OOFFSETOF-111]
+       _ = x[OSIZEOF-112]
+       _ = x[OUNSAFEADD-113]
+       _ = x[OUNSAFESLICE-114]
+       _ = x[OUNSAFESLICEDATA-115]
+       _ = x[OUNSAFESTRING-116]
+       _ = x[OUNSAFESTRINGDATA-117]
+       _ = x[OMETHEXPR-118]
+       _ = x[OMETHVALUE-119]
+       _ = x[OBLOCK-120]
+       _ = x[OBREAK-121]
+       _ = x[OCASE-122]
+       _ = x[OCONTINUE-123]
+       _ = x[ODEFER-124]
+       _ = x[OFALL-125]
+       _ = x[OFOR-126]
+       _ = x[OGOTO-127]
+       _ = x[OIF-128]
+       _ = x[OLABEL-129]
+       _ = x[OGO-130]
+       _ = x[ORANGE-131]
+       _ = x[ORETURN-132]
+       _ = x[OSELECT-133]
+       _ = x[OSWITCH-134]
+       _ = x[OTYPESW-135]
+       _ = x[OFUNCINST-136]
+       _ = x[OINLCALL-137]
+       _ = x[OEFACE-138]
+       _ = x[OITAB-139]
+       _ = x[OIDATA-140]
+       _ = x[OSPTR-141]
+       _ = x[OCFUNC-142]
+       _ = x[OCHECKNIL-143]
+       _ = x[ORESULT-144]
+       _ = x[OINLMARK-145]
+       _ = x[OLINKSYMOFFSET-146]
+       _ = x[OJUMPTABLE-147]
+       _ = x[ODYNAMICDOTTYPE-148]
+       _ = x[ODYNAMICDOTTYPE2-149]
+       _ = x[ODYNAMICTYPE-150]
+       _ = x[OTAILCALL-151]
+       _ = x[OGETG-152]
+       _ = x[OGETCALLERPC-153]
+       _ = 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 {
        if i >= Op(len(_Op_index)-1) {
index edc399ffd74c77f3e646032f1b1184aa0dbd6b9b..26a3753c5fde0b89d57c433e8c5877ad61df3444 100644 (file)
@@ -743,6 +743,7 @@ func callOrChan(n ir.Node) bool {
                ir.OCALLINTER,
                ir.OCALLMETH,
                ir.OCAP,
+               ir.OCLEAR,
                ir.OCLOSE,
                ir.OCOMPLEX,
                ir.OCOPY,
index 065007b04eacd4f28b2ba1da80cdbeefaa65ccaa..f64523c9a0356dbf26097ee085aadda86aec2022 100644 (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
                        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)
                        fallthrough
                case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
@@ -441,6 +441,28 @@ func tcAppend(n *ir.CallExpr) ir.Node {
        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.
 func tcClose(n *ir.UnaryExpr) ir.Node {
        n.X = Expr(n.X)
index 5eeab4115e3a61c97ae6e12183fba650ab0c2f06..2af6c26a1635d4d8dcc4e3271a0a5ee7b5272bae 100644 (file)
@@ -273,6 +273,7 @@ func tcGoDefer(n *ir.GoDeferStmt) {
        case ir.OCALLINTER,
                ir.OCALLMETH,
                ir.OCALLFUNC,
+               ir.OCLEAR,
                ir.OCLOSE,
                ir.OCOPY,
                ir.ODELETE,
index ea49e76a3e37e7cfbeb3e16e76e2f1f75a264e44..b06b9d9753fba71dd038e0b01a2e89a20819fd92 100644 (file)
@@ -336,7 +336,7 @@ func typecheck(n ir.Node, top int) (res ir.Node) {
        case ir.OAPPEND:
                // Must be used (and not BinaryExpr/UnaryExpr).
                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.
                isExpr = false
                isStmt = true
@@ -621,6 +621,10 @@ func typecheck1(n ir.Node, top int) ir.Node {
                n := n.(*ir.BinaryExpr)
                return tcComplex(n)
 
+       case ir.OCLEAR:
+               n := n.(*ir.UnaryExpr)
+               return tcClear(n)
+
        case ir.OCLOSE:
                n := n.(*ir.UnaryExpr)
                return tcClose(n)
index 828a8db3e7f71ade3c3f3c62e29e0a9b6002cc79..6c6a504606f7d6a690525b76a1529592301832c4 100644 (file)
@@ -34,6 +34,7 @@ var builtinFuncs = [...]struct {
 }{
        {"append", ir.OAPPEND},
        {"cap", ir.OCAP},
+       {"clear", ir.OCLEAR},
        {"close", ir.OCLOSE},
        {"complex", ir.OCOMPLEX},
        {"copy", ir.OCOPY},
index 4c5ee9baecb1f1d230b4d4bc9cdc44d942243c74..3c85b19a36a0d3c28d93c8b8c2da4edfb4e4ac8a 100644 (file)
@@ -130,6 +130,18 @@ func walkAppend(n *ir.CallExpr, init *ir.Nodes, dst ir.Node) ir.Node {
        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.
 func walkClose(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
        // cannot use chanfn - closechan takes any, not chan any
index 24fe0d0b9f639d17a1333b261df8f81eff188c73..6f4a5339ce37cf833b0233814006dc69451cd586 100644 (file)
@@ -279,6 +279,10 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
        case ir.OCOPY:
                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:
                n := n.(*ir.UnaryExpr)
                return walkClose(n, init)
index d6712ae0fc4a569c3a6489dca1d6d825178745eb..b6b277c9a51781c1c04997932c87158d7ed6130c 100644 (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)
                t := o.markTemp()
                n.X = o.expr(n.X, nil)
index 64af26bf29c587c97d9241f0a2644d7853701e56..67c13a847c8fa01d640d8adcc99536b025aec5a2 100644 (file)
@@ -13,6 +13,7 @@ import (
        "cmd/compile/internal/ssagen"
        "cmd/compile/internal/typecheck"
        "cmd/compile/internal/types"
+       "cmd/internal/src"
        "cmd/internal/sys"
 )
 
@@ -38,7 +39,7 @@ func cheapComputableIndex(width int64) bool {
 // the returned node.
 func walkRange(nrange *ir.RangeStmt) ir.Node {
        if isMapClear(nrange) {
-               return mapClear(nrange)
+               return mapRangeClear(nrange)
        }
 
        nfor := ir.NewForStmt(nrange.Pos(), nil, nil, nil, nil)
@@ -77,7 +78,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
                base.Fatalf("walkRange")
 
        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
                        return nn
                }
@@ -437,18 +438,23 @@ func isMapClear(n *ir.RangeStmt) bool {
        return true
 }
 
-// mapClear constructs a call to runtime.mapclear for the map m.
-func mapClear(nrange *ir.RangeStmt) ir.Node {
+// mapRangeClear constructs a call to runtime.mapclear for the map range idiom.
+func mapRangeClear(nrange *ir.RangeStmt) ir.Node {
        m := nrange.X
        origPos := ir.SetPos(m)
        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()
 
        // instantiate mapclear(typ *type, hmap map[any]any)
        fn := typecheck.LookupRuntime("mapclear")
        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))
 }
 
@@ -463,7 +469,7 @@ func mapClear(nrange *ir.RangeStmt) ir.Node {
 // in which the evaluation of a is side-effect-free.
 //
 // 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 {
                return nil
        }
@@ -496,8 +502,17 @@ func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
                return nil
        }
 
-       elemsize := typecheck.RangeExprType(loop.X.Type()).Elem().Size()
-       if elemsize <= 0 || !ir.IsZero(stmt.Y) {
+       if !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
        }
 
@@ -527,7 +542,7 @@ func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
        var fn ir.Node
        if a.Type().Elem().HasPointers() {
                // memclrHasPointers(hp, hn)
-               ir.CurFunc.SetWBPos(stmt.Pos())
+               ir.CurFunc.SetWBPos(wbPos)
                fn = mkcallstmt("memclrHasPointers", hp, hn)
        } else {
                // memclrNoHeapPointers(hp, hn)
@@ -536,10 +551,11 @@ func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
 
        n.Body.Append(fn)
 
-       // 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)))
-
-       n.Body.Append(v1)
+       // For array range clear, also set "i = len(a) - 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(idx)
+       }
 
        n.Cond = typecheck.Expr(n.Cond)
        n.Cond = typecheck.DefaultLit(n.Cond, nil)
index ceee1b1b75ff66b26271ea985cd89fe27d695ebe..c6a03d2bd810e42e5b1e89e42a4ab321352cfebc 100644 (file)
@@ -39,6 +39,7 @@ func walkStmt(n ir.Node) ir.Node {
                ir.OAS2RECV,
                ir.OAS2FUNC,
                ir.OAS2MAPR,
+               ir.OCLEAR,
                ir.OCLOSE,
                ir.OCOPY,
                ir.OCALLINTER,
diff --git a/test/clear.go b/test/clear.go
new file mode 100644 (file)
index 0000000..60ee4ec
--- /dev/null
@@ -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()
+}