diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/subr.go')
-rw-r--r-- | src/cmd/compile/internal/gc/subr.go | 1028 |
1 files changed, 335 insertions, 693 deletions
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index defefd76b3..fcda219737 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -5,14 +5,14 @@ package gc import ( + "cmd/compile/internal/base" + "cmd/compile/internal/ir" "cmd/compile/internal/types" - "cmd/internal/objabi" "cmd/internal/src" "crypto/md5" "encoding/binary" "fmt" - "os" - "runtime/debug" + "go/constant" "sort" "strconv" "strings" @@ -21,13 +21,6 @@ import ( "unicode/utf8" ) -type Error struct { - pos src.XPos - msg string -} - -var errors []Error - // largeStack is info about a function whose stack frame is too large (rare). type largeStack struct { locals int64 @@ -41,189 +34,25 @@ var ( largeStackFrames []largeStack ) -func errorexit() { - flusherrors() - if outfile != "" { - os.Remove(outfile) - } - os.Exit(2) -} - -func adderrorname(n *Node) { - if n.Op != ODOT { - return - } - old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left) - if len(errors) > 0 && errors[len(errors)-1].pos.Line() == n.Pos.Line() && errors[len(errors)-1].msg == old { - errors[len(errors)-1].msg = fmt.Sprintf("%v: undefined: %v in %v\n", n.Line(), n.Left, n) - } -} - -func adderr(pos src.XPos, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - // Only add the position if know the position. - // See issue golang.org/issue/11361. - if pos.IsKnown() { - msg = fmt.Sprintf("%v: %s", linestr(pos), msg) - } - errors = append(errors, Error{ - pos: pos, - msg: msg + "\n", - }) -} - -// byPos sorts errors by source position. -type byPos []Error - -func (x byPos) Len() int { return len(x) } -func (x byPos) Less(i, j int) bool { return x[i].pos.Before(x[j].pos) } -func (x byPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -// flusherrors sorts errors seen so far by line number, prints them to stdout, -// and empties the errors array. -func flusherrors() { - Ctxt.Bso.Flush() - if len(errors) == 0 { - return - } - sort.Stable(byPos(errors)) - for i, err := range errors { - if i == 0 || err.msg != errors[i-1].msg { - fmt.Printf("%s", err.msg) - } - } - errors = errors[:0] -} - -func hcrash() { - if Debug.h != 0 { - flusherrors() - if outfile != "" { - os.Remove(outfile) - } - var x *int - *x = 0 - } -} - -func linestr(pos src.XPos) string { - return Ctxt.OutermostPos(pos).Format(Debug.C == 0, Debug.L == 1) -} - -// lasterror keeps track of the most recently issued error. -// It is used to avoid multiple error messages on the same -// line. -var lasterror struct { - syntax src.XPos // source position of last syntax error - other src.XPos // source position of last non-syntax error - msg string // error message of last non-syntax error -} - -// sameline reports whether two positions a, b are on the same line. -func sameline(a, b src.XPos) bool { - p := Ctxt.PosTable.Pos(a) - q := Ctxt.PosTable.Pos(b) - return p.Base() == q.Base() && p.Line() == q.Line() -} - -func yyerrorl(pos src.XPos, format string, args ...interface{}) { - msg := fmt.Sprintf(format, args...) - - if strings.HasPrefix(msg, "syntax error") { - nsyntaxerrors++ - // only one syntax error per line, no matter what error - if sameline(lasterror.syntax, pos) { - return - } - lasterror.syntax = pos - } else { - // only one of multiple equal non-syntax errors per line - // (flusherrors shows only one of them, so we filter them - // here as best as we can (they may not appear in order) - // so that we don't count them here and exit early, and - // then have nothing to show for.) - if sameline(lasterror.other, pos) && lasterror.msg == msg { - return - } - lasterror.other = pos - lasterror.msg = msg - } - - adderr(pos, "%s", msg) - - hcrash() - nerrors++ - if nsavederrors+nerrors >= 10 && Debug.e == 0 { - flusherrors() - fmt.Printf("%v: too many errors\n", linestr(pos)) - errorexit() - } -} - -func yyerrorv(lang string, format string, args ...interface{}) { - what := fmt.Sprintf(format, args...) - yyerrorl(lineno, "%s requires %s or later (-lang was set to %s; check go.mod)", what, lang, flag_lang) -} - -func yyerror(format string, args ...interface{}) { - yyerrorl(lineno, format, args...) -} - -func Warn(fmt_ string, args ...interface{}) { - Warnl(lineno, fmt_, args...) -} - -func Warnl(line src.XPos, fmt_ string, args ...interface{}) { - adderr(line, fmt_, args...) - if Debug.m != 0 { - flusherrors() - } -} - -func Fatalf(fmt_ string, args ...interface{}) { - flusherrors() - - if Debug_panic != 0 || nsavederrors+nerrors == 0 { - fmt.Printf("%v: internal compiler error: ", linestr(lineno)) - fmt.Printf(fmt_, args...) - fmt.Printf("\n") - - // If this is a released compiler version, ask for a bug report. - if strings.HasPrefix(objabi.Version, "go") { - fmt.Printf("\n") - fmt.Printf("Please file a bug report including a short program that triggers the error.\n") - fmt.Printf("https://golang.org/issue/new\n") - } else { - // Not a release; dump a stack trace, too. - fmt.Println() - os.Stdout.Write(debug.Stack()) - fmt.Println() - } - } - - hcrash() - errorexit() -} - // hasUniquePos reports whether n has a unique position that can be // used for reporting error messages. // // It's primarily used to distinguish references to named objects, // whose Pos will point back to their declaration position rather than // their usage position. -func hasUniquePos(n *Node) bool { - switch n.Op { - case ONAME, OPACK: +func hasUniquePos(n ir.Node) bool { + switch n.Op() { + case ir.ONAME, ir.OPACK: return false - case OLITERAL, OTYPE: - if n.Sym != nil { + case ir.OLITERAL, ir.ONIL, ir.OTYPE: + if n.Sym() != nil { return false } } - if !n.Pos.IsKnown() { - if Debug.K != 0 { - Warn("setlineno: unknown position (line 0)") + if !n.Pos().IsKnown() { + if base.Flag.K != 0 { + base.Warn("setlineno: unknown position (line 0)") } return false } @@ -231,16 +60,16 @@ func hasUniquePos(n *Node) bool { return true } -func setlineno(n *Node) src.XPos { - lno := lineno +func setlineno(n ir.Node) src.XPos { + lno := base.Pos if n != nil && hasUniquePos(n) { - lineno = n.Pos + base.Pos = n.Pos() } return lno } func lookup(name string) *types.Sym { - return localpkg.Lookup(name) + return ir.LocalPkg.Lookup(name) } // lookupN looks up the symbol starting with prefix and ending with @@ -249,7 +78,7 @@ func lookupN(prefix string, n int) *types.Sym { var buf [20]byte // plenty long enough for all current users copy(buf[:], prefix) b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10) - return localpkg.LookupBytes(b) + return ir.LocalPkg.LookupBytes(b) } // autolabel generates a new Name node for use with @@ -260,20 +89,20 @@ func lookupN(prefix string, n int) *types.Sym { // user labels. func autolabel(prefix string) *types.Sym { if prefix[0] != '.' { - Fatalf("autolabel prefix must start with '.', have %q", prefix) + base.Fatalf("autolabel prefix must start with '.', have %q", prefix) } fn := Curfn if Curfn == nil { - Fatalf("autolabel outside function") + base.Fatalf("autolabel outside function") } - n := fn.Func.Label - fn.Func.Label++ + n := fn.Func().Label + fn.Func().Label++ return lookupN(prefix, int(n)) } // find all the exported symbols in package opkg // and make them available in the current package -func importdot(opkg *types.Pkg, pack *Node) { +func importdot(opkg *types.Pkg, pack ir.Node) { n := 0 for _, s := range opkg.Syms { if s.Def == nil { @@ -285,138 +114,48 @@ func importdot(opkg *types.Pkg, pack *Node) { s1 := lookup(s.Name) if s1.Def != nil { pkgerror := fmt.Sprintf("during import %q", opkg.Path) - redeclare(lineno, s1, pkgerror) + redeclare(base.Pos, s1, pkgerror) continue } s1.Def = s.Def s1.Block = s.Block - if asNode(s1.Def).Name == nil { - Dump("s1def", asNode(s1.Def)) - Fatalf("missing Name") + if ir.AsNode(s1.Def).Name() == nil { + ir.Dump("s1def", ir.AsNode(s1.Def)) + base.Fatalf("missing Name") } - asNode(s1.Def).Name.Pack = pack + ir.AsNode(s1.Def).Name().Pack = pack s1.Origpkg = opkg n++ } if n == 0 { // can't possibly be used - there were no symbols - yyerrorl(pack.Pos, "imported and not used: %q", opkg.Path) + base.ErrorfAt(pack.Pos(), "imported and not used: %q", opkg.Path) } } -func nod(op Op, nleft, nright *Node) *Node { - return nodl(lineno, op, nleft, nright) -} - -func nodl(pos src.XPos, op Op, nleft, nright *Node) *Node { - var n *Node - switch op { - case OCLOSURE, ODCLFUNC: - var x struct { - n Node - f Func - } - n = &x.n - n.Func = &x.f - case ONAME: - Fatalf("use newname instead") - case OLABEL, OPACK: - var x struct { - n Node - m Name - } - n = &x.n - n.Name = &x.m - default: - n = new(Node) - } - n.Op = op - n.Left = nleft - n.Right = nright - n.Pos = pos - n.Xoffset = BADWIDTH - n.Orig = n - return n -} - // newname returns a new ONAME Node associated with symbol s. -func newname(s *types.Sym) *Node { - n := newnamel(lineno, s) - n.Name.Curfn = Curfn - return n -} - -// newnamel returns a new ONAME Node associated with symbol s at position pos. -// The caller is responsible for setting n.Name.Curfn. -func newnamel(pos src.XPos, s *types.Sym) *Node { - if s == nil { - Fatalf("newnamel nil") - } - - var x struct { - n Node - m Name - p Param - } - n := &x.n - n.Name = &x.m - n.Name.Param = &x.p - - n.Op = ONAME - n.Pos = pos - n.Orig = n - - n.Sym = s +func NewName(s *types.Sym) ir.Node { + n := ir.NewNameAt(base.Pos, s) + n.Name().Curfn = Curfn return n } // nodSym makes a Node with Op op and with the Left field set to left // and the Sym field set to sym. This is for ODOT and friends. -func nodSym(op Op, left *Node, sym *types.Sym) *Node { - return nodlSym(lineno, op, left, sym) +func nodSym(op ir.Op, left ir.Node, sym *types.Sym) ir.Node { + return nodlSym(base.Pos, op, left, sym) } // nodlSym makes a Node with position Pos, with Op op, and with the Left field set to left // and the Sym field set to sym. This is for ODOT and friends. -func nodlSym(pos src.XPos, op Op, left *Node, sym *types.Sym) *Node { - n := nodl(pos, op, left, nil) - n.Sym = sym +func nodlSym(pos src.XPos, op ir.Op, left ir.Node, sym *types.Sym) ir.Node { + n := ir.NodAt(pos, op, left, nil) + n.SetSym(sym) return n } -// rawcopy returns a shallow copy of n. -// Note: copy or sepcopy (rather than rawcopy) is usually the -// correct choice (see comment with Node.copy, below). -func (n *Node) rawcopy() *Node { - copy := *n - return © -} - -// sepcopy returns a separate shallow copy of n, with the copy's -// Orig pointing to itself. -func (n *Node) sepcopy() *Node { - copy := *n - copy.Orig = © - return © -} - -// copy returns shallow copy of n and adjusts the copy's Orig if -// necessary: In general, if n.Orig points to itself, the copy's -// Orig should point to itself as well. Otherwise, if n is modified, -// the copy's Orig node appears modified, too, and then doesn't -// represent the original node anymore. -// (This caused the wrong complit Op to be used when printing error -// messages; see issues #26855, #27765). -func (n *Node) copy() *Node { - copy := *n - if n.Orig == n { - copy.Orig = © - } - return © -} - // methcmp sorts methods by symbol. type methcmp []*types.Field @@ -424,67 +163,60 @@ func (x methcmp) Len() int { return len(x) } func (x methcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x methcmp) Less(i, j int) bool { return x[i].Sym.Less(x[j].Sym) } -func nodintconst(v int64) *Node { - u := new(Mpint) - u.SetInt64(v) - return nodlit(Val{u}) +func nodintconst(v int64) ir.Node { + return ir.NewLiteral(constant.MakeInt64(v)) } -func nodnil() *Node { - return nodlit(Val{new(NilVal)}) +func nodnil() ir.Node { + n := ir.Nod(ir.ONIL, nil, nil) + n.SetType(types.Types[types.TNIL]) + return n } -func nodbool(b bool) *Node { - return nodlit(Val{b}) +func nodbool(b bool) ir.Node { + return ir.NewLiteral(constant.MakeBool(b)) } -func nodstr(s string) *Node { - return nodlit(Val{s}) +func nodstr(s string) ir.Node { + return ir.NewLiteral(constant.MakeString(s)) } // treecopy recursively copies n, with the exception of // ONAME, OLITERAL, OTYPE, and ONONAME leaves. // If pos.IsKnown(), it sets the source position of newly // allocated nodes to pos. -func treecopy(n *Node, pos src.XPos) *Node { +func treecopy(n ir.Node, pos src.XPos) ir.Node { if n == nil { return nil } - switch n.Op { + switch n.Op() { default: - m := n.sepcopy() - m.Left = treecopy(n.Left, pos) - m.Right = treecopy(n.Right, pos) - m.List.Set(listtreecopy(n.List.Slice(), pos)) + m := ir.SepCopy(n) + m.SetLeft(treecopy(n.Left(), pos)) + m.SetRight(treecopy(n.Right(), pos)) + m.PtrList().Set(listtreecopy(n.List().Slice(), pos)) if pos.IsKnown() { - m.Pos = pos + m.SetPos(pos) } - if m.Name != nil && n.Op != ODCLFIELD { - Dump("treecopy", n) - Fatalf("treecopy Name") + if m.Name() != nil && n.Op() != ir.ODCLFIELD { + ir.Dump("treecopy", n) + base.Fatalf("treecopy Name") } return m - case OPACK: + case ir.OPACK: // OPACK nodes are never valid in const value declarations, // but allow them like any other declared symbol to avoid // crashing (golang.org/issue/11361). fallthrough - case ONAME, ONONAME, OLITERAL, OTYPE: + case ir.ONAME, ir.ONONAME, ir.OLITERAL, ir.ONIL, ir.OTYPE: return n } } -// isNil reports whether n represents the universal untyped zero value "nil". -func (n *Node) isNil() bool { - // Check n.Orig because constant propagation may produce typed nil constants, - // which don't exist in the Go spec. - return Isconst(n.Orig, CTNIL) -} - func isptrto(t *types.Type, et types.EType) bool { if t == nil { return false @@ -502,13 +234,6 @@ func isptrto(t *types.Type, et types.EType) bool { return true } -func (n *Node) isBlank() bool { - if n == nil { - return false - } - return n.Sym.IsBlank() -} - // methtype returns the underlying type, if any, // that owns methods with receiver parameter t. // The result is either a named type or an anonymous struct. @@ -538,7 +263,7 @@ func methtype(t *types.Type) *types.Type { return t } switch t.Etype { - case TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRING, TSTRUCT: + case types.TARRAY, types.TCHAN, types.TFUNC, types.TMAP, types.TSLICE, types.TSTRING, types.TSTRUCT: return t } return nil @@ -548,17 +273,17 @@ func methtype(t *types.Type) *types.Type { // If so, return op code to use in conversion. // If not, return OXXX. In this case, the string return parameter may // hold a reason why. In all other cases, it'll be the empty string. -func assignop(src, dst *types.Type) (Op, string) { +func assignop(src, dst *types.Type) (ir.Op, string) { if src == dst { - return OCONVNOP, "" + return ir.OCONVNOP, "" } - if src == nil || dst == nil || src.Etype == TFORW || dst.Etype == TFORW || src.Orig == nil || dst.Orig == nil { - return OXXX, "" + if src == nil || dst == nil || src.Etype == types.TFORW || dst.Etype == types.TFORW || src.Orig == nil || dst.Orig == nil { + return ir.OXXX, "" } // 1. src type is identical to dst. if types.Identical(src, dst) { - return OCONVNOP, "" + return ir.OCONVNOP, "" } // 2. src and dst have identical underlying types @@ -572,31 +297,31 @@ func assignop(src, dst *types.Type) (Op, string) { if src.IsEmptyInterface() { // Conversion between two empty interfaces // requires no code. - return OCONVNOP, "" + return ir.OCONVNOP, "" } if (src.Sym == nil || dst.Sym == nil) && !src.IsInterface() { // Conversion between two types, at least one unnamed, // needs no conversion. The exception is nonempty interfaces // which need to have their itab updated. - return OCONVNOP, "" + return ir.OCONVNOP, "" } } // 3. dst is an interface type and src implements dst. - if dst.IsInterface() && src.Etype != TNIL { + if dst.IsInterface() && src.Etype != types.TNIL { var missing, have *types.Field var ptr int if implements(src, dst, &missing, &have, &ptr) { - return OCONVIFACE, "" + return ir.OCONVIFACE, "" } // we'll have complained about this method anyway, suppress spurious messages. if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) { - return OCONVIFACE, "" + return ir.OCONVIFACE, "" } var why string - if isptrto(src, TINTER) { + if isptrto(src, types.TINTER) { why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src) } else if have != nil && have.Sym == missing.Sym && have.Nointerface() { why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym) @@ -612,22 +337,22 @@ func assignop(src, dst *types.Type) (Op, string) { why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym) } - return OXXX, why + return ir.OXXX, why } - if isptrto(dst, TINTER) { + if isptrto(dst, types.TINTER) { why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst) - return OXXX, why + return ir.OXXX, why } - if src.IsInterface() && dst.Etype != TBLANK { + if src.IsInterface() && dst.Etype != types.TBLANK { var missing, have *types.Field var ptr int var why string if implements(dst, src, &missing, &have, &ptr) { why = ": need type assertion" } - return OXXX, why + return ir.OXXX, why } // 4. src is a bidirectional channel value, dst is a channel type, @@ -635,31 +360,31 @@ func assignop(src, dst *types.Type) (Op, string) { // either src or dst is not a named type. if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() { if types.Identical(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) { - return OCONVNOP, "" + return ir.OCONVNOP, "" } } // 5. src is the predeclared identifier nil and dst is a nillable type. - if src.Etype == TNIL { + if src.Etype == types.TNIL { switch dst.Etype { - case TPTR, - TFUNC, - TMAP, - TCHAN, - TINTER, - TSLICE: - return OCONVNOP, "" + case types.TPTR, + types.TFUNC, + types.TMAP, + types.TCHAN, + types.TINTER, + types.TSLICE: + return ir.OCONVNOP, "" } } // 6. rule about untyped constants - already converted by defaultlit. // 7. Any typed value can be assigned to the blank identifier. - if dst.Etype == TBLANK { - return OCONVNOP, "" + if dst.Etype == types.TBLANK { + return ir.OCONVNOP, "" } - return OXXX, "" + return ir.OXXX, "" } // Can we convert a value of type src to a value of type dst? @@ -667,12 +392,12 @@ func assignop(src, dst *types.Type) (Op, string) { // If not, return OXXX. In this case, the string return parameter may // hold a reason why. In all other cases, it'll be the empty string. // srcConstant indicates whether the value of type src is a constant. -func convertop(srcConstant bool, src, dst *types.Type) (Op, string) { +func convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) { if src == dst { - return OCONVNOP, "" + return ir.OCONVNOP, "" } if src == nil || dst == nil { - return OXXX, "" + return ir.OXXX, "" } // Conversions from regular to go:notinheap are not allowed @@ -681,17 +406,17 @@ func convertop(srcConstant bool, src, dst *types.Type) (Op, string) { // (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't. if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() { why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem()) - return OXXX, why + return ir.OXXX, why } // (b) Disallow string to []T where T is go:notinheap. if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Etype == types.Bytetype.Etype || dst.Elem().Etype == types.Runetype.Etype) { why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem()) - return OXXX, why + return ir.OXXX, why } // 1. src can be assigned to dst. op, why := assignop(src, dst) - if op != OXXX { + if op != ir.OXXX { return op, why } @@ -700,57 +425,57 @@ func convertop(srcConstant bool, src, dst *types.Type) (Op, string) { // with the good message from assignop. // Otherwise clear the error. if src.IsInterface() || dst.IsInterface() { - return OXXX, why + return ir.OXXX, why } // 2. Ignoring struct tags, src and dst have identical underlying types. if types.IdenticalIgnoreTags(src.Orig, dst.Orig) { - return OCONVNOP, "" + return ir.OCONVNOP, "" } // 3. src and dst are unnamed pointer types and, ignoring struct tags, // their base types have identical underlying types. if src.IsPtr() && dst.IsPtr() && src.Sym == nil && dst.Sym == nil { if types.IdenticalIgnoreTags(src.Elem().Orig, dst.Elem().Orig) { - return OCONVNOP, "" + return ir.OCONVNOP, "" } } // 4. src and dst are both integer or floating point types. if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) { if simtype[src.Etype] == simtype[dst.Etype] { - return OCONVNOP, "" + return ir.OCONVNOP, "" } - return OCONV, "" + return ir.OCONV, "" } // 5. src and dst are both complex types. if src.IsComplex() && dst.IsComplex() { if simtype[src.Etype] == simtype[dst.Etype] { - return OCONVNOP, "" + return ir.OCONVNOP, "" } - return OCONV, "" + return ir.OCONV, "" } // Special case for constant conversions: any numeric // conversion is potentially okay. We'll validate further // within evconst. See #38117. if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) { - return OCONV, "" + return ir.OCONV, "" } // 6. src is an integer or has type []byte or []rune // and dst is a string type. if src.IsInteger() && dst.IsString() { - return ORUNESTR, "" + return ir.ORUNESTR, "" } if src.IsSlice() && dst.IsString() { if src.Elem().Etype == types.Bytetype.Etype { - return OBYTES2STR, "" + return ir.OBYTES2STR, "" } if src.Elem().Etype == types.Runetype.Etype { - return ORUNES2STR, "" + return ir.ORUNES2STR, "" } } @@ -758,202 +483,128 @@ func convertop(srcConstant bool, src, dst *types.Type) (Op, string) { // String to slice. if src.IsString() && dst.IsSlice() { if dst.Elem().Etype == types.Bytetype.Etype { - return OSTR2BYTES, "" + return ir.OSTR2BYTES, "" } if dst.Elem().Etype == types.Runetype.Etype { - return OSTR2RUNES, "" + return ir.OSTR2RUNES, "" } } // 8. src is a pointer or uintptr and dst is unsafe.Pointer. if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() { - return OCONVNOP, "" + return ir.OCONVNOP, "" } // 9. src is unsafe.Pointer and dst is a pointer or uintptr. if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) { - return OCONVNOP, "" + return ir.OCONVNOP, "" } // src is map and dst is a pointer to corresponding hmap. // This rule is needed for the implementation detail that // go gc maps are implemented as a pointer to a hmap struct. - if src.Etype == TMAP && dst.IsPtr() && + if src.Etype == types.TMAP && dst.IsPtr() && src.MapType().Hmap == dst.Elem() { - return OCONVNOP, "" + return ir.OCONVNOP, "" } - return OXXX, "" + return ir.OXXX, "" } -func assignconv(n *Node, t *types.Type, context string) *Node { +func assignconv(n ir.Node, t *types.Type, context string) ir.Node { return assignconvfn(n, t, func() string { return context }) } // Convert node n for assignment to type t. -func assignconvfn(n *Node, t *types.Type, context func() string) *Node { - if n == nil || n.Type == nil || n.Type.Broke() { +func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node { + if n == nil || n.Type() == nil || n.Type().Broke() { return n } - if t.Etype == TBLANK && n.Type.Etype == TNIL { - yyerror("use of untyped nil") + if t.Etype == types.TBLANK && n.Type().Etype == types.TNIL { + base.Errorf("use of untyped nil") } n = convlit1(n, t, false, context) - if n.Type == nil { + if n.Type() == nil { return n } - if t.Etype == TBLANK { + if t.Etype == types.TBLANK { return n } // Convert ideal bool from comparison to plain bool // if the next step is non-bool (like interface{}). - if n.Type == types.UntypedBool && !t.IsBoolean() { - if n.Op == ONAME || n.Op == OLITERAL { - r := nod(OCONVNOP, n, nil) - r.Type = types.Types[TBOOL] + if n.Type() == types.UntypedBool && !t.IsBoolean() { + if n.Op() == ir.ONAME || n.Op() == ir.OLITERAL { + r := ir.Nod(ir.OCONVNOP, n, nil) + r.SetType(types.Types[types.TBOOL]) r.SetTypecheck(1) r.SetImplicit(true) n = r } } - if types.Identical(n.Type, t) { + if types.Identical(n.Type(), t) { return n } - op, why := assignop(n.Type, t) - if op == OXXX { - yyerror("cannot use %L as type %v in %s%s", n, t, context(), why) - op = OCONV + op, why := assignop(n.Type(), t) + if op == ir.OXXX { + base.Errorf("cannot use %L as type %v in %s%s", n, t, context(), why) + op = ir.OCONV } - r := nod(op, n, nil) - r.Type = t + r := ir.Nod(op, n, nil) + r.SetType(t) r.SetTypecheck(1) r.SetImplicit(true) - r.Orig = n.Orig + r.SetOrig(n.Orig()) return r } -// IsMethod reports whether n is a method. -// n must be a function or a method. -func (n *Node) IsMethod() bool { - return n.Type.Recv() != nil -} - -// SliceBounds returns n's slice bounds: low, high, and max in expr[low:high:max]. -// n must be a slice expression. max is nil if n is a simple slice expression. -func (n *Node) SliceBounds() (low, high, max *Node) { - if n.List.Len() == 0 { - return nil, nil, nil - } - - switch n.Op { - case OSLICE, OSLICEARR, OSLICESTR: - s := n.List.Slice() - return s[0], s[1], nil - case OSLICE3, OSLICE3ARR: - s := n.List.Slice() - return s[0], s[1], s[2] - } - Fatalf("SliceBounds op %v: %v", n.Op, n) - return nil, nil, nil -} - -// SetSliceBounds sets n's slice bounds, where n is a slice expression. -// n must be a slice expression. If max is non-nil, n must be a full slice expression. -func (n *Node) SetSliceBounds(low, high, max *Node) { - switch n.Op { - case OSLICE, OSLICEARR, OSLICESTR: - if max != nil { - Fatalf("SetSliceBounds %v given three bounds", n.Op) - } - s := n.List.Slice() - if s == nil { - if low == nil && high == nil { - return - } - n.List.Set2(low, high) - return - } - s[0] = low - s[1] = high - return - case OSLICE3, OSLICE3ARR: - s := n.List.Slice() - if s == nil { - if low == nil && high == nil && max == nil { - return - } - n.List.Set3(low, high, max) - return - } - s[0] = low - s[1] = high - s[2] = max - return - } - Fatalf("SetSliceBounds op %v: %v", n.Op, n) -} - -// IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR). -// o must be a slicing op. -func (o Op) IsSlice3() bool { - switch o { - case OSLICE, OSLICEARR, OSLICESTR: - return false - case OSLICE3, OSLICE3ARR: - return true - } - Fatalf("IsSlice3 op %v", o) - return false -} - // backingArrayPtrLen extracts the pointer and length from a slice or string. // This constructs two nodes referring to n, so n must be a cheapexpr. -func (n *Node) backingArrayPtrLen() (ptr, len *Node) { - var init Nodes +func backingArrayPtrLen(n ir.Node) (ptr, len ir.Node) { + var init ir.Nodes c := cheapexpr(n, &init) if c != n || init.Len() != 0 { - Fatalf("backingArrayPtrLen not cheap: %v", n) + base.Fatalf("backingArrayPtrLen not cheap: %v", n) } - ptr = nod(OSPTR, n, nil) - if n.Type.IsString() { - ptr.Type = types.Types[TUINT8].PtrTo() + ptr = ir.Nod(ir.OSPTR, n, nil) + if n.Type().IsString() { + ptr.SetType(types.Types[types.TUINT8].PtrTo()) } else { - ptr.Type = n.Type.Elem().PtrTo() + ptr.SetType(n.Type().Elem().PtrTo()) } - len = nod(OLEN, n, nil) - len.Type = types.Types[TINT] + len = ir.Nod(ir.OLEN, n, nil) + len.SetType(types.Types[types.TINT]) return ptr, len } // labeledControl returns the control flow Node (for, switch, select) // associated with the label n, if any. -func (n *Node) labeledControl() *Node { - if n.Op != OLABEL { - Fatalf("labeledControl %v", n.Op) +func labeledControl(n ir.Node) ir.Node { + if n.Op() != ir.OLABEL { + base.Fatalf("labeledControl %v", n.Op()) } - ctl := n.Name.Defn + ctl := n.Name().Defn if ctl == nil { return nil } - switch ctl.Op { - case OFOR, OFORUNTIL, OSWITCH, OSELECT: + switch ctl.Op() { + case ir.OFOR, ir.OFORUNTIL, ir.OSWITCH, ir.OSELECT: return ctl } return nil } -func syslook(name string) *Node { +func syslook(name string) ir.Node { s := Runtimepkg.Lookup(name) if s == nil || s.Def == nil { - Fatalf("syslook: can't find runtime.%s", name) + base.Fatalf("syslook: can't find runtime.%s", name) } - return asNode(s.Def) + return ir.AsNode(s.Def) } // typehash computes a hash value for type t to use in type switch statements. @@ -967,64 +618,64 @@ func typehash(t *types.Type) uint32 { // updateHasCall checks whether expression n contains any function // calls and sets the n.HasCall flag if so. -func updateHasCall(n *Node) { +func updateHasCall(n ir.Node) { if n == nil { return } n.SetHasCall(calcHasCall(n)) } -func calcHasCall(n *Node) bool { - if n.Ninit.Len() != 0 { +func calcHasCall(n ir.Node) bool { + if n.Init().Len() != 0 { // TODO(mdempsky): This seems overly conservative. return true } - switch n.Op { - case OLITERAL, ONAME, OTYPE: + switch n.Op() { + case ir.OLITERAL, ir.ONIL, ir.ONAME, ir.OTYPE: if n.HasCall() { - Fatalf("OLITERAL/ONAME/OTYPE should never have calls: %+v", n) + base.Fatalf("OLITERAL/ONAME/OTYPE should never have calls: %+v", n) } return false - case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER: + case ir.OCALL, ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER: return true - case OANDAND, OOROR: + case ir.OANDAND, ir.OOROR: // hard with instrumented code if instrumenting { return true } - case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR, - ODEREF, ODOTPTR, ODOTTYPE, ODIV, OMOD: + case ir.OINDEX, ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR, + ir.ODEREF, ir.ODOTPTR, ir.ODOTTYPE, ir.ODIV, ir.OMOD: // These ops might panic, make sure they are done // before we start marshaling args for a call. See issue 16760. return true // When using soft-float, these ops might be rewritten to function calls // so we ensure they are evaluated first. - case OADD, OSUB, ONEG, OMUL: - if thearch.SoftFloat && (isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) { + case ir.OADD, ir.OSUB, ir.ONEG, ir.OMUL: + if thearch.SoftFloat && (isFloat[n.Type().Etype] || isComplex[n.Type().Etype]) { return true } - case OLT, OEQ, ONE, OLE, OGE, OGT: - if thearch.SoftFloat && (isFloat[n.Left.Type.Etype] || isComplex[n.Left.Type.Etype]) { + case ir.OLT, ir.OEQ, ir.ONE, ir.OLE, ir.OGE, ir.OGT: + if thearch.SoftFloat && (isFloat[n.Left().Type().Etype] || isComplex[n.Left().Type().Etype]) { return true } - case OCONV: - if thearch.SoftFloat && ((isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) || (isFloat[n.Left.Type.Etype] || isComplex[n.Left.Type.Etype])) { + case ir.OCONV: + if thearch.SoftFloat && ((isFloat[n.Type().Etype] || isComplex[n.Type().Etype]) || (isFloat[n.Left().Type().Etype] || isComplex[n.Left().Type().Etype])) { return true } } - if n.Left != nil && n.Left.HasCall() { + if n.Left() != nil && n.Left().HasCall() { return true } - if n.Right != nil && n.Right.HasCall() { + if n.Right() != nil && n.Right().HasCall() { return true } return false } -func badtype(op Op, tl, tr *types.Type) { +func badtype(op ir.Op, tl, tr *types.Type) { var s string if tl != nil { s += fmt.Sprintf("\n\t%v", tl) @@ -1042,101 +693,101 @@ func badtype(op Op, tl, tr *types.Type) { } } - yyerror("illegal types for operand: %v%s", op, s) + base.Errorf("illegal types for operand: %v%s", op, s) } // brcom returns !(op). // For example, brcom(==) is !=. -func brcom(op Op) Op { +func brcom(op ir.Op) ir.Op { switch op { - case OEQ: - return ONE - case ONE: - return OEQ - case OLT: - return OGE - case OGT: - return OLE - case OLE: - return OGT - case OGE: - return OLT - } - Fatalf("brcom: no com for %v\n", op) + case ir.OEQ: + return ir.ONE + case ir.ONE: + return ir.OEQ + case ir.OLT: + return ir.OGE + case ir.OGT: + return ir.OLE + case ir.OLE: + return ir.OGT + case ir.OGE: + return ir.OLT + } + base.Fatalf("brcom: no com for %v\n", op) return op } // brrev returns reverse(op). // For example, Brrev(<) is >. -func brrev(op Op) Op { +func brrev(op ir.Op) ir.Op { switch op { - case OEQ: - return OEQ - case ONE: - return ONE - case OLT: - return OGT - case OGT: - return OLT - case OLE: - return OGE - case OGE: - return OLE - } - Fatalf("brrev: no rev for %v\n", op) + case ir.OEQ: + return ir.OEQ + case ir.ONE: + return ir.ONE + case ir.OLT: + return ir.OGT + case ir.OGT: + return ir.OLT + case ir.OLE: + return ir.OGE + case ir.OGE: + return ir.OLE + } + base.Fatalf("brrev: no rev for %v\n", op) return op } // return side effect-free n, appending side effects to init. // result is assignable if n is. -func safeexpr(n *Node, init *Nodes) *Node { +func safeexpr(n ir.Node, init *ir.Nodes) ir.Node { if n == nil { return nil } - if n.Ninit.Len() != 0 { - walkstmtlist(n.Ninit.Slice()) - init.AppendNodes(&n.Ninit) + if n.Init().Len() != 0 { + walkstmtlist(n.Init().Slice()) + init.AppendNodes(n.PtrInit()) } - switch n.Op { - case ONAME, OLITERAL: + switch n.Op() { + case ir.ONAME, ir.OLITERAL, ir.ONIL: return n - case ODOT, OLEN, OCAP: - l := safeexpr(n.Left, init) - if l == n.Left { + case ir.ODOT, ir.OLEN, ir.OCAP: + l := safeexpr(n.Left(), init) + if l == n.Left() { return n } - r := n.copy() - r.Left = l + r := ir.Copy(n) + r.SetLeft(l) r = typecheck(r, ctxExpr) r = walkexpr(r, init) return r - case ODOTPTR, ODEREF: - l := safeexpr(n.Left, init) - if l == n.Left { + case ir.ODOTPTR, ir.ODEREF: + l := safeexpr(n.Left(), init) + if l == n.Left() { return n } - a := n.copy() - a.Left = l + a := ir.Copy(n) + a.SetLeft(l) a = walkexpr(a, init) return a - case OINDEX, OINDEXMAP: - l := safeexpr(n.Left, init) - r := safeexpr(n.Right, init) - if l == n.Left && r == n.Right { + case ir.OINDEX, ir.OINDEXMAP: + l := safeexpr(n.Left(), init) + r := safeexpr(n.Right(), init) + if l == n.Left() && r == n.Right() { return n } - a := n.copy() - a.Left = l - a.Right = r + a := ir.Copy(n) + a.SetLeft(l) + a.SetRight(r) a = walkexpr(a, init) return a - case OSTRUCTLIT, OARRAYLIT, OSLICELIT: + case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT: if isStaticCompositeLiteral(n) { return n } @@ -1144,14 +795,14 @@ func safeexpr(n *Node, init *Nodes) *Node { // make a copy; must not be used as an lvalue if islvalue(n) { - Fatalf("missing lvalue case in safeexpr: %v", n) + base.Fatalf("missing lvalue case in safeexpr: %v", n) } return cheapexpr(n, init) } -func copyexpr(n *Node, t *types.Type, init *Nodes) *Node { +func copyexpr(n ir.Node, t *types.Type, init *ir.Nodes) ir.Node { l := temp(t) - a := nod(OAS, l, n) + a := ir.Nod(ir.OAS, l, n) a = typecheck(a, ctxStmt) a = walkexpr(a, init) init.Append(a) @@ -1160,13 +811,13 @@ func copyexpr(n *Node, t *types.Type, init *Nodes) *Node { // return side-effect free and cheap n, appending side effects to init. // result may not be assignable. -func cheapexpr(n *Node, init *Nodes) *Node { - switch n.Op { - case ONAME, OLITERAL: +func cheapexpr(n ir.Node, init *ir.Nodes) ir.Node { + switch n.Op() { + case ir.ONAME, ir.OLITERAL, ir.ONIL: return n } - return copyexpr(n, n.Type, init) + return copyexpr(n, n.Type(), init) } // Code to resolve elided DOTs in embedded types. @@ -1306,21 +957,21 @@ func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) ( // find missing fields that // will give shortest unique addressing. // modify the tree with missing type names. -func adddot(n *Node) *Node { - n.Left = typecheck(n.Left, ctxType|ctxExpr) - if n.Left.Diag() { +func adddot(n ir.Node) ir.Node { + n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr)) + if n.Left().Diag() { n.SetDiag(true) } - t := n.Left.Type + t := n.Left().Type() if t == nil { return n } - if n.Left.Op == OTYPE { + if n.Left().Op() == ir.OTYPE { return n } - s := n.Sym + s := n.Sym() if s == nil { return n } @@ -1329,12 +980,12 @@ func adddot(n *Node) *Node { case path != nil: // rebuild elided dots for c := len(path) - 1; c >= 0; c-- { - n.Left = nodSym(ODOT, n.Left, path[c].field.Sym) - n.Left.SetImplicit(true) + n.SetLeft(nodSym(ir.ODOT, n.Left(), path[c].field.Sym)) + n.Left().SetImplicit(true) } case ambig: - yyerror("ambiguous selector %v", n) - n.Left = nil + base.Errorf("ambiguous selector %v", n) + n.SetLeft(nil) } return n @@ -1465,8 +1116,8 @@ func expandmeth(t *types.Type) { } // Given funarg struct list, return list of ODCLFIELD Node fn args. -func structargs(tl *types.Type, mustname bool) []*Node { - var args []*Node +func structargs(tl *types.Type, mustname bool) []ir.Node { + var args []ir.Node gen := 0 for _, t := range tl.Fields().Slice() { s := t.Sym @@ -1476,7 +1127,7 @@ func structargs(tl *types.Type, mustname bool) []*Node { gen++ } a := symfield(s, t.Type) - a.Pos = t.Pos + a.SetPos(t.Pos) a.SetIsDDD(t.IsDDD()) args = append(args, a) } @@ -1506,48 +1157,48 @@ func structargs(tl *types.Type, mustname bool) []*Node { // method - M func (t T)(), a TFIELD type struct // newnam - the eventual mangled name of this function func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { - if false && Debug.r != 0 { + if false && base.Flag.LowerR != 0 { fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam) } // Only generate (*T).M wrappers for T.M in T's own package. if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && - rcvr.Elem().Sym != nil && rcvr.Elem().Sym.Pkg != localpkg { + rcvr.Elem().Sym != nil && rcvr.Elem().Sym.Pkg != ir.LocalPkg { return } // Only generate I.M wrappers for I in I's own package // but keep doing it for error.Error (was issue #29304). - if rcvr.IsInterface() && rcvr.Sym != nil && rcvr.Sym.Pkg != localpkg && rcvr != types.Errortype { + if rcvr.IsInterface() && rcvr.Sym != nil && rcvr.Sym.Pkg != ir.LocalPkg && rcvr != types.Errortype { return } - lineno = autogeneratedPos - dclcontext = PEXTERN + base.Pos = autogeneratedPos + dclcontext = ir.PEXTERN - tfn := nod(OTFUNC, nil, nil) - tfn.Left = namedfield(".this", rcvr) - tfn.List.Set(structargs(method.Type.Params(), true)) - tfn.Rlist.Set(structargs(method.Type.Results(), false)) + tfn := ir.Nod(ir.OTFUNC, nil, nil) + tfn.SetLeft(namedfield(".this", rcvr)) + tfn.PtrList().Set(structargs(method.Type.Params(), true)) + tfn.PtrRlist().Set(structargs(method.Type.Results(), false)) fn := dclfunc(newnam, tfn) - fn.Func.SetDupok(true) + fn.Func().SetDupok(true) - nthis := asNode(tfn.Type.Recv().Nname) + nthis := ir.AsNode(tfn.Type().Recv().Nname) methodrcvr := method.Type.Recv().Type // generate nil pointer check for better error if rcvr.IsPtr() && rcvr.Elem() == methodrcvr { // generating wrapper from *T to T. - n := nod(OIF, nil, nil) - n.Left = nod(OEQ, nthis, nodnil()) - call := nod(OCALL, syslook("panicwrap"), nil) - n.Nbody.Set1(call) - fn.Nbody.Append(n) + n := ir.Nod(ir.OIF, nil, nil) + n.SetLeft(ir.Nod(ir.OEQ, nthis, nodnil())) + call := ir.Nod(ir.OCALL, syslook("panicwrap"), nil) + n.PtrBody().Set1(call) + fn.PtrBody().Append(n) } - dot := adddot(nodSym(OXDOT, nthis, method.Sym)) + dot := adddot(nodSym(ir.OXDOT, nthis, method.Sym)) // generate call // It's not possible to use a tail call when dynamic linking on ppc64le. The @@ -1556,42 +1207,42 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { // the TOC to the appropriate value for that module. But if it returns // directly to the wrapper's caller, nothing will reset it to the correct // value for that function. - if !instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !isifacemethod(method.Type) && !(thearch.LinkArch.Name == "ppc64le" && Ctxt.Flag_dynlink) { + if !instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !isifacemethod(method.Type) && !(thearch.LinkArch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) { // generate tail call: adjust pointer receiver and jump to embedded method. - dot = dot.Left // skip final .M + dot = dot.Left() // skip final .M // TODO(mdempsky): Remove dependency on dotlist. if !dotlist[0].field.Type.IsPtr() { - dot = nod(OADDR, dot, nil) + dot = ir.Nod(ir.OADDR, dot, nil) } - as := nod(OAS, nthis, convnop(dot, rcvr)) - fn.Nbody.Append(as) - fn.Nbody.Append(nodSym(ORETJMP, nil, methodSym(methodrcvr, method.Sym))) + as := ir.Nod(ir.OAS, nthis, convnop(dot, rcvr)) + fn.PtrBody().Append(as) + fn.PtrBody().Append(nodSym(ir.ORETJMP, nil, methodSym(methodrcvr, method.Sym))) } else { - fn.Func.SetWrapper(true) // ignore frame for panic+recover matching - call := nod(OCALL, dot, nil) - call.List.Set(paramNnames(tfn.Type)) - call.SetIsDDD(tfn.Type.IsVariadic()) + fn.Func().SetWrapper(true) // ignore frame for panic+recover matching + call := ir.Nod(ir.OCALL, dot, nil) + call.PtrList().Set(paramNnames(tfn.Type())) + call.SetIsDDD(tfn.Type().IsVariadic()) if method.Type.NumResults() > 0 { - n := nod(ORETURN, nil, nil) - n.List.Set1(call) + n := ir.Nod(ir.ORETURN, nil, nil) + n.PtrList().Set1(call) call = n } - fn.Nbody.Append(call) + fn.PtrBody().Append(call) } - if false && Debug.r != 0 { - dumplist("genwrapper body", fn.Nbody) + if false && base.Flag.LowerR != 0 { + ir.DumpList("genwrapper body", fn.Body()) } funcbody() - if debug_dclstack != 0 { + if base.Debug.DclStack != 0 { testdclstack() } fn = typecheck(fn, ctxStmt) Curfn = fn - typecheckslice(fn.Nbody.Slice(), ctxStmt) + typecheckslice(fn.Body().Slice(), ctxStmt) // Inline calls within (*T).M wrappers. This is safe because we only // generate those wrappers within the same compilation unit as (T).M. @@ -1599,32 +1250,32 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym != nil { inlcalls(fn) } - escapeFuncs([]*Node{fn}, false) + escapeFuncs([]ir.Node{fn}, false) Curfn = nil xtop = append(xtop, fn) } -func paramNnames(ft *types.Type) []*Node { - args := make([]*Node, ft.NumParams()) +func paramNnames(ft *types.Type) []ir.Node { + args := make([]ir.Node, ft.NumParams()) for i, f := range ft.Params().FieldSlice() { - args[i] = asNode(f.Nname) + args[i] = ir.AsNode(f.Nname) } return args } -func hashmem(t *types.Type) *Node { +func hashmem(t *types.Type) ir.Node { sym := Runtimepkg.Lookup("memhash") - n := newname(sym) + n := NewName(sym) setNodeNameFunc(n) - n.Type = functype(nil, []*Node{ + n.SetType(functype(nil, []ir.Node{ anonfield(types.NewPtr(t)), - anonfield(types.Types[TUINTPTR]), - anonfield(types.Types[TUINTPTR]), - }, []*Node{ - anonfield(types.Types[TUINTPTR]), - }) + anonfield(types.Types[types.TUINTPTR]), + anonfield(types.Types[types.TUINTPTR]), + }, []ir.Node{ + anonfield(types.Types[types.TUINTPTR]), + })) return n } @@ -1636,7 +1287,7 @@ func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) (m *types.Field, path, ambig := dotpath(s, t, &m, ignorecase) if path == nil { if ambig { - yyerror("%v.%v is ambiguous", t, s) + base.Errorf("%v.%v is ambiguous", t, s) } return nil, false } @@ -1649,7 +1300,7 @@ func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) (m *types.Field, } if !m.IsMethod() { - yyerror("%v.%v is a field, not a method", t, s) + base.Errorf("%v.%v is a field, not a method", t, s) return nil, followptr } @@ -1720,8 +1371,8 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool // the method does not exist for value types. rcvr := tm.Type.Recv().Type if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) { - if false && Debug.r != 0 { - yyerror("interface pointer mismatch") + if false && base.Flag.LowerR != 0 { + base.Errorf("interface pointer mismatch") } *m = im @@ -1742,53 +1393,44 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool return true } -func listtreecopy(l []*Node, pos src.XPos) []*Node { - var out []*Node +func listtreecopy(l []ir.Node, pos src.XPos) []ir.Node { + var out []ir.Node for _, n := range l { out = append(out, treecopy(n, pos)) } return out } -func liststmt(l []*Node) *Node { - n := nod(OBLOCK, nil, nil) - n.List.Set(l) +func liststmt(l []ir.Node) ir.Node { + n := ir.Nod(ir.OBLOCK, nil, nil) + n.PtrList().Set(l) if len(l) != 0 { - n.Pos = l[0].Pos - } - return n -} - -func (l Nodes) asblock() *Node { - n := nod(OBLOCK, nil, nil) - n.List = l - if l.Len() != 0 { - n.Pos = l.First().Pos + n.SetPos(l[0].Pos()) } return n } -func ngotype(n *Node) *types.Sym { - if n.Type != nil { - return typenamesym(n.Type) +func ngotype(n ir.Node) *types.Sym { + if n.Type() != nil { + return typenamesym(n.Type()) } return nil } // The result of addinit MUST be assigned back to n, e.g. // n.Left = addinit(n.Left, init) -func addinit(n *Node, init []*Node) *Node { +func addinit(n ir.Node, init []ir.Node) ir.Node { if len(init) == 0 { return n } - if n.mayBeShared() { + if ir.MayBeShared(n) { // Introduce OCONVNOP to hold init list. - n = nod(OCONVNOP, n, nil) - n.Type = n.Left.Type + n = ir.Nod(ir.OCONVNOP, n, nil) + n.SetType(n.Left().Type()) n.SetTypecheck(1) } - n.Ninit.Prepend(init...) + n.PtrInit().Prepend(init...) n.SetHasCall(true) return n } @@ -1805,40 +1447,40 @@ var reservedimports = []string{ func isbadimport(path string, allowSpace bool) bool { if strings.Contains(path, "\x00") { - yyerror("import path contains NUL") + base.Errorf("import path contains NUL") return true } for _, ri := range reservedimports { if path == ri { - yyerror("import path %q is reserved and cannot be used", path) + base.Errorf("import path %q is reserved and cannot be used", path) return true } } for _, r := range path { if r == utf8.RuneError { - yyerror("import path contains invalid UTF-8 sequence: %q", path) + base.Errorf("import path contains invalid UTF-8 sequence: %q", path) return true } if r < 0x20 || r == 0x7f { - yyerror("import path contains control character: %q", path) + base.Errorf("import path contains control character: %q", path) return true } if r == '\\' { - yyerror("import path contains backslash; use slash: %q", path) + base.Errorf("import path contains backslash; use slash: %q", path) return true } if !allowSpace && unicode.IsSpace(r) { - yyerror("import path contains space character: %q", path) + base.Errorf("import path contains space character: %q", path) return true } if strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r) { - yyerror("import path contains invalid character '%c': %q", r, path) + base.Errorf("import path contains invalid character '%c': %q", r, path) return true } } @@ -1854,20 +1496,20 @@ func isdirectiface(t *types.Type) bool { } switch t.Etype { - case TPTR: + case types.TPTR: // Pointers to notinheap types must be stored indirectly. See issue 42076. return !t.Elem().NotInHeap() - case TCHAN, - TMAP, - TFUNC, - TUNSAFEPTR: + case types.TCHAN, + types.TMAP, + types.TFUNC, + types.TUNSAFEPTR: return true - case TARRAY: + case types.TARRAY: // Array of 1 direct iface type can be direct. return t.NumElem() == 1 && isdirectiface(t.Elem()) - case TSTRUCT: + case types.TSTRUCT: // Struct with 1 field of direct iface type can be direct. return t.NumFields() == 1 && isdirectiface(t.Field(0).Type) } @@ -1876,32 +1518,32 @@ func isdirectiface(t *types.Type) bool { } // itabType loads the _type field from a runtime.itab struct. -func itabType(itab *Node) *Node { - typ := nodSym(ODOTPTR, itab, nil) - typ.Type = types.NewPtr(types.Types[TUINT8]) +func itabType(itab ir.Node) ir.Node { + typ := nodSym(ir.ODOTPTR, itab, nil) + typ.SetType(types.NewPtr(types.Types[types.TUINT8])) typ.SetTypecheck(1) - typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab - typ.SetBounded(true) // guaranteed not to fault + typ.SetOffset(int64(Widthptr)) // offset of _type in runtime.itab + typ.SetBounded(true) // guaranteed not to fault return typ } // ifaceData loads the data field from an interface. // The concrete type must be known to have type t. // It follows the pointer if !isdirectiface(t). -func ifaceData(pos src.XPos, n *Node, t *types.Type) *Node { +func ifaceData(pos src.XPos, n ir.Node, t *types.Type) ir.Node { if t.IsInterface() { - Fatalf("ifaceData interface: %v", t) + base.Fatalf("ifaceData interface: %v", t) } - ptr := nodlSym(pos, OIDATA, n, nil) + ptr := nodlSym(pos, ir.OIDATA, n, nil) if isdirectiface(t) { - ptr.Type = t + ptr.SetType(t) ptr.SetTypecheck(1) return ptr } - ptr.Type = types.NewPtr(t) + ptr.SetType(types.NewPtr(t)) ptr.SetTypecheck(1) - ind := nodl(pos, ODEREF, ptr, nil) - ind.Type = t + ind := ir.NodAt(pos, ir.ODEREF, ptr, nil) + ind.SetType(t) ind.SetTypecheck(1) ind.SetBounded(true) return ind @@ -1910,9 +1552,9 @@ func ifaceData(pos src.XPos, n *Node, t *types.Type) *Node { // typePos returns the position associated with t. // This is where t was declared or where it appeared as a type expression. func typePos(t *types.Type) src.XPos { - n := asNode(t.Nod) - if n == nil || !n.Pos.IsKnown() { - Fatalf("bad type: %v", t) + n := ir.AsNode(t.Nod) + if n == nil || !n.Pos().IsKnown() { + base.Fatalf("bad type: %v", t) } - return n.Pos + return n.Pos() } |