]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.regabi] cmd/compile: update ir/fmt for concrete types
authorRuss Cox <rsc@golang.org>
Fri, 11 Dec 2020 01:55:10 +0000 (20:55 -0500)
committerRuss Cox <rsc@golang.org>
Thu, 17 Dec 2020 03:50:03 +0000 (03:50 +0000)
An automated rewrite will add concrete type assertions after
a test of n.Op(), when n can be safely type-asserted
(meaning, n is not reassigned a different type, n is not reassigned
and then used outside the scope of the type assertion,
and so on).

This sequence of CLs handles the code that the automated
rewrite does not: adding specific types to function arguments,
adjusting code not to call n.Left() etc when n may have multiple
representations, and so on.

This CL handles package fmt. There are various type assertions
but also some rewriting to lean more heavily on reflection.

Passes buildall w/ toolstash -cmp.

Change-Id: I503467468b42ace11bff2ba014b03cfa345e6d03
Reviewed-on: https://go-review.googlesource.com/c/go/+/277915
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/ir/fmt.go
src/cmd/compile/internal/ir/name.go
test/escape_param.go

index 4bea6e2ae0938a1f901f981d6539ac4f6bf04674..3cda9c8c38d4ba5853e7ce2ae0229dcc85d83ec7 100644 (file)
@@ -9,6 +9,7 @@ import (
        "fmt"
        "go/constant"
        "io"
+       "math"
        "os"
        "path/filepath"
        "reflect"
@@ -141,7 +142,7 @@ func FmtNode(n Node, s fmt.State, verb rune) {
        }
 
        if n == nil {
-               fmt.Fprint(s, "<N>")
+               fmt.Fprint(s, "<nil>")
                return
        }
 
@@ -330,12 +331,14 @@ func stmtFmt(n Node, s fmt.State) {
 
        switch n.Op() {
        case ODCL:
+               n := n.(*Decl)
                fmt.Fprintf(s, "var %v %v", n.Left().Sym(), n.Left().Type())
 
        // Don't export "v = <N>" initializing statements, hope they're always
        // preceded by the DCL which will be re-parsed and typechecked to reproduce
        // the "v = <N>" again.
        case OAS:
+               n := n.(*AssignStmt)
                if n.Colas() && !complexinit {
                        fmt.Fprintf(s, "%v := %v", n.Left(), n.Right())
                } else {
@@ -343,6 +346,7 @@ func stmtFmt(n Node, s fmt.State) {
                }
 
        case OASOP:
+               n := n.(*AssignOpStmt)
                if n.Implicit() {
                        if n.SubOp() == OADD {
                                fmt.Fprintf(s, "%v++", n.Left())
@@ -355,6 +359,7 @@ func stmtFmt(n Node, s fmt.State) {
                fmt.Fprintf(s, "%v %v= %v", n.Left(), n.SubOp(), n.Right())
 
        case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+               n := n.(*AssignListStmt)
                if n.Colas() && !complexinit {
                        fmt.Fprintf(s, "%.v := %.v", n.List(), n.Rlist())
                } else {
@@ -362,26 +367,33 @@ func stmtFmt(n Node, s fmt.State) {
                }
 
        case OBLOCK:
+               n := n.(*BlockStmt)
                if n.List().Len() != 0 {
                        fmt.Fprintf(s, "%v", n.List())
                }
 
        case ORETURN:
+               n := n.(*ReturnStmt)
                fmt.Fprintf(s, "return %.v", n.List())
 
        case ORETJMP:
+               n := n.(*BranchStmt)
                fmt.Fprintf(s, "retjmp %v", n.Sym())
 
        case OINLMARK:
+               n := n.(*InlineMarkStmt)
                fmt.Fprintf(s, "inlmark %d", n.Offset())
 
        case OGO:
+               n := n.(*GoDeferStmt)
                fmt.Fprintf(s, "go %v", n.Left())
 
        case ODEFER:
+               n := n.(*GoDeferStmt)
                fmt.Fprintf(s, "defer %v", n.Left())
 
        case OIF:
+               n := n.(*IfStmt)
                if simpleinit {
                        fmt.Fprintf(s, "if %v; %v { %v }", n.Init().First(), n.Left(), n.Body())
                } else {
@@ -392,6 +404,7 @@ func stmtFmt(n Node, s fmt.State) {
                }
 
        case OFOR, OFORUNTIL:
+               n := n.(*ForStmt)
                opname := "for"
                if n.Op() == OFORUNTIL {
                        opname = "foruntil"
@@ -425,6 +438,7 @@ func stmtFmt(n Node, s fmt.State) {
                fmt.Fprintf(s, " { %v }", n.Body())
 
        case ORANGE:
+               n := n.(*RangeStmt)
                if !exportFormat {
                        fmt.Fprint(s, "for loop")
                        break
@@ -437,23 +451,31 @@ func stmtFmt(n Node, s fmt.State) {
 
                fmt.Fprintf(s, "for %.v = range %v { %v }", n.List(), n.Right(), n.Body())
 
-       case OSELECT, OSWITCH:
+       case OSELECT:
+               n := n.(*SelectStmt)
                if !exportFormat {
                        fmt.Fprintf(s, "%v statement", n.Op())
                        break
                }
+               fmt.Fprintf(s, "select { %v }", n.List())
 
-               fmt.Fprintf(s, "%v", n.Op())
+       case OSWITCH:
+               n := n.(*SwitchStmt)
+               if !exportFormat {
+                       fmt.Fprintf(s, "%v statement", n.Op())
+                       break
+               }
+               fmt.Fprintf(s, "switch")
                if simpleinit {
                        fmt.Fprintf(s, " %v;", n.Init().First())
                }
                if n.Left() != nil {
                        fmt.Fprintf(s, " %v ", n.Left())
                }
-
                fmt.Fprintf(s, " { %v }", n.List())
 
        case OCASE:
+               n := n.(*CaseStmt)
                if n.List().Len() != 0 {
                        fmt.Fprintf(s, "case %.v", n.List())
                } else {
@@ -462,6 +484,7 @@ func stmtFmt(n Node, s fmt.State) {
                fmt.Fprintf(s, ": %v", n.Body())
 
        case OBREAK, OCONTINUE, OGOTO, OFALL:
+               n := n.(*BranchStmt)
                if n.Sym() != nil {
                        fmt.Fprintf(s, "%v %v", n.Op(), n.Sym())
                } else {
@@ -469,6 +492,7 @@ func stmtFmt(n Node, s fmt.State) {
                }
 
        case OLABEL:
+               n := n.(*LabelStmt)
                fmt.Fprintf(s, "%v: ", n.Sym())
        }
 
@@ -488,7 +512,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
 
        for {
                if n == nil {
-                       fmt.Fprint(s, "<N>")
+                       fmt.Fprint(s, "<nil>")
                        return
                }
 
@@ -499,10 +523,23 @@ func exprFmt(n Node, s fmt.State, prec int) {
                }
 
                // Skip implicit operations introduced during typechecking.
-               switch n.Op() {
-               case OADDR, ODEREF, OCONV, OCONVNOP, OCONVIFACE:
-                       if n.Implicit() {
-                               n = n.Left()
+               switch nn := n; nn.Op() {
+               case OADDR:
+                       nn := nn.(*AddrExpr)
+                       if nn.Implicit() {
+                               n = nn.Left()
+                               continue
+                       }
+               case ODEREF:
+                       nn := nn.(*StarExpr)
+                       if nn.Implicit() {
+                               n = nn.Left()
+                               continue
+                       }
+               case OCONV, OCONVNOP, OCONVIFACE:
+                       nn := nn.(*ConvExpr)
+                       if nn.Implicit() {
+                               n = nn.Left()
                                continue
                        }
                }
@@ -522,6 +559,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
 
        switch n.Op() {
        case OPAREN:
+               n := n.(*ParenExpr)
                fmt.Fprintf(s, "(%v)", n.Left())
 
        case ONIL:
@@ -570,6 +608,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
                }
 
        case ODCLFUNC:
+               n := n.(*Func)
                if sym := n.Sym(); sym != nil {
                        fmt.Fprint(s, sym)
                        return
@@ -577,6 +616,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprintf(s, "<unnamed Func>")
 
        case ONAME:
+               n := n.(*Name)
                // Special case: name used as local variable in export.
                // _ becomes ~b%d internally; print as _ for export
                if !exportFormat && n.Sym() != nil && n.Sym().Name[0] == '~' && n.Sym().Name[1] == 'b' {
@@ -641,17 +681,15 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprint(s, "<func>")
 
        case OCLOSURE:
+               n := n.(*ClosureExpr)
                if !exportFormat {
                        fmt.Fprint(s, "func literal")
                        return
                }
-               if n.Body().Len() != 0 {
-                       fmt.Fprintf(s, "%v { %v }", n.Type(), n.Body())
-                       return
-               }
                fmt.Fprintf(s, "%v { %v }", n.Type(), n.Func().Body())
 
        case OCOMPLIT:
+               n := n.(*CompLitExpr)
                if !exportFormat {
                        if n.Implicit() {
                                fmt.Fprintf(s, "... argument")
@@ -668,9 +706,11 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprintf(s, "(%v{ %.v })", n.Right(), n.List())
 
        case OPTRLIT:
+               n := n.(*AddrExpr)
                fmt.Fprintf(s, "&%v", n.Left())
 
        case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
+               n := n.(*CompLitExpr)
                if !exportFormat {
                        fmt.Fprintf(s, "%v{%s}", n.Type(), ellipsisIf(n.List().Len() != 0))
                        return
@@ -678,6 +718,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprintf(s, "(%v{ %.v })", n.Type(), n.List())
 
        case OKEY:
+               n := n.(*KeyExpr)
                if n.Left() != nil && n.Right() != nil {
                        fmt.Fprintf(s, "%v:%v", n.Left(), n.Right())
                        return
@@ -694,9 +735,11 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprint(s, ":")
 
        case OSTRUCTKEY:
+               n := n.(*StructKeyExpr)
                fmt.Fprintf(s, "%v:%v", n.Sym(), n.Left())
 
        case OCALLPART:
+               n := n.(*CallPartExpr)
                exprFmt(n.Left(), s, nprec)
                if n.Sym() == nil {
                        fmt.Fprint(s, ".<nil>")
@@ -705,6 +748,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprintf(s, ".%s", types.SymMethodName(n.Sym()))
 
        case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
+               n := n.(*SelectorExpr)
                exprFmt(n.Left(), s, nprec)
                if n.Sym() == nil {
                        fmt.Fprint(s, ".<nil>")
@@ -713,6 +757,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprintf(s, ".%s", types.SymMethodName(n.Sym()))
 
        case ODOTTYPE, ODOTTYPE2:
+               n := n.(*TypeAssertExpr)
                exprFmt(n.Left(), s, nprec)
                if n.Right() != nil {
                        fmt.Fprintf(s, ".(%v)", n.Right())
@@ -721,10 +766,12 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprintf(s, ".(%v)", n.Type())
 
        case OINDEX, OINDEXMAP:
+               n := n.(*IndexExpr)
                exprFmt(n.Left(), s, nprec)
                fmt.Fprintf(s, "[%v]", n.Right())
 
        case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
+               n := n.(*SliceExpr)
                exprFmt(n.Left(), s, nprec)
                fmt.Fprint(s, "[")
                low, high, max := n.SliceBounds()
@@ -744,17 +791,15 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprint(s, "]")
 
        case OSLICEHEADER:
+               n := n.(*SliceHeaderExpr)
                if n.List().Len() != 2 {
                        base.Fatalf("bad OSLICEHEADER list length %d", n.List().Len())
                }
                fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Left(), n.List().First(), n.List().Second())
 
        case OCOMPLEX, OCOPY:
-               if n.Left() != nil {
-                       fmt.Fprintf(s, "%v(%v, %v)", n.Op(), n.Left(), n.Right())
-               } else {
-                       fmt.Fprintf(s, "%v(%.v)", n.Op(), n.List())
-               }
+               n := n.(*BinaryExpr)
+               fmt.Fprintf(s, "%v(%v, %v)", n.Op(), n.Left(), n.Right())
 
        case OCONV,
                OCONVIFACE,
@@ -764,37 +809,34 @@ func exprFmt(n Node, s fmt.State, prec int) {
                OSTR2BYTES,
                OSTR2RUNES,
                ORUNESTR:
+               n := n.(*ConvExpr)
                if n.Type() == nil || n.Type().Sym() == nil {
                        fmt.Fprintf(s, "(%v)", n.Type())
                } else {
                        fmt.Fprintf(s, "%v", n.Type())
                }
-               if n.Left() != nil {
-                       fmt.Fprintf(s, "(%v)", n.Left())
-               } else {
-                       fmt.Fprintf(s, "(%.v)", n.List())
-               }
+               fmt.Fprintf(s, "(%v)", n.Left())
 
        case OREAL,
                OIMAG,
-               OAPPEND,
                OCAP,
                OCLOSE,
-               ODELETE,
                OLEN,
-               OMAKE,
                ONEW,
                OPANIC,
-               ORECOVER,
                OALIGNOF,
                OOFFSETOF,
-               OSIZEOF,
+               OSIZEOF:
+               n := n.(*UnaryExpr)
+               fmt.Fprintf(s, "%v(%v)", n.Op(), n.Left())
+
+       case OAPPEND,
+               ODELETE,
+               OMAKE,
+               ORECOVER,
                OPRINT,
                OPRINTN:
-               if n.Left() != nil {
-                       fmt.Fprintf(s, "%v(%v)", n.Op(), n.Left())
-                       return
-               }
+               n := n.(*CallExpr)
                if n.IsDDD() {
                        fmt.Fprintf(s, "%v(%.v...)", n.Op(), n.List())
                        return
@@ -802,6 +844,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprintf(s, "%v(%.v)", n.Op(), n.List())
 
        case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
+               n := n.(*CallExpr)
                exprFmt(n.Left(), s, nprec)
                if n.IsDDD() {
                        fmt.Fprintf(s, "(%.v...)", n.List())
@@ -810,10 +853,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprintf(s, "(%.v)", n.List())
 
        case OMAKEMAP, OMAKECHAN, OMAKESLICE:
-               if n.List().Len() != 0 { // pre-typecheck
-                       fmt.Fprintf(s, "make(%v, %.v)", n.Type(), n.List())
-                       return
-               }
+               n := n.(*MakeExpr)
                if n.Right() != nil {
                        fmt.Fprintf(s, "make(%v, %v, %v)", n.Type(), n.Left(), n.Right())
                        return
@@ -825,20 +865,34 @@ func exprFmt(n Node, s fmt.State, prec int) {
                fmt.Fprintf(s, "make(%v)", n.Type())
 
        case OMAKESLICECOPY:
+               n := n.(*MakeExpr)
                fmt.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type(), n.Left(), n.Right())
 
-       case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
+       case OPLUS, ONEG, OBITNOT, ONOT, ORECV:
                // Unary
+               n := n.(*UnaryExpr)
+               fmt.Fprintf(s, "%v", n.Op())
+               if n.Left() != nil && n.Left().Op() == n.Op() {
+                       fmt.Fprint(s, " ")
+               }
+               exprFmt(n.Left(), s, nprec+1)
+
+       case OADDR:
+               n := n.(*AddrExpr)
                fmt.Fprintf(s, "%v", n.Op())
                if n.Left() != nil && n.Left().Op() == n.Op() {
                        fmt.Fprint(s, " ")
                }
                exprFmt(n.Left(), s, nprec+1)
 
+       case ODEREF:
+               n := n.(*StarExpr)
+               fmt.Fprintf(s, "%v", n.Op())
+               exprFmt(n.Left(), s, nprec+1)
+
                // Binary
        case OADD,
                OAND,
-               OANDAND,
                OANDNOT,
                ODIV,
                OEQ,
@@ -851,16 +905,29 @@ func exprFmt(n Node, s fmt.State, prec int) {
                OMUL,
                ONE,
                OOR,
-               OOROR,
                ORSH,
-               OSEND,
                OSUB,
                OXOR:
+               n := n.(*BinaryExpr)
+               exprFmt(n.Left(), s, nprec)
+               fmt.Fprintf(s, " %v ", n.Op())
+               exprFmt(n.Right(), s, nprec+1)
+
+       case OANDAND,
+               OOROR:
+               n := n.(*LogicalExpr)
                exprFmt(n.Left(), s, nprec)
                fmt.Fprintf(s, " %v ", n.Op())
                exprFmt(n.Right(), s, nprec+1)
 
+       case OSEND:
+               n := n.(*SendStmt)
+               exprFmt(n.Left(), s, nprec)
+               fmt.Fprintf(s, " <- ")
+               exprFmt(n.Right(), s, nprec+1)
+
        case OADDSTR:
+               n := n.(*AddStringExpr)
                for i, n1 := range n.List().Slice() {
                        if i != 0 {
                                fmt.Fprint(s, " + ")
@@ -951,27 +1018,12 @@ func dumpNodeHeader(w io.Writer, n Node) {
        if base.Debug.DumpPtrs != 0 {
                fmt.Fprintf(w, " p(%p)", n)
        }
-       if n.Name() != nil && n.Name().Vargen != 0 {
-               fmt.Fprintf(w, " g(%d)", n.Name().Vargen)
-       }
 
        if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Defn != nil {
                // Useful to see where Defn is set and what node it points to
                fmt.Fprintf(w, " defn(%p)", n.Name().Defn)
        }
 
-       if n.Offset() != types.BADWIDTH {
-               fmt.Fprintf(w, " x(%d)", n.Offset())
-       }
-
-       if n.Class() != 0 {
-               fmt.Fprintf(w, " class(%v)", n.Class())
-       }
-
-       if n.Colas() {
-               fmt.Fprintf(w, " colas(%v)", n.Colas())
-       }
-
        if EscFmt != nil {
                if esc := EscFmt(n); esc != "" {
                        fmt.Fprintf(w, " %s", esc)
@@ -982,47 +1034,62 @@ func dumpNodeHeader(w io.Writer, n Node) {
                fmt.Fprintf(w, " tc(%d)", n.Typecheck())
        }
 
-       if n.IsDDD() {
-               fmt.Fprintf(w, " isddd(%v)", n.IsDDD())
-       }
-
-       if n.Implicit() {
-               fmt.Fprintf(w, " implicit(%v)", n.Implicit())
-       }
-
-       if n.Op() == ONAME {
-               if n.Name().Addrtaken() {
-                       fmt.Fprint(w, " addrtaken")
-               }
-               if n.Name().Assigned() {
-                       fmt.Fprint(w, " assigned")
-               }
-               if n.Name().IsClosureVar() {
-                       fmt.Fprint(w, " closurevar")
-               }
-               if n.Name().Captured() {
-                       fmt.Fprint(w, " captured")
+       // Print Node-specific fields of basic type in header line.
+       v := reflect.ValueOf(n).Elem()
+       t := v.Type()
+       nf := t.NumField()
+       for i := 0; i < nf; i++ {
+               tf := t.Field(i)
+               if tf.PkgPath != "" {
+                       // skip unexported field - Interface will fail
+                       continue
                }
-               if n.Name().IsOutputParamHeapAddr() {
-                       fmt.Fprint(w, " outputparamheapaddr")
+               k := tf.Type.Kind()
+               if reflect.Bool <= k && k <= reflect.Complex128 {
+                       name := strings.TrimSuffix(tf.Name, "_")
+                       vf := v.Field(i)
+                       vfi := vf.Interface()
+                       if name == "Offset" && vfi == types.BADWIDTH || name != "Offset" && isZero(vf) {
+                               continue
+                       }
+                       if vfi == true {
+                               fmt.Fprintf(w, " %s", name)
+                       } else {
+                               fmt.Fprintf(w, " %s:%+v", name, vf.Interface())
+                       }
                }
        }
-       if n.Bounded() {
-               fmt.Fprint(w, " bounded")
-       }
-       if n.NonNil() {
-               fmt.Fprint(w, " nonnil")
-       }
-
-       if n.HasCall() {
-               fmt.Fprint(w, " hascall")
-       }
 
-       if n.Name() != nil && n.Name().Used() {
-               fmt.Fprint(w, " used")
+       // Print Node-specific booleans by looking for methods.
+       // Different v, t from above - want *Struct not Struct, for methods.
+       v = reflect.ValueOf(n)
+       t = v.Type()
+       nm := t.NumMethod()
+       for i := 0; i < nm; i++ {
+               tm := t.Method(i)
+               if tm.PkgPath != "" {
+                       // skip unexported method - call will fail
+                       continue
+               }
+               m := v.Method(i)
+               mt := m.Type()
+               if mt.NumIn() == 0 && mt.NumOut() == 1 && mt.Out(0).Kind() == reflect.Bool {
+                       // TODO(rsc): Remove the func/defer/recover wrapping,
+                       // which is guarding against panics in miniExpr,
+                       // once we get down to the simpler state in which
+                       // nodes have no getter methods that aren't allowed to be called.
+                       func() {
+                               defer func() { recover() }()
+                               if m.Call(nil)[0].Bool() {
+                                       name := strings.TrimSuffix(tm.Name, "_")
+                                       fmt.Fprintf(w, " %s", name)
+                               }
+                       }()
+               }
        }
 
        if n.Op() == OCLOSURE {
+               n := n.(*ClosureExpr)
                if fn := n.Func(); fn != nil && fn.Nname.Sym() != nil {
                        fmt.Fprintf(w, " fnName(%+v)", fn.Nname.Sym())
                }
@@ -1087,6 +1154,7 @@ func dumpNode(w io.Writer, n Node, depth int) {
                return
 
        case OASOP:
+               n := n.(*AssignOpStmt)
                fmt.Fprintf(w, "%+v-%+v", n.Op(), n.SubOp())
                dumpNodeHeader(w, n)
 
@@ -1120,7 +1188,7 @@ func dumpNode(w io.Writer, n Node, depth int) {
                if fn.Body().Len() > 0 {
                        indent(w, depth)
                        fmt.Fprintf(w, "%+v-body", n.Op())
-                       dumpNodes(w, n.Body(), depth+1)
+                       dumpNodes(w, fn.Body(), depth+1)
                }
                return
        }
@@ -1186,3 +1254,40 @@ func dumpNodes(w io.Writer, list Nodes, depth int) {
                dumpNode(w, n, depth)
        }
 }
+
+// reflect.IsZero is not available in Go 1.4 (added in Go 1.13), so we use this copy instead.
+func isZero(v reflect.Value) bool {
+       switch v.Kind() {
+       case reflect.Bool:
+               return !v.Bool()
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+               return v.Int() == 0
+       case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+               return v.Uint() == 0
+       case reflect.Float32, reflect.Float64:
+               return math.Float64bits(v.Float()) == 0
+       case reflect.Complex64, reflect.Complex128:
+               c := v.Complex()
+               return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
+       case reflect.Array:
+               for i := 0; i < v.Len(); i++ {
+                       if !isZero(v.Index(i)) {
+                               return false
+                       }
+               }
+               return true
+       case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
+               return v.IsNil()
+       case reflect.String:
+               return v.Len() == 0
+       case reflect.Struct:
+               for i := 0; i < v.NumField(); i++ {
+                       if !isZero(v.Field(i)) {
+                               return false
+                       }
+               }
+               return true
+       default:
+               return false
+       }
+}
index 7f1a47e13cbe95e68cf3ecc2116839d469f6a26f..96cb0ee0546cb8a0a00a8591aeeaaa505a7bfa67 100644 (file)
@@ -34,13 +34,13 @@ func (*Ident) CanBeNtype() {}
 // Name holds Node fields used only by named nodes (ONAME, OTYPE, some OLITERAL).
 type Name struct {
        miniExpr
-       subOp      Op    // uint8
-       class      Class // uint8
+       BuiltinOp  Op    // uint8
+       Class_     Class // uint8
        flags      bitset16
        pragma     PragmaFlag // int16
        sym        *types.Sym
        fn         *Func
-       offset     int64
+       Offset_    int64
        val        constant.Value
        orig       Node
        embedFiles *[]string // list of embedded files, for ONAME var
@@ -180,16 +180,16 @@ func newNameAt(pos src.XPos, op Op, sym *types.Sym) *Name {
 func (n *Name) Name() *Name         { return n }
 func (n *Name) Sym() *types.Sym     { return n.sym }
 func (n *Name) SetSym(x *types.Sym) { n.sym = x }
-func (n *Name) SubOp() Op           { return n.subOp }
-func (n *Name) SetSubOp(x Op)       { n.subOp = x }
-func (n *Name) Class() Class        { return n.class }
-func (n *Name) SetClass(x Class)    { n.class = x }
+func (n *Name) SubOp() Op           { return n.BuiltinOp }
+func (n *Name) SetSubOp(x Op)       { n.BuiltinOp = x }
+func (n *Name) Class() Class        { return n.Class_ }
+func (n *Name) SetClass(x Class)    { n.Class_ = x }
 func (n *Name) Func() *Func         { return n.fn }
 func (n *Name) SetFunc(x *Func)     { n.fn = x }
-func (n *Name) Offset() int64       { return n.offset }
-func (n *Name) SetOffset(x int64)   { n.offset = x }
-func (n *Name) Iota() int64         { return n.offset }
-func (n *Name) SetIota(x int64)     { n.offset = x }
+func (n *Name) Offset() int64       { return n.Offset_ }
+func (n *Name) SetOffset(x int64)   { n.Offset_ = x }
+func (n *Name) Iota() int64         { return n.Offset_ }
+func (n *Name) SetIota(x int64)     { n.Offset_ = x }
 
 func (*Name) CanBeNtype()    {}
 func (*Name) CanBeAnSSASym() {}
index 993e914e1d0d4f65f8512c7179bb9970853fa865..dc93f689cf9fbd8e17a52097fbe95f244c525ddb 100644 (file)
@@ -212,7 +212,7 @@ func caller7() {
 
 // **in -> heap
 func param8(i **int) { // ERROR "i does not escape$"
-       sink = **i // ERROR "\* \(\*i\) escapes to heap"
+       sink = **i // ERROR "\*\(\*i\) escapes to heap"
 }
 
 func caller8() {
@@ -402,7 +402,7 @@ func caller13h() {
        var p *int
        v := &Val{&p} // ERROR "&Val{...} does not escape$"
        v.param13(&i)
-       sink = **v.p // ERROR "\* \(\*v\.p\) escapes to heap"
+       sink = **v.p // ERROR "\*\(\*v\.p\) escapes to heap"
 }
 
 type Node struct {