Passes toolstash-check -all.
Change-Id: I9fb91dd78dff149b5e1e1329d00855fd41f12523
Reviewed-on: https://go-review.googlesource.com/39796
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
}
}
- var arg *Node
- var note string
- param, it := iterFields(fntype.Params())
- i := 0
- for ; i < len(args); i++ {
- arg = args[i]
- note = param.Note
+ for i, param := range fntype.Params().FieldSlice() {
+ note := param.Note
+ var arg *Node
if param.Isddd() && !call.Isddd() {
+ rest := args[i:]
+ if len(rest) == 0 {
+ break
+ }
+
// Introduce ODDDARG node to represent ... allocation.
arg = nod(ODDDARG, nil, nil)
arg.Pos = call.Pos
- arr := typArray(param.Type.Elem(), int64(len(args)-i))
+ arr := typArray(param.Type.Elem(), int64(len(rest)))
arg.Type = typPtr(arr) // make pointer so it will be tracked
e.track(arg)
call.Right = arg
- }
- if haspointers(param.Type) {
- if e.escassignfromtag(note, cE.Retval, arg, call)&EscMask == EscNone && parent.Op != ODEFER && parent.Op != OPROC {
- a := arg
- for a.Op == OCONVNOP {
- a = a.Left
+ // Store arguments into slice for ... arg.
+ for _, a := range rest {
+ if Debug['m'] > 3 {
+ fmt.Printf("%v::esccall:: ... <- %S\n", linestr(lineno), a)
}
- switch a.Op {
- // The callee has already been analyzed, so its arguments have esc tags.
- // The argument is marked as not escaping at all.
- // Record that fact so that any temporary used for
- // synthesizing this expression can be reclaimed when
- // the function returns.
- // This 'noescape' is even stronger than the usual esc == EscNone.
- // arg.Esc == EscNone means that arg does not escape the current function.
- // arg.SetNoescape(true) here means that arg does not escape this statement
- // in the current function.
- case OCALLPART,
- OCLOSURE,
- ODDDARG,
- OARRAYLIT,
- OSLICELIT,
- OPTRLIT,
- OSTRUCTLIT:
- a.SetNoescape(true)
+ if note == uintptrEscapesTag {
+ e.escassignSinkWhyWhere(arg, a, "arg to uintptrescapes ...", call)
+ } else {
+ e.escassignWhyWhere(arg, a, "arg to ...", call)
}
}
+ } else {
+ arg = args[i]
+ if note == uintptrEscapesTag {
+ e.escassignSinkWhy(arg, arg, "escaping uintptr")
+ }
}
- if arg != args[i] {
- // This occurs when function parameter field Isddd and call not Isddd
- break
- }
-
- if note == uintptrEscapesTag {
- e.escassignSinkWhy(arg, arg, "escaping uintptr")
- }
-
- param = it.Next()
- }
-
- // Store arguments into slice for ... arg.
- for ; i < len(args); i++ {
- if Debug['m'] > 3 {
- fmt.Printf("%v::esccall:: ... <- %S\n", linestr(lineno), args[i])
- }
- if note == uintptrEscapesTag {
- e.escassignSinkWhyWhere(arg, args[i], "arg to uintptrescapes ...", call)
- } else {
- e.escassignWhyWhere(arg, args[i], "arg to ...", call)
+ if haspointers(param.Type) && e.escassignfromtag(note, cE.Retval, arg, call)&EscMask == EscNone && parent.Op != ODEFER && parent.Op != OPROC {
+ a := arg
+ for a.Op == OCONVNOP {
+ a = a.Left
+ }
+ switch a.Op {
+ // The callee has already been analyzed, so its arguments have esc tags.
+ // The argument is marked as not escaping at all.
+ // Record that fact so that any temporary used for
+ // synthesizing this expression can be reclaimed when
+ // the function returns.
+ // This 'noescape' is even stronger than the usual esc == EscNone.
+ // arg.Esc == EscNone means that arg does not escape the current function.
+ // arg.SetNoescape(true) here means that arg does not escape this statement
+ // in the current function.
+ case OCALLPART, OCLOSURE, ODDDARG, OARRAYLIT, OSLICELIT, OPTRLIT, OSTRUCTLIT:
+ a.SetNoescape(true)
+ }
}
}
}
ordercallargs(&n.List, order)
if n.Op == OCALLFUNC {
- t, it := iterFields(n.Left.Type.Params())
- for i := range n.List.Slice() {
- // Check for "unsafe-uintptr" tag provided by escape analysis.
- // If present and the argument is really a pointer being converted
- // to uintptr, arrange for the pointer to be kept alive until the call
- // returns, by copying it into a temp and marking that temp
+ keepAlive := func(i int) {
+ // If the argument is really a pointer being converted to uintptr,
+ // arrange for the pointer to be kept alive until the call returns,
+ // by copying it into a temp and marking that temp
// still alive when we pop the temp stack.
- if t == nil {
- break
+ xp := n.List.Addr(i)
+ for (*xp).Op == OCONVNOP && !(*xp).Type.IsPtr() {
+ xp = &(*xp).Left
}
- if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag {
- xp := n.List.Addr(i)
- for (*xp).Op == OCONVNOP && !(*xp).Type.IsPtr() {
- xp = &(*xp).Left
+ x := *xp
+ if x.Type.IsPtr() {
+ x = ordercopyexpr(x, x.Type, order, 0)
+ x.Name.SetKeepalive(true)
+ *xp = x
+ }
+ }
+
+ for i, t := range n.Left.Type.Params().FieldSlice() {
+ // Check for "unsafe-uintptr" tag provided by escape analysis.
+ if t.Isddd() && !n.Isddd() {
+ if t.Note == uintptrEscapesTag {
+ for ; i < n.List.Len(); i++ {
+ keepAlive(i)
+ }
}
- x := *xp
- if x.Type.IsPtr() {
- x = ordercopyexpr(x, x.Type, order, 0)
- x.Name.SetKeepalive(true)
- *xp = x
+ } else {
+ if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag {
+ keepAlive(i)
}
}
- next := it.Next()
- if next == nil && t.Isddd() && t.Note == uintptrEscapesTag {
- next = t
- }
- t = next
}
}
}
assumedEqual[typePair{t1, t2}] = struct{}{}
switch t1.Etype {
- case TINTER, TSTRUCT:
- t1, i1 := iterFields(t1)
- t2, i2 := iterFields(t2)
- for ; t1 != nil && t2 != nil; t1, t2 = i1.Next(), i2.Next() {
- if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, cmpTags, assumedEqual) || cmpTags && t1.Note != t2.Note {
+ case TINTER:
+ if t1.NumFields() != t2.NumFields() {
+ return false
+ }
+ for i, f1 := range t1.FieldSlice() {
+ f2 := t2.Field(i)
+ if f1.Sym != f2.Sym || !eqtype1(f1.Type, f2.Type, cmpTags, assumedEqual) {
return false
}
}
+ return true
- if t1 == nil && t2 == nil {
- return true
+ case TSTRUCT:
+ if t1.NumFields() != t2.NumFields() {
+ return false
}
- return false
+ for i, f1 := range t1.FieldSlice() {
+ f2 := t2.Field(i)
+ if f1.Sym != f2.Sym || f1.Embedded != f2.Embedded || !eqtype1(f1.Type, f2.Type, cmpTags, assumedEqual) {
+ return false
+ }
+ if cmpTags && f1.Note != f2.Note {
+ return false
+ }
+ }
+ return true
case TFUNC:
// Check parameters and result parameters for type equality.
// equality, because they're never relevant.
for _, f := range paramsResults {
// Loop over fields in structs, ignoring argument names.
- ta, ia := iterFields(f(t1))
- tb, ib := iterFields(f(t2))
- for ; ta != nil && tb != nil; ta, tb = ia.Next(), ib.Next() {
- if ta.Isddd() != tb.Isddd() || !eqtype1(ta.Type, tb.Type, cmpTags, assumedEqual) {
+ fs1, fs2 := f(t1).FieldSlice(), f(t2).FieldSlice()
+ if len(fs1) != len(fs2) {
+ return false
+ }
+ for i, f1 := range fs1 {
+ f2 := fs2[i]
+ if f1.Isddd() != f2.Isddd() || !eqtype1(f1.Type, f2.Type, cmpTags, assumedEqual) {
return false
}
}
- if ta != nil || tb != nil {
- return false
- }
}
return true
return false
}
- f1, i1 := iterFields(t1)
- f2, i2 := iterFields(t2)
- for {
+ if t1.NumFields() != t2.NumFields() {
+ return false
+ }
+ for i, f1 := range t1.FieldSlice() {
+ f2 := t2.Field(i)
if !eqtype(f1.Type, f2.Type) {
return false
}
- if f1 == nil {
- return true
- }
- f1 = i1.Next()
- f2 = i2.Next()
}
+ return true
}
// Is type src assignment compatible to type dst?
return ssa.CMPgt // bucket maps are least
} // If t != t.Map.Bucket, fall through to general case
- fallthrough
- case TINTER:
- t1, ti := iterFields(t)
- x1, xi := iterFields(x)
- for ; t1 != nil && x1 != nil; t1, x1 = ti.Next(), xi.Next() {
+ tfs := t.FieldSlice()
+ xfs := x.FieldSlice()
+ for i := 0; i < len(tfs) && i < len(xfs); i++ {
+ t1, x1 := tfs[i], xfs[i]
if t1.Embedded != x1.Embedded {
return cmpForNe(t1.Embedded < x1.Embedded)
}
return c
}
}
- if t1 != x1 {
- return cmpForNe(t1 == nil)
+ if len(tfs) != len(xfs) {
+ return cmpForNe(len(tfs) < len(xfs))
+ }
+ return ssa.CMPeq
+
+ case TINTER:
+ tfs := t.FieldSlice()
+ xfs := x.FieldSlice()
+ for i := 0; i < len(tfs) && i < len(xfs); i++ {
+ t1, x1 := tfs[i], xfs[i]
+ if c := t1.Sym.cmpsym(x1.Sym); c != ssa.CMPeq {
+ return c
+ }
+ if c := t1.Type.cmp(x1.Type); c != ssa.CMPeq {
+ return c
+ }
+ }
+ if len(tfs) != len(xfs) {
+ return cmpForNe(len(tfs) < len(xfs))
}
return ssa.CMPeq
case TFUNC:
for _, f := range recvsParamsResults {
// Loop over fields in structs, ignoring argument names.
- ta, ia := iterFields(f(t))
- tb, ib := iterFields(f(x))
- for ; ta != nil && tb != nil; ta, tb = ia.Next(), ib.Next() {
+ tfs := f(t).FieldSlice()
+ xfs := f(x).FieldSlice()
+ for i := 0; i < len(tfs) && i < len(xfs); i++ {
+ ta := tfs[i]
+ tb := xfs[i]
if ta.Isddd() != tb.Isddd() {
return cmpForNe(!ta.Isddd())
}
return c
}
}
- if ta != tb {
- return cmpForNe(ta == nil)
+ if len(tfs) != len(xfs) {
+ return cmpForNe(len(tfs) < len(xfs))
}
}
return ssa.CMPeq
}
if funarg != nil {
- _, it := iterFields(funarg) // Skip first field
- for t := it.Next(); t != nil; t = it.Next() {
+ for _, t := range funarg.FieldSlice()[1:] {
if assignop(t.Type, n.Type.Elem(), nil) == 0 {
yyerror("cannot append %v value to []%v", t.Type, n.Type.Elem())
}
}
}
- tn, it := iterFields(n.Type)
+ lfs := tstruct.FieldSlice()
+ rfs := n.Type.FieldSlice()
var why string
- for _, tl := range tstruct.Fields().Slice() {
+ for i, tl := range lfs {
if tl.Isddd() {
- for ; tn != nil; tn = it.Next() {
+ for _, tn := range rfs[i:] {
if assignop(tn.Type, tl.Type.Elem(), &why) == 0 {
if call != nil {
yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type.Elem(), call, why)
}
}
}
-
goto out
}
- if tn == nil {
+ if i >= len(rfs) {
goto notenough
}
+ tn := rfs[i]
if assignop(tn.Type, tl.Type, &why) == 0 {
if call != nil {
yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type, call, why)
yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type, desc(), why)
}
}
-
- tn = it.Next()
}
- if tn != nil {
+ if len(rfs) > len(lfs) {
goto toomany
}
goto out
bad := 0
if n.List.Len() != 0 && nokeys(n.List) {
// simple list of variables
- f, it := iterFields(t)
-
ls := n.List.Slice()
- for i1, n1 := range ls {
+ for i, n1 := range ls {
setlineno(n1)
- ls[i1] = typecheck(ls[i1], Erv)
- n1 = ls[i1]
- if f == nil {
+ n1 = typecheck(n1, Erv)
+ ls[i] = n1
+ if i >= t.NumFields() {
if bad == 0 {
yyerror("too many values in struct initializer")
}
continue
}
+ f := t.Field(i)
s := f.Sym
if s != nil && !exportname(s.Name) && s.Pkg != localpkg {
yyerror("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
n1 = assignconv(n1, f.Type, "field value")
n1 = nodSym(OSTRUCTKEY, n1, f.Sym)
n1.Xoffset = f.Offset
- ls[i1] = n1
- f = it.Next()
+ ls[i] = n1
}
-
- if f != nil {
+ if len(ls) < t.NumFields() {
yyerror("too few values in struct initializer")
}
} else {
goto mismatch
}
n.Op = OAS2FUNC
- t, s := iterFields(r.Type)
- for _, n3 := range n.List.Slice() {
- if t.Type != nil && n3.Type != nil {
- checkassignto(t.Type, n3)
+ for i, l := range n.List.Slice() {
+ f := r.Type.Field(i)
+ if f.Type != nil && l.Type != nil {
+ checkassignto(f.Type, l)
}
- if n3.Name != nil && n3.Name.Defn == n && n3.Name.Param.Ntype == nil {
- n3.Type = t.Type
+ if l.Name != nil && l.Name.Defn == n && l.Name.Param.Ntype == nil {
+ l.Type = f.Type
}
- t = s.Next()
}
-
goto out
}
}
// a expression list. called in
// expr-list = func()
func ascompatet(op Op, nl Nodes, nr *Type) []*Node {
- r, saver := iterFields(nr)
+ if nl.Len() != nr.NumFields() {
+ Fatalf("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
+ }
var nn, mm Nodes
- var ullmanOverflow bool
- var i int
- for i = 0; i < nl.Len(); i++ {
- if r == nil {
- break
- }
- l := nl.Index(i)
+ for i, l := range nl.Slice() {
if isblank(l) {
- r = saver.Next()
continue
}
+ r := nr.Field(i)
// any lv that causes a fn call must be
// deferred until all the return arguments
updateHasCall(a)
if a.HasCall() {
Dump("ascompatet ucount", a)
- ullmanOverflow = true
+ Fatalf("ascompatet: too many function calls evaluating parameters")
}
nn.Append(a)
- r = saver.Next()
- }
-
- if i < nl.Len() || r != nil {
- Fatalf("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
- }
-
- if ullmanOverflow {
- Fatalf("ascompatet: too many function calls evaluating parameters")
}
return append(nn.Slice(), mm.Slice()...)
}