[dev.typeparams] all: merge dev.regabi (07569da) into dev.typeparams

Conflicts:

- test/fixedbugs/issue27595.go
- test/fixedbugs/issue30087.go
- test/used.go

Merge List:

+ 2020-12-28 07569dac4e [dev.regabi] all: merge master (1d78139) into dev.regabi
+ 2020-12-28 76136be027 [dev.regabi] cmd/compile: check for recursive import in ImportBody
+ 2020-12-28 fda7ec3a3f [dev.regabi] cmd/compile: remove Name.IsDDD, etc
+ 2020-12-28 098a6490b9 [dev.regabi] cmd/compile: remove Declare in makepartialcall
+ 2020-12-28 137f0d2e06 [dev.regabi] cmd/compile: remove unnecessary Name.Sym call
+ 2020-12-28 3383b5c74a [dev.regabi] cmd/compile: flatten dependency graph [generated]
+ 2020-12-28 f8afb8216a [dev.regabi] cmd/compile: rename CommStmt and CaseStmt [generated]
+ 2020-12-28 5f3bd59a0d [dev.regabi] cmd/compile: remove some unneeded code in package ir
+ 2020-12-28 3bdafb0d82 [dev.regabi] cmd/compile: remove CommStmt.List
+ 2020-12-28 2ecf52b841 [dev.regabi] cmd/compile: separate CommStmt from CaseStmt
+ 2020-12-28 ed9772e130 [dev.regabi] cmd/compile: add explicit file name in types generation
+ 2020-12-28 a59d26603f [dev.regabi] cmd/compile: use []*CaseStmt in {Select,Switch}Stmt
+ 2020-12-28 fbc4458c06 [dev.regabi] cmd/compile: simplify some tree traversal code
+ 2020-12-28 6c67677541 [dev.regabi] cmd/compile: simplify FuncName and PkgFuncName
+ 2020-12-28 676d794b81 [dev.regabi] cmd/compile: remove refersToCommonName
+ 2020-12-28 c98548e110 [dev.regabi] cmd/compile: merge ascompatee, ascompatee1, and reorder3
+ 2020-12-28 4c215c4fa9 [dev.regabi] cmd/compile: simplify and optimize reorder3
+ 2020-12-28 e6c973198d [dev.regabi] cmd/compile: stop mangling SelectorExpr.Sel for ODOTMETH
+ 2020-12-28 135ce1c485 [dev.regabi] cmd/compile: desugar OMETHEXPR into ONAME during walk
+ 2020-12-28 0f732f8c91 [dev.regabi] cmd/compile: minor walkExpr cleanups
+ 2020-12-28 0de8eafd98 [dev.regabi] cmd/compile: remove SelectorExpr.Offset field
+ 2020-12-28 a4f335f420 [dev.regabi] cmd/compile: always use a Field for ODOTPTR expressions
+ 2020-12-26 1d78139128 runtime/cgo: fix Android build with NDK 22
+ 2020-12-25 2018b68a65 net/mail: don't use MDT in test
+ 2020-12-25 e4f293d853 [dev.regabi] cmd/compile: fix OCALLMETH desugaring
+ 2020-12-25 1d9a1f67d5 [dev.regabi] cmd/compile: don't emit reflect data for method types
+ 2020-12-25 396b6c2e7c [dev.regabi] cmd/compile: cleanup assignment typechecking
+ 2020-12-25 e24d2f3d05 [dev.regabi] cmd/compile: remove typ from RangeStmt
+ 2020-12-25 2785c691c2 [dev.regabi] cmd/compile: cleanup devirtualization docs
+ 2020-12-25 4b1d0fe66f [dev.regabi] cmd/compile: new devirtualization pkg [generated]
+ 2020-12-24 082cc8b7d9 [dev.regabi] cmd/compile: change ir.IsAssignable -> ir.IsAddressable
+ 2020-12-24 27b248b307 [dev.regabi] cmd/compile: separate range stmt Vars to Key, Value nodes
+ 2020-12-23 40818038bf [dev.regabi] cmd/compile: change CaseStmt.Vars to Var
+ 2020-12-23 b116404444 runtime: shift timeHistogram buckets and allow negative durations
+ 2020-12-23 8db7e2fecd runtime: fix allocs-by-size and frees-by-size buckets
+ 2020-12-23 fb96f07e1a runtime: fix nStackRoots comment about stack roots
+ 2020-12-23 d1502b3c72 lib/time, time/tzdata: update tzdata to 2020e
+ 2020-12-23 30c99cbb7a cmd/go: add the Retract field to 'go help mod edit' definition of the GoMod struct
+ 2020-12-23 49d0b239cb doc: fix a typo in contribute.html
+ 2020-12-23 9eeed291bc [dev.regabi] cmd/compile: eliminate usage of ir.Node in liveness
+ 2020-12-23 d1d64e4cea [dev.regabi] cmd/compile: split SliceExpr.List into separate fields
+ 2020-12-23 98a73030b0 cmd/go: in 'go get', promote named implicit dependencies to explicit
+ 2020-12-23 d19018e8f1 [dev.regabi] cmd/compile: split SliceHeaderExpr.LenCap into separate fields
+ 2020-12-23 53f082b0ee [dev.regabi] cmd/compile: cleanup export code further
+ 2020-12-23 31267f82e1 [dev.regabi] cmd/compile: simplify function/interface/struct typechecking
+ 2020-12-23 addade2cce [dev.regabi] cmd/compile: prefer types constructors over typecheck
+ 2020-12-23 18ebfb49e9 [dev.regabi] cmd/compile: cleanup noder
+ 2020-12-23 87a592b356 [dev.regabi] cmd/compile: cleanup import/export code
+ 2020-12-23 5898025026 [dev.regabi] cmd/compile: update mkbuiltin.go to use new type constructors
+ 2020-12-23 63c96c2ee7 [dev.regabi] cmd/compile: update mkbuiltin.go and re-enable TestBuiltin
+ 2020-12-23 fd6ba1c8a2 os/signal: fix a deadlock with syscall.AllThreadsSyscall() use
+ 2020-12-23 b0b0d98283 runtime: linux iscgo support for not blocking nptl signals
+ 2020-12-22 223331fc0c cmd/go/internal/modload: add hint for missing implicit dependency

Change-Id: Iecb8a7dfb401b6ab383e97101cd81bfc201683f6
This commit is contained in:
Matthew Dempsky 2020-12-28 00:39:13 -08:00
commit a800acaae1
90 changed files with 8552 additions and 8722 deletions

View File

@ -1129,7 +1129,7 @@ sometimes required because the standard library code you're modifying
might require a newer version than the stable one you have installed). might require a newer version than the stable one you have installed).
<pre> <pre>
$ cd $GODIR/src/hash/sha1 $ cd $GODIR/src/crypto/sha1
$ [make changes...] $ [make changes...]
$ $GODIR/bin/go test . $ $GODIR/bin/go test .
</pre> </pre>

View File

@ -8,8 +8,8 @@
# Consult https://www.iana.org/time-zones for the latest versions. # Consult https://www.iana.org/time-zones for the latest versions.
# Versions to use. # Versions to use.
CODE=2020d CODE=2020e
DATA=2020d DATA=2020e
set -e set -e
rm -rf work rm -rf work

Binary file not shown.

View File

@ -0,0 +1,85 @@
// Copyright 2020 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 devirtualize implements a simple "devirtualization"
// optimization pass, which replaces interface method calls with
// direct concrete-type method calls where possible.
package devirtualize
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
)
// Func devirtualizes calls within fn where possible.
func Func(fn *ir.Func) {
ir.CurFunc = fn
ir.VisitList(fn.Body, func(n ir.Node) {
if call, ok := n.(*ir.CallExpr); ok {
Call(call)
}
})
}
// Call devirtualizes the given call if possible.
func Call(call *ir.CallExpr) {
if call.Op() != ir.OCALLINTER {
return
}
sel := call.X.(*ir.SelectorExpr)
r := ir.StaticValue(sel.X)
if r.Op() != ir.OCONVIFACE {
return
}
recv := r.(*ir.ConvExpr)
typ := recv.X.Type()
if typ.IsInterface() {
return
}
dt := ir.NewTypeAssertExpr(sel.Pos(), sel.X, nil)
dt.SetType(typ)
x := typecheck.Callee(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sel))
switch x.Op() {
case ir.ODOTMETH:
x := x.(*ir.SelectorExpr)
if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
}
call.SetOp(ir.OCALLMETH)
call.X = x
case ir.ODOTINTER:
// Promoted method from embedded interface-typed field (#42279).
x := x.(*ir.SelectorExpr)
if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos(), "partially devirtualizing %v to %v", sel, typ)
}
call.SetOp(ir.OCALLINTER)
call.X = x
default:
// TODO(mdempsky): Turn back into Fatalf after more testing.
if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos(), "failed to devirtualize %v (%v)", x, x.Op())
}
return
}
// Duplicated logic from typecheck for function call return
// value types.
//
// Receiver parameter size may have changed; need to update
// call.Type to get correct stack offsets for result
// parameters.
types.CheckSize(x.Type())
switch ft := x.Type(); ft.NumResults() {
case 0:
case 1:
call.SetType(ft.Results().Field(0).Type)
default:
call.SetType(ft.Results())
}
}

View File

@ -347,21 +347,19 @@ func (e *escape) stmt(n ir.Node) {
e.loopDepth-- e.loopDepth--
case ir.ORANGE: case ir.ORANGE:
// for List = range Right { Nbody } // for Key, Value = range X { Body }
n := n.(*ir.RangeStmt) n := n.(*ir.RangeStmt)
e.loopDepth++ e.loopDepth++
ks := e.addrs(n.Vars) e.addr(n.Key)
k := e.addr(n.Value)
e.block(n.Body) e.block(n.Body)
e.loopDepth-- e.loopDepth--
// Right is evaluated outside the loop. // X is evaluated outside the loop.
k := e.discardHole() if n.X.Type().IsArray() {
if len(ks) >= 2 { k = k.note(n, "range")
if n.X.Type().IsArray() { } else {
k = ks[1].note(n, "range") k = k.deref(n, "range-deref")
} else {
k = ks[1].deref(n, "range-deref")
}
} }
e.expr(e.later(k), n.X) e.expr(e.later(k), n.X)
@ -371,9 +369,8 @@ func (e *escape) stmt(n ir.Node) {
var ks []hole var ks []hole
for _, cas := range n.Cases { // cases for _, cas := range n.Cases { // cases
cas := cas.(*ir.CaseStmt)
if typesw && n.Tag.(*ir.TypeSwitchGuard).Tag != nil { if typesw && n.Tag.(*ir.TypeSwitchGuard).Tag != nil {
cv := cas.Vars[0] cv := cas.Var
k := e.dcl(cv) // type switch variables have no ODCL. k := e.dcl(cv) // type switch variables have no ODCL.
if cv.Type().HasPointers() { if cv.Type().HasPointers() {
ks = append(ks, k.dotType(cv.Type(), cas, "switch case")) ks = append(ks, k.dotType(cv.Type(), cas, "switch case"))
@ -393,7 +390,6 @@ func (e *escape) stmt(n ir.Node) {
case ir.OSELECT: case ir.OSELECT:
n := n.(*ir.SelectStmt) n := n.(*ir.SelectStmt)
for _, cas := range n.Cases { for _, cas := range n.Cases {
cas := cas.(*ir.CaseStmt)
e.stmt(cas.Comm) e.stmt(cas.Comm)
e.block(cas.Body) e.block(cas.Body)
} }
@ -559,10 +555,9 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR: case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR:
n := n.(*ir.SliceExpr) n := n.(*ir.SliceExpr)
e.expr(k.note(n, "slice"), n.X) e.expr(k.note(n, "slice"), n.X)
low, high, max := n.SliceBounds() e.discard(n.Low)
e.discard(low) e.discard(n.High)
e.discard(high) e.discard(n.Max)
e.discard(max)
case ir.OCONV, ir.OCONVNOP: case ir.OCONV, ir.OCONVNOP:
n := n.(*ir.ConvExpr) n := n.(*ir.ConvExpr)

View File

@ -10,6 +10,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/devirtualize"
"cmd/compile/internal/dwarfgen" "cmd/compile/internal/dwarfgen"
"cmd/compile/internal/escape" "cmd/compile/internal/escape"
"cmd/compile/internal/inline" "cmd/compile/internal/inline"
@ -243,7 +244,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
// Devirtualize. // Devirtualize.
for _, n := range typecheck.Target.Decls { for _, n := range typecheck.Target.Decls {
if n.Op() == ir.ODCLFUNC { if n.Op() == ir.ODCLFUNC {
inline.Devirtualize(n.(*ir.Func)) devirtualize.Func(n.(*ir.Func))
} }
} }
ir.CurFunc = nil ir.CurFunc = nil

View File

@ -324,19 +324,17 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
if t == nil { if t == nil {
base.Fatalf("no function type for [%p] %+v\n", n.X, n.X) base.Fatalf("no function type for [%p] %+v\n", n.X, n.X)
} }
if types.IsRuntimePkg(n.X.Sym().Pkg) { fn := ir.MethodExprName(n.X).Func
fn := n.X.Sym().Name if types.IsRuntimePkg(fn.Sym().Pkg) && fn.Sym().Name == "heapBits.nextArena" {
if fn == "heapBits.nextArena" { // Special case: explicitly allow
// Special case: explicitly allow // mid-stack inlining of
// mid-stack inlining of // runtime.heapBits.next even though
// runtime.heapBits.next even though // it calls slow-path
// it calls slow-path // runtime.heapBits.nextArena.
// runtime.heapBits.nextArena. break
break
}
} }
if inlfn := ir.MethodExprName(n.X).Func; inlfn.Inl != nil { if fn.Inl != nil {
v.budget -= inlfn.Inl.Cost v.budget -= fn.Inl.Cost
break break
} }
// Call cost for non-leaf inlining. // Call cost for non-leaf inlining.
@ -531,7 +529,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
// Prevent inlining some reflect.Value methods when using checkptr, // Prevent inlining some reflect.Value methods when using checkptr,
// even when package reflect was compiled without it (#35073). // even when package reflect was compiled without it (#35073).
n := n.(*ir.CallExpr) n := n.(*ir.CallExpr)
if s := n.X.Sym(); base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") { if s := ir.MethodExprName(n.X).Sym(); base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
return n return n
} }
} }
@ -1203,73 +1201,6 @@ func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
return s return s
} }
// Devirtualize replaces interface method calls within fn with direct
// concrete-type method calls where applicable.
func Devirtualize(fn *ir.Func) {
ir.CurFunc = fn
ir.VisitList(fn.Body, func(n ir.Node) {
if n.Op() == ir.OCALLINTER {
devirtualizeCall(n.(*ir.CallExpr))
}
})
}
func devirtualizeCall(call *ir.CallExpr) {
sel := call.X.(*ir.SelectorExpr)
r := ir.StaticValue(sel.X)
if r.Op() != ir.OCONVIFACE {
return
}
recv := r.(*ir.ConvExpr)
typ := recv.X.Type()
if typ.IsInterface() {
return
}
dt := ir.NewTypeAssertExpr(sel.Pos(), sel.X, nil)
dt.SetType(typ)
x := typecheck.Callee(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sel))
switch x.Op() {
case ir.ODOTMETH:
x := x.(*ir.SelectorExpr)
if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
}
call.SetOp(ir.OCALLMETH)
call.X = x
case ir.ODOTINTER:
// Promoted method from embedded interface-typed field (#42279).
x := x.(*ir.SelectorExpr)
if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos(), "partially devirtualizing %v to %v", sel, typ)
}
call.SetOp(ir.OCALLINTER)
call.X = x
default:
// TODO(mdempsky): Turn back into Fatalf after more testing.
if base.Flag.LowerM != 0 {
base.WarnfAt(call.Pos(), "failed to devirtualize %v (%v)", x, x.Op())
}
return
}
// Duplicated logic from typecheck for function call return
// value types.
//
// Receiver parameter size may have changed; need to update
// call.Type to get correct stack offsets for result
// parameters.
types.CheckSize(x.Type())
switch ft := x.Type(); ft.NumResults() {
case 0:
case 1:
call.SetType(ft.Results().Field(0).Type)
default:
call.SetType(ft.Results())
}
}
// numNonClosures returns the number of functions in list which are not closures. // numNonClosures returns the number of functions in list which are not closures.
func numNonClosures(list []*ir.Func) int { func numNonClosures(list []*ir.Func) int {
count := 0 count := 0

View File

@ -572,14 +572,12 @@ type SelectorExpr struct {
miniExpr miniExpr
X Node X Node
Sel *types.Sym Sel *types.Sym
Offset int64
Selection *types.Field Selection *types.Field
} }
func NewSelectorExpr(pos src.XPos, op Op, x Node, sel *types.Sym) *SelectorExpr { func NewSelectorExpr(pos src.XPos, op Op, x Node, sel *types.Sym) *SelectorExpr {
n := &SelectorExpr{X: x, Sel: sel} n := &SelectorExpr{X: x, Sel: sel}
n.pos = pos n.pos = pos
n.Offset = types.BADWIDTH
n.SetOp(op) n.SetOp(op)
return n return n
} }
@ -596,6 +594,7 @@ func (n *SelectorExpr) SetOp(op Op) {
func (n *SelectorExpr) Sym() *types.Sym { return n.Sel } func (n *SelectorExpr) Sym() *types.Sym { return n.Sel }
func (n *SelectorExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 } func (n *SelectorExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 }
func (n *SelectorExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) } func (n *SelectorExpr) SetImplicit(b bool) { n.flags.set(miniExprImplicit, b) }
func (n *SelectorExpr) Offset() int64 { return n.Selection.Offset }
// Before type-checking, bytes.Buffer is a SelectorExpr. // Before type-checking, bytes.Buffer is a SelectorExpr.
// After type-checking it becomes a Name. // After type-checking it becomes a Name.
@ -605,11 +604,13 @@ func (*SelectorExpr) CanBeNtype() {}
type SliceExpr struct { type SliceExpr struct {
miniExpr miniExpr
X Node X Node
List Nodes // TODO(rsc): Use separate Nodes Low Node
High Node
Max Node
} }
func NewSliceExpr(pos src.XPos, op Op, x Node) *SliceExpr { func NewSliceExpr(pos src.XPos, op Op, x, low, high, max Node) *SliceExpr {
n := &SliceExpr{X: x} n := &SliceExpr{X: x, Low: low, High: high, Max: max}
n.pos = pos n.pos = pos
n.op = op n.op = op
return n return n
@ -624,61 +625,6 @@ func (n *SliceExpr) SetOp(op Op) {
} }
} }
// 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 *SliceExpr) SliceBounds() (low, high, max Node) {
if len(n.List) == 0 {
return nil, nil, nil
}
switch n.Op() {
case OSLICE, OSLICEARR, OSLICESTR:
s := n.List
return s[0], s[1], nil
case OSLICE3, OSLICE3ARR:
s := n.List
return s[0], s[1], s[2]
}
base.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 *SliceExpr) SetSliceBounds(low, high, max Node) {
switch n.Op() {
case OSLICE, OSLICEARR, OSLICESTR:
if max != nil {
base.Fatalf("SetSliceBounds %v given three bounds", n.Op())
}
s := n.List
if s == nil {
if low == nil && high == nil {
return
}
n.List = []Node{low, high}
return
}
s[0] = low
s[1] = high
return
case OSLICE3, OSLICE3ARR:
s := n.List
if s == nil {
if low == nil && high == nil && max == nil {
return
}
n.List = []Node{low, high, max}
return
}
s[0] = low
s[1] = high
s[2] = max
return
}
base.Fatalf("SetSliceBounds op %v: %v", n.Op(), n)
}
// IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR). // IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR).
// o must be a slicing op. // o must be a slicing op.
func (o Op) IsSlice3() bool { func (o Op) IsSlice3() bool {
@ -695,16 +641,16 @@ func (o Op) IsSlice3() bool {
// A SliceHeader expression constructs a slice header from its parts. // A SliceHeader expression constructs a slice header from its parts.
type SliceHeaderExpr struct { type SliceHeaderExpr struct {
miniExpr miniExpr
Ptr Node Ptr Node
LenCap Nodes // TODO(rsc): Split into two Node fields Len Node
Cap Node
} }
func NewSliceHeaderExpr(pos src.XPos, typ *types.Type, ptr, len, cap Node) *SliceHeaderExpr { func NewSliceHeaderExpr(pos src.XPos, typ *types.Type, ptr, len, cap Node) *SliceHeaderExpr {
n := &SliceHeaderExpr{Ptr: ptr} n := &SliceHeaderExpr{Ptr: ptr, Len: len, Cap: cap}
n.pos = pos n.pos = pos
n.op = OSLICEHEADER n.op = OSLICEHEADER
n.typ = typ n.typ = typ
n.LenCap = []Node{len, cap}
return n return n
} }
@ -829,12 +775,12 @@ func IsZero(n Node) bool {
} }
// lvalue etc // lvalue etc
func IsAssignable(n Node) bool { func IsAddressable(n Node) bool {
switch n.Op() { switch n.Op() {
case OINDEX: case OINDEX:
n := n.(*IndexExpr) n := n.(*IndexExpr)
if n.X.Type() != nil && n.X.Type().IsArray() { if n.X.Type() != nil && n.X.Type().IsArray() {
return IsAssignable(n.X) return IsAddressable(n.X)
} }
if n.X.Type() != nil && n.X.Type().IsString() { if n.X.Type() != nil && n.X.Type().IsString() {
return false return false
@ -845,7 +791,7 @@ func IsAssignable(n Node) bool {
case ODOT: case ODOT:
n := n.(*SelectorExpr) n := n.(*SelectorExpr)
return IsAssignable(n.X) return IsAddressable(n.X)
case ONAME: case ONAME:
n := n.(*Name) n := n.(*Name)

View File

@ -444,12 +444,15 @@ func stmtFmt(n Node, s fmt.State) {
break break
} }
if len(n.Vars) == 0 { fmt.Fprint(s, "for")
fmt.Fprintf(s, "for range %v { %v }", n.X, n.Body) if n.Key != nil {
break fmt.Fprintf(s, " %v", n.Key)
if n.Value != nil {
fmt.Fprintf(s, ", %v", n.Value)
}
fmt.Fprint(s, " =")
} }
fmt.Fprintf(s, " range %v { %v }", n.X, n.Body)
fmt.Fprintf(s, "for %.v = range %v { %v }", n.Vars, n.X, n.Body)
case OSELECT: case OSELECT:
n := n.(*SelectStmt) n := n.(*SelectStmt)
@ -475,7 +478,7 @@ func stmtFmt(n Node, s fmt.State) {
fmt.Fprintf(s, " { %v }", n.Cases) fmt.Fprintf(s, " { %v }", n.Cases)
case OCASE: case OCASE:
n := n.(*CaseStmt) n := n.(*CaseClause)
if len(n.List) != 0 { if len(n.List) != 0 {
fmt.Fprintf(s, "case %.v", n.List) fmt.Fprintf(s, "case %.v", n.List)
} else { } else {
@ -753,7 +756,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprint(s, ".<nil>") fmt.Fprint(s, ".<nil>")
return return
} }
fmt.Fprintf(s, ".%s", types.SymMethodName(n.Method.Sym)) fmt.Fprintf(s, ".%s", n.Method.Sym.Name)
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
n := n.(*SelectorExpr) n := n.(*SelectorExpr)
@ -762,7 +765,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprint(s, ".<nil>") fmt.Fprint(s, ".<nil>")
return return
} }
fmt.Fprintf(s, ".%s", types.SymMethodName(n.Sel)) fmt.Fprintf(s, ".%s", n.Sel.Name)
case ODOTTYPE, ODOTTYPE2: case ODOTTYPE, ODOTTYPE2:
n := n.(*TypeAssertExpr) n := n.(*TypeAssertExpr)
@ -782,28 +785,24 @@ func exprFmt(n Node, s fmt.State, prec int) {
n := n.(*SliceExpr) n := n.(*SliceExpr)
exprFmt(n.X, s, nprec) exprFmt(n.X, s, nprec)
fmt.Fprint(s, "[") fmt.Fprint(s, "[")
low, high, max := n.SliceBounds() if n.Low != nil {
if low != nil { fmt.Fprint(s, n.Low)
fmt.Fprint(s, low)
} }
fmt.Fprint(s, ":") fmt.Fprint(s, ":")
if high != nil { if n.High != nil {
fmt.Fprint(s, high) fmt.Fprint(s, n.High)
} }
if n.Op().IsSlice3() { if n.Op().IsSlice3() {
fmt.Fprint(s, ":") fmt.Fprint(s, ":")
if max != nil { if n.Max != nil {
fmt.Fprint(s, max) fmt.Fprint(s, n.Max)
} }
} }
fmt.Fprint(s, "]") fmt.Fprint(s, "]")
case OSLICEHEADER: case OSLICEHEADER:
n := n.(*SliceHeaderExpr) n := n.(*SliceHeaderExpr)
if len(n.LenCap) != 2 { fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Ptr, n.Len, n.Cap)
base.Fatalf("bad OSLICEHEADER list length %d", len(n.LenCap))
}
fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Ptr, n.LenCap[0], n.LenCap[1])
case OCOMPLEX, OCOPY: case OCOMPLEX, OCOPY:
n := n.(*BinaryExpr) n := n.(*BinaryExpr)

View File

@ -206,50 +206,22 @@ func (f *Func) SetWBPos(pos src.XPos) {
} }
// funcname returns the name (without the package) of the function n. // funcname returns the name (without the package) of the function n.
func FuncName(n Node) string { func FuncName(f *Func) string {
var f *Func
switch n := n.(type) {
case *Func:
f = n
case *Name:
f = n.Func
case *CallPartExpr:
f = n.Func
case *ClosureExpr:
f = n.Func
}
if f == nil || f.Nname == nil { if f == nil || f.Nname == nil {
return "<nil>" return "<nil>"
} }
return f.Nname.Sym().Name return f.Sym().Name
} }
// pkgFuncName returns the name of the function referenced by n, with package prepended. // pkgFuncName returns the name of the function referenced by n, with package prepended.
// This differs from the compiler's internal convention where local functions lack a package // This differs from the compiler's internal convention where local functions lack a package
// because the ultimate consumer of this is a human looking at an IDE; package is only empty // because the ultimate consumer of this is a human looking at an IDE; package is only empty
// if the compilation package is actually the empty string. // if the compilation package is actually the empty string.
func PkgFuncName(n Node) string { func PkgFuncName(f *Func) string {
var s *types.Sym if f == nil || f.Nname == nil {
if n == nil {
return "<nil>" return "<nil>"
} }
if n.Op() == ONAME { s := f.Sym()
s = n.Sym()
} else {
var f *Func
switch n := n.(type) {
case *CallPartExpr:
f = n.Func
case *ClosureExpr:
f = n.Func
case *Func:
f = n
}
if f == nil || f.Nname == nil {
return "<nil>"
}
s = f.Nname.Sym()
}
pkg := s.Pkg pkg := s.Pkg
p := base.Ctxt.Pkgpath p := base.Ctxt.Pkgpath

View File

@ -37,6 +37,8 @@ func main() {
nodeType := lookup("Node") nodeType := lookup("Node")
ntypeType := lookup("Ntype") ntypeType := lookup("Ntype")
nodesType := lookup("Nodes") nodesType := lookup("Nodes")
slicePtrCaseClauseType := types.NewSlice(types.NewPointer(lookup("CaseClause")))
slicePtrCommClauseType := types.NewSlice(types.NewPointer(lookup("CommClause")))
ptrFieldType := types.NewPointer(lookup("Field")) ptrFieldType := types.NewPointer(lookup("Field"))
slicePtrFieldType := types.NewSlice(ptrFieldType) slicePtrFieldType := types.NewSlice(ptrFieldType)
ptrIdentType := types.NewPointer(lookup("Ident")) ptrIdentType := types.NewPointer(lookup("Ident"))
@ -76,6 +78,10 @@ func main() {
switch { switch {
case is(nodesType): case is(nodesType):
fmt.Fprintf(&buf, "c.%s = c.%s.Copy()\n", name, name) fmt.Fprintf(&buf, "c.%s = c.%s.Copy()\n", name, name)
case is(slicePtrCaseClauseType):
fmt.Fprintf(&buf, "c.%s = copyCases(c.%s)\n", name, name)
case is(slicePtrCommClauseType):
fmt.Fprintf(&buf, "c.%s = copyComms(c.%s)\n", name, name)
case is(ptrFieldType): case is(ptrFieldType):
fmt.Fprintf(&buf, "if c.%s != nil { c.%s = c.%s.copy() }\n", name, name, name) fmt.Fprintf(&buf, "if c.%s != nil { c.%s = c.%s.copy() }\n", name, name, name)
case is(slicePtrFieldType): case is(slicePtrFieldType):
@ -94,6 +100,10 @@ func main() {
fmt.Fprintf(&buf, "err = maybeDo(n.%s, err, do)\n", name) fmt.Fprintf(&buf, "err = maybeDo(n.%s, err, do)\n", name)
case is(nodesType): case is(nodesType):
fmt.Fprintf(&buf, "err = maybeDoList(n.%s, err, do)\n", name) fmt.Fprintf(&buf, "err = maybeDoList(n.%s, err, do)\n", name)
case is(slicePtrCaseClauseType):
fmt.Fprintf(&buf, "err = maybeDoCases(n.%s, err, do)\n", name)
case is(slicePtrCommClauseType):
fmt.Fprintf(&buf, "err = maybeDoComms(n.%s, err, do)\n", name)
case is(ptrFieldType): case is(ptrFieldType):
fmt.Fprintf(&buf, "err = maybeDoField(n.%s, err, do)\n", name) fmt.Fprintf(&buf, "err = maybeDoField(n.%s, err, do)\n", name)
case is(slicePtrFieldType): case is(slicePtrFieldType):
@ -113,6 +123,10 @@ func main() {
fmt.Fprintf(&buf, "n.%s = toNtype(maybeEdit(n.%s, edit))\n", name, name) fmt.Fprintf(&buf, "n.%s = toNtype(maybeEdit(n.%s, edit))\n", name, name)
case is(nodesType): case is(nodesType):
fmt.Fprintf(&buf, "editList(n.%s, edit)\n", name) fmt.Fprintf(&buf, "editList(n.%s, edit)\n", name)
case is(slicePtrCaseClauseType):
fmt.Fprintf(&buf, "editCases(n.%s, edit)\n", name)
case is(slicePtrCommClauseType):
fmt.Fprintf(&buf, "editComms(n.%s, edit)\n", name)
case is(ptrFieldType): case is(ptrFieldType):
fmt.Fprintf(&buf, "editField(n.%s, edit)\n", name) fmt.Fprintf(&buf, "editField(n.%s, edit)\n", name)
case is(slicePtrFieldType): case is(slicePtrFieldType):
@ -155,10 +169,6 @@ func forNodeFields(typName string, typ *types.Struct, f func(name string, is fun
case "orig": case "orig":
continue continue
} }
switch typName + "." + v.Name() {
case "AddStringExpr.Alloc":
continue
}
f(v.Name(), func(t types.Type) bool { return types.Identical(t, v.Type()) }) f(v.Name(), func(t types.Type) bool { return types.Identical(t, v.Type()) })
} }
} }

View File

@ -268,7 +268,6 @@ const (
nameInlLocal // PAUTO created by inliner, derived from callee local nameInlLocal // PAUTO created by inliner, derived from callee local
nameOpenDeferSlot // if temporary var storing info for open-coded defers nameOpenDeferSlot // if temporary var storing info for open-coded defers
nameLibfuzzerExtraCounter // if PEXTERN should be assigned to __libfuzzer_extra_counters section nameLibfuzzerExtraCounter // if PEXTERN should be assigned to __libfuzzer_extra_counters section
nameIsDDD // is function argument a ...
nameAlias // is type name an alias nameAlias // is type name an alias
) )
@ -286,7 +285,6 @@ func (n *Name) InlFormal() bool { return n.flags&nameInlFormal != 0
func (n *Name) InlLocal() bool { return n.flags&nameInlLocal != 0 } func (n *Name) InlLocal() bool { return n.flags&nameInlLocal != 0 }
func (n *Name) OpenDeferSlot() bool { return n.flags&nameOpenDeferSlot != 0 } func (n *Name) OpenDeferSlot() bool { return n.flags&nameOpenDeferSlot != 0 }
func (n *Name) LibfuzzerExtraCounter() bool { return n.flags&nameLibfuzzerExtraCounter != 0 } func (n *Name) LibfuzzerExtraCounter() bool { return n.flags&nameLibfuzzerExtraCounter != 0 }
func (n *Name) IsDDD() bool { return n.flags&nameIsDDD != 0 }
func (n *Name) SetCaptured(b bool) { n.flags.set(nameCaptured, b) } func (n *Name) SetCaptured(b bool) { n.flags.set(nameCaptured, b) }
func (n *Name) setReadonly(b bool) { n.flags.set(nameReadonly, b) } func (n *Name) setReadonly(b bool) { n.flags.set(nameReadonly, b) }
@ -302,7 +300,6 @@ func (n *Name) SetInlFormal(b bool) { n.flags.set(nameInlFormal, b)
func (n *Name) SetInlLocal(b bool) { n.flags.set(nameInlLocal, b) } func (n *Name) SetInlLocal(b bool) { n.flags.set(nameInlLocal, b) }
func (n *Name) SetOpenDeferSlot(b bool) { n.flags.set(nameOpenDeferSlot, b) } func (n *Name) SetOpenDeferSlot(b bool) { n.flags.set(nameOpenDeferSlot, b) }
func (n *Name) SetLibfuzzerExtraCounter(b bool) { n.flags.set(nameLibfuzzerExtraCounter, b) } func (n *Name) SetLibfuzzerExtraCounter(b bool) { n.flags.set(nameLibfuzzerExtraCounter, b) }
func (n *Name) SetIsDDD(b bool) { n.flags.set(nameIsDDD, b) }
// MarkReadonly indicates that n is an ONAME with readonly contents. // MarkReadonly indicates that n is an ONAME with readonly contents.
func (n *Name) MarkReadonly() { func (n *Name) MarkReadonly() {

View File

@ -226,29 +226,26 @@ func (n *CallPartExpr) editChildren(edit func(Node) Node) {
n.X = maybeEdit(n.X, edit) n.X = maybeEdit(n.X, edit)
} }
func (n *CaseStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } func (n *CaseClause) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
func (n *CaseStmt) copy() Node { func (n *CaseClause) copy() Node {
c := *n c := *n
c.init = c.init.Copy() c.init = c.init.Copy()
c.Vars = c.Vars.Copy()
c.List = c.List.Copy() c.List = c.List.Copy()
c.Body = c.Body.Copy() c.Body = c.Body.Copy()
return &c return &c
} }
func (n *CaseStmt) doChildren(do func(Node) error) error { func (n *CaseClause) doChildren(do func(Node) error) error {
var err error var err error
err = maybeDoList(n.init, err, do) err = maybeDoList(n.init, err, do)
err = maybeDoList(n.Vars, err, do) err = maybeDo(n.Var, err, do)
err = maybeDoList(n.List, err, do) err = maybeDoList(n.List, err, do)
err = maybeDo(n.Comm, err, do)
err = maybeDoList(n.Body, err, do) err = maybeDoList(n.Body, err, do)
return err return err
} }
func (n *CaseStmt) editChildren(edit func(Node) Node) { func (n *CaseClause) editChildren(edit func(Node) Node) {
editList(n.init, edit) editList(n.init, edit)
editList(n.Vars, edit) n.Var = maybeEdit(n.Var, edit)
editList(n.List, edit) editList(n.List, edit)
n.Comm = maybeEdit(n.Comm, edit)
editList(n.Body, edit) editList(n.Body, edit)
} }
@ -296,6 +293,26 @@ func (n *ClosureReadExpr) editChildren(edit func(Node) Node) {
editList(n.init, edit) editList(n.init, edit)
} }
func (n *CommClause) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
func (n *CommClause) copy() Node {
c := *n
c.init = c.init.Copy()
c.Body = c.Body.Copy()
return &c
}
func (n *CommClause) doChildren(do func(Node) error) error {
var err error
err = maybeDoList(n.init, err, do)
err = maybeDo(n.Comm, err, do)
err = maybeDoList(n.Body, err, do)
return err
}
func (n *CommClause) editChildren(edit func(Node) Node) {
editList(n.init, edit)
n.Comm = maybeEdit(n.Comm, edit)
editList(n.Body, edit)
}
func (n *CompLitExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } func (n *CompLitExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
func (n *CompLitExpr) copy() Node { func (n *CompLitExpr) copy() Node {
c := *n c := *n
@ -725,22 +742,23 @@ func (n *RangeStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
func (n *RangeStmt) copy() Node { func (n *RangeStmt) copy() Node {
c := *n c := *n
c.init = c.init.Copy() c.init = c.init.Copy()
c.Vars = c.Vars.Copy()
c.Body = c.Body.Copy() c.Body = c.Body.Copy()
return &c return &c
} }
func (n *RangeStmt) doChildren(do func(Node) error) error { func (n *RangeStmt) doChildren(do func(Node) error) error {
var err error var err error
err = maybeDoList(n.init, err, do) err = maybeDoList(n.init, err, do)
err = maybeDoList(n.Vars, err, do)
err = maybeDo(n.X, err, do) err = maybeDo(n.X, err, do)
err = maybeDo(n.Key, err, do)
err = maybeDo(n.Value, err, do)
err = maybeDoList(n.Body, err, do) err = maybeDoList(n.Body, err, do)
return err return err
} }
func (n *RangeStmt) editChildren(edit func(Node) Node) { func (n *RangeStmt) editChildren(edit func(Node) Node) {
editList(n.init, edit) editList(n.init, edit)
editList(n.Vars, edit)
n.X = maybeEdit(n.X, edit) n.X = maybeEdit(n.X, edit)
n.Key = maybeEdit(n.Key, edit)
n.Value = maybeEdit(n.Value, edit)
editList(n.Body, edit) editList(n.Body, edit)
} }
@ -781,20 +799,20 @@ func (n *SelectStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
func (n *SelectStmt) copy() Node { func (n *SelectStmt) copy() Node {
c := *n c := *n
c.init = c.init.Copy() c.init = c.init.Copy()
c.Cases = c.Cases.Copy() c.Cases = copyComms(c.Cases)
c.Compiled = c.Compiled.Copy() c.Compiled = c.Compiled.Copy()
return &c return &c
} }
func (n *SelectStmt) doChildren(do func(Node) error) error { func (n *SelectStmt) doChildren(do func(Node) error) error {
var err error var err error
err = maybeDoList(n.init, err, do) err = maybeDoList(n.init, err, do)
err = maybeDoList(n.Cases, err, do) err = maybeDoComms(n.Cases, err, do)
err = maybeDoList(n.Compiled, err, do) err = maybeDoList(n.Compiled, err, do)
return err return err
} }
func (n *SelectStmt) editChildren(edit func(Node) Node) { func (n *SelectStmt) editChildren(edit func(Node) Node) {
editList(n.init, edit) editList(n.init, edit)
editList(n.Cases, edit) editComms(n.Cases, edit)
editList(n.Compiled, edit) editList(n.Compiled, edit)
} }
@ -838,40 +856,44 @@ func (n *SliceExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
func (n *SliceExpr) copy() Node { func (n *SliceExpr) copy() Node {
c := *n c := *n
c.init = c.init.Copy() c.init = c.init.Copy()
c.List = c.List.Copy()
return &c return &c
} }
func (n *SliceExpr) doChildren(do func(Node) error) error { func (n *SliceExpr) doChildren(do func(Node) error) error {
var err error var err error
err = maybeDoList(n.init, err, do) err = maybeDoList(n.init, err, do)
err = maybeDo(n.X, err, do) err = maybeDo(n.X, err, do)
err = maybeDoList(n.List, err, do) err = maybeDo(n.Low, err, do)
err = maybeDo(n.High, err, do)
err = maybeDo(n.Max, err, do)
return err return err
} }
func (n *SliceExpr) editChildren(edit func(Node) Node) { func (n *SliceExpr) editChildren(edit func(Node) Node) {
editList(n.init, edit) editList(n.init, edit)
n.X = maybeEdit(n.X, edit) n.X = maybeEdit(n.X, edit)
editList(n.List, edit) n.Low = maybeEdit(n.Low, edit)
n.High = maybeEdit(n.High, edit)
n.Max = maybeEdit(n.Max, edit)
} }
func (n *SliceHeaderExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } func (n *SliceHeaderExpr) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
func (n *SliceHeaderExpr) copy() Node { func (n *SliceHeaderExpr) copy() Node {
c := *n c := *n
c.init = c.init.Copy() c.init = c.init.Copy()
c.LenCap = c.LenCap.Copy()
return &c return &c
} }
func (n *SliceHeaderExpr) doChildren(do func(Node) error) error { func (n *SliceHeaderExpr) doChildren(do func(Node) error) error {
var err error var err error
err = maybeDoList(n.init, err, do) err = maybeDoList(n.init, err, do)
err = maybeDo(n.Ptr, err, do) err = maybeDo(n.Ptr, err, do)
err = maybeDoList(n.LenCap, err, do) err = maybeDo(n.Len, err, do)
err = maybeDo(n.Cap, err, do)
return err return err
} }
func (n *SliceHeaderExpr) editChildren(edit func(Node) Node) { func (n *SliceHeaderExpr) editChildren(edit func(Node) Node) {
editList(n.init, edit) editList(n.init, edit)
n.Ptr = maybeEdit(n.Ptr, edit) n.Ptr = maybeEdit(n.Ptr, edit)
editList(n.LenCap, edit) n.Len = maybeEdit(n.Len, edit)
n.Cap = maybeEdit(n.Cap, edit)
} }
func (n *SliceType) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) } func (n *SliceType) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
@ -941,7 +963,7 @@ func (n *SwitchStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
func (n *SwitchStmt) copy() Node { func (n *SwitchStmt) copy() Node {
c := *n c := *n
c.init = c.init.Copy() c.init = c.init.Copy()
c.Cases = c.Cases.Copy() c.Cases = copyCases(c.Cases)
c.Compiled = c.Compiled.Copy() c.Compiled = c.Compiled.Copy()
return &c return &c
} }
@ -949,14 +971,14 @@ func (n *SwitchStmt) doChildren(do func(Node) error) error {
var err error var err error
err = maybeDoList(n.init, err, do) err = maybeDoList(n.init, err, do)
err = maybeDo(n.Tag, err, do) err = maybeDo(n.Tag, err, do)
err = maybeDoList(n.Cases, err, do) err = maybeDoCases(n.Cases, err, do)
err = maybeDoList(n.Compiled, err, do) err = maybeDoList(n.Compiled, err, do)
return err return err
} }
func (n *SwitchStmt) editChildren(edit func(Node) Node) { func (n *SwitchStmt) editChildren(edit func(Node) Node) {
editList(n.init, edit) editList(n.init, edit)
n.Tag = maybeEdit(n.Tag, edit) n.Tag = maybeEdit(n.Tag, edit)
editList(n.Cases, edit) editCases(n.Cases, edit)
editList(n.Compiled, edit) editList(n.Compiled, edit)
} }

View File

@ -76,48 +76,27 @@ func (v *bottomUpVisitor) visit(n *Func) uint32 {
min := v.visitgen min := v.visitgen
v.stack = append(v.stack, n) v.stack = append(v.stack, n)
do := func(defn Node) {
if defn != nil {
if m := v.visit(defn.(*Func)); m < min {
min = m
}
}
}
Visit(n, func(n Node) { Visit(n, func(n Node) {
switch n.Op() { switch n.Op() {
case ONAME: case ONAME:
n := n.(*Name) if n := n.(*Name); n.Class_ == PFUNC {
if n.Class_ == PFUNC { do(n.Defn)
if n != nil && n.Name().Defn != nil {
if m := v.visit(n.Name().Defn.(*Func)); m < min {
min = m
}
}
} }
case OMETHEXPR: case ODOTMETH, OCALLPART, OMETHEXPR:
n := n.(*MethodExpr) if fn := MethodExprName(n); fn != nil {
fn := MethodExprName(n) do(fn.Defn)
if fn != nil && fn.Defn != nil {
if m := v.visit(fn.Defn.(*Func)); m < min {
min = m
}
}
case ODOTMETH:
n := n.(*SelectorExpr)
fn := MethodExprName(n)
if fn != nil && fn.Op() == ONAME && fn.Class_ == PFUNC && fn.Defn != nil {
if m := v.visit(fn.Defn.(*Func)); m < min {
min = m
}
}
case OCALLPART:
n := n.(*CallPartExpr)
fn := AsNode(n.Method.Nname)
if fn != nil && fn.Op() == ONAME {
if fn := fn.(*Name); fn.Class_ == PFUNC && fn.Name().Defn != nil {
if m := v.visit(fn.Name().Defn.(*Func)); m < min {
min = m
}
}
} }
case OCLOSURE: case OCLOSURE:
n := n.(*ClosureExpr) n := n.(*ClosureExpr)
if m := v.visit(n.Func); m < min { do(n.Func)
min = m
}
} }
}) })

View File

@ -173,24 +173,94 @@ func NewBranchStmt(pos src.XPos, op Op, label *types.Sym) *BranchStmt {
func (n *BranchStmt) Sym() *types.Sym { return n.Label } func (n *BranchStmt) Sym() *types.Sym { return n.Label }
// A CaseStmt is a case statement in a switch or select: case List: Body. // A CaseClause is a case statement in a switch or select: case List: Body.
type CaseStmt struct { type CaseClause struct {
miniStmt miniStmt
Vars Nodes // declared variable for this case in type switch Var Node // declared variable for this case in type switch
List Nodes // list of expressions for switch, early select List Nodes // list of expressions for switch, early select
Comm Node // communication case (Exprs[0]) after select is type-checked
Body Nodes Body Nodes
} }
func NewCaseStmt(pos src.XPos, list, body []Node) *CaseStmt { func NewCaseStmt(pos src.XPos, list, body []Node) *CaseClause {
n := &CaseStmt{} n := &CaseClause{List: list, Body: body}
n.pos = pos n.pos = pos
n.op = OCASE n.op = OCASE
n.List.Set(list)
n.Body.Set(body)
return n return n
} }
// TODO(mdempsky): Generate these with mknode.go.
func copyCases(list []*CaseClause) []*CaseClause {
if list == nil {
return nil
}
c := make([]*CaseClause, len(list))
copy(c, list)
return c
}
func maybeDoCases(list []*CaseClause, err error, do func(Node) error) error {
if err != nil {
return err
}
for _, x := range list {
if x != nil {
if err := do(x); err != nil {
return err
}
}
}
return nil
}
func editCases(list []*CaseClause, edit func(Node) Node) {
for i, x := range list {
if x != nil {
list[i] = edit(x).(*CaseClause)
}
}
}
type CommClause struct {
miniStmt
Comm Node // communication case
Body Nodes
}
func NewCommStmt(pos src.XPos, comm Node, body []Node) *CommClause {
n := &CommClause{Comm: comm, Body: body}
n.pos = pos
n.op = OCASE
return n
}
// TODO(mdempsky): Generate these with mknode.go.
func copyComms(list []*CommClause) []*CommClause {
if list == nil {
return nil
}
c := make([]*CommClause, len(list))
copy(c, list)
return c
}
func maybeDoComms(list []*CommClause, err error, do func(Node) error) error {
if err != nil {
return err
}
for _, x := range list {
if x != nil {
if err := do(x); err != nil {
return err
}
}
}
return nil
}
func editComms(list []*CommClause, edit func(Node) Node) {
for i, x := range list {
if x != nil {
list[i] = edit(x).(*CommClause)
}
}
}
// A ForStmt is a non-range for loop: for Init; Cond; Post { Body } // A ForStmt is a non-range for loop: for Init; Cond; Post { Body }
// Op can be OFOR or OFORUNTIL (!Cond). // Op can be OFOR or OFORUNTIL (!Cond).
type ForStmt struct { type ForStmt struct {
@ -203,11 +273,13 @@ type ForStmt struct {
HasBreak bool HasBreak bool
} }
func NewForStmt(pos src.XPos, init []Node, cond, post Node, body []Node) *ForStmt { func NewForStmt(pos src.XPos, init Node, cond, post Node, body []Node) *ForStmt {
n := &ForStmt{Cond: cond, Post: post} n := &ForStmt{Cond: cond, Post: post}
n.pos = pos n.pos = pos
n.op = OFOR n.op = OFOR
n.init.Set(init) if init != nil {
n.init = []Node{init}
}
n.Body.Set(body) n.Body.Set(body)
return n return n
} }
@ -290,32 +362,27 @@ func NewLabelStmt(pos src.XPos, label *types.Sym) *LabelStmt {
func (n *LabelStmt) Sym() *types.Sym { return n.Label } func (n *LabelStmt) Sym() *types.Sym { return n.Label }
// A RangeStmt is a range loop: for Vars = range X { Stmts } // A RangeStmt is a range loop: for Key, Value = range X { Body }
// Op can be OFOR or OFORUNTIL (!Cond).
type RangeStmt struct { type RangeStmt struct {
miniStmt miniStmt
Label *types.Sym Label *types.Sym
Vars Nodes // TODO(rsc): Replace with Key, Value Node
Def bool Def bool
X Node X Node
Key Node
Value Node
Body Nodes Body Nodes
HasBreak bool HasBreak bool
typ *types.Type // TODO(rsc): Remove - use X.Type() instead
Prealloc *Name Prealloc *Name
} }
func NewRangeStmt(pos src.XPos, vars []Node, x Node, body []Node) *RangeStmt { func NewRangeStmt(pos src.XPos, key, value, x Node, body []Node) *RangeStmt {
n := &RangeStmt{X: x} n := &RangeStmt{X: x, Key: key, Value: value}
n.pos = pos n.pos = pos
n.op = ORANGE n.op = ORANGE
n.Vars.Set(vars)
n.Body.Set(body) n.Body.Set(body)
return n return n
} }
func (n *RangeStmt) Type() *types.Type { return n.typ }
func (n *RangeStmt) SetType(x *types.Type) { n.typ = x }
// A ReturnStmt is a return statement. // A ReturnStmt is a return statement.
type ReturnStmt struct { type ReturnStmt struct {
miniStmt miniStmt
@ -339,18 +406,17 @@ func (n *ReturnStmt) SetOrig(x Node) { n.orig = x }
type SelectStmt struct { type SelectStmt struct {
miniStmt miniStmt
Label *types.Sym Label *types.Sym
Cases Nodes Cases []*CommClause
HasBreak bool HasBreak bool
// TODO(rsc): Instead of recording here, replace with a block? // TODO(rsc): Instead of recording here, replace with a block?
Compiled Nodes // compiled form, after walkswitch Compiled Nodes // compiled form, after walkswitch
} }
func NewSelectStmt(pos src.XPos, cases []Node) *SelectStmt { func NewSelectStmt(pos src.XPos, cases []*CommClause) *SelectStmt {
n := &SelectStmt{} n := &SelectStmt{Cases: cases}
n.pos = pos n.pos = pos
n.op = OSELECT n.op = OSELECT
n.Cases.Set(cases)
return n return n
} }
@ -372,7 +438,7 @@ func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt {
type SwitchStmt struct { type SwitchStmt struct {
miniStmt miniStmt
Tag Node Tag Node
Cases Nodes // list of *CaseStmt Cases []*CaseClause
Label *types.Sym Label *types.Sym
HasBreak bool HasBreak bool
@ -380,11 +446,10 @@ type SwitchStmt struct {
Compiled Nodes // compiled form, after walkswitch Compiled Nodes // compiled form, after walkswitch
} }
func NewSwitchStmt(pos src.XPos, tag Node, cases []Node) *SwitchStmt { func NewSwitchStmt(pos src.XPos, tag Node, cases []*CaseClause) *SwitchStmt {
n := &SwitchStmt{Tag: tag} n := &SwitchStmt{Tag: tag, Cases: cases}
n.pos = pos n.pos = pos
n.op = OSWITCH n.op = OSWITCH
n.Cases.Set(cases)
return n return n
} }

View File

@ -115,14 +115,6 @@ func (n *StructType) SetOTYPE(t *types.Type) {
n.Fields = nil n.Fields = nil
} }
func deepCopyFields(pos src.XPos, fields []*Field) []*Field {
var out []*Field
for _, f := range fields {
out = append(out, f.deepCopy(pos))
}
return out
}
// An InterfaceType represents a struct { ... } type syntax. // An InterfaceType represents a struct { ... } type syntax.
type InterfaceType struct { type InterfaceType struct {
miniType miniType
@ -250,26 +242,6 @@ func editFields(list []*Field, edit func(Node) Node) {
} }
} }
func (f *Field) deepCopy(pos src.XPos) *Field {
if f == nil {
return nil
}
fpos := pos
if !pos.IsKnown() {
fpos = f.Pos
}
decl := f.Decl
if decl != nil {
decl = DeepCopy(pos, decl).(*Name)
}
ntype := f.Ntype
if ntype != nil {
ntype = DeepCopy(pos, ntype).(Ntype)
}
// No keyed literal here: if a new struct field is added, we want this to stop compiling.
return &Field{fpos, f.Sym, ntype, f.Type, f.Embedded, f.IsDDD, f.Note, decl}
}
// A SliceType represents a []Elem type syntax. // A SliceType represents a []Elem type syntax.
// If DDD is true, it's the ...Elem at the end of a function list. // If DDD is true, it's the ...Elem at the end of a function list.
type SliceType struct { type SliceType struct {

View File

@ -217,10 +217,9 @@ func EditChildren(n Node, edit func(Node) Node) {
// Note that editList only calls edit on the nodes in the list, not their children. // Note that editList only calls edit on the nodes in the list, not their children.
// If x's children should be processed, edit(x) must call EditChildren(x, edit) itself. // If x's children should be processed, edit(x) must call EditChildren(x, edit) itself.
func editList(list Nodes, edit func(Node) Node) { func editList(list Nodes, edit func(Node) Node) {
s := list
for i, x := range list { for i, x := range list {
if x != nil { if x != nil {
s[i] = edit(x) list[i] = edit(x)
} }
} }
} }

View File

@ -24,6 +24,7 @@ import (
"cmd/compile/internal/ir" "cmd/compile/internal/ir"
"cmd/compile/internal/objw" "cmd/compile/internal/objw"
"cmd/compile/internal/ssa" "cmd/compile/internal/ssa"
"cmd/compile/internal/typebits"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/objabi" "cmd/internal/objabi"
@ -179,11 +180,7 @@ type progeffectscache struct {
// nor do we care about non-local variables, // nor do we care about non-local variables,
// nor do we care about empty structs (handled by the pointer check), // nor do we care about empty structs (handled by the pointer check),
// nor do we care about the fake PAUTOHEAP variables. // nor do we care about the fake PAUTOHEAP variables.
func ShouldTrack(nn ir.Node) bool { func ShouldTrack(n *ir.Name) bool {
if nn.Op() != ir.ONAME {
return false
}
n := nn.(*ir.Name)
return (n.Class_ == ir.PAUTO || n.Class_ == ir.PPARAM || n.Class_ == ir.PPARAMOUT) && n.Type().HasPointers() return (n.Class_ == ir.PAUTO || n.Class_ == ir.PPARAM || n.Class_ == ir.PPARAMOUT) && n.Type().HasPointers()
} }
@ -248,19 +245,17 @@ const (
// liveness effects v has on that variable. // liveness effects v has on that variable.
// If v does not affect any tracked variables, it returns -1, 0. // If v does not affect any tracked variables, it returns -1, 0.
func (lv *liveness) valueEffects(v *ssa.Value) (int32, liveEffect) { func (lv *liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
n, e := affectedNode(v) n, e := affectedVar(v)
if e == 0 || n == nil || n.Op() != ir.ONAME { // cheapest checks first if e == 0 || n == nil { // cheapest checks first
return -1, 0 return -1, 0
} }
nn := n.(*ir.Name)
// AllocFrame has dropped unused variables from // AllocFrame has dropped unused variables from
// lv.fn.Func.Dcl, but they might still be referenced by // lv.fn.Func.Dcl, but they might still be referenced by
// OpVarFoo pseudo-ops. Ignore them to prevent "lost track of // OpVarFoo pseudo-ops. Ignore them to prevent "lost track of
// variable" ICEs (issue 19632). // variable" ICEs (issue 19632).
switch v.Op { switch v.Op {
case ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive: case ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive:
if !nn.Name().Used() { if !n.Name().Used() {
return -1, 0 return -1, 0
} }
} }
@ -283,14 +278,14 @@ func (lv *liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
return -1, 0 return -1, 0
} }
if pos, ok := lv.idx[nn]; ok { if pos, ok := lv.idx[n]; ok {
return pos, effect return pos, effect
} }
return -1, 0 return -1, 0
} }
// affectedNode returns the *Node affected by v // affectedVar returns the *ir.Name node affected by v
func affectedNode(v *ssa.Value) (ir.Node, ssa.SymEffect) { func affectedVar(v *ssa.Value) (*ir.Name, ssa.SymEffect) {
// Special cases. // Special cases.
switch v.Op { switch v.Op {
case ssa.OpLoadReg: case ssa.OpLoadReg:
@ -381,82 +376,6 @@ func (lv *liveness) blockEffects(b *ssa.Block) *blockEffects {
return &lv.be[b.ID] return &lv.be[b.ID]
} }
// NOTE: The bitmap for a specific type t could be cached in t after
// the first run and then simply copied into bv at the correct offset
// on future calls with the same type t.
func SetTypeBits(t *types.Type, off int64, bv bitvec.BitVec) {
if t.Align > 0 && off&int64(t.Align-1) != 0 {
base.Fatalf("onebitwalktype1: invalid initial alignment: type %v has alignment %d, but offset is %v", t, t.Align, off)
}
if !t.HasPointers() {
// Note: this case ensures that pointers to go:notinheap types
// are not considered pointers by garbage collection and stack copying.
return
}
switch t.Kind() {
case types.TPTR, types.TUNSAFEPTR, types.TFUNC, types.TCHAN, types.TMAP:
if off&int64(types.PtrSize-1) != 0 {
base.Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
bv.Set(int32(off / int64(types.PtrSize))) // pointer
case types.TSTRING:
// struct { byte *str; intgo len; }
if off&int64(types.PtrSize-1) != 0 {
base.Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
bv.Set(int32(off / int64(types.PtrSize))) //pointer in first slot
case types.TINTER:
// struct { Itab *tab; void *data; }
// or, when isnilinter(t)==true:
// struct { Type *type; void *data; }
if off&int64(types.PtrSize-1) != 0 {
base.Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
// The first word of an interface is a pointer, but we don't
// treat it as such.
// 1. If it is a non-empty interface, the pointer points to an itab
// which is always in persistentalloc space.
// 2. If it is an empty interface, the pointer points to a _type.
// a. If it is a compile-time-allocated type, it points into
// the read-only data section.
// b. If it is a reflect-allocated type, it points into the Go heap.
// Reflect is responsible for keeping a reference to
// the underlying type so it won't be GCd.
// If we ever have a moving GC, we need to change this for 2b (as
// well as scan itabs to update their itab._type fields).
bv.Set(int32(off/int64(types.PtrSize) + 1)) // pointer in second slot
case types.TSLICE:
// struct { byte *array; uintgo len; uintgo cap; }
if off&int64(types.PtrSize-1) != 0 {
base.Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t)
}
bv.Set(int32(off / int64(types.PtrSize))) // pointer in first slot (BitsPointer)
case types.TARRAY:
elt := t.Elem()
if elt.Width == 0 {
// Short-circuit for #20739.
break
}
for i := int64(0); i < t.NumElem(); i++ {
SetTypeBits(elt, off, bv)
off += elt.Width
}
case types.TSTRUCT:
for _, f := range t.Fields().Slice() {
SetTypeBits(f.Type, off+f.Offset, bv)
}
default:
base.Fatalf("onebitwalktype1: unexpected type, %v", t)
}
}
// Generates live pointer value maps for arguments and local variables. The // Generates live pointer value maps for arguments and local variables. The
// this argument and the in arguments are always assumed live. The vars // this argument and the in arguments are always assumed live. The vars
// argument is a slice of *Nodes. // argument is a slice of *Nodes.
@ -469,10 +388,10 @@ func (lv *liveness) pointerMap(liveout bitvec.BitVec, vars []*ir.Name, args, loc
node := vars[i] node := vars[i]
switch node.Class_ { switch node.Class_ {
case ir.PAUTO: case ir.PAUTO:
SetTypeBits(node.Type(), node.FrameOffset()+lv.stkptrsize, locals) typebits.Set(node.Type(), node.FrameOffset()+lv.stkptrsize, locals)
case ir.PPARAM, ir.PPARAMOUT: case ir.PPARAM, ir.PPARAMOUT:
SetTypeBits(node.Type(), node.FrameOffset(), args) typebits.Set(node.Type(), node.FrameOffset(), args)
} }
} }
} }
@ -1315,15 +1234,15 @@ func WriteFuncMap(fn *ir.Func) {
off = objw.Uint32(lsym, off, uint32(bv.N)) off = objw.Uint32(lsym, off, uint32(bv.N))
if ir.IsMethod(fn) { if ir.IsMethod(fn) {
SetTypeBits(fn.Type().Recvs(), 0, bv) typebits.Set(fn.Type().Recvs(), 0, bv)
} }
if fn.Type().NumParams() > 0 { if fn.Type().NumParams() > 0 {
SetTypeBits(fn.Type().Params(), 0, bv) typebits.Set(fn.Type().Params(), 0, bv)
} }
off = objw.BitVec(lsym, off, bv) off = objw.BitVec(lsym, off, bv)
if fn.Type().NumResults() > 0 { if fn.Type().NumResults() > 0 {
SetTypeBits(fn.Type().Results(), 0, bv) typebits.Set(fn.Type().Results(), 0, bv)
off = objw.BitVec(lsym, off, bv) off = objw.BitVec(lsym, off, bv)
} }

View File

@ -510,11 +510,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
func (p *noder) varDecl(decl *syntax.VarDecl) []ir.Node { func (p *noder) varDecl(decl *syntax.VarDecl) []ir.Node {
names := p.declNames(ir.ONAME, decl.NameList) names := p.declNames(ir.ONAME, decl.NameList)
typ := p.typeExprOrNil(decl.Type) typ := p.typeExprOrNil(decl.Type)
exprs := p.exprList(decl.Values)
var exprs []ir.Node
if decl.Values != nil {
exprs = p.exprList(decl.Values)
}
if pragma, ok := decl.Pragma.(*pragmas); ok { if pragma, ok := decl.Pragma.(*pragmas); ok {
if len(pragma.Embeds) > 0 { if len(pragma.Embeds) > 0 {
@ -753,10 +749,14 @@ func (p *noder) param(param *syntax.Field, dddOk, final bool) *ir.Field {
} }
func (p *noder) exprList(expr syntax.Expr) []ir.Node { func (p *noder) exprList(expr syntax.Expr) []ir.Node {
if list, ok := expr.(*syntax.ListExpr); ok { switch expr := expr.(type) {
return p.exprs(list.ElemList) case nil:
return nil
case *syntax.ListExpr:
return p.exprs(expr.ElemList)
default:
return []ir.Node{p.expr(expr)}
} }
return []ir.Node{p.expr(expr)}
} }
func (p *noder) exprs(exprs []syntax.Expr) []ir.Node { func (p *noder) exprs(exprs []syntax.Expr) []ir.Node {
@ -775,17 +775,14 @@ func (p *noder) expr(expr syntax.Expr) ir.Node {
case *syntax.Name: case *syntax.Name:
return p.mkname(expr) return p.mkname(expr)
case *syntax.BasicLit: case *syntax.BasicLit:
n := ir.NewLiteral(p.basicLit(expr)) n := ir.NewBasicLit(p.pos(expr), p.basicLit(expr))
if expr.Kind == syntax.RuneLit { if expr.Kind == syntax.RuneLit {
n.SetType(types.UntypedRune) n.SetType(types.UntypedRune)
} }
n.SetDiag(expr.Bad) // avoid follow-on errors if there was a syntax error n.SetDiag(expr.Bad) // avoid follow-on errors if there was a syntax error
return n return n
case *syntax.CompositeLit: case *syntax.CompositeLit:
n := ir.NewCompLitExpr(p.pos(expr), ir.OCOMPLIT, nil, nil) n := ir.NewCompLitExpr(p.pos(expr), ir.OCOMPLIT, p.typeExpr(expr.Type), nil)
if expr.Type != nil {
n.Ntype = ir.Node(p.expr(expr.Type)).(ir.Ntype)
}
l := p.exprs(expr.ElemList) l := p.exprs(expr.ElemList)
for i, e := range l { for i, e := range l {
l[i] = p.wrapname(expr.ElemList[i], e) l[i] = p.wrapname(expr.ElemList[i], e)
@ -818,17 +815,16 @@ func (p *noder) expr(expr syntax.Expr) ir.Node {
if expr.Full { if expr.Full {
op = ir.OSLICE3 op = ir.OSLICE3
} }
n := ir.NewSliceExpr(p.pos(expr), op, p.expr(expr.X)) x := p.expr(expr.X)
var index [3]ir.Node var index [3]ir.Node
for i, x := range &expr.Index { for i, n := range &expr.Index {
if x != nil { if n != nil {
index[i] = p.expr(x) index[i] = p.expr(n)
} }
} }
n.SetSliceBounds(index[0], index[1], index[2]) return ir.NewSliceExpr(p.pos(expr), op, x, index[0], index[1], index[2])
return n
case *syntax.AssertExpr: case *syntax.AssertExpr:
return ir.NewTypeAssertExpr(p.pos(expr), p.expr(expr.X), p.typeExpr(expr.Type).(ir.Ntype)) return ir.NewTypeAssertExpr(p.pos(expr), p.expr(expr.X), p.typeExpr(expr.Type))
case *syntax.Operation: case *syntax.Operation:
if expr.Op == syntax.Add && expr.Y != nil { if expr.Op == syntax.Add && expr.Y != nil {
return p.sum(expr) return p.sum(expr)
@ -852,8 +848,7 @@ func (p *noder) expr(expr syntax.Expr) ir.Node {
} }
return ir.NewBinaryExpr(pos, op, x, y) return ir.NewBinaryExpr(pos, op, x, y)
case *syntax.CallExpr: case *syntax.CallExpr:
n := ir.NewCallExpr(p.pos(expr), ir.OCALL, p.expr(expr.Fun), nil) n := ir.NewCallExpr(p.pos(expr), ir.OCALL, p.expr(expr.Fun), p.exprs(expr.ArgList))
n.Args.Set(p.exprs(expr.ArgList))
n.IsDDD = expr.HasDots n.IsDDD = expr.HasDots
return n return n
@ -1120,7 +1115,7 @@ func (p *noder) stmt(stmt syntax.Stmt) ir.Node {
func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node { func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node {
p.setlineno(stmt) p.setlineno(stmt)
switch stmt := stmt.(type) { switch stmt := stmt.(type) {
case *syntax.EmptyStmt: case nil, *syntax.EmptyStmt:
return nil return nil
case *syntax.LabeledStmt: case *syntax.LabeledStmt:
return p.labeledStmt(stmt, fallOK) return p.labeledStmt(stmt, fallOK)
@ -1193,12 +1188,7 @@ func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) ir.Node {
} }
return ir.NewGoDeferStmt(p.pos(stmt), op, p.expr(stmt.Call)) return ir.NewGoDeferStmt(p.pos(stmt), op, p.expr(stmt.Call))
case *syntax.ReturnStmt: case *syntax.ReturnStmt:
var results []ir.Node n := ir.NewReturnStmt(p.pos(stmt), p.exprList(stmt.Results))
if stmt.Results != nil {
results = p.exprList(stmt.Results)
}
n := ir.NewReturnStmt(p.pos(stmt), nil)
n.Results.Set(results)
if len(n.Results) == 0 && ir.CurFunc != nil { if len(n.Results) == 0 && ir.CurFunc != nil {
for _, ln := range ir.CurFunc.Dcl { for _, ln := range ir.CurFunc.Dcl {
if ln.Class_ == ir.PPARAM { if ln.Class_ == ir.PPARAM {
@ -1292,14 +1282,11 @@ func (p *noder) blockStmt(stmt *syntax.BlockStmt) []ir.Node {
func (p *noder) ifStmt(stmt *syntax.IfStmt) ir.Node { func (p *noder) ifStmt(stmt *syntax.IfStmt) ir.Node {
p.openScope(stmt.Pos()) p.openScope(stmt.Pos())
n := ir.NewIfStmt(p.pos(stmt), nil, nil, nil) init := p.stmt(stmt.Init)
if stmt.Init != nil { n := ir.NewIfStmt(p.pos(stmt), p.expr(stmt.Cond), p.blockStmt(stmt.Then), nil)
*n.PtrInit() = []ir.Node{p.stmt(stmt.Init)} if init != nil {
*n.PtrInit() = []ir.Node{init}
} }
if stmt.Cond != nil {
n.Cond = p.expr(stmt.Cond)
}
n.Body.Set(p.blockStmt(stmt.Then))
if stmt.Else != nil { if stmt.Else != nil {
e := p.stmt(stmt.Else) e := p.stmt(stmt.Else)
if e.Op() == ir.OBLOCK { if e.Op() == ir.OBLOCK {
@ -1320,53 +1307,46 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) ir.Node {
panic("unexpected RangeClause") panic("unexpected RangeClause")
} }
n := ir.NewRangeStmt(p.pos(r), nil, p.expr(r.X), nil) n := ir.NewRangeStmt(p.pos(r), nil, nil, p.expr(r.X), nil)
if r.Lhs != nil { if r.Lhs != nil {
n.Def = r.Def n.Def = r.Def
n.Vars.Set(p.assignList(r.Lhs, n, n.Def)) lhs := p.assignList(r.Lhs, n, n.Def)
n.Key = lhs[0]
if len(lhs) > 1 {
n.Value = lhs[1]
}
} }
n.Body.Set(p.blockStmt(stmt.Body)) n.Body.Set(p.blockStmt(stmt.Body))
p.closeAnotherScope() p.closeAnotherScope()
return n return n
} }
n := ir.NewForStmt(p.pos(stmt), nil, nil, nil, nil) n := ir.NewForStmt(p.pos(stmt), p.stmt(stmt.Init), p.expr(stmt.Cond), p.stmt(stmt.Post), p.blockStmt(stmt.Body))
if stmt.Init != nil {
*n.PtrInit() = []ir.Node{p.stmt(stmt.Init)}
}
if stmt.Cond != nil {
n.Cond = p.expr(stmt.Cond)
}
if stmt.Post != nil {
n.Post = p.stmt(stmt.Post)
}
n.Body.Set(p.blockStmt(stmt.Body))
p.closeAnotherScope() p.closeAnotherScope()
return n return n
} }
func (p *noder) switchStmt(stmt *syntax.SwitchStmt) ir.Node { func (p *noder) switchStmt(stmt *syntax.SwitchStmt) ir.Node {
p.openScope(stmt.Pos()) p.openScope(stmt.Pos())
n := ir.NewSwitchStmt(p.pos(stmt), nil, nil)
if stmt.Init != nil { init := p.stmt(stmt.Init)
*n.PtrInit() = []ir.Node{p.stmt(stmt.Init)} n := ir.NewSwitchStmt(p.pos(stmt), p.expr(stmt.Tag), nil)
} if init != nil {
if stmt.Tag != nil { *n.PtrInit() = []ir.Node{init}
n.Tag = p.expr(stmt.Tag)
} }
var tswitch *ir.TypeSwitchGuard var tswitch *ir.TypeSwitchGuard
if l := n.Tag; l != nil && l.Op() == ir.OTYPESW { if l := n.Tag; l != nil && l.Op() == ir.OTYPESW {
tswitch = l.(*ir.TypeSwitchGuard) tswitch = l.(*ir.TypeSwitchGuard)
} }
n.Cases.Set(p.caseClauses(stmt.Body, tswitch, stmt.Rbrace)) n.Cases = p.caseClauses(stmt.Body, tswitch, stmt.Rbrace)
p.closeScope(stmt.Rbrace) p.closeScope(stmt.Rbrace)
return n return n
} }
func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.TypeSwitchGuard, rbrace syntax.Pos) []ir.Node { func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.TypeSwitchGuard, rbrace syntax.Pos) []*ir.CaseClause {
nodes := make([]ir.Node, 0, len(clauses)) nodes := make([]*ir.CaseClause, 0, len(clauses))
for i, clause := range clauses { for i, clause := range clauses {
p.setlineno(clause) p.setlineno(clause)
if i > 0 { if i > 0 {
@ -1374,14 +1354,11 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.TypeSwitch
} }
p.openScope(clause.Pos()) p.openScope(clause.Pos())
n := ir.NewCaseStmt(p.pos(clause), nil, nil) n := ir.NewCaseStmt(p.pos(clause), p.exprList(clause.Cases), nil)
if clause.Cases != nil {
n.List.Set(p.exprList(clause.Cases))
}
if tswitch != nil && tswitch.Tag != nil { if tswitch != nil && tswitch.Tag != nil {
nn := typecheck.NewName(tswitch.Tag.Sym()) nn := typecheck.NewName(tswitch.Tag.Sym())
typecheck.Declare(nn, typecheck.DeclContext) typecheck.Declare(nn, typecheck.DeclContext)
n.Vars = []ir.Node{nn} n.Var = nn
// keep track of the instances for reporting unused // keep track of the instances for reporting unused
nn.Defn = tswitch nn.Defn = tswitch
} }
@ -1416,13 +1393,11 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.TypeSwitch
} }
func (p *noder) selectStmt(stmt *syntax.SelectStmt) ir.Node { func (p *noder) selectStmt(stmt *syntax.SelectStmt) ir.Node {
n := ir.NewSelectStmt(p.pos(stmt), nil) return ir.NewSelectStmt(p.pos(stmt), p.commClauses(stmt.Body, stmt.Rbrace))
n.Cases.Set(p.commClauses(stmt.Body, stmt.Rbrace))
return n
} }
func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []ir.Node { func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []*ir.CommClause {
nodes := make([]ir.Node, 0, len(clauses)) nodes := make([]*ir.CommClause, len(clauses))
for i, clause := range clauses { for i, clause := range clauses {
p.setlineno(clause) p.setlineno(clause)
if i > 0 { if i > 0 {
@ -1430,12 +1405,7 @@ func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []i
} }
p.openScope(clause.Pos()) p.openScope(clause.Pos())
n := ir.NewCaseStmt(p.pos(clause), nil, nil) nodes[i] = ir.NewCommStmt(p.pos(clause), p.stmt(clause.Comm), p.stmts(clause.Body))
if clause.Comm != nil {
n.List = []ir.Node{p.stmt(clause.Comm)}
}
n.Body.Set(p.stmts(clause.Body))
nodes = append(nodes, n)
} }
if len(clauses) > 0 { if len(clauses) > 0 {
p.closeScope(rbrace) p.closeScope(rbrace)
@ -2001,7 +1971,6 @@ func oldname(s *types.Sym) ir.Node {
c = typecheck.NewName(s) c = typecheck.NewName(s)
c.Class_ = ir.PAUTOHEAP c.Class_ = ir.PAUTOHEAP
c.SetIsClosureVar(true) c.SetIsClosureVar(true)
c.SetIsDDD(n.IsDDD())
c.Defn = n c.Defn = n
// Link into list of active closure variables. // Link into list of active closure variables.

View File

@ -33,7 +33,6 @@ package objw
import ( import (
"cmd/compile/internal/base" "cmd/compile/internal/base"
"cmd/compile/internal/ir" "cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/objabi" "cmd/internal/objabi"
"cmd/internal/src" "cmd/internal/src"
@ -173,7 +172,7 @@ func (pp *Progs) Prog(as obj.As) *obj.Prog {
p.Pos = pp.Pos p.Pos = pp.Pos
if pp.Pos.IsStmt() == src.PosIsStmt { if pp.Pos.IsStmt() == src.PosIsStmt {
// Clear IsStmt for later Progs at this pos provided that as can be marked as a stmt // Clear IsStmt for later Progs at this pos provided that as can be marked as a stmt
if ssa.LosesStmtMark(as) { if LosesStmtMark(as) {
return p return p
} }
pp.Pos = pp.Pos.WithNotStmt() pp.Pos = pp.Pos.WithNotStmt()
@ -216,3 +215,12 @@ func (pp *Progs) SetText(fn *ir.Func) {
ptxt.From.Name = obj.NAME_EXTERN ptxt.From.Name = obj.NAME_EXTERN
ptxt.From.Sym = fn.LSym ptxt.From.Sym = fn.LSym
} }
// LosesStmtMark reports whether a prog with op as loses its statement mark on the way to DWARF.
// The attributes from some opcodes are lost in translation.
// TODO: this is an artifact of how funcpctab combines information for instructions at a single PC.
// Should try to fix it there.
func LosesStmtMark(as obj.As) bool {
// is_stmt does not work for these; it DOES for ANOP even though that generates no code.
return as == obj.APCDATA || as == obj.AFUNCDATA
}

View File

@ -289,10 +289,6 @@ func (d *initDeps) inspectList(l ir.Nodes) { ir.VisitList(l, d.cachedVisit()) }
// referenced by n, if any. // referenced by n, if any.
func (d *initDeps) visit(n ir.Node) { func (d *initDeps) visit(n ir.Node) {
switch n.Op() { switch n.Op() {
case ir.OMETHEXPR:
n := n.(*ir.MethodExpr)
d.foundDep(ir.MethodExprName(n))
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name) n := n.(*ir.Name)
switch n.Class_ { switch n.Class_ {
@ -304,7 +300,7 @@ func (d *initDeps) visit(n ir.Node) {
n := n.(*ir.ClosureExpr) n := n.(*ir.ClosureExpr)
d.inspectList(n.Func.Body) d.inspectList(n.Func.Body)
case ir.ODOTMETH, ir.OCALLPART: case ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
d.foundDep(ir.MethodExprName(n)) d.foundDep(ir.MethodExprName(n))
} }
} }

View File

@ -289,11 +289,11 @@ func hashfor(t *types.Type) ir.Node {
n := typecheck.NewName(sym) n := typecheck.NewName(sym)
ir.MarkFunc(n) ir.MarkFunc(n)
n.SetType(typecheck.NewFuncType(nil, []*ir.Field{ n.SetType(types.NewSignature(types.NoPkg, nil, []*types.Field{
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)), types.NewField(base.Pos, nil, types.NewPtr(t)),
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]), types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
}, []*ir.Field{ }, []*types.Field{
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]), types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
})) }))
return n return n
} }
@ -777,12 +777,12 @@ func hashmem(t *types.Type) ir.Node {
n := typecheck.NewName(sym) n := typecheck.NewName(sym)
ir.MarkFunc(n) ir.MarkFunc(n)
n.SetType(typecheck.NewFuncType(nil, []*ir.Field{ n.SetType(types.NewSignature(types.NoPkg, nil, []*types.Field{
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)), types.NewField(base.Pos, nil, types.NewPtr(t)),
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]), types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]), types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
}, []*ir.Field{ }, []*types.Field{
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]), types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
})) }))
return n return n
} }

View File

@ -16,8 +16,8 @@ import (
"cmd/compile/internal/escape" "cmd/compile/internal/escape"
"cmd/compile/internal/inline" "cmd/compile/internal/inline"
"cmd/compile/internal/ir" "cmd/compile/internal/ir"
"cmd/compile/internal/liveness"
"cmd/compile/internal/objw" "cmd/compile/internal/objw"
"cmd/compile/internal/typebits"
"cmd/compile/internal/typecheck" "cmd/compile/internal/typecheck"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/gcprog" "cmd/internal/gcprog"
@ -835,6 +835,9 @@ func TypeSym(t *types.Type) *types.Sym {
if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() { if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
base.Fatalf("typenamesym %v", t) base.Fatalf("typenamesym %v", t)
} }
if t.Kind() == types.TFUNC && t.Recv() != nil {
base.Fatalf("misuse of method type: %v", t)
}
s := types.TypeSym(t) s := types.TypeSym(t)
signatmu.Lock() signatmu.Lock()
NeedRuntimeType(t) NeedRuntimeType(t)
@ -1419,7 +1422,11 @@ func WriteBasicTypes() {
// The latter is the type of an auto-generated wrapper. // The latter is the type of an auto-generated wrapper.
WriteType(types.NewPtr(types.ErrorType)) WriteType(types.NewPtr(types.ErrorType))
WriteType(typecheck.NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.ErrorType)}, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.Types[types.TSTRING])})) WriteType(types.NewSignature(types.NoPkg, nil, []*types.Field{
types.NewField(base.Pos, nil, types.ErrorType),
}, []*types.Field{
types.NewField(base.Pos, nil, types.Types[types.TSTRING]),
}))
// add paths for runtime and main, which 6l imports implicitly. // add paths for runtime and main, which 6l imports implicitly.
dimportpath(ir.Pkgs.Runtime) dimportpath(ir.Pkgs.Runtime)
@ -1545,7 +1552,7 @@ func fillptrmask(t *types.Type, ptrmask []byte) {
} }
vec := bitvec.New(8 * int32(len(ptrmask))) vec := bitvec.New(8 * int32(len(ptrmask)))
liveness.SetTypeBits(t, 0, vec) typebits.Set(t, 0, vec)
nptr := types.PtrDataSize(t) / int64(types.PtrSize) nptr := types.PtrDataSize(t) / int64(types.PtrSize)
for i := int64(0); i < nptr; i++ { for i := int64(0); i < nptr; i++ {
@ -1856,7 +1863,7 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) {
r.Sym = tsym r.Sym = tsym
// dot.Xoffset is the method index * Widthptr (the offset of code pointer // dot.Xoffset is the method index * Widthptr (the offset of code pointer
// in itab). // in itab).
midx := dot.Offset / int64(types.PtrSize) midx := dot.Offset() / int64(types.PtrSize)
r.Add = InterfaceMethodOffset(ityp, midx) r.Add = InterfaceMethodOffset(ityp, midx)
r.Type = objabi.R_USEIFACEMETHOD r.Type = objabi.R_USEIFACEMETHOD
} }

View File

@ -5,7 +5,6 @@
package ssa package ssa
import ( import (
"cmd/internal/obj"
"cmd/internal/src" "cmd/internal/src"
"fmt" "fmt"
"sort" "sort"
@ -23,15 +22,6 @@ func isPoorStatementOp(op Op) bool {
return false return false
} }
// LosesStmtMark reports whether a prog with op as loses its statement mark on the way to DWARF.
// The attributes from some opcodes are lost in translation.
// TODO: this is an artifact of how funcpctab combines information for instructions at a single PC.
// Should try to fix it there.
func LosesStmtMark(as obj.As) bool {
// is_stmt does not work for these; it DOES for ANOP even though that generates no code.
return as == obj.APCDATA || as == obj.AFUNCDATA
}
// nextGoodStatementIndex returns an index at i or later that is believed // nextGoodStatementIndex returns an index at i or later that is believed
// to be a good place to start the statement for b. This decision is // to be a good place to start the statement for b. This decision is
// based on v's Op, the possibility of a better later operation, and // based on v's Op, the possibility of a better later operation, and

View File

@ -214,10 +214,7 @@ func InitConfig() {
func getParam(n *ir.CallExpr, i int) *types.Field { func getParam(n *ir.CallExpr, i int) *types.Field {
t := n.X.Type() t := n.X.Type()
if n.Op() == ir.OCALLMETH { if n.Op() == ir.OCALLMETH {
if i == 0 { base.Fatalf("OCALLMETH missed by walkCall")
return t.Recv()
}
return t.Params().Field(i - 1)
} }
return t.Params().Field(i) return t.Params().Field(i)
} }
@ -1166,7 +1163,7 @@ func (s *state) stmt(n ir.Node) {
} }
fallthrough fallthrough
case ir.OCALLMETH, ir.OCALLINTER: case ir.OCALLINTER:
n := n.(*ir.CallExpr) n := n.(*ir.CallExpr)
s.callResult(n, callNormal) s.callResult(n, callNormal)
if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class_ == ir.PFUNC { if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class_ == ir.PFUNC {
@ -1367,7 +1364,7 @@ func (s *state) stmt(n ir.Node) {
// We're assigning a slicing operation back to its source. // We're assigning a slicing operation back to its source.
// Don't write back fields we aren't changing. See issue #14855. // Don't write back fields we aren't changing. See issue #14855.
rhs := rhs.(*ir.SliceExpr) rhs := rhs.(*ir.SliceExpr)
i, j, k := rhs.SliceBounds() i, j, k := rhs.Low, rhs.High, rhs.Max
if i != nil && (i.Op() == ir.OLITERAL && i.Val().Kind() == constant.Int && ir.Int64Val(i) == 0) { if i != nil && (i.Op() == ir.OLITERAL && i.Val().Kind() == constant.Int && ir.Int64Val(i) == 0) {
// [0:...] is the same as [:...] // [0:...] is the same as [:...]
i = nil i = nil
@ -2111,10 +2108,6 @@ func (s *state) expr(n ir.Node) *ssa.Value {
n := n.(*ir.UnaryExpr) n := n.(*ir.UnaryExpr)
aux := n.X.Sym().Linksym() aux := n.X.Sym().Linksym()
return s.entryNewValue1A(ssa.OpAddr, n.Type(), aux, s.sb) return s.entryNewValue1A(ssa.OpAddr, n.Type(), aux, s.sb)
case ir.OMETHEXPR:
n := n.(*ir.MethodExpr)
sym := staticdata.FuncSym(n.FuncName().Sym()).Linksym()
return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type()), sym, s.sb)
case ir.ONAME: case ir.ONAME:
n := n.(*ir.Name) n := n.(*ir.Name)
if n.Class_ == ir.PFUNC { if n.Class_ == ir.PFUNC {
@ -2736,7 +2729,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
// SSA, then load just the selected field. This // SSA, then load just the selected field. This
// prevents false memory dependencies in race/msan // prevents false memory dependencies in race/msan
// instrumentation. // instrumentation.
if ir.IsAssignable(n) && !s.canSSA(n) { if ir.IsAddressable(n) && !s.canSSA(n) {
p := s.addr(n) p := s.addr(n)
return s.load(n.Type(), p) return s.load(n.Type(), p)
} }
@ -2746,7 +2739,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
case ir.ODOTPTR: case ir.ODOTPTR:
n := n.(*ir.SelectorExpr) n := n.(*ir.SelectorExpr)
p := s.exprPtr(n.X, n.Bounded(), n.Pos()) p := s.exprPtr(n.X, n.Bounded(), n.Pos())
p = s.newValue1I(ssa.OpOffPtr, types.NewPtr(n.Type()), n.Offset, p) p = s.newValue1I(ssa.OpOffPtr, types.NewPtr(n.Type()), n.Offset(), p)
return s.load(n.Type(), p) return s.load(n.Type(), p)
case ir.OINDEX: case ir.OINDEX:
@ -2844,23 +2837,22 @@ func (s *state) expr(n ir.Node) *ssa.Value {
case ir.OSLICEHEADER: case ir.OSLICEHEADER:
n := n.(*ir.SliceHeaderExpr) n := n.(*ir.SliceHeaderExpr)
p := s.expr(n.Ptr) p := s.expr(n.Ptr)
l := s.expr(n.LenCap[0]) l := s.expr(n.Len)
c := s.expr(n.LenCap[1]) c := s.expr(n.Cap)
return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c) return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR: case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
n := n.(*ir.SliceExpr) n := n.(*ir.SliceExpr)
v := s.expr(n.X) v := s.expr(n.X)
var i, j, k *ssa.Value var i, j, k *ssa.Value
low, high, max := n.SliceBounds() if n.Low != nil {
if low != nil { i = s.expr(n.Low)
i = s.expr(low)
} }
if high != nil { if n.High != nil {
j = s.expr(high) j = s.expr(n.High)
} }
if max != nil { if n.Max != nil {
k = s.expr(max) k = s.expr(n.Max)
} }
p, l, c := s.slice(v, i, j, k, n.Bounded()) p, l, c := s.slice(v, i, j, k, n.Bounded())
return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c) return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
@ -2869,12 +2861,11 @@ func (s *state) expr(n ir.Node) *ssa.Value {
n := n.(*ir.SliceExpr) n := n.(*ir.SliceExpr)
v := s.expr(n.X) v := s.expr(n.X)
var i, j *ssa.Value var i, j *ssa.Value
low, high, _ := n.SliceBounds() if n.Low != nil {
if low != nil { i = s.expr(n.Low)
i = s.expr(low)
} }
if high != nil { if n.High != nil {
j = s.expr(high) j = s.expr(n.High)
} }
p, l, _ := s.slice(v, i, j, nil, n.Bounded()) p, l, _ := s.slice(v, i, j, nil, n.Bounded())
return s.newValue2(ssa.OpStringMake, n.Type(), p, l) return s.newValue2(ssa.OpStringMake, n.Type(), p, l)
@ -4398,16 +4389,7 @@ func (s *state) openDeferRecord(n *ir.CallExpr) {
opendefer.closure = closure opendefer.closure = closure
} }
} else if n.Op() == ir.OCALLMETH { } else if n.Op() == ir.OCALLMETH {
if fn.Op() != ir.ODOTMETH { base.Fatalf("OCALLMETH missed by walkCall")
base.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
}
fn := fn.(*ir.SelectorExpr)
closureVal := s.getMethodClosure(fn)
// We must always store the function value in a stack slot for the
// runtime panic code to use. But in the defer exit code, we will
// call the method directly.
closure := s.openDeferSave(nil, fn.Type(), closureVal)
opendefer.closureNode = closure.Aux.(*ir.Name)
} else { } else {
if fn.Op() != ir.ODOTINTER { if fn.Op() != ir.ODOTINTER {
base.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op()) base.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op())
@ -4681,18 +4663,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
s.maybeNilCheckClosure(closure, k) s.maybeNilCheckClosure(closure, k)
} }
case ir.OCALLMETH: case ir.OCALLMETH:
if fn.Op() != ir.ODOTMETH { base.Fatalf("OCALLMETH missed by walkCall")
s.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
}
fn := fn.(*ir.SelectorExpr)
testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
if k == callNormal {
sym = fn.Sel
break
}
closure = s.getMethodClosure(fn)
// Note: receiver is already present in n.Rlist, so we don't
// want to set it here.
case ir.OCALLINTER: case ir.OCALLINTER:
if fn.Op() != ir.ODOTINTER { if fn.Op() != ir.ODOTINTER {
s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op()) s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op())
@ -4757,9 +4728,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
} }
// Set receiver (for method calls). // Set receiver (for method calls).
if n.Op() == ir.OCALLMETH { if n.Op() == ir.OCALLMETH {
f := ft.Recv() base.Fatalf("OCALLMETH missed by walkCall")
s.storeArgWithBase(args[0], f.Type, addr, off+f.Offset)
args = args[1:]
} }
// Set other args. // Set other args.
for _, f := range ft.Params().Fields().Slice() { for _, f := range ft.Params().Fields().Slice() {
@ -4827,11 +4796,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
t := n.X.Type() t := n.X.Type()
args := n.Rargs args := n.Rargs
if n.Op() == ir.OCALLMETH { if n.Op() == ir.OCALLMETH {
f := t.Recv() base.Fatalf("OCALLMETH missed by walkCall")
ACArg, arg := s.putArg(args[0], f.Type, argStart+f.Offset, testLateExpansion)
ACArgs = append(ACArgs, ACArg)
callArgs = append(callArgs, arg)
args = args[1:]
} }
for i, n := range args { for i, n := range args {
f := t.Params().Field(i) f := t.Params().Field(i)
@ -4949,29 +4914,13 @@ func (s *state) maybeNilCheckClosure(closure *ssa.Value, k callKind) {
} }
} }
// getMethodClosure returns a value representing the closure for a method call
func (s *state) getMethodClosure(fn *ir.SelectorExpr) *ssa.Value {
// Make a name n2 for the function.
// fn.Sym might be sync.(*Mutex).Unlock.
// Make a PFUNC node out of that, then evaluate it.
// We get back an SSA value representing &sync.(*Mutex).Unlock·f.
// We can then pass that to defer or go.
n2 := ir.NewNameAt(fn.Pos(), fn.Sel)
n2.Curfn = s.curfn
n2.Class_ = ir.PFUNC
// n2.Sym already existed, so it's already marked as a function.
n2.SetPos(fn.Pos())
n2.SetType(types.Types[types.TUINT8]) // fake type for a static closure. Could use runtime.funcval if we had it.
return s.expr(n2)
}
// getClosureAndRcvr returns values for the appropriate closure and receiver of an // getClosureAndRcvr returns values for the appropriate closure and receiver of an
// interface call // interface call
func (s *state) getClosureAndRcvr(fn *ir.SelectorExpr) (*ssa.Value, *ssa.Value) { func (s *state) getClosureAndRcvr(fn *ir.SelectorExpr) (*ssa.Value, *ssa.Value) {
i := s.expr(fn.X) i := s.expr(fn.X)
itab := s.newValue1(ssa.OpITab, types.Types[types.TUINTPTR], i) itab := s.newValue1(ssa.OpITab, types.Types[types.TUINTPTR], i)
s.nilCheck(itab) s.nilCheck(itab)
itabidx := fn.Offset + 2*int64(types.PtrSize) + 8 // offset of fun field in runtime.itab itabidx := fn.Offset() + 2*int64(types.PtrSize) + 8 // offset of fun field in runtime.itab
closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab) closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
rcvr := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, i) rcvr := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, i)
return closure, rcvr return closure, rcvr
@ -5075,11 +5024,11 @@ func (s *state) addr(n ir.Node) *ssa.Value {
case ir.ODOT: case ir.ODOT:
n := n.(*ir.SelectorExpr) n := n.(*ir.SelectorExpr)
p := s.addr(n.X) p := s.addr(n.X)
return s.newValue1I(ssa.OpOffPtr, t, n.Offset, p) return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p)
case ir.ODOTPTR: case ir.ODOTPTR:
n := n.(*ir.SelectorExpr) n := n.(*ir.SelectorExpr)
p := s.exprPtr(n.X, n.Bounded(), n.Pos()) p := s.exprPtr(n.X, n.Bounded(), n.Pos())
return s.newValue1I(ssa.OpOffPtr, t, n.Offset, p) return s.newValue1I(ssa.OpOffPtr, t, n.Offset(), p)
case ir.OCLOSUREREAD: case ir.OCLOSUREREAD:
n := n.(*ir.ClosureReadExpr) n := n.(*ir.ClosureReadExpr)
return s.newValue1I(ssa.OpOffPtr, t, n.Offset, return s.newValue1I(ssa.OpOffPtr, t, n.Offset,
@ -5091,7 +5040,7 @@ func (s *state) addr(n ir.Node) *ssa.Value {
} }
addr := s.addr(n.X) addr := s.addr(n.X)
return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH: case ir.OCALLFUNC, ir.OCALLINTER:
n := n.(*ir.CallExpr) n := n.(*ir.CallExpr)
return s.callAddr(n, callNormal) return s.callAddr(n, callNormal)
case ir.ODOTTYPE: case ir.ODOTTYPE:
@ -6328,7 +6277,7 @@ type State struct {
// Prog appends a new Prog. // Prog appends a new Prog.
func (s *State) Prog(as obj.As) *obj.Prog { func (s *State) Prog(as obj.As) *obj.Prog {
p := s.pp.Prog(as) p := s.pp.Prog(as)
if ssa.LosesStmtMark(as) { if objw.LosesStmtMark(as) {
return p return p
} }
// Float a statement start to the beginning of any same-line run. // Float a statement start to the beginning of any same-line run.
@ -7116,21 +7065,17 @@ func (s *State) UseArgs(n int64) {
// fieldIdx finds the index of the field referred to by the ODOT node n. // fieldIdx finds the index of the field referred to by the ODOT node n.
func fieldIdx(n *ir.SelectorExpr) int { func fieldIdx(n *ir.SelectorExpr) int {
t := n.X.Type() t := n.X.Type()
f := n.Sel
if !t.IsStruct() { if !t.IsStruct() {
panic("ODOT's LHS is not a struct") panic("ODOT's LHS is not a struct")
} }
var i int for i, f := range t.Fields().Slice() {
for _, t1 := range t.Fields().Slice() { if f.Sym == n.Sel {
if t1.Sym != f { if f.Offset != n.Offset() {
i++ panic("field offset doesn't match")
continue }
return i
} }
if t1.Offset != n.Offset {
panic("field offset doesn't match")
}
return i
} }
panic(fmt.Sprintf("can't find field in expr %v\n", n)) panic(fmt.Sprintf("can't find field in expr %v\n", n))

View File

@ -469,7 +469,7 @@ func StaticLoc(n ir.Node) (name *ir.Name, offset int64, ok bool) {
if name, offset, ok = StaticLoc(n.X); !ok { if name, offset, ok = StaticLoc(n.X); !ok {
break break
} }
offset += n.Offset offset += n.Offset()
return name, offset, true return name, offset, true
case ir.OINDEX: case ir.OINDEX:

View File

@ -0,0 +1,87 @@
// Copyright 2013 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 typebits
import (
"cmd/compile/internal/base"
"cmd/compile/internal/bitvec"
"cmd/compile/internal/types"
)
// NOTE: The bitmap for a specific type t could be cached in t after
// the first run and then simply copied into bv at the correct offset
// on future calls with the same type t.
func Set(t *types.Type, off int64, bv bitvec.BitVec) {
if t.Align > 0 && off&int64(t.Align-1) != 0 {
base.Fatalf("onebitwalktype1: invalid initial alignment: type %v has alignment %d, but offset is %v", t, t.Align, off)
}
if !t.HasPointers() {
// Note: this case ensures that pointers to go:notinheap types
// are not considered pointers by garbage collection and stack copying.
return
}
switch t.Kind() {
case types.TPTR, types.TUNSAFEPTR, types.TFUNC, types.TCHAN, types.TMAP:
if off&int64(types.PtrSize-1) != 0 {
base.Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
bv.Set(int32(off / int64(types.PtrSize))) // pointer
case types.TSTRING:
// struct { byte *str; intgo len; }
if off&int64(types.PtrSize-1) != 0 {
base.Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
bv.Set(int32(off / int64(types.PtrSize))) //pointer in first slot
case types.TINTER:
// struct { Itab *tab; void *data; }
// or, when isnilinter(t)==true:
// struct { Type *type; void *data; }
if off&int64(types.PtrSize-1) != 0 {
base.Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
// The first word of an interface is a pointer, but we don't
// treat it as such.
// 1. If it is a non-empty interface, the pointer points to an itab
// which is always in persistentalloc space.
// 2. If it is an empty interface, the pointer points to a _type.
// a. If it is a compile-time-allocated type, it points into
// the read-only data section.
// b. If it is a reflect-allocated type, it points into the Go heap.
// Reflect is responsible for keeping a reference to
// the underlying type so it won't be GCd.
// If we ever have a moving GC, we need to change this for 2b (as
// well as scan itabs to update their itab._type fields).
bv.Set(int32(off/int64(types.PtrSize) + 1)) // pointer in second slot
case types.TSLICE:
// struct { byte *array; uintgo len; uintgo cap; }
if off&int64(types.PtrSize-1) != 0 {
base.Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t)
}
bv.Set(int32(off / int64(types.PtrSize))) // pointer in first slot (BitsPointer)
case types.TARRAY:
elt := t.Elem()
if elt.Width == 0 {
// Short-circuit for #20739.
break
}
for i := int64(0); i < t.NumElem(); i++ {
Set(elt, off, bv)
off += elt.Width
}
case types.TSTRUCT:
for _, f := range t.Fields().Slice() {
Set(f.Type, off+f.Offset, bv)
}
default:
base.Fatalf("onebitwalktype1: unexpected type, %v", t)
}
}

View File

@ -3,9 +3,8 @@
package typecheck package typecheck
import ( import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/src"
) )
var runtimeDecls = [...]struct { var runtimeDecls = [...]struct {
@ -212,133 +211,133 @@ func runtimeTypes() []*types.Type {
typs[1] = types.NewPtr(typs[0]) typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[types.TANY] typs[2] = types.Types[types.TANY]
typs[3] = types.NewPtr(typs[2]) typs[3] = types.NewPtr(typs[2])
typs[4] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])}) typs[4] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[3])})
typs[5] = types.Types[types.TUINTPTR] typs[5] = types.Types[types.TUINTPTR]
typs[6] = types.Types[types.TBOOL] typs[6] = types.Types[types.TBOOL]
typs[7] = types.Types[types.TUNSAFEPTR] typs[7] = types.Types[types.TUNSAFEPTR]
typs[8] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[6])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])}) typs[8] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[5]), types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[6])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[7])})
typs[9] = NewFuncType(nil, nil, nil) typs[9] = types.NewSignature(types.NoPkg, nil, nil, nil)
typs[10] = types.Types[types.TINTER] typs[10] = types.Types[types.TINTER]
typs[11] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[10])}, nil) typs[11] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[10])}, nil)
typs[12] = types.Types[types.TINT32] typs[12] = types.Types[types.TINT32]
typs[13] = types.NewPtr(typs[12]) typs[13] = types.NewPtr(typs[12])
typs[14] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[13])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[10])}) typs[14] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[13])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[10])})
typs[15] = types.Types[types.TINT] typs[15] = types.Types[types.TINT]
typs[16] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15])}, nil) typs[16] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[15]), types.NewField(src.NoXPos, nil, typs[15])}, nil)
typs[17] = types.Types[types.TUINT] typs[17] = types.Types[types.TUINT]
typs[18] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[17]), ir.NewField(base.Pos, nil, nil, typs[15])}, nil) typs[18] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[17]), types.NewField(src.NoXPos, nil, typs[15])}, nil)
typs[19] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}, nil) typs[19] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[6])}, nil)
typs[20] = types.Types[types.TFLOAT64] typs[20] = types.Types[types.TFLOAT64]
typs[21] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, nil) typs[21] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[20])}, nil)
typs[22] = types.Types[types.TINT64] typs[22] = types.Types[types.TINT64]
typs[23] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}, nil) typs[23] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[22])}, nil)
typs[24] = types.Types[types.TUINT64] typs[24] = types.Types[types.TUINT64]
typs[25] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}, nil) typs[25] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[24])}, nil)
typs[26] = types.Types[types.TCOMPLEX128] typs[26] = types.Types[types.TCOMPLEX128]
typs[27] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26])}, nil) typs[27] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[26])}, nil)
typs[28] = types.Types[types.TSTRING] typs[28] = types.Types[types.TSTRING]
typs[29] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, nil) typs[29] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])}, nil)
typs[30] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, nil) typs[30] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[2])}, nil)
typs[31] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])}, nil) typs[31] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[5])}, nil)
typs[32] = types.NewArray(typs[0], 32) typs[32] = types.NewArray(typs[0], 32)
typs[33] = types.NewPtr(typs[32]) typs[33] = types.NewPtr(typs[32])
typs[34] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}) typs[34] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[33]), types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[28])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])})
typs[35] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}) typs[35] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[33]), types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[28])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])})
typs[36] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}) typs[36] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[33]), types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[28])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])})
typs[37] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}) typs[37] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[33]), types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[28])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])})
typs[38] = types.NewSlice(typs[28]) typs[38] = types.NewSlice(typs[28])
typs[39] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[38])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}) typs[39] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[33]), types.NewField(src.NoXPos, nil, typs[38])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])})
typs[40] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])}) typs[40] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[28])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[15])})
typs[41] = types.NewArray(typs[0], 4) typs[41] = types.NewArray(typs[0], 4)
typs[42] = types.NewPtr(typs[41]) typs[42] = types.NewPtr(typs[41])
typs[43] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[42]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}) typs[43] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[42]), types.NewField(src.NoXPos, nil, typs[22])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])})
typs[44] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}) typs[44] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[33]), types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[15])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])})
typs[45] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}) typs[45] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[15])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])})
typs[46] = types.RuneType typs[46] = types.RuneType
typs[47] = types.NewSlice(typs[46]) typs[47] = types.NewSlice(typs[46])
typs[48] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[47])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}) typs[48] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[33]), types.NewField(src.NoXPos, nil, typs[47])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])})
typs[49] = types.NewSlice(typs[0]) typs[49] = types.NewSlice(typs[0])
typs[50] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[49])}) typs[50] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[33]), types.NewField(src.NoXPos, nil, typs[28])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[49])})
typs[51] = types.NewArray(typs[46], 32) typs[51] = types.NewArray(typs[46], 32)
typs[52] = types.NewPtr(typs[51]) typs[52] = types.NewPtr(typs[51])
typs[53] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[52]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[47])}) typs[53] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[52]), types.NewField(src.NoXPos, nil, typs[28])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[47])})
typs[54] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])}) typs[54] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[15]), types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[15]), types.NewField(src.NoXPos, nil, typs[5])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[15])})
typs[55] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[46]), ir.NewField(base.Pos, nil, nil, typs[15])}) typs[55] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[28]), types.NewField(src.NoXPos, nil, typs[15])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[46]), types.NewField(src.NoXPos, nil, typs[15])})
typs[56] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])}) typs[56] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[15])})
typs[57] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}) typs[57] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[2])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[2])})
typs[58] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])}) typs[58] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[2])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[7])})
typs[59] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}) typs[59] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[3])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[2])})
typs[60] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2]), ir.NewField(base.Pos, nil, nil, typs[6])}) typs[60] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[2])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[2]), types.NewField(src.NoXPos, nil, typs[6])})
typs[61] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1])}, nil) typs[61] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[1])}, nil)
typs[62] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1])}, nil) typs[62] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1])}, nil)
typs[63] = types.NewPtr(typs[5]) typs[63] = types.NewPtr(typs[5])
typs[64] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[63]), ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}) typs[64] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[63]), types.NewField(src.NoXPos, nil, typs[7]), types.NewField(src.NoXPos, nil, typs[7])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[6])})
typs[65] = types.Types[types.TUINT32] typs[65] = types.Types[types.TUINT32]
typs[66] = NewFuncType(nil, nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])}) typs[66] = types.NewSignature(types.NoPkg, nil, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[65])})
typs[67] = types.NewMap(typs[2], typs[2]) typs[67] = types.NewMap(typs[2], typs[2])
typs[68] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])}) typs[68] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[22]), types.NewField(src.NoXPos, nil, typs[3])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[67])})
typs[69] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])}) typs[69] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[15]), types.NewField(src.NoXPos, nil, typs[3])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[67])})
typs[70] = NewFuncType(nil, nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])}) typs[70] = types.NewSignature(types.NoPkg, nil, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[67])})
typs[71] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])}) typs[71] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[67]), types.NewField(src.NoXPos, nil, typs[3])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[3])})
typs[72] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])}) typs[72] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[67]), types.NewField(src.NoXPos, nil, typs[2])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[3])})
typs[73] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])}) typs[73] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[67]), types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[1])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[3])})
typs[74] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])}) typs[74] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[67]), types.NewField(src.NoXPos, nil, typs[3])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[6])})
typs[75] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])}) typs[75] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[67]), types.NewField(src.NoXPos, nil, typs[2])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[6])})
typs[76] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])}) typs[76] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[67]), types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[1])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[6])})
typs[77] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil) typs[77] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[67]), types.NewField(src.NoXPos, nil, typs[3])}, nil)
typs[78] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, nil) typs[78] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[67]), types.NewField(src.NoXPos, nil, typs[2])}, nil)
typs[79] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])}, nil) typs[79] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[3])}, nil)
typs[80] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67])}, nil) typs[80] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[67])}, nil)
typs[81] = types.NewChan(typs[2], types.Cboth) typs[81] = types.NewChan(typs[2], types.Cboth)
typs[82] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[81])}) typs[82] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[22])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[81])})
typs[83] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[81])}) typs[83] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[15])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[81])})
typs[84] = types.NewChan(typs[2], types.Crecv) typs[84] = types.NewChan(typs[2], types.Crecv)
typs[85] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[84]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil) typs[85] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[84]), types.NewField(src.NoXPos, nil, typs[3])}, nil)
typs[86] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[84]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}) typs[86] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[84]), types.NewField(src.NoXPos, nil, typs[3])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[6])})
typs[87] = types.NewChan(typs[2], types.Csend) typs[87] = types.NewChan(typs[2], types.Csend)
typs[88] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[87]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil) typs[88] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[87]), types.NewField(src.NoXPos, nil, typs[3])}, nil)
typs[89] = types.NewArray(typs[0], 3) typs[89] = types.NewArray(typs[0], 3)
typs[90] = NewStructType([]*ir.Field{ir.NewField(base.Pos, Lookup("enabled"), nil, typs[6]), ir.NewField(base.Pos, Lookup("pad"), nil, typs[89]), ir.NewField(base.Pos, Lookup("needed"), nil, typs[6]), ir.NewField(base.Pos, Lookup("cgo"), nil, typs[6]), ir.NewField(base.Pos, Lookup("alignme"), nil, typs[24])}) typs[90] = types.NewStruct(types.NoPkg, []*types.Field{types.NewField(src.NoXPos, Lookup("enabled"), typs[6]), types.NewField(src.NoXPos, Lookup("pad"), typs[89]), types.NewField(src.NoXPos, Lookup("needed"), typs[6]), types.NewField(src.NoXPos, Lookup("cgo"), typs[6]), types.NewField(src.NoXPos, Lookup("alignme"), typs[24])})
typs[91] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil) typs[91] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[3])}, nil)
typs[92] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil) typs[92] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[3])}, nil)
typs[93] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])}) typs[93] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[15]), types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[15])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[15])})
typs[94] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[87]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}) typs[94] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[87]), types.NewField(src.NoXPos, nil, typs[3])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[6])})
typs[95] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[84])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}) typs[95] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[84])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[6])})
typs[96] = types.NewPtr(typs[6]) typs[96] = types.NewPtr(typs[6])
typs[97] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[96]), ir.NewField(base.Pos, nil, nil, typs[84])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}) typs[97] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[96]), types.NewField(src.NoXPos, nil, typs[84])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[6])})
typs[98] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[63])}, nil) typs[98] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[63])}, nil)
typs[99] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[63]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[6])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[6])}) typs[99] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[63]), types.NewField(src.NoXPos, nil, typs[15]), types.NewField(src.NoXPos, nil, typs[15]), types.NewField(src.NoXPos, nil, typs[6])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[15]), types.NewField(src.NoXPos, nil, typs[6])})
typs[100] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])}) typs[100] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[15]), types.NewField(src.NoXPos, nil, typs[15])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[7])})
typs[101] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])}) typs[101] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[22]), types.NewField(src.NoXPos, nil, typs[22])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[7])})
typs[102] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])}) typs[102] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[15]), types.NewField(src.NoXPos, nil, typs[15]), types.NewField(src.NoXPos, nil, typs[7])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[7])})
typs[103] = types.NewSlice(typs[2]) typs[103] = types.NewSlice(typs[2])
typs[104] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[103]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[103])}) typs[104] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[103]), types.NewField(src.NoXPos, nil, typs[15])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[103])})
typs[105] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil) typs[105] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[5])}, nil)
typs[106] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil) typs[106] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[7]), types.NewField(src.NoXPos, nil, typs[5])}, nil)
typs[107] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}) typs[107] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[5])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[6])})
typs[108] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}) typs[108] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[3]), types.NewField(src.NoXPos, nil, typs[3])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[6])})
typs[109] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}) typs[109] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[7]), types.NewField(src.NoXPos, nil, typs[7])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[6])})
typs[110] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])}) typs[110] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[7]), types.NewField(src.NoXPos, nil, typs[5]), types.NewField(src.NoXPos, nil, typs[5])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[5])})
typs[111] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])}) typs[111] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[7]), types.NewField(src.NoXPos, nil, typs[5])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[5])})
typs[112] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}) typs[112] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[22]), types.NewField(src.NoXPos, nil, typs[22])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[22])})
typs[113] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24]), ir.NewField(base.Pos, nil, nil, typs[24])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}) typs[113] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[24]), types.NewField(src.NoXPos, nil, typs[24])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[24])})
typs[114] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}) typs[114] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[20])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[22])})
typs[115] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}) typs[115] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[20])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[24])})
typs[116] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])}) typs[116] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[20])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[65])})
typs[117] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}) typs[117] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[22])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[20])})
typs[118] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}) typs[118] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[24])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[20])})
typs[119] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}) typs[119] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[65])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[20])})
typs[120] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26]), ir.NewField(base.Pos, nil, nil, typs[26])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26])}) typs[120] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[26]), types.NewField(src.NoXPos, nil, typs[26])}, []*types.Field{types.NewField(src.NoXPos, nil, typs[26])})
typs[121] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil) typs[121] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[5]), types.NewField(src.NoXPos, nil, typs[5])}, nil)
typs[122] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil) typs[122] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[5]), types.NewField(src.NoXPos, nil, typs[5]), types.NewField(src.NoXPos, nil, typs[5])}, nil)
typs[123] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil) typs[123] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[7]), types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[5])}, nil)
typs[124] = types.NewSlice(typs[7]) typs[124] = types.NewSlice(typs[7])
typs[125] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[124])}, nil) typs[125] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[7]), types.NewField(src.NoXPos, nil, typs[124])}, nil)
typs[126] = types.Types[types.TUINT8] typs[126] = types.Types[types.TUINT8]
typs[127] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[126]), ir.NewField(base.Pos, nil, nil, typs[126])}, nil) typs[127] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[126]), types.NewField(src.NoXPos, nil, typs[126])}, nil)
typs[128] = types.Types[types.TUINT16] typs[128] = types.Types[types.TUINT16]
typs[129] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[128]), ir.NewField(base.Pos, nil, nil, typs[128])}, nil) typs[129] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[128]), types.NewField(src.NoXPos, nil, typs[128])}, nil)
typs[130] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65]), ir.NewField(base.Pos, nil, nil, typs[65])}, nil) typs[130] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[65]), types.NewField(src.NoXPos, nil, typs[65])}, nil)
typs[131] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24]), ir.NewField(base.Pos, nil, nil, typs[24])}, nil) typs[131] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[24]), types.NewField(src.NoXPos, nil, typs[24])}, nil)
return typs[:] return typs[:]
} }

View File

@ -13,7 +13,6 @@ import (
) )
func TestBuiltin(t *testing.T) { func TestBuiltin(t *testing.T) {
t.Skip("mkbuiltin needs fixing")
testenv.MustHaveGoRun(t) testenv.MustHaveGoRun(t)
t.Parallel() t.Parallel()

View File

@ -929,7 +929,7 @@ func evalunsafe(n ir.Node) int64 {
fallthrough fallthrough
case ir.ODOT: case ir.ODOT:
r := r.(*ir.SelectorExpr) r := r.(*ir.SelectorExpr)
v += r.Offset v += r.Offset()
next = r.X next = r.X
default: default:
ir.Dump("unsafenmagic", tsel) ir.Dump("unsafenmagic", tsel)

View File

@ -281,72 +281,6 @@ func CheckFuncStack() {
} }
} }
// turn a parsed function declaration into a type
func NewFuncType(nrecv *ir.Field, nparams, nresults []*ir.Field) *types.Type {
funarg := func(n *ir.Field) *types.Field {
lno := base.Pos
base.Pos = n.Pos
if n.Ntype != nil {
n.Type = typecheckNtype(n.Ntype).Type()
n.Ntype = nil
}
f := types.NewField(n.Pos, n.Sym, n.Type)
f.SetIsDDD(n.IsDDD)
if n.Decl != nil {
n.Decl.SetType(f.Type)
f.Nname = n.Decl
}
base.Pos = lno
return f
}
funargs := func(nn []*ir.Field) []*types.Field {
res := make([]*types.Field, len(nn))
for i, n := range nn {
res[i] = funarg(n)
}
return res
}
var recv *types.Field
if nrecv != nil {
recv = funarg(nrecv)
}
t := types.NewSignature(types.LocalPkg, recv, funargs(nparams), funargs(nresults))
checkdupfields("argument", t.Recvs().FieldSlice(), t.Params().FieldSlice(), t.Results().FieldSlice())
return t
}
// convert a parsed id/type list into
// a type for struct/interface/arglist
func NewStructType(l []*ir.Field) *types.Type {
lno := base.Pos
fields := make([]*types.Field, len(l))
for i, n := range l {
base.Pos = n.Pos
if n.Ntype != nil {
n.Type = typecheckNtype(n.Ntype).Type()
n.Ntype = nil
}
f := types.NewField(n.Pos, n.Sym, n.Type)
if n.Embedded {
checkembeddedtype(n.Type)
f.Embedded = 1
}
f.Note = n.Note
fields[i] = f
}
checkdupfields("field", fields)
base.Pos = lno
return types.NewStruct(types.LocalPkg, fields)
}
// Add a method, declared as a function. // Add a method, declared as a function.
// - msym is the method symbol // - msym is the method symbol
// - t is function type (with receiver) // - t is function type (with receiver)
@ -513,7 +447,6 @@ func funcarg(n *ir.Field, ctxt ir.Class) {
name := ir.NewNameAt(n.Pos, n.Sym) name := ir.NewNameAt(n.Pos, n.Sym)
n.Decl = name n.Decl = name
name.Ntype = n.Ntype name.Ntype = n.Ntype
name.SetIsDDD(n.IsDDD)
Declare(name, ctxt) Declare(name, ctxt)
vargen++ vargen++
@ -527,7 +460,6 @@ func funcarg2(f *types.Field, ctxt ir.Class) {
n := ir.NewNameAt(f.Pos, f.Sym) n := ir.NewNameAt(f.Pos, f.Sym)
f.Nname = n f.Nname = n
n.SetType(f.Type) n.SetType(f.Type)
n.SetIsDDD(f.IsDDD())
Declare(n, ctxt) Declare(n, ctxt)
} }
@ -604,27 +536,6 @@ func initname(s string) bool {
return s == "init" return s == "init"
} }
func tointerface(nmethods []*ir.Field) *types.Type {
if len(nmethods) == 0 {
return types.Types[types.TINTER]
}
lno := base.Pos
methods := make([]*types.Field, len(nmethods))
for i, n := range nmethods {
base.Pos = n.Pos
if n.Ntype != nil {
n.Type = typecheckNtype(n.Ntype).Type()
n.Ntype = nil
}
methods[i] = types.NewField(n.Pos, n.Sym, n.Type)
}
base.Pos = lno
return types.NewInterface(types.LocalPkg, methods)
}
var vargen int var vargen int
func Temp(t *types.Type) *ir.Name { func Temp(t *types.Type) *ir.Name {
@ -643,6 +554,9 @@ func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
if t == nil { if t == nil {
base.Fatalf("tempAt called with nil type") base.Fatalf("tempAt called with nil type")
} }
if t.Kind() == types.TFUNC && t.Recv() != nil {
base.Fatalf("misuse of method type: %v", t)
}
s := &types.Sym{ s := &types.Sym{
Name: autotmpname(len(curfn.Dcl)), Name: autotmpname(len(curfn.Dcl)),
@ -676,30 +590,26 @@ func autotmpname(n int) string {
// f is method type, with receiver. // f is method type, with receiver.
// return function type, receiver as first argument (or not). // return function type, receiver as first argument (or not).
func NewMethodType(f *types.Type, receiver *types.Type) *types.Type { func NewMethodType(sig *types.Type, recv *types.Type) *types.Type {
inLen := f.Params().Fields().Len() nrecvs := 0
if receiver != nil { if recv != nil {
inLen++ nrecvs++
}
in := make([]*ir.Field, 0, inLen)
if receiver != nil {
d := ir.NewField(base.Pos, nil, nil, receiver)
in = append(in, d)
} }
for _, t := range f.Params().Fields().Slice() { params := make([]*types.Field, nrecvs+sig.Params().Fields().Len())
d := ir.NewField(base.Pos, nil, nil, t.Type) if recv != nil {
d.IsDDD = t.IsDDD() params[0] = types.NewField(base.Pos, nil, recv)
in = append(in, d) }
for i, param := range sig.Params().Fields().Slice() {
d := types.NewField(base.Pos, nil, param.Type)
d.SetIsDDD(param.IsDDD())
params[nrecvs+i] = d
} }
outLen := f.Results().Fields().Len() results := make([]*types.Field, sig.Results().Fields().Len())
out := make([]*ir.Field, 0, outLen) for i, t := range sig.Results().Fields().Slice() {
for _, t := range f.Results().Fields().Slice() { results[i] = types.NewField(base.Pos, nil, t.Type)
d := ir.NewField(base.Pos, nil, nil, t.Type)
out = append(out, d)
} }
return NewFuncType(nil, in, out) return types.NewSignature(types.LocalPkg, nil, params, results)
} }

View File

@ -571,7 +571,6 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
} }
n.X = typecheck(n.X, ctxExpr|ctxType) n.X = typecheck(n.X, ctxExpr|ctxType)
n.X = DefaultLit(n.X, nil) n.X = DefaultLit(n.X, nil)
t := n.X.Type() t := n.X.Type()
@ -581,8 +580,6 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
return n return n
} }
s := n.Sel
if n.X.Op() == ir.OTYPE { if n.X.Op() == ir.OTYPE {
return typecheckMethodExpr(n) return typecheckMethodExpr(n)
} }
@ -629,7 +626,10 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
} }
if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 { if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
return tcCallPart(n, s) // Create top-level function.
fn := makepartialcall(n)
return ir.NewCallPartExpr(n.Pos(), n.X, n.Selection, fn)
} }
return n return n
} }
@ -831,24 +831,18 @@ func tcSPtr(n *ir.UnaryExpr) ir.Node {
// tcSlice typechecks an OSLICE or OSLICE3 node. // tcSlice typechecks an OSLICE or OSLICE3 node.
func tcSlice(n *ir.SliceExpr) ir.Node { func tcSlice(n *ir.SliceExpr) ir.Node {
n.X = Expr(n.X) n.X = DefaultLit(Expr(n.X), nil)
low, high, max := n.SliceBounds() n.Low = indexlit(Expr(n.Low))
n.High = indexlit(Expr(n.High))
n.Max = indexlit(Expr(n.Max))
hasmax := n.Op().IsSlice3() hasmax := n.Op().IsSlice3()
low = Expr(low)
high = Expr(high)
max = Expr(max)
n.X = DefaultLit(n.X, nil)
low = indexlit(low)
high = indexlit(high)
max = indexlit(max)
n.SetSliceBounds(low, high, max)
l := n.X l := n.X
if l.Type() == nil { if l.Type() == nil {
n.SetType(nil) n.SetType(nil)
return n return n
} }
if l.Type().IsArray() { if l.Type().IsArray() {
if !ir.IsAssignable(n.X) { if !ir.IsAddressable(n.X) {
base.Errorf("invalid operation %v (slice of unaddressable value)", n) base.Errorf("invalid operation %v (slice of unaddressable value)", n)
n.SetType(nil) n.SetType(nil)
return n return n
@ -886,19 +880,19 @@ func tcSlice(n *ir.SliceExpr) ir.Node {
return n return n
} }
if low != nil && !checksliceindex(l, low, tp) { if n.Low != nil && !checksliceindex(l, n.Low, tp) {
n.SetType(nil) n.SetType(nil)
return n return n
} }
if high != nil && !checksliceindex(l, high, tp) { if n.High != nil && !checksliceindex(l, n.High, tp) {
n.SetType(nil) n.SetType(nil)
return n return n
} }
if max != nil && !checksliceindex(l, max, tp) { if n.Max != nil && !checksliceindex(l, n.Max, tp) {
n.SetType(nil) n.SetType(nil)
return n return n
} }
if !checksliceconst(low, high) || !checksliceconst(low, max) || !checksliceconst(high, max) { if !checksliceconst(n.Low, n.High) || !checksliceconst(n.Low, n.Max) || !checksliceconst(n.High, n.Max) {
n.SetType(nil) n.SetType(nil)
return n return n
} }
@ -924,30 +918,22 @@ func tcSliceHeader(n *ir.SliceHeaderExpr) ir.Node {
base.Fatalf("need unsafe.Pointer for OSLICEHEADER") base.Fatalf("need unsafe.Pointer for OSLICEHEADER")
} }
if x := len(n.LenCap); x != 2 {
base.Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x)
}
n.Ptr = Expr(n.Ptr) n.Ptr = Expr(n.Ptr)
l := Expr(n.LenCap[0]) n.Len = DefaultLit(Expr(n.Len), types.Types[types.TINT])
c := Expr(n.LenCap[1]) n.Cap = DefaultLit(Expr(n.Cap), types.Types[types.TINT])
l = DefaultLit(l, types.Types[types.TINT])
c = DefaultLit(c, types.Types[types.TINT])
if ir.IsConst(l, constant.Int) && ir.Int64Val(l) < 0 { if ir.IsConst(n.Len, constant.Int) && ir.Int64Val(n.Len) < 0 {
base.Fatalf("len for OSLICEHEADER must be non-negative") base.Fatalf("len for OSLICEHEADER must be non-negative")
} }
if ir.IsConst(c, constant.Int) && ir.Int64Val(c) < 0 { if ir.IsConst(n.Cap, constant.Int) && ir.Int64Val(n.Cap) < 0 {
base.Fatalf("cap for OSLICEHEADER must be non-negative") base.Fatalf("cap for OSLICEHEADER must be non-negative")
} }
if ir.IsConst(l, constant.Int) && ir.IsConst(c, constant.Int) && constant.Compare(l.Val(), token.GTR, c.Val()) { if ir.IsConst(n.Len, constant.Int) && ir.IsConst(n.Cap, constant.Int) && constant.Compare(n.Len.Val(), token.GTR, n.Cap.Val()) {
base.Fatalf("len larger than cap for OSLICEHEADER") base.Fatalf("len larger than cap for OSLICEHEADER")
} }
n.LenCap[0] = l
n.LenCap[1] = c
return n return n
} }

View File

@ -73,17 +73,17 @@ func ClosureType(clo *ir.ClosureExpr) *types.Type {
// The information appears in the binary in the form of type descriptors; // The information appears in the binary in the form of type descriptors;
// the struct is unnamed so that closures in multiple packages with the // the struct is unnamed so that closures in multiple packages with the
// same struct type can share the descriptor. // same struct type can share the descriptor.
fields := []*ir.Field{ fields := []*types.Field{
ir.NewField(base.Pos, Lookup(".F"), nil, types.Types[types.TUINTPTR]), types.NewField(base.Pos, Lookup(".F"), types.Types[types.TUINTPTR]),
} }
for _, v := range clo.Func.ClosureVars { for _, v := range clo.Func.ClosureVars {
typ := v.Type() typ := v.Type()
if !v.Byval() { if !v.Byval() {
typ = types.NewPtr(typ) typ = types.NewPtr(typ)
} }
fields = append(fields, ir.NewField(base.Pos, v.Sym(), nil, typ)) fields = append(fields, types.NewField(base.Pos, v.Sym(), typ))
} }
typ := NewStructType(fields) typ := types.NewStruct(types.NoPkg, fields)
typ.SetNoalg(true) typ.SetNoalg(true)
return typ return typ
} }
@ -92,9 +92,9 @@ func ClosureType(clo *ir.ClosureExpr) *types.Type {
// needed in the closure for n (n must be a OCALLPART node). // needed in the closure for n (n must be a OCALLPART node).
// The address of a variable of the returned type can be cast to a func. // The address of a variable of the returned type can be cast to a func.
func PartialCallType(n *ir.CallPartExpr) *types.Type { func PartialCallType(n *ir.CallPartExpr) *types.Type {
t := NewStructType([]*ir.Field{ t := types.NewStruct(types.NoPkg, []*types.Field{
ir.NewField(base.Pos, Lookup("F"), nil, types.Types[types.TUINTPTR]), types.NewField(base.Pos, Lookup("F"), types.Types[types.TUINTPTR]),
ir.NewField(base.Pos, Lookup("R"), nil, n.X.Type()), types.NewField(base.Pos, Lookup("R"), n.X.Type()),
}) })
t.SetNoalg(true) t.SetNoalg(true)
return t return t
@ -249,7 +249,9 @@ var globClosgen int32
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed // makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
// for partial calls. // for partial calls.
func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.Func { func makepartialcall(dot *ir.SelectorExpr) *ir.Func {
t0 := dot.Type()
meth := dot.Sel
rcvrtype := dot.X.Type() rcvrtype := dot.X.Type()
sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm") sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
@ -263,11 +265,10 @@ func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.
ir.CurFunc = nil ir.CurFunc = nil
// Set line number equal to the line number where the method is declared. // Set line number equal to the line number where the method is declared.
var m *types.Field if pos := dot.Selection.Pos; pos.IsKnown() {
if lookdot0(meth, rcvrtype, &m, false) == 1 && m.Pos.IsKnown() { base.Pos = pos
base.Pos = m.Pos
} }
// Note: !m.Pos.IsKnown() happens for method expressions where // Note: !dot.Selection.Pos.IsKnown() happens for method expressions where
// the method is implicitly declared. The Error method of the // the method is implicitly declared. The Error method of the
// built-in error type is one such method. We leave the line // built-in error type is one such method. We leave the line
// number at the use of the method expression in this // number at the use of the method expression in this
@ -280,18 +281,17 @@ func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.
fn := DeclFunc(sym, tfn) fn := DeclFunc(sym, tfn)
fn.SetDupok(true) fn.SetDupok(true)
fn.SetNeedctxt(true) fn.SetNeedctxt(true)
fn.SetWrapper(true)
// Declare and initialize variable holding receiver. // Declare and initialize variable holding receiver.
cr := ir.NewClosureRead(rcvrtype, types.Rnd(int64(types.PtrSize), int64(rcvrtype.Align))) cr := ir.NewClosureRead(rcvrtype, types.Rnd(int64(types.PtrSize), int64(rcvrtype.Align)))
ptr := NewName(Lookup(".this")) var ptr *ir.Name
Declare(ptr, ir.PAUTO)
ptr.SetUsed(true)
var body []ir.Node var body []ir.Node
if rcvrtype.IsPtr() || rcvrtype.IsInterface() { if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
ptr.SetType(rcvrtype) ptr = Temp(rcvrtype)
body = append(body, ir.NewAssignStmt(base.Pos, ptr, cr)) body = append(body, ir.NewAssignStmt(base.Pos, ptr, cr))
} else { } else {
ptr.SetType(types.NewPtr(rcvrtype)) ptr = Temp(types.NewPtr(rcvrtype))
body = append(body, ir.NewAssignStmt(base.Pos, ptr, NodAddr(cr))) body = append(body, ir.NewAssignStmt(base.Pos, ptr, NodAddr(cr)))
} }
@ -382,23 +382,6 @@ func tcClosure(clo *ir.ClosureExpr, top int) {
Target.Decls = append(Target.Decls, fn) Target.Decls = append(Target.Decls, fn)
} }
func tcCallPart(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
switch n.Op() {
case ir.ODOTINTER, ir.ODOTMETH:
break
default:
base.Fatalf("invalid typecheckpartialcall")
}
dot := n.(*ir.SelectorExpr)
// Create top-level function.
fn := makepartialcall(dot, dot.Type(), sym)
fn.SetWrapper(true)
return ir.NewCallPartExpr(dot.Pos(), dot.X, dot.Selection, fn)
}
// type check function definition // type check function definition
// To be called by typecheck, not directly. // To be called by typecheck, not directly.
// (Call typecheckFunc instead.) // (Call typecheckFunc instead.)
@ -542,9 +525,7 @@ func tcCall(n *ir.CallExpr, top int) ir.Node {
default: default:
n.SetOp(ir.OCALLFUNC) n.SetOp(ir.OCALLFUNC)
if t.Kind() != types.TFUNC { if t.Kind() != types.TFUNC {
// TODO(mdempsky): Remove "o.Sym() != nil" once we stop if o := ir.Orig(l); o.Name() != nil && types.BuiltinPkg.Lookup(o.Sym().Name).Def != nil {
// using ir.Name for numeric literals.
if o := ir.Orig(l); o.Name() != nil && o.Sym() != nil && types.BuiltinPkg.Lookup(o.Sym().Name).Def != nil {
// be more specific when the non-function // be more specific when the non-function
// name matches a predeclared function // name matches a predeclared function
base.Errorf("cannot call non-function %L, declared at %s", base.Errorf("cannot call non-function %L, declared at %s",

View File

@ -594,23 +594,15 @@ func (w *exportWriter) selector(s *types.Sym) {
base.Fatalf("missing currPkg") base.Fatalf("missing currPkg")
} }
// Method selectors are rewritten into method symbols (of the pkg := w.currPkg
// form T.M) during typechecking, but we want to write out if types.IsExported(s.Name) {
// just the bare method name. pkg = types.LocalPkg
name := s.Name }
if i := strings.LastIndex(name, "."); i >= 0 { if s.Pkg != pkg {
name = name[i+1:] base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path)
} else {
pkg := w.currPkg
if types.IsExported(name) {
pkg = types.LocalPkg
}
if s.Pkg != pkg {
base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path)
}
} }
w.string(name) w.string(s.Name)
} }
func (w *exportWriter) typ(t *types.Type) { func (w *exportWriter) typ(t *types.Type) {
@ -858,8 +850,6 @@ func intSize(typ *types.Type) (signed bool, maxBytes uint) {
// according to the maximum number of bytes needed to encode a value // according to the maximum number of bytes needed to encode a value
// of type typ. As a special case, 8-bit types are always encoded as a // of type typ. As a special case, 8-bit types are always encoded as a
// single byte. // single byte.
//
// TODO(mdempsky): Is this level of complexity really worthwhile?
func (w *exportWriter) mpint(x constant.Value, typ *types.Type) { func (w *exportWriter) mpint(x constant.Value, typ *types.Type) {
signed, maxBytes := intSize(typ) signed, maxBytes := intSize(typ)
@ -1145,7 +1135,7 @@ func (w *exportWriter) stmt(n ir.Node) {
n := n.(*ir.RangeStmt) n := n.(*ir.RangeStmt)
w.op(ir.ORANGE) w.op(ir.ORANGE)
w.pos(n.Pos()) w.pos(n.Pos())
w.stmtList(n.Vars) w.exprsOrNil(n.Key, n.Value)
w.expr(n.X) w.expr(n.X)
w.stmtList(n.Body) w.stmtList(n.Body)
@ -1154,8 +1144,7 @@ func (w *exportWriter) stmt(n ir.Node) {
w.op(n.Op()) w.op(n.Op())
w.pos(n.Pos()) w.pos(n.Pos())
w.stmtList(n.Init()) w.stmtList(n.Init())
w.exprsOrNil(nil, nil) // TODO(rsc): Delete (and fix importer). w.commList(n.Cases)
w.caseList(n)
case ir.OSWITCH: case ir.OSWITCH:
n := n.(*ir.SwitchStmt) n := n.(*ir.SwitchStmt)
@ -1163,7 +1152,7 @@ func (w *exportWriter) stmt(n ir.Node) {
w.pos(n.Pos()) w.pos(n.Pos())
w.stmtList(n.Init()) w.stmtList(n.Init())
w.exprsOrNil(n.Tag, nil) w.exprsOrNil(n.Tag, nil)
w.caseList(n) w.caseList(n.Cases, isNamedTypeSwitch(n.Tag))
// case OCASE: // case OCASE:
// handled by caseList // handled by caseList
@ -1187,39 +1176,32 @@ func (w *exportWriter) stmt(n ir.Node) {
} }
} }
func isNamedTypeSwitch(n ir.Node) bool { func isNamedTypeSwitch(x ir.Node) bool {
if n.Op() != ir.OSWITCH { guard, ok := x.(*ir.TypeSwitchGuard)
return false return ok && guard.Tag != nil
}
sw := n.(*ir.SwitchStmt)
if sw.Tag == nil || sw.Tag.Op() != ir.OTYPESW {
return false
}
guard := sw.Tag.(*ir.TypeSwitchGuard)
return guard.Tag != nil
} }
func (w *exportWriter) caseList(sw ir.Node) { func (w *exportWriter) caseList(cases []*ir.CaseClause, namedTypeSwitch bool) {
namedTypeSwitch := isNamedTypeSwitch(sw)
var cases []ir.Node
if sw.Op() == ir.OSWITCH {
cases = sw.(*ir.SwitchStmt).Cases
} else {
cases = sw.(*ir.SelectStmt).Cases
}
w.uint64(uint64(len(cases))) w.uint64(uint64(len(cases)))
for _, cas := range cases { for _, cas := range cases {
cas := cas.(*ir.CaseStmt)
w.pos(cas.Pos()) w.pos(cas.Pos())
w.stmtList(cas.List) w.stmtList(cas.List)
if namedTypeSwitch { if namedTypeSwitch {
w.localName(cas.Vars[0].(*ir.Name)) w.localName(cas.Var.(*ir.Name))
} }
w.stmtList(cas.Body) w.stmtList(cas.Body)
} }
} }
func (w *exportWriter) commList(cases []*ir.CommClause) {
w.uint64(uint64(len(cases)))
for _, cas := range cases {
w.pos(cas.Pos())
w.node(cas.Comm)
w.stmtList(cas.Body)
}
}
func (w *exportWriter) exprList(list ir.Nodes) { func (w *exportWriter) exprList(list ir.Nodes) {
for _, n := range list { for _, n := range list {
w.expr(n) w.expr(n)
@ -1313,7 +1295,7 @@ func (w *exportWriter) expr(n ir.Node) {
s = n.Tag.Sym() s = n.Tag.Sym()
} }
w.localIdent(s, 0) // declared pseudo-variable, if any w.localIdent(s, 0) // declared pseudo-variable, if any
w.exprsOrNil(n.X, nil) w.expr(n.X)
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
// should have been resolved by typechecking - handled by default case // should have been resolved by typechecking - handled by default case
@ -1348,7 +1330,8 @@ func (w *exportWriter) expr(n ir.Node) {
n := n.(*ir.KeyExpr) n := n.(*ir.KeyExpr)
w.op(ir.OKEY) w.op(ir.OKEY)
w.pos(n.Pos()) w.pos(n.Pos())
w.exprsOrNil(n.Key, n.Value) w.expr(n.Key)
w.expr(n.Value)
// case OSTRUCTKEY: // case OSTRUCTKEY:
// unreachable - handled in case OSTRUCTLIT by elemList // unreachable - handled in case OSTRUCTLIT by elemList
@ -1387,17 +1370,15 @@ func (w *exportWriter) expr(n ir.Node) {
w.op(ir.OSLICE) w.op(ir.OSLICE)
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.X) w.expr(n.X)
low, high, _ := n.SliceBounds() w.exprsOrNil(n.Low, n.High)
w.exprsOrNil(low, high)
case ir.OSLICE3, ir.OSLICE3ARR: case ir.OSLICE3, ir.OSLICE3ARR:
n := n.(*ir.SliceExpr) n := n.(*ir.SliceExpr)
w.op(ir.OSLICE3) w.op(ir.OSLICE3)
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.X) w.expr(n.X)
low, high, max := n.SliceBounds() w.exprsOrNil(n.Low, n.High)
w.exprsOrNil(low, high) w.expr(n.Max)
w.expr(max)
case ir.OCOPY, ir.OCOMPLEX: case ir.OCOPY, ir.OCOMPLEX:
// treated like other builtin calls (see e.g., OREAL) // treated like other builtin calls (see e.g., OREAL)
@ -1412,8 +1393,8 @@ func (w *exportWriter) expr(n ir.Node) {
n := n.(*ir.ConvExpr) n := n.(*ir.ConvExpr)
w.op(ir.OCONV) w.op(ir.OCONV)
w.pos(n.Pos()) w.pos(n.Pos())
w.expr(n.X)
w.typ(n.Type()) w.typ(n.Type())
w.expr(n.X)
case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC: case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
n := n.(*ir.UnaryExpr) n := n.(*ir.UnaryExpr)
@ -1544,6 +1525,7 @@ func (w *exportWriter) fieldList(list ir.Nodes) {
w.uint64(uint64(len(list))) w.uint64(uint64(len(list)))
for _, n := range list { for _, n := range list {
n := n.(*ir.StructKeyExpr) n := n.(*ir.StructKeyExpr)
w.pos(n.Pos())
w.selector(n.Field) w.selector(n.Field)
w.expr(n.Value) w.expr(n.Value)
} }

View File

@ -71,7 +71,12 @@ func ImportBody(fn *ir.Func) {
base.Fatalf("missing import reader for %v", fn) base.Fatalf("missing import reader for %v", fn)
} }
if inimport {
base.Fatalf("recursive inimport")
}
inimport = true
r.doInline(fn) r.doInline(fn)
inimport = false
} }
func importReaderFor(sym *types.Sym, importers map[*types.Sym]iimporterAndOffset) *importReader { func importReaderFor(sym *types.Sym, importers map[*types.Sym]iimporterAndOffset) *importReader {
@ -767,10 +772,10 @@ func (r *importReader) stmtList() []ir.Node {
return list return list
} }
func (r *importReader) caseList(sw ir.Node) []ir.Node { func (r *importReader) caseList(switchExpr ir.Node) []*ir.CaseClause {
namedTypeSwitch := isNamedTypeSwitch(sw) namedTypeSwitch := isNamedTypeSwitch(switchExpr)
cases := make([]ir.Node, r.uint64()) cases := make([]*ir.CaseClause, r.uint64())
for i := range cases { for i := range cases {
cas := ir.NewCaseStmt(r.pos(), nil, nil) cas := ir.NewCaseStmt(r.pos(), nil, nil)
cas.List.Set(r.stmtList()) cas.List.Set(r.stmtList())
@ -780,8 +785,8 @@ func (r *importReader) caseList(sw ir.Node) []ir.Node {
// Sym for diagnostics anyway. // Sym for diagnostics anyway.
caseVar := ir.NewNameAt(cas.Pos(), r.ident()) caseVar := ir.NewNameAt(cas.Pos(), r.ident())
Declare(caseVar, DeclContext) Declare(caseVar, DeclContext)
cas.Vars = []ir.Node{caseVar} cas.Var = caseVar
caseVar.Defn = sw.(*ir.SwitchStmt).Tag caseVar.Defn = switchExpr
} }
cas.Body.Set(r.stmtList()) cas.Body.Set(r.stmtList())
cases[i] = cas cases[i] = cas
@ -789,6 +794,14 @@ func (r *importReader) caseList(sw ir.Node) []ir.Node {
return cases return cases
} }
func (r *importReader) commList() []*ir.CommClause {
cases := make([]*ir.CommClause, r.uint64())
for i := range cases {
cases[i] = ir.NewCommStmt(r.pos(), r.node(), r.stmtList())
}
return cases
}
func (r *importReader) exprList() []ir.Node { func (r *importReader) exprList() []ir.Node {
var list []ir.Node var list []ir.Node
for { for {
@ -821,7 +834,7 @@ func (r *importReader) node() ir.Node {
pos := r.pos() pos := r.pos()
typ := r.typ() typ := r.typ()
n := npos(pos, NodNil()) n := ir.NewNilExpr(pos)
n.SetType(typ) n.SetType(typ)
return n return n
@ -829,7 +842,7 @@ func (r *importReader) node() ir.Node {
pos := r.pos() pos := r.pos()
typ := r.typ() typ := r.typ()
n := npos(pos, ir.NewLiteral(r.value(typ))) n := ir.NewBasicLit(pos, r.value(typ))
n.SetType(typ) n.SetType(typ)
return n return n
@ -851,8 +864,7 @@ func (r *importReader) node() ir.Node {
if s := r.ident(); s != nil { if s := r.ident(); s != nil {
tag = ir.NewIdent(pos, s) tag = ir.NewIdent(pos, s)
} }
expr, _ := r.exprsOrNil() return ir.NewTypeSwitchGuard(pos, tag, r.expr())
return ir.NewTypeSwitchGuard(pos, tag, expr)
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC: // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
// unreachable - should have been resolved by typechecking // unreachable - should have been resolved by typechecking
@ -864,26 +876,16 @@ func (r *importReader) node() ir.Node {
// unreachable - mapped to case OADDR below by exporter // unreachable - mapped to case OADDR below by exporter
case ir.OSTRUCTLIT: case ir.OSTRUCTLIT:
// TODO(mdempsky): Export position information for OSTRUCTKEY nodes. return ir.NewCompLitExpr(r.pos(), ir.OCOMPLIT, ir.TypeNode(r.typ()), r.fieldList())
savedlineno := base.Pos
base.Pos = r.pos()
n := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(r.typ()).(ir.Ntype), nil)
n.List.Set(r.elemList()) // special handling of field names
base.Pos = savedlineno
return n
// case OARRAYLIT, OSLICELIT, OMAPLIT: // case OARRAYLIT, OSLICELIT, OMAPLIT:
// unreachable - mapped to case OCOMPLIT below by exporter // unreachable - mapped to case OCOMPLIT below by exporter
case ir.OCOMPLIT: case ir.OCOMPLIT:
n := ir.NewCompLitExpr(r.pos(), ir.OCOMPLIT, ir.TypeNode(r.typ()).(ir.Ntype), nil) return ir.NewCompLitExpr(r.pos(), ir.OCOMPLIT, ir.TypeNode(r.typ()), r.exprList())
n.List.Set(r.exprList())
return n
case ir.OKEY: case ir.OKEY:
pos := r.pos() return ir.NewKeyExpr(r.pos(), r.expr(), r.expr())
left, right := r.exprsOrNil()
return ir.NewKeyExpr(pos, left, right)
// case OSTRUCTKEY: // case OSTRUCTKEY:
// unreachable - handled in case OSTRUCTLIT by elemList // unreachable - handled in case OSTRUCTLIT by elemList
@ -913,22 +915,19 @@ func (r *importReader) node() ir.Node {
return ir.NewIndexExpr(r.pos(), r.expr(), r.expr()) return ir.NewIndexExpr(r.pos(), r.expr(), r.expr())
case ir.OSLICE, ir.OSLICE3: case ir.OSLICE, ir.OSLICE3:
n := ir.NewSliceExpr(r.pos(), op, r.expr()) pos, x := r.pos(), r.expr()
low, high := r.exprsOrNil() low, high := r.exprsOrNil()
var max ir.Node var max ir.Node
if n.Op().IsSlice3() { if op.IsSlice3() {
max = r.expr() max = r.expr()
} }
n.SetSliceBounds(low, high, max) return ir.NewSliceExpr(pos, op, x, low, high, max)
return n
// case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR: // case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR:
// unreachable - mapped to OCONV case below by exporter // unreachable - mapped to OCONV case below by exporter
case ir.OCONV: case ir.OCONV:
n := ir.NewConvExpr(r.pos(), ir.OCONV, nil, r.expr()) return ir.NewConvExpr(r.pos(), ir.OCONV, r.typ(), r.expr())
n.SetType(r.typ())
return n
case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN: case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN:
n := builtinCall(r.pos(), op) n := builtinCall(r.pos(), op)
@ -942,10 +941,10 @@ func (r *importReader) node() ir.Node {
// unreachable - mapped to OCALL case below by exporter // unreachable - mapped to OCALL case below by exporter
case ir.OCALL: case ir.OCALL:
n := ir.NewCallExpr(r.pos(), ir.OCALL, nil, nil) pos := r.pos()
n.PtrInit().Set(r.stmtList()) init := r.stmtList()
n.X = r.expr() n := ir.NewCallExpr(pos, ir.OCALL, r.expr(), r.exprList())
n.Args.Set(r.exprList()) n.PtrInit().Set(init)
n.IsDDD = r.bool() n.IsDDD = r.bool()
return n return n
@ -979,7 +978,7 @@ func (r *importReader) node() ir.Node {
case ir.OADDSTR: case ir.OADDSTR:
pos := r.pos() pos := r.pos()
list := r.exprList() list := r.exprList()
x := npos(pos, list[0]) x := list[0]
for _, y := range list[1:] { for _, y := range list[1:] {
x = ir.NewBinaryExpr(pos, ir.OADD, x, y) x = ir.NewBinaryExpr(pos, ir.OADD, x, y)
} }
@ -1006,9 +1005,7 @@ func (r *importReader) node() ir.Node {
return ir.NewAssignStmt(r.pos(), r.expr(), r.expr()) return ir.NewAssignStmt(r.pos(), r.expr(), r.expr())
case ir.OASOP: case ir.OASOP:
n := ir.NewAssignOpStmt(r.pos(), ir.OXXX, nil, nil) n := ir.NewAssignOpStmt(r.pos(), r.op(), r.expr(), nil)
n.AsOp = r.op()
n.X = r.expr()
if !r.bool() { if !r.bool() {
n.Y = ir.NewInt(1) n.Y = ir.NewInt(1)
n.IncDec = true n.IncDec = true
@ -1021,15 +1018,10 @@ func (r *importReader) node() ir.Node {
// unreachable - mapped to OAS2 case below by exporter // unreachable - mapped to OAS2 case below by exporter
case ir.OAS2: case ir.OAS2:
n := ir.NewAssignListStmt(r.pos(), ir.OAS2, nil, nil) return ir.NewAssignListStmt(r.pos(), ir.OAS2, r.exprList(), r.exprList())
n.Lhs.Set(r.exprList())
n.Rhs.Set(r.exprList())
return n
case ir.ORETURN: case ir.ORETURN:
n := ir.NewReturnStmt(r.pos(), nil) return ir.NewReturnStmt(r.pos(), r.exprList())
n.Results.Set(r.exprList())
return n
// case ORETJMP: // case ORETJMP:
// unreachable - generated by compiler for trampolin routines (not exported) // unreachable - generated by compiler for trampolin routines (not exported)
@ -1038,57 +1030,50 @@ func (r *importReader) node() ir.Node {
return ir.NewGoDeferStmt(r.pos(), op, r.expr()) return ir.NewGoDeferStmt(r.pos(), op, r.expr())
case ir.OIF: case ir.OIF:
n := ir.NewIfStmt(r.pos(), nil, nil, nil) pos, init := r.pos(), r.stmtList()
n.PtrInit().Set(r.stmtList()) n := ir.NewIfStmt(pos, r.expr(), r.stmtList(), r.stmtList())
n.Cond = r.expr() n.PtrInit().Set(init)
n.Body.Set(r.stmtList())
n.Else.Set(r.stmtList())
return n return n
case ir.OFOR: case ir.OFOR:
n := ir.NewForStmt(r.pos(), nil, nil, nil, nil) pos, init := r.pos(), r.stmtList()
n.PtrInit().Set(r.stmtList()) cond, post := r.exprsOrNil()
left, right := r.exprsOrNil() n := ir.NewForStmt(pos, nil, cond, post, r.stmtList())
n.Cond = left n.PtrInit().Set(init)
n.Post = right
n.Body.Set(r.stmtList())
return n return n
case ir.ORANGE: case ir.ORANGE:
n := ir.NewRangeStmt(r.pos(), nil, nil, nil) pos := r.pos()
n.Vars.Set(r.stmtList()) k, v := r.exprsOrNil()
n.X = r.expr() return ir.NewRangeStmt(pos, k, v, r.expr(), r.stmtList())
n.Body.Set(r.stmtList())
return n
case ir.OSELECT: case ir.OSELECT:
n := ir.NewSelectStmt(r.pos(), nil) pos := r.pos()
n.PtrInit().Set(r.stmtList()) init := r.stmtList()
r.exprsOrNil() // TODO(rsc): Delete (and fix exporter). These are always nil. n := ir.NewSelectStmt(pos, r.commList())
n.Cases.Set(r.caseList(n)) n.PtrInit().Set(init)
return n return n
case ir.OSWITCH: case ir.OSWITCH:
n := ir.NewSwitchStmt(r.pos(), nil, nil) pos := r.pos()
n.PtrInit().Set(r.stmtList()) init := r.stmtList()
left, _ := r.exprsOrNil() x, _ := r.exprsOrNil()
n.Tag = left n := ir.NewSwitchStmt(pos, x, r.caseList(x))
n.Cases.Set(r.caseList(n)) n.PtrInit().Set(init)
return n return n
// case OCASE: // case OCASE:
// handled by caseList // handled by caseList
case ir.OFALL: case ir.OFALL:
n := ir.NewBranchStmt(r.pos(), ir.OFALL, nil) return ir.NewBranchStmt(r.pos(), ir.OFALL, nil)
return n
// case OEMPTY: // case OEMPTY:
// unreachable - not emitted by exporter // unreachable - not emitted by exporter
case ir.OBREAK, ir.OCONTINUE, ir.OGOTO: case ir.OBREAK, ir.OCONTINUE, ir.OGOTO:
var sym *types.Sym
pos := r.pos() pos := r.pos()
var sym *types.Sym
if label := r.string(); label != "" { if label := r.string(); label != "" {
sym = Lookup(label) sym = Lookup(label)
} }
@ -1111,12 +1096,10 @@ func (r *importReader) op() ir.Op {
return ir.Op(r.uint64()) return ir.Op(r.uint64())
} }
func (r *importReader) elemList() []ir.Node { func (r *importReader) fieldList() []ir.Node {
c := r.uint64() list := make([]ir.Node, r.uint64())
list := make([]ir.Node, c)
for i := range list { for i := range list {
s := r.ident() list[i] = ir.NewStructKeyExpr(r.pos(), r.ident(), r.expr())
list[i] = ir.NewStructKeyExpr(base.Pos, s, r.expr())
} }
return list return list
} }
@ -1135,8 +1118,3 @@ func (r *importReader) exprsOrNil() (a, b ir.Node) {
func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr { func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr {
return ir.NewCallExpr(pos, ir.OCALL, ir.NewIdent(base.Pos, types.BuiltinPkg.Lookup(ir.OpNames[op])), nil) return ir.NewCallExpr(pos, ir.OCALL, ir.NewIdent(base.Pos, types.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
} }
func npos(pos src.XPos, n ir.Node) ir.Node {
n.SetPos(pos)
return n
}

View File

@ -36,8 +36,8 @@ func main() {
fmt.Fprintln(&b, "package typecheck") fmt.Fprintln(&b, "package typecheck")
fmt.Fprintln(&b) fmt.Fprintln(&b)
fmt.Fprintln(&b, `import (`) fmt.Fprintln(&b, `import (`)
fmt.Fprintln(&b, ` "cmd/compile/internal/ir"`)
fmt.Fprintln(&b, ` "cmd/compile/internal/types"`) fmt.Fprintln(&b, ` "cmd/compile/internal/types"`)
fmt.Fprintln(&b, ` "cmd/internal/src"`)
fmt.Fprintln(&b, `)`) fmt.Fprintln(&b, `)`)
mkbuiltin(&b, "runtime") mkbuiltin(&b, "runtime")
@ -169,7 +169,7 @@ func (i *typeInterner) mktype(t ast.Expr) string {
} }
return fmt.Sprintf("types.NewChan(%s, %s)", i.subtype(t.Value), dir) return fmt.Sprintf("types.NewChan(%s, %s)", i.subtype(t.Value), dir)
case *ast.FuncType: case *ast.FuncType:
return fmt.Sprintf("functype(nil, %s, %s)", i.fields(t.Params, false), i.fields(t.Results, false)) return fmt.Sprintf("types.NewSignature(types.NoPkg, nil, %s, %s)", i.fields(t.Params, false), i.fields(t.Results, false))
case *ast.InterfaceType: case *ast.InterfaceType:
if len(t.Methods.List) != 0 { if len(t.Methods.List) != 0 {
log.Fatal("non-empty interfaces unsupported") log.Fatal("non-empty interfaces unsupported")
@ -180,7 +180,7 @@ func (i *typeInterner) mktype(t ast.Expr) string {
case *ast.StarExpr: case *ast.StarExpr:
return fmt.Sprintf("types.NewPtr(%s)", i.subtype(t.X)) return fmt.Sprintf("types.NewPtr(%s)", i.subtype(t.X))
case *ast.StructType: case *ast.StructType:
return fmt.Sprintf("tostruct(%s)", i.fields(t.Fields, true)) return fmt.Sprintf("types.NewStruct(types.NoPkg, %s)", i.fields(t.Fields, true))
default: default:
log.Fatalf("unhandled type: %#v", t) log.Fatalf("unhandled type: %#v", t)
@ -196,18 +196,18 @@ func (i *typeInterner) fields(fl *ast.FieldList, keepNames bool) string {
for _, f := range fl.List { for _, f := range fl.List {
typ := i.subtype(f.Type) typ := i.subtype(f.Type)
if len(f.Names) == 0 { if len(f.Names) == 0 {
res = append(res, fmt.Sprintf("anonfield(%s)", typ)) res = append(res, fmt.Sprintf("types.NewField(src.NoXPos, nil, %s)", typ))
} else { } else {
for _, name := range f.Names { for _, name := range f.Names {
if keepNames { if keepNames {
res = append(res, fmt.Sprintf("namedfield(%q, %s)", name.Name, typ)) res = append(res, fmt.Sprintf("types.NewField(src.NoXPos, Lookup(%q), %s)", name.Name, typ))
} else { } else {
res = append(res, fmt.Sprintf("anonfield(%s)", typ)) res = append(res, fmt.Sprintf("types.NewField(src.NoXPos, nil, %s)", typ))
} }
} }
} }
} }
return fmt.Sprintf("[]*ir.Field{%s}", strings.Join(res, ", ")) return fmt.Sprintf("[]*types.Field{%s}", strings.Join(res, ", "))
} }
func intconst(e ast.Expr) int64 { func intconst(e ast.Expr) int64 {

View File

@ -11,27 +11,29 @@ import (
"cmd/internal/src" "cmd/internal/src"
) )
func RangeExprType(t *types.Type) *types.Type {
if t.IsPtr() && t.Elem().IsArray() {
return t.Elem()
}
return t
}
func typecheckrangeExpr(n *ir.RangeStmt) { func typecheckrangeExpr(n *ir.RangeStmt) {
n.X = Expr(n.X) n.X = Expr(n.X)
if n.X.Type() == nil {
t := n.X.Type()
if t == nil {
return return
} }
t := RangeExprType(n.X.Type())
// delicate little dance. see typecheckas2 // delicate little dance. see typecheckas2
ls := n.Vars if n.Key != nil && !ir.DeclaredBy(n.Key, n) {
for i1, n1 := range ls { n.Key = AssignExpr(n.Key)
if !ir.DeclaredBy(n1, n) { }
ls[i1] = AssignExpr(ls[i1]) if n.Value != nil && !ir.DeclaredBy(n.Value, n) {
} n.Value = AssignExpr(n.Value)
} }
if t.IsPtr() && t.Elem().IsArray() { var tk, tv *types.Type
t = t.Elem()
}
n.SetType(t)
var t1, t2 *types.Type
toomany := false toomany := false
switch t.Kind() { switch t.Kind() {
default: default:
@ -39,12 +41,12 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
return return
case types.TARRAY, types.TSLICE: case types.TARRAY, types.TSLICE:
t1 = types.Types[types.TINT] tk = types.Types[types.TINT]
t2 = t.Elem() tv = t.Elem()
case types.TMAP: case types.TMAP:
t1 = t.Key() tk = t.Key()
t2 = t.Elem() tv = t.Elem()
case types.TCHAN: case types.TCHAN:
if !t.ChanDir().CanRecv() { if !t.ChanDir().CanRecv() {
@ -52,61 +54,35 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
return return
} }
t1 = t.Elem() tk = t.Elem()
t2 = nil tv = nil
if len(n.Vars) == 2 { if n.Value != nil {
toomany = true toomany = true
} }
case types.TSTRING: case types.TSTRING:
t1 = types.Types[types.TINT] tk = types.Types[types.TINT]
t2 = types.RuneType tv = types.RuneType
} }
if len(n.Vars) > 2 || toomany { if toomany {
base.ErrorfAt(n.Pos(), "too many variables in range") base.ErrorfAt(n.Pos(), "too many variables in range")
} }
var v1, v2 ir.Node do := func(nn ir.Node, t *types.Type) {
if len(n.Vars) != 0 { if nn != nil {
v1 = n.Vars[0] if ir.DeclaredBy(nn, n) {
} nn.SetType(t)
if len(n.Vars) > 1 { } else if nn.Type() != nil {
v2 = n.Vars[1] if op, why := assignop(t, nn.Type()); op == ir.OXXX {
} base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t, nn, why)
}
// this is not only an optimization but also a requirement in the spec.
// "if the second iteration variable is the blank identifier, the range
// clause is equivalent to the same clause with only the first variable
// present."
if ir.IsBlank(v2) {
if v1 != nil {
n.Vars = []ir.Node{v1}
}
v2 = nil
}
if v1 != nil {
if ir.DeclaredBy(v1, n) {
v1.SetType(t1)
} else if v1.Type() != nil {
if op, why := assignop(t1, v1.Type()); op == ir.OXXX {
base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t1, v1, why)
} }
checkassign(n, nn)
} }
checkassign(n, v1)
}
if v2 != nil {
if ir.DeclaredBy(v2, n) {
v2.SetType(t2)
} else if v2.Type() != nil {
if op, why := assignop(t2, v2.Type()); op == ir.OXXX {
base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t2, v2, why)
}
}
checkassign(n, v2)
} }
do(n.Key, tk)
do(n.Value, tv)
} }
// type check assignment. // type check assignment.
@ -117,47 +93,16 @@ func tcAssign(n *ir.AssignStmt) {
defer tracePrint("typecheckas", n)(nil) defer tracePrint("typecheckas", n)(nil)
} }
// delicate little dance. if n.Y == nil {
// the definition of n may refer to this assignment
// as its definition, in which case it will call typecheckas.
// in that case, do not call typecheck back, or it will cycle.
// if the variable has a type (ntype) then typechecking
// will not look at defn, so it is okay (and desirable,
// so that the conversion below happens).
n.X = Resolve(n.X)
if !ir.DeclaredBy(n.X, n) || n.X.Name().Ntype != nil {
n.X = AssignExpr(n.X) n.X = AssignExpr(n.X)
return
} }
// Use ctxMultiOK so we can emit an "N variables but M values" error lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
// to be consistent with typecheckas2 (#26616). assign(n, lhs, rhs)
n.Y = typecheck(n.Y, ctxExpr|ctxMultiOK) n.X, n.Y = lhs[0], rhs[0]
checkassign(n, n.X)
if n.Y != nil && n.Y.Type() != nil {
if n.Y.Type().IsFuncArgStruct() {
base.Errorf("assignment mismatch: 1 variable but %v returns %d values", n.Y.(*ir.CallExpr).X, n.Y.Type().NumFields())
// Multi-value RHS isn't actually valid for OAS; nil out
// to indicate failed typechecking.
n.Y.SetType(nil)
} else if n.X.Type() != nil {
n.Y = AssignConv(n.Y, n.X.Type(), "assignment")
}
}
if ir.DeclaredBy(n.X, n) && n.X.Name().Ntype == nil { // TODO(mdempsky): This seems out of place.
n.Y = DefaultLit(n.Y, nil)
n.X.SetType(n.Y.Type())
}
// second half of dance.
// now that right is done, typecheck the left
// just to get it over with. see dance above.
n.SetTypecheck(1)
if n.X.Typecheck() == 0 {
n.X = AssignExpr(n.X)
}
if !ir.IsBlank(n.X) { if !ir.IsBlank(n.X) {
types.CheckSize(n.X.Type()) // ensure width is calculated for backend types.CheckSize(n.X.Type()) // ensure width is calculated for backend
} }
@ -168,132 +113,118 @@ func tcAssignList(n *ir.AssignListStmt) {
defer tracePrint("typecheckas2", n)(nil) defer tracePrint("typecheckas2", n)(nil)
} }
ls := n.Lhs assign(n, n.Lhs, n.Rhs)
for i1, n1 := range ls { }
// delicate little dance.
n1 = Resolve(n1)
ls[i1] = n1
if !ir.DeclaredBy(n1, n) || n1.Name().Ntype != nil { func assign(stmt ir.Node, lhs, rhs []ir.Node) {
ls[i1] = AssignExpr(ls[i1]) // delicate little dance.
// the definition of lhs may refer to this assignment
// as its definition, in which case it will call typecheckas.
// in that case, do not call typecheck back, or it will cycle.
// if the variable has a type (ntype) then typechecking
// will not look at defn, so it is okay (and desirable,
// so that the conversion below happens).
checkLHS := func(i int, typ *types.Type) {
lhs[i] = Resolve(lhs[i])
if n := lhs[i]; typ != nil && ir.DeclaredBy(n, stmt) && n.Name().Ntype == nil {
if typ.Kind() != types.TNIL {
n.SetType(defaultType(typ))
} else {
base.Errorf("use of untyped nil")
}
}
if lhs[i].Typecheck() == 0 {
lhs[i] = AssignExpr(lhs[i])
}
checkassign(stmt, lhs[i])
}
assignType := func(i int, typ *types.Type) {
checkLHS(i, typ)
if typ != nil {
checkassignto(typ, lhs[i])
} }
} }
cl := len(n.Lhs) cr := len(rhs)
cr := len(n.Rhs) if len(rhs) == 1 {
if cl > 1 && cr == 1 { rhs[0] = typecheck(rhs[0], ctxExpr|ctxMultiOK)
n.Rhs[0] = typecheck(n.Rhs[0], ctxExpr|ctxMultiOK) if rtyp := rhs[0].Type(); rtyp != nil && rtyp.IsFuncArgStruct() {
cr = rtyp.NumFields()
}
} else { } else {
Exprs(n.Rhs) Exprs(rhs)
}
checkassignlist(n, n.Lhs)
var l ir.Node
var r ir.Node
if cl == cr {
// easy
ls := n.Lhs
rs := n.Rhs
for il, nl := range ls {
nr := rs[il]
if nl.Type() != nil && nr.Type() != nil {
rs[il] = AssignConv(nr, nl.Type(), "assignment")
}
if ir.DeclaredBy(nl, n) && nl.Name().Ntype == nil {
rs[il] = DefaultLit(rs[il], nil)
nl.SetType(rs[il].Type())
}
}
goto out
}
l = n.Lhs[0]
r = n.Rhs[0]
// x,y,z = f()
if cr == 1 {
if r.Type() == nil {
goto out
}
switch r.Op() {
case ir.OCALLMETH, ir.OCALLINTER, ir.OCALLFUNC:
if !r.Type().IsFuncArgStruct() {
break
}
cr = r.Type().NumFields()
if cr != cl {
goto mismatch
}
r.(*ir.CallExpr).Use = ir.CallUseList
n.SetOp(ir.OAS2FUNC)
for i, l := range n.Lhs {
f := r.Type().Field(i)
if f.Type != nil && l.Type() != nil {
checkassignto(f.Type, l)
}
if ir.DeclaredBy(l, n) && l.Name().Ntype == nil {
l.SetType(f.Type)
}
}
goto out
}
} }
// x, ok = y // x, ok = y
if cl == 2 && cr == 1 { assignOK:
if r.Type() == nil { for len(lhs) == 2 && cr == 1 {
goto out stmt := stmt.(*ir.AssignListStmt)
} r := rhs[0]
switch r.Op() { switch r.Op() {
case ir.OINDEXMAP, ir.ORECV, ir.ODOTTYPE: case ir.OINDEXMAP:
switch r.Op() { stmt.SetOp(ir.OAS2MAPR)
case ir.OINDEXMAP: case ir.ORECV:
n.SetOp(ir.OAS2MAPR) stmt.SetOp(ir.OAS2RECV)
case ir.ORECV: case ir.ODOTTYPE:
n.SetOp(ir.OAS2RECV) r := r.(*ir.TypeAssertExpr)
case ir.ODOTTYPE: stmt.SetOp(ir.OAS2DOTTYPE)
r := r.(*ir.TypeAssertExpr) r.SetOp(ir.ODOTTYPE2)
n.SetOp(ir.OAS2DOTTYPE) default:
r.SetOp(ir.ODOTTYPE2) break assignOK
}
if l.Type() != nil {
checkassignto(r.Type(), l)
}
if ir.DeclaredBy(l, n) {
l.SetType(r.Type())
}
l := n.Lhs[1]
if l.Type() != nil && !l.Type().IsBoolean() {
checkassignto(types.Types[types.TBOOL], l)
}
if ir.DeclaredBy(l, n) && l.Name().Ntype == nil {
l.SetType(types.Types[types.TBOOL])
}
goto out
} }
assignType(0, r.Type())
assignType(1, types.UntypedBool)
return
} }
mismatch: if len(lhs) != cr {
switch r.Op() { if r, ok := rhs[0].(*ir.CallExpr); ok && len(rhs) == 1 {
default: if r.Type() != nil {
base.Errorf("assignment mismatch: %d variables but %d values", cl, cr) base.ErrorfAt(stmt.Pos(), "assignment mismatch: %d variable%s but %v returns %d value%s", len(lhs), plural(len(lhs)), r.X, cr, plural(cr))
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER: }
r := r.(*ir.CallExpr) } else {
base.Errorf("assignment mismatch: %d variables but %v returns %d values", cl, r.X, cr) base.ErrorfAt(stmt.Pos(), "assignment mismatch: %d variable%s but %v value%s", len(lhs), plural(len(lhs)), len(rhs), plural(len(rhs)))
}
for i := range lhs {
checkLHS(i, nil)
}
return
} }
// second half of dance // x,y,z = f()
out: if cr > len(rhs) {
n.SetTypecheck(1) stmt := stmt.(*ir.AssignListStmt)
ls = n.Lhs stmt.SetOp(ir.OAS2FUNC)
for i1, n1 := range ls { r := rhs[0].(*ir.CallExpr)
if n1.Typecheck() == 0 { r.Use = ir.CallUseList
ls[i1] = AssignExpr(ls[i1]) rtyp := r.Type()
for i := range lhs {
assignType(i, rtyp.Field(i).Type)
}
return
}
for i, r := range rhs {
checkLHS(i, r.Type())
if lhs[i].Type() != nil {
rhs[i] = AssignConv(r, lhs[i].Type(), "assignment")
} }
} }
} }
func plural(n int) string {
if n == 1 {
return ""
}
return "s"
}
// tcFor typechecks an OFOR node. // tcFor typechecks an OFOR node.
func tcFor(n *ir.ForStmt) ir.Node { func tcFor(n *ir.ForStmt) ir.Node {
Stmts(n.Init()) Stmts(n.Init())
@ -399,11 +330,11 @@ func tcRange(n *ir.RangeStmt) {
// second half of dance, the first half being typecheckrangeExpr // second half of dance, the first half being typecheckrangeExpr
n.SetTypecheck(1) n.SetTypecheck(1)
ls := n.Vars if n.Key != nil && n.Key.Typecheck() == 0 {
for i1, n1 := range ls { n.Key = AssignExpr(n.Key)
if n1.Typecheck() == 0 { }
ls[i1] = AssignExpr(ls[i1]) if n.Value != nil && n.Value.Typecheck() == 0 {
} n.Value = AssignExpr(n.Value)
} }
decldepth++ decldepth++
@ -429,31 +360,23 @@ func tcReturn(n *ir.ReturnStmt) ir.Node {
// select // select
func tcSelect(sel *ir.SelectStmt) { func tcSelect(sel *ir.SelectStmt) {
var def ir.Node var def *ir.CommClause
lno := ir.SetPos(sel) lno := ir.SetPos(sel)
Stmts(sel.Init()) Stmts(sel.Init())
for _, ncase := range sel.Cases { for _, ncase := range sel.Cases {
ncase := ncase.(*ir.CaseStmt) if ncase.Comm == nil {
if len(ncase.List) == 0 {
// default // default
if def != nil { if def != nil {
base.ErrorfAt(ncase.Pos(), "multiple defaults in select (first at %v)", ir.Line(def)) base.ErrorfAt(ncase.Pos(), "multiple defaults in select (first at %v)", ir.Line(def))
} else { } else {
def = ncase def = ncase
} }
} else if len(ncase.List) > 1 {
base.ErrorfAt(ncase.Pos(), "select cases cannot be lists")
} else { } else {
ncase.List[0] = Stmt(ncase.List[0]) n := Stmt(ncase.Comm)
n := ncase.List[0]
ncase.Comm = n ncase.Comm = n
ncase.List.Set(nil) oselrecv2 := func(dst, recv ir.Node, def bool) {
oselrecv2 := func(dst, recv ir.Node, colas bool) { n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, nil, nil) n.Def = def
n.Lhs = []ir.Node{dst, ir.BlankNode}
n.Rhs = []ir.Node{recv}
n.Def = colas
n.SetTypecheck(1) n.SetTypecheck(1)
ncase.Comm = n ncase.Comm = n
} }
@ -577,7 +500,6 @@ func tcSwitchExpr(n *ir.SwitchStmt) {
var defCase ir.Node var defCase ir.Node
var cs constSet var cs constSet
for _, ncase := range n.Cases { for _, ncase := range n.Cases {
ncase := ncase.(*ir.CaseStmt)
ls := ncase.List ls := ncase.List
if len(ls) == 0 { // default: if len(ls) == 0 { // default:
if defCase != nil { if defCase != nil {
@ -646,7 +568,6 @@ func tcSwitchType(n *ir.SwitchStmt) {
var defCase, nilCase ir.Node var defCase, nilCase ir.Node
var ts typeSet var ts typeSet
for _, ncase := range n.Cases { for _, ncase := range n.Cases {
ncase := ncase.(*ir.CaseStmt)
ls := ncase.List ls := ncase.List
if len(ls) == 0 { // default: if len(ls) == 0 { // default:
if defCase != nil { if defCase != nil {
@ -694,7 +615,7 @@ func tcSwitchType(n *ir.SwitchStmt) {
ts.add(ncase.Pos(), n1.Type()) ts.add(ncase.Pos(), n1.Type())
} }
if len(ncase.Vars) != 0 { if ncase.Var != nil {
// Assign the clause variable's type. // Assign the clause variable's type.
vt := t vt := t
if len(ls) == 1 { if len(ls) == 1 {
@ -707,7 +628,7 @@ func tcSwitchType(n *ir.SwitchStmt) {
} }
} }
nvar := ncase.Vars[0] nvar := ncase.Var
nvar.SetType(vt) nvar.SetType(vt)
if vt != nil { if vt != nil {
nvar = AssignExpr(nvar) nvar = AssignExpr(nvar)
@ -716,7 +637,7 @@ func tcSwitchType(n *ir.SwitchStmt) {
nvar.SetTypecheck(1) nvar.SetTypecheck(1)
nvar.SetWalkdef(1) nvar.SetWalkdef(1)
} }
ncase.Vars[0] = nvar ncase.Var = nvar
} }
Stmts(ncase.Body) Stmts(ncase.Body)

View File

@ -73,13 +73,42 @@ func tcChanType(n *ir.ChanType) ir.Node {
// tcFuncType typechecks an OTFUNC node. // tcFuncType typechecks an OTFUNC node.
func tcFuncType(n *ir.FuncType) ir.Node { func tcFuncType(n *ir.FuncType) ir.Node {
n.SetOTYPE(NewFuncType(n.Recv, n.Params, n.Results)) misc := func(f *types.Field, nf *ir.Field) {
f.SetIsDDD(nf.IsDDD)
if nf.Decl != nil {
nf.Decl.SetType(f.Type)
f.Nname = nf.Decl
}
}
lno := base.Pos
var recv *types.Field
if n.Recv != nil {
recv = tcField(n.Recv, misc)
}
t := types.NewSignature(types.LocalPkg, recv, tcFields(n.Params, misc), tcFields(n.Results, misc))
checkdupfields("argument", t.Recvs().FieldSlice(), t.Params().FieldSlice(), t.Results().FieldSlice())
base.Pos = lno
n.SetOTYPE(t)
return n return n
} }
// tcInterfaceType typechecks an OTINTER node. // tcInterfaceType typechecks an OTINTER node.
func tcInterfaceType(n *ir.InterfaceType) ir.Node { func tcInterfaceType(n *ir.InterfaceType) ir.Node {
n.SetOTYPE(tointerface(n.Methods)) if len(n.Methods) == 0 {
n.SetOTYPE(types.Types[types.TINTER])
return n
}
lno := base.Pos
methods := tcFields(n.Methods, nil)
base.Pos = lno
n.SetOTYPE(types.NewInterface(types.LocalPkg, methods))
return n return n
} }
@ -117,6 +146,43 @@ func tcSliceType(n *ir.SliceType) ir.Node {
// tcStructType typechecks an OTSTRUCT node. // tcStructType typechecks an OTSTRUCT node.
func tcStructType(n *ir.StructType) ir.Node { func tcStructType(n *ir.StructType) ir.Node {
n.SetOTYPE(NewStructType(n.Fields)) lno := base.Pos
fields := tcFields(n.Fields, func(f *types.Field, nf *ir.Field) {
if nf.Embedded {
checkembeddedtype(f.Type)
f.Embedded = 1
}
f.Note = nf.Note
})
checkdupfields("field", fields)
base.Pos = lno
n.SetOTYPE(types.NewStruct(types.LocalPkg, fields))
return n return n
} }
// tcField typechecks a generic Field.
// misc can be provided to handle specialized typechecking.
func tcField(n *ir.Field, misc func(*types.Field, *ir.Field)) *types.Field {
base.Pos = n.Pos
if n.Ntype != nil {
n.Type = typecheckNtype(n.Ntype).Type()
n.Ntype = nil
}
f := types.NewField(n.Pos, n.Sym, n.Type)
if misc != nil {
misc(f, n)
}
return f
}
// tcFields typechecks a slice of generic Fields.
// misc can be provided to handle specialized typechecking.
func tcFields(l []*ir.Field, misc func(*types.Field, *ir.Field)) []*types.Field {
fields := make([]*types.Field, len(l))
for i, n := range l {
fields[i] = tcField(n, misc)
}
return fields
}

View File

@ -251,13 +251,7 @@ func Resolve(n ir.Node) (res ir.Node) {
} }
} }
if inimport { return expandDecl(n)
base.Fatalf("recursive inimport")
}
inimport = true
n = expandDecl(n)
inimport = false
return n
} }
r := ir.AsNode(n.Sym().Def) r := ir.AsNode(n.Sym().Def)
@ -1232,7 +1226,7 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
if f1.Offset == types.BADWIDTH { if f1.Offset == types.BADWIDTH {
base.Fatalf("lookdot badwidth %v %p", f1, f1) base.Fatalf("lookdot badwidth %v %p", f1, f1)
} }
n.Offset = f1.Offset n.Selection = f1
n.SetType(f1.Type) n.SetType(f1.Type)
if t.IsInterface() { if t.IsInterface() {
if n.X.Type().IsPtr() { if n.X.Type().IsPtr() {
@ -1243,7 +1237,6 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
n.SetOp(ir.ODOTINTER) n.SetOp(ir.ODOTINTER)
} }
n.Selection = f1
return f1 return f1
} }
@ -1298,11 +1291,9 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
return nil return nil
} }
n.Sel = ir.MethodSym(n.X.Type(), f2.Sym) n.Selection = f2
n.Offset = f2.Offset
n.SetType(f2.Type) n.SetType(f2.Type)
n.SetOp(ir.ODOTMETH) n.SetOp(ir.ODOTMETH)
n.Selection = f2
return f2 return f2
} }
@ -1638,7 +1629,7 @@ func nonexported(sym *types.Sym) bool {
} }
func checklvalue(n ir.Node, verb string) { func checklvalue(n ir.Node, verb string) {
if !ir.IsAssignable(n) { if !ir.IsAddressable(n) {
base.Errorf("cannot %s %v", verb, n) base.Errorf("cannot %s %v", verb, n)
} }
} }
@ -1656,7 +1647,7 @@ func checkassign(stmt ir.Node, n ir.Node) {
} }
} }
if ir.IsAssignable(n) { if ir.IsAddressable(n) {
return return
} }
if n.Op() == ir.OINDEXMAP { if n.Op() == ir.OINDEXMAP {
@ -1690,6 +1681,11 @@ func checkassignlist(stmt ir.Node, l ir.Nodes) {
} }
func checkassignto(src *types.Type, dst ir.Node) { func checkassignto(src *types.Type, dst ir.Node) {
// TODO(mdempsky): Handle all untyped types correctly.
if src == types.UntypedBool && dst.Type().IsBoolean() {
return
}
if op, why := assignop(src, dst.Type()); op == ir.OXXX { if op, why := assignop(src, dst.Type()); op == ir.OXXX {
base.Errorf("cannot assign %v to %L in multiple assignment%s", src, dst, why) base.Errorf("cannot assign %v to %L in multiple assignment%s", src, dst, why)
return return
@ -2101,7 +2097,6 @@ func isTermNode(n ir.Node) bool {
} }
def := false def := false
for _, cas := range n.Cases { for _, cas := range n.Cases {
cas := cas.(*ir.CaseStmt)
if !isTermNodes(cas.Body) { if !isTermNodes(cas.Body) {
return false return false
} }
@ -2117,7 +2112,6 @@ func isTermNode(n ir.Node) bool {
return false return false
} }
for _, cas := range n.Cases { for _, cas := range n.Cases {
cas := cas.(*ir.CaseStmt)
if !isTermNodes(cas.Body) { if !isTermNodes(cas.Body) {
return false return false
} }
@ -2216,9 +2210,6 @@ func deadcodeslice(nn *ir.Nodes) {
case ir.OBLOCK: case ir.OBLOCK:
n := n.(*ir.BlockStmt) n := n.(*ir.BlockStmt)
deadcodeslice(&n.List) deadcodeslice(&n.List)
case ir.OCASE:
n := n.(*ir.CaseStmt)
deadcodeslice(&n.Body)
case ir.OFOR: case ir.OFOR:
n := n.(*ir.ForStmt) n := n.(*ir.ForStmt)
deadcodeslice(&n.Body) deadcodeslice(&n.Body)
@ -2231,10 +2222,14 @@ func deadcodeslice(nn *ir.Nodes) {
deadcodeslice(&n.Body) deadcodeslice(&n.Body)
case ir.OSELECT: case ir.OSELECT:
n := n.(*ir.SelectStmt) n := n.(*ir.SelectStmt)
deadcodeslice(&n.Cases) for _, cas := range n.Cases {
deadcodeslice(&cas.Body)
}
case ir.OSWITCH: case ir.OSWITCH:
n := n.(*ir.SwitchStmt) n := n.(*ir.SwitchStmt)
deadcodeslice(&n.Cases) for _, cas := range n.Cases {
deadcodeslice(&cas.Body)
}
} }
if cut { if cut {

View File

@ -10,7 +10,7 @@ import "cmd/compile/internal/base"
// hashing a Type. // hashing a Type.
type AlgKind int type AlgKind int
//go:generate stringer -type AlgKind -trimprefix A //go:generate stringer -type AlgKind -trimprefix A alg.go
const ( const (
// These values are known by runtime. // These values are known by runtime.

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type AlgKind -trimprefix A"; DO NOT EDIT. // Code generated by "stringer -type AlgKind -trimprefix A alg.go"; DO NOT EDIT.
package types package types

View File

@ -180,15 +180,6 @@ func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
b.WriteString(s.Name) b.WriteString(s.Name)
} }
func SymMethodName(s *Sym) string {
// Skip leading "type." in method name
name := s.Name
if i := strings.LastIndex(name, "."); i >= 0 {
name = name[i+1:]
}
return name
}
// Type // Type
var BasicTypeNames = []string{ var BasicTypeNames = []string{
@ -595,7 +586,10 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
if funarg != FunargNone { if funarg != FunargNone {
name = fmt.Sprint(f.Nname) name = fmt.Sprint(f.Nname)
} else if verb == 'L' { } else if verb == 'L' {
name = SymMethodName(s) name = s.Name
if name == ".F" {
name = "F" // Hack for toolstash -cmp.
}
if !IsExported(name) && mode != fmtTypeIDName { if !IsExported(name) && mode != fmtTypeIDName {
name = sconv(s, 0, mode) // qualify non-exported names (used on structs, not on funarg) name = sconv(s, 0, mode) // qualify non-exported names (used on structs, not on funarg)
} }

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:generate go run mkbuiltin.go
package types package types
import ( import (

View File

@ -1,4 +1,4 @@
// Code generated by "stringer -type EType -trimprefix T"; DO NOT EDIT. // Code generated by "stringer -type Kind -trimprefix T type.go"; DO NOT EDIT.
package types package types
@ -48,13 +48,13 @@ func _() {
_ = x[NTYPE-37] _ = x[NTYPE-37]
} }
const _EType_name = "xxxINT8UINT8INT16UINT16INT32UINT32INT64UINT64INTUINTUINTPTRCOMPLEX64COMPLEX128FLOAT32FLOAT64BOOLPTRFUNCSLICEARRAYSTRUCTCHANMAPINTERFORWANYSTRINGUNSAFEPTRIDEALNILBLANKFUNCARGSCHANARGSSSATUPLERESULTSNTYPE" const _Kind_name = "xxxINT8UINT8INT16UINT16INT32UINT32INT64UINT64INTUINTUINTPTRCOMPLEX64COMPLEX128FLOAT32FLOAT64BOOLPTRFUNCSLICEARRAYSTRUCTCHANMAPINTERFORWANYSTRINGUNSAFEPTRIDEALNILBLANKFUNCARGSCHANARGSSSATUPLERESULTSNTYPE"
var _EType_index = [...]uint8{0, 3, 7, 12, 17, 23, 28, 34, 39, 45, 48, 52, 59, 68, 78, 85, 92, 96, 99, 103, 108, 113, 119, 123, 126, 131, 135, 138, 144, 153, 158, 161, 166, 174, 182, 185, 190, 197, 202} var _Kind_index = [...]uint8{0, 3, 7, 12, 17, 23, 28, 34, 39, 45, 48, 52, 59, 68, 78, 85, 92, 96, 99, 103, 108, 113, 119, 123, 126, 131, 135, 138, 144, 153, 158, 161, 166, 174, 182, 185, 190, 197, 202}
func (i Kind) String() string { func (i Kind) String() string {
if i >= Kind(len(_EType_index)-1) { if i >= Kind(len(_Kind_index)-1) {
return "EType(" + strconv.FormatInt(int64(i), 10) + ")" return "Kind(" + strconv.FormatInt(int64(i), 10) + ")"
} }
return _EType_name[_EType_index[i]:_EType_index[i+1]] return _Kind_name[_Kind_index[i]:_Kind_index[i+1]]
} }

View File

@ -33,9 +33,9 @@ type VarObject interface {
RecordFrameOffset(int64) // save frame offset RecordFrameOffset(int64) // save frame offset
} }
//go:generate stringer -type EType -trimprefix T //go:generate stringer -type Kind -trimprefix T type.go
// EType describes a kind of type. // Kind describes a kind of type.
type Kind uint8 type Kind uint8
const ( const (

View File

@ -297,54 +297,6 @@ func fncall(l ir.Node, rt *types.Type) bool {
return true return true
} }
func ascompatee(op ir.Op, nl, nr []ir.Node, init *ir.Nodes) []ir.Node {
// check assign expression list to
// an expression list. called in
// expr-list = expr-list
// ensure order of evaluation for function calls
for i := range nl {
nl[i] = safeExpr(nl[i], init)
}
for i1 := range nr {
nr[i1] = safeExpr(nr[i1], init)
}
var nn []*ir.AssignStmt
i := 0
for ; i < len(nl); i++ {
if i >= len(nr) {
break
}
// Do not generate 'x = x' during return. See issue 4014.
if op == ir.ORETURN && ir.SameSafeExpr(nl[i], nr[i]) {
continue
}
nn = append(nn, ascompatee1(nl[i], nr[i], init))
}
// cannot happen: caller checked that lists had same length
if i < len(nl) || i < len(nr) {
var nln, nrn ir.Nodes
nln.Set(nl)
nrn.Set(nr)
base.Fatalf("error in shape across %+v %v %+v / %d %d [%s]", nln, op, nrn, len(nl), len(nr), ir.FuncName(ir.CurFunc))
}
return reorder3(nn)
}
func ascompatee1(l ir.Node, r ir.Node, init *ir.Nodes) *ir.AssignStmt {
// convas will turn map assigns into function calls,
// making it impossible for reorder3 to work.
n := ir.NewAssignStmt(base.Pos, l, r)
if l.Op() == ir.OINDEXMAP {
return n
}
return convas(n, init)
}
// check assign type list to // check assign type list to
// an expression list. called in // an expression list. called in
// expr-list = func() // expr-list = func()
@ -387,39 +339,79 @@ func ascompatet(nl ir.Nodes, nr *types.Type) []ir.Node {
return append(nn, mm...) return append(nn, mm...)
} }
// reorder3 // check assign expression list to
// from ascompatee // an expression list. called in
// a,b = c,d // expr-list = expr-list
// simultaneous assignment. there cannot func ascompatee(op ir.Op, nl, nr []ir.Node, init *ir.Nodes) []ir.Node {
// be later use of an earlier lvalue. // cannot happen: should have been rejected during type checking
// if len(nl) != len(nr) {
// function calls have been removed. base.Fatalf("assignment operands mismatch: %+v / %+v", ir.Nodes(nl), ir.Nodes(nr))
func reorder3(all []*ir.AssignStmt) []ir.Node { }
// ensure order of evaluation for function calls
for i := range nl {
nl[i] = safeExpr(nl[i], init)
}
for i := range nr {
nr[i] = safeExpr(nr[i], init)
}
var assigned ir.NameSet
var memWrite bool
// affected reports whether expression n could be affected by
// the assignments applied so far.
affected := func(n ir.Node) bool {
return ir.Any(n, func(n ir.Node) bool {
if n.Op() == ir.ONAME && assigned.Has(n.(*ir.Name)) {
return true
}
if memWrite && readsMemory(n) {
return true
}
return false
})
}
// If a needed expression may be affected by an // If a needed expression may be affected by an
// earlier assignment, make an early copy of that // earlier assignment, make an early copy of that
// expression and use the copy instead. // expression and use the copy instead.
var early []ir.Node var early []ir.Node
save := func(np *ir.Node) {
if n := *np; affected(n) {
tmp := ir.Node(typecheck.Temp(n.Type()))
as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, tmp, n))
early = append(early, as)
*np = tmp
}
}
var mapinit ir.Nodes var late []ir.Node
for i, n := range all { for i, l := range nl {
l := n.X r := nr[i]
// Do not generate 'x = x' during return. See issue 4014.
if op == ir.ORETURN && ir.SameSafeExpr(l, r) {
continue
}
as := ir.NewAssignStmt(base.Pos, l, r)
// Save subexpressions needed on left side. // Save subexpressions needed on left side.
// Drill through non-dereferences. // Drill through non-dereferences.
for { for {
switch ll := l; ll.Op() { switch ll := l.(type) {
case ir.ODOT: case *ir.IndexExpr:
ll := ll.(*ir.SelectorExpr)
l = ll.X
continue
case ir.OPAREN:
ll := ll.(*ir.ParenExpr)
l = ll.X
continue
case ir.OINDEX:
ll := ll.(*ir.IndexExpr)
if ll.X.Type().IsArray() { if ll.X.Type().IsArray() {
ll.Index = reorder3save(ll.Index, all, i, &early) save(&ll.Index)
l = ll.X
continue
}
case *ir.ParenExpr:
l = ll.X
continue
case *ir.SelectorExpr:
if ll.Op() == ir.ODOT {
l = ll.X l = ll.X
continue continue
} }
@ -427,230 +419,82 @@ func reorder3(all []*ir.AssignStmt) []ir.Node {
break break
} }
var name *ir.Name
switch l.Op() { switch l.Op() {
default: default:
base.Fatalf("reorder3 unexpected lvalue %v", l.Op()) base.Fatalf("unexpected lvalue %v", l.Op())
case ir.ONAME: case ir.ONAME:
break name = l.(*ir.Name)
case ir.OINDEX, ir.OINDEXMAP: case ir.OINDEX, ir.OINDEXMAP:
l := l.(*ir.IndexExpr) l := l.(*ir.IndexExpr)
l.X = reorder3save(l.X, all, i, &early) save(&l.X)
l.Index = reorder3save(l.Index, all, i, &early) save(&l.Index)
if l.Op() == ir.OINDEXMAP {
all[i] = convas(all[i], &mapinit)
}
case ir.ODEREF: case ir.ODEREF:
l := l.(*ir.StarExpr) l := l.(*ir.StarExpr)
l.X = reorder3save(l.X, all, i, &early) save(&l.X)
case ir.ODOTPTR: case ir.ODOTPTR:
l := l.(*ir.SelectorExpr) l := l.(*ir.SelectorExpr)
l.X = reorder3save(l.X, all, i, &early) save(&l.X)
} }
// Save expression on right side. // Save expression on right side.
all[i].Y = reorder3save(all[i].Y, all, i, &early) save(&as.Y)
late = append(late, convas(as, init))
if name == nil || name.Addrtaken() || name.Class_ == ir.PEXTERN || name.Class_ == ir.PAUTOHEAP {
memWrite = true
continue
}
if ir.IsBlank(name) {
// We can ignore assignments to blank.
continue
}
assigned.Add(name)
} }
early = append(mapinit, early...) return append(early, late...)
for _, as := range all {
early = append(early, as)
}
return early
} }
// if the evaluation of *np would be affected by the // readsMemory reports whether the evaluation n directly reads from
// assignments in all up to but not including the ith assignment, // memory that might be written to indirectly.
// copy into a temporary during *early and func readsMemory(n ir.Node) bool {
// replace *np with that temp. switch n.Op() {
// The result of reorder3save MUST be assigned back to n, e.g. case ir.ONAME:
// n.Left = reorder3save(n.Left, all, i, early) n := n.(*ir.Name)
func reorder3save(n ir.Node, all []*ir.AssignStmt, i int, early *[]ir.Node) ir.Node { return n.Class_ == ir.PEXTERN || n.Class_ == ir.PAUTOHEAP || n.Addrtaken()
if !aliased(n, all[:i]) {
return n
}
q := ir.Node(typecheck.Temp(n.Type())) case ir.OADD,
as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, q, n)) ir.OAND,
*early = append(*early, as) ir.OANDAND,
return q ir.OANDNOT,
} ir.OBITNOT,
ir.OCONV,
// Is it possible that the computation of r might be ir.OCONVIFACE,
// affected by assignments in all? ir.OCONVNOP,
func aliased(r ir.Node, all []*ir.AssignStmt) bool { ir.ODIV,
if r == nil { ir.ODOT,
ir.ODOTTYPE,
ir.OLITERAL,
ir.OLSH,
ir.OMOD,
ir.OMUL,
ir.ONEG,
ir.ONIL,
ir.OOR,
ir.OOROR,
ir.OPAREN,
ir.OPLUS,
ir.ORSH,
ir.OSUB,
ir.OXOR:
return false return false
} }
// Treat all fields of a struct as referring to the whole struct. // Be conservative.
// We could do better but we would have to keep track of the fields.
for r.Op() == ir.ODOT {
r = r.(*ir.SelectorExpr).X
}
// Look for obvious aliasing: a variable being assigned
// during the all list and appearing in n.
// Also record whether there are any writes to addressable
// memory (either main memory or variables whose addresses
// have been taken).
memwrite := false
for _, as := range all {
// We can ignore assignments to blank.
if ir.IsBlank(as.X) {
continue
}
lv := ir.OuterValue(as.X)
if lv.Op() != ir.ONAME {
memwrite = true
continue
}
l := lv.(*ir.Name)
switch l.Class_ {
default:
base.Fatalf("unexpected class: %v, %v", l, l.Class_)
case ir.PAUTOHEAP, ir.PEXTERN:
memwrite = true
continue
case ir.PAUTO, ir.PPARAM, ir.PPARAMOUT:
if l.Name().Addrtaken() {
memwrite = true
continue
}
if refersToName(l, r) {
// Direct hit: l appears in r.
return true
}
}
}
// The variables being written do not appear in r.
// However, r might refer to computed addresses
// that are being written.
// If no computed addresses are affected by the writes, no aliasing.
if !memwrite {
return false
}
// If r does not refer to any variables whose addresses have been taken,
// then the only possible writes to r would be directly to the variables,
// and we checked those above, so no aliasing problems.
if !anyAddrTaken(r) {
return false
}
// Otherwise, both the writes and r refer to computed memory addresses.
// Assume that they might conflict.
return true return true
} }
// anyAddrTaken reports whether the evaluation n,
// which appears on the left side of an assignment,
// may refer to variables whose addresses have been taken.
func anyAddrTaken(n ir.Node) bool {
return ir.Any(n, func(n ir.Node) bool {
switch n.Op() {
case ir.ONAME:
n := n.(*ir.Name)
return n.Class_ == ir.PEXTERN || n.Class_ == ir.PAUTOHEAP || n.Name().Addrtaken()
case ir.ODOT: // but not ODOTPTR - should have been handled in aliased.
base.Fatalf("anyAddrTaken unexpected ODOT")
case ir.OADD,
ir.OAND,
ir.OANDAND,
ir.OANDNOT,
ir.OBITNOT,
ir.OCONV,
ir.OCONVIFACE,
ir.OCONVNOP,
ir.ODIV,
ir.ODOTTYPE,
ir.OLITERAL,
ir.OLSH,
ir.OMOD,
ir.OMUL,
ir.ONEG,
ir.ONIL,
ir.OOR,
ir.OOROR,
ir.OPAREN,
ir.OPLUS,
ir.ORSH,
ir.OSUB,
ir.OXOR:
return false
}
// Be conservative.
return true
})
}
// refersToName reports whether r refers to name.
func refersToName(name *ir.Name, r ir.Node) bool {
return ir.Any(r, func(r ir.Node) bool {
return r.Op() == ir.ONAME && r == name
})
}
// refersToCommonName reports whether any name
// appears in common between l and r.
// This is called from sinit.go.
func refersToCommonName(l ir.Node, r ir.Node) bool {
if l == nil || r == nil {
return false
}
// This could be written elegantly as a Find nested inside a Find:
//
// found := ir.Find(l, func(l ir.Node) interface{} {
// if l.Op() == ir.ONAME {
// return ir.Find(r, func(r ir.Node) interface{} {
// if r.Op() == ir.ONAME && l.Name() == r.Name() {
// return r
// }
// return nil
// })
// }
// return nil
// })
// return found != nil
//
// But that would allocate a new closure for the inner Find
// for each name found on the left side.
// It may not matter at all, but the below way of writing it
// only allocates two closures, not O(|L|) closures.
var doL, doR func(ir.Node) error
var targetL *ir.Name
doR = func(r ir.Node) error {
if r.Op() == ir.ONAME && r.Name() == targetL {
return stop
}
return ir.DoChildren(r, doR)
}
doL = func(l ir.Node) error {
if l.Op() == ir.ONAME {
l := l.(*ir.Name)
targetL = l.Name()
if doR(r) == stop {
return stop
}
}
return ir.DoChildren(l, doL)
}
return doL(l) == stop
}
// expand append(l1, l2...) to // expand append(l1, l2...) to
// init { // init {
// s := l1 // s := l1
@ -700,17 +544,15 @@ func appendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
nodes.Append(nif) nodes.Append(nif)
// s = s[:n] // s = s[:n]
nt := ir.NewSliceExpr(base.Pos, ir.OSLICE, s) nt := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, nil, nn, nil)
nt.SetSliceBounds(nil, nn, nil)
nt.SetBounded(true) nt.SetBounded(true)
nodes.Append(ir.NewAssignStmt(base.Pos, s, nt)) nodes.Append(ir.NewAssignStmt(base.Pos, s, nt))
var ncopy ir.Node var ncopy ir.Node
if elemtype.HasPointers() { if elemtype.HasPointers() {
// copy(s[len(l1):], l2) // copy(s[len(l1):], l2)
slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, s) slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, ir.NewUnaryExpr(base.Pos, ir.OLEN, l1), nil, nil)
slice.SetType(s.Type()) slice.SetType(s.Type())
slice.SetSliceBounds(ir.NewUnaryExpr(base.Pos, ir.OLEN, l1), nil, nil)
ir.CurFunc.SetWBPos(n.Pos()) ir.CurFunc.SetWBPos(n.Pos())
@ -724,9 +566,8 @@ func appendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
// rely on runtime to instrument: // rely on runtime to instrument:
// copy(s[len(l1):], l2) // copy(s[len(l1):], l2)
// l2 can be a slice or string. // l2 can be a slice or string.
slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, s) slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, ir.NewUnaryExpr(base.Pos, ir.OLEN, l1), nil, nil)
slice.SetType(s.Type()) slice.SetType(s.Type())
slice.SetSliceBounds(ir.NewUnaryExpr(base.Pos, ir.OLEN, l1), nil, nil)
ptr1, len1 := backingArrayPtrLen(cheapExpr(slice, &nodes)) ptr1, len1 := backingArrayPtrLen(cheapExpr(slice, &nodes))
ptr2, len2 := backingArrayPtrLen(l2) ptr2, len2 := backingArrayPtrLen(l2)
@ -870,8 +711,7 @@ func extendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
nodes = append(nodes, nif) nodes = append(nodes, nif)
// s = s[:n] // s = s[:n]
nt := ir.NewSliceExpr(base.Pos, ir.OSLICE, s) nt := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, nil, nn, nil)
nt.SetSliceBounds(nil, nn, nil)
nt.SetBounded(true) nt.SetBounded(true)
nodes = append(nodes, ir.NewAssignStmt(base.Pos, s, nt)) nodes = append(nodes, ir.NewAssignStmt(base.Pos, s, nt))

View File

@ -95,8 +95,7 @@ func walkAppend(n *ir.CallExpr, init *ir.Nodes, dst ir.Node) ir.Node {
nn := typecheck.Temp(types.Types[types.TINT]) nn := typecheck.Temp(types.Types[types.TINT])
l = append(l, ir.NewAssignStmt(base.Pos, nn, ir.NewUnaryExpr(base.Pos, ir.OLEN, ns))) // n = len(s) l = append(l, ir.NewAssignStmt(base.Pos, nn, ir.NewUnaryExpr(base.Pos, ir.OLEN, ns))) // n = len(s)
slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, ns) // ...s[:n+argc] slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, ns, nil, ir.NewBinaryExpr(base.Pos, ir.OADD, nn, na), nil) // ...s[:n+argc]
slice.SetSliceBounds(nil, ir.NewBinaryExpr(base.Pos, ir.OADD, nn, na), nil)
slice.SetBounded(true) slice.SetBounded(true)
l = append(l, ir.NewAssignStmt(base.Pos, ns, slice)) // s = s[:n+argc] l = append(l, ir.NewAssignStmt(base.Pos, ns, slice)) // s = s[:n+argc]
@ -407,9 +406,8 @@ func walkMakeSlice(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
t = types.NewArray(t.Elem(), i) // [r]T t = types.NewArray(t.Elem(), i) // [r]T
var_ := typecheck.Temp(t) var_ := typecheck.Temp(t)
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil)) // zero temp appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil)) // zero temp
r := ir.NewSliceExpr(base.Pos, ir.OSLICE, var_) // arr[:l] r := ir.NewSliceExpr(base.Pos, ir.OSLICE, var_, nil, l, nil) // arr[:l]
r.SetSliceBounds(nil, l, nil)
// The conv is necessary in case n.Type is named. // The conv is necessary in case n.Type is named.
return walkExpr(typecheck.Expr(typecheck.Conv(r, n.Type())), init) return walkExpr(typecheck.Expr(typecheck.Conv(r, n.Type())), init)
} }
@ -438,7 +436,8 @@ func walkMakeSlice(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
fn := typecheck.LookupRuntime(fnname) fn := typecheck.LookupRuntime(fnname)
m.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(len, argtype), typecheck.Conv(cap, argtype)) m.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.TypePtr(t.Elem()), typecheck.Conv(len, argtype), typecheck.Conv(cap, argtype))
m.Ptr.MarkNonNil() m.Ptr.MarkNonNil()
m.LenCap = []ir.Node{typecheck.Conv(len, types.Types[types.TINT]), typecheck.Conv(cap, types.Types[types.TINT])} m.Len = typecheck.Conv(len, types.Types[types.TINT])
m.Cap = typecheck.Conv(cap, types.Types[types.TINT])
return walkExpr(typecheck.Expr(m), init) return walkExpr(typecheck.Expr(m), init)
} }
@ -471,7 +470,8 @@ func walkMakeSliceCopy(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
sh := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil) sh := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil)
sh.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, size, typecheck.NodNil(), ir.NewBool(false)) sh.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, size, typecheck.NodNil(), ir.NewBool(false))
sh.Ptr.MarkNonNil() sh.Ptr.MarkNonNil()
sh.LenCap = []ir.Node{length, length} sh.Len = length
sh.Cap = length
sh.SetType(t) sh.SetType(t)
s := typecheck.Temp(t) s := typecheck.Temp(t)
@ -493,7 +493,8 @@ func walkMakeSliceCopy(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
s := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil) s := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil)
s.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.TypePtr(t.Elem()), length, copylen, typecheck.Conv(copyptr, types.Types[types.TUNSAFEPTR])) s.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.TypePtr(t.Elem()), length, copylen, typecheck.Conv(copyptr, types.Types[types.TUNSAFEPTR]))
s.Ptr.MarkNonNil() s.Ptr.MarkNonNil()
s.LenCap = []ir.Node{length, length} s.Len = length
s.Cap = length
s.SetType(t) s.SetType(t)
return walkExpr(typecheck.Expr(s), init) return walkExpr(typecheck.Expr(s), init)
} }

View File

@ -155,7 +155,7 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
// Chose not to inline. Call equality function directly. // Chose not to inline. Call equality function directly.
if !inline { if !inline {
// eq algs take pointers; cmpl and cmpr must be addressable // eq algs take pointers; cmpl and cmpr must be addressable
if !ir.IsAssignable(cmpl) || !ir.IsAssignable(cmpr) { if !ir.IsAddressable(cmpl) || !ir.IsAddressable(cmpr) {
base.Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr) base.Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
} }
@ -428,11 +428,11 @@ func eqFor(t *types.Type) (n ir.Node, needsize bool) {
sym := reflectdata.TypeSymPrefix(".eq", t) sym := reflectdata.TypeSymPrefix(".eq", t)
n := typecheck.NewName(sym) n := typecheck.NewName(sym)
ir.MarkFunc(n) ir.MarkFunc(n)
n.SetType(typecheck.NewFuncType(nil, []*ir.Field{ n.SetType(types.NewSignature(types.NoPkg, nil, []*types.Field{
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)), types.NewField(base.Pos, nil, types.NewPtr(t)),
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)), types.NewField(base.Pos, nil, types.NewPtr(t)),
}, []*ir.Field{ }, []*types.Field{
ir.NewField(base.Pos, nil, nil, types.Types[types.TBOOL]), types.NewField(base.Pos, nil, types.Types[types.TBOOL]),
})) }))
return n, false return n, false
} }

View File

@ -425,7 +425,7 @@ func slicelit(ctxt initContext, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes)
} }
// make slice out of heap (6) // make slice out of heap (6)
a = ir.NewAssignStmt(base.Pos, var_, ir.NewSliceExpr(base.Pos, ir.OSLICE, vauto)) a = ir.NewAssignStmt(base.Pos, var_, ir.NewSliceExpr(base.Pos, ir.OSLICE, vauto, nil, nil, nil))
a = typecheck.Stmt(a) a = typecheck.Stmt(a)
a = orderStmtInPlace(a, map[string][]*ir.Name{}) a = orderStmtInPlace(a, map[string][]*ir.Name{})
@ -629,6 +629,7 @@ func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
// not a special composite literal assignment // not a special composite literal assignment
return false return false
} }
x := n.X.(*ir.Name)
if !types.Identical(n.X.Type(), n.Y.Type()) { if !types.Identical(n.X.Type(), n.Y.Type()) {
// not a special composite literal assignment // not a special composite literal assignment
return false return false
@ -640,7 +641,7 @@ func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
return false return false
case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT: case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
if refersToCommonName(n.X, n.Y) { if ir.Any(n.Y, func(y ir.Node) bool { return ir.Uses(y, x) }) {
// not a special composite literal assignment // not a special composite literal assignment
return false return false
} }

View File

@ -178,7 +178,7 @@ func walkConvInterface(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
// with a non-interface, especially in a switch on interface value // with a non-interface, especially in a switch on interface value
// with non-interface cases, is not visible to order.stmt, so we // with non-interface cases, is not visible to order.stmt, so we
// have to fall back on allocating a temp here. // have to fall back on allocating a temp here.
if !ir.IsAssignable(v) { if !ir.IsAddressable(v) {
v = copyExpr(v, v.Type(), init) v = copyExpr(v, v.Type(), init)
} }
v = typecheck.NodAddr(v) v = typecheck.NodAddr(v)
@ -260,7 +260,7 @@ func walkStringToBytes(n *ir.ConvExpr, init *ir.Nodes) ir.Node {
} }
// Slice the [n]byte to a []byte. // Slice the [n]byte to a []byte.
slice := ir.NewSliceExpr(n.Pos(), ir.OSLICEARR, p) slice := ir.NewSliceExpr(n.Pos(), ir.OSLICEARR, p, nil, nil, nil)
slice.SetType(n.Type()) slice.SetType(n.Type())
slice.SetTypecheck(1) slice.SetTypecheck(1)
return walkExpr(slice, init) return walkExpr(slice, init)

View File

@ -26,15 +26,6 @@ func walkExpr(n ir.Node, init *ir.Nodes) ir.Node {
return n return n
} }
// Eagerly checkwidth all expressions for the back end.
if n.Type() != nil && !n.Type().WidthCalculated() {
switch n.Type().Kind() {
case types.TBLANK, types.TNIL, types.TIDEAL:
default:
types.CheckSize(n.Type())
}
}
if init == n.PtrInit() { if init == n.PtrInit() {
// not okay to use n->ninit when walking n, // not okay to use n->ninit when walking n,
// because we might replace n with some other node // because we might replace n with some other node
@ -70,23 +61,14 @@ func walkExpr(n ir.Node, init *ir.Nodes) ir.Node {
n = walkExpr1(n, init) n = walkExpr1(n, init)
// Expressions that are constant at run time but not // Eagerly compute sizes of all expressions for the back end.
// considered const by the language spec are not turned into if typ := n.Type(); typ != nil && typ.Kind() != types.TBLANK && !typ.IsFuncArgStruct() {
// constants until walk. For example, if n is y%1 == 0, the types.CheckSize(typ)
// walk of y%1 may have replaced it by 0.
// Check whether n with its updated args is itself now a constant.
t := n.Type()
n = typecheck.EvalConst(n)
if n.Type() != t {
base.Fatalf("evconst changed Type: %v had type %v, now %v", n, t, n.Type())
} }
if n.Op() == ir.OLITERAL { if ir.IsConst(n, constant.String) {
n = typecheck.Expr(n)
// Emit string symbol now to avoid emitting // Emit string symbol now to avoid emitting
// any concurrently during the backend. // any concurrently during the backend.
if v := n.Val(); v.Kind() == constant.String { _ = staticdata.StringSym(n.Pos(), constant.StringVal(n.Val()))
_ = staticdata.StringSym(n.Pos(), constant.StringVal(v))
}
} }
updateHasCall(n) updateHasCall(n)
@ -106,7 +88,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
base.Fatalf("walkexpr: switch 1 unknown op %+v", n.Op()) base.Fatalf("walkexpr: switch 1 unknown op %+v", n.Op())
panic("unreachable") panic("unreachable")
case ir.ONONAME, ir.OGETG, ir.ONEWOBJ, ir.OMETHEXPR: case ir.ONONAME, ir.OGETG, ir.ONEWOBJ:
return n return n
case ir.OTYPE, ir.ONAME, ir.OLITERAL, ir.ONIL, ir.ONAMEOFFSET: case ir.OTYPE, ir.ONAME, ir.OLITERAL, ir.ONIL, ir.ONAMEOFFSET:
@ -116,6 +98,11 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
// stringsym for constant strings. // stringsym for constant strings.
return n return n
case ir.OMETHEXPR:
// TODO(mdempsky): Do this right after type checking.
n := n.(*ir.MethodExpr)
return n.FuncName()
case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.OSPTR, ir.OITAB, ir.OIDATA: case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.OSPTR, ir.OITAB, ir.OIDATA:
n := n.(*ir.UnaryExpr) n := n.(*ir.UnaryExpr)
n.X = walkExpr(n.X, init) n.X = walkExpr(n.X, init)
@ -429,7 +416,7 @@ func safeExpr(n ir.Node, init *ir.Nodes) ir.Node {
} }
// make a copy; must not be used as an lvalue // make a copy; must not be used as an lvalue
if ir.IsAssignable(n) { if ir.IsAddressable(n) {
base.Fatalf("missing lvalue case in safeexpr: %v", n) base.Fatalf("missing lvalue case in safeexpr: %v", n)
} }
return cheapExpr(n, init) return cheapExpr(n, init)
@ -535,22 +522,28 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
return // already walked return // already walked
} }
params := n.X.Type().Params() // If this is a method call t.M(...),
// rewrite into a function call T.M(t, ...).
// TODO(mdempsky): Do this right after type checking.
if n.Op() == ir.OCALLMETH {
withRecv := make([]ir.Node, len(n.Args)+1)
dot := n.X.(*ir.SelectorExpr)
withRecv[0] = dot.X
copy(withRecv[1:], n.Args)
n.Args = withRecv
dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym)
n.SetOp(ir.OCALLFUNC)
n.X = typecheck.Expr(dot)
}
args := n.Args args := n.Args
params := n.X.Type().Params()
n.X = walkExpr(n.X, init) n.X = walkExpr(n.X, init)
walkExprList(args, init) walkExprList(args, init)
// If this is a method call, add the receiver at the beginning of the args.
if n.Op() == ir.OCALLMETH {
withRecv := make([]ir.Node, len(args)+1)
dot := n.X.(*ir.SelectorExpr)
withRecv[0] = dot.X
dot.X = nil
copy(withRecv[1:], args)
args = withRecv
}
// For any argument whose evaluation might require a function call, // For any argument whose evaluation might require a function call,
// store that argument into a temporary variable, // store that argument into a temporary variable,
// to prevent that calls from clobbering arguments already on the stack. // to prevent that calls from clobbering arguments already on the stack.
@ -559,16 +552,7 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
for i, arg := range args { for i, arg := range args {
updateHasCall(arg) updateHasCall(arg)
// Determine param type. // Determine param type.
var t *types.Type t := params.Field(i).Type
if n.Op() == ir.OCALLMETH {
if i == 0 {
t = n.X.Type().Recv().Type
} else {
t = params.Field(i - 1).Type
}
} else {
t = params.Field(i).Type
}
if base.Flag.Cfg.Instrumenting || fncall(arg, t) { if base.Flag.Cfg.Instrumenting || fncall(arg, t) {
// make assignment of fncall to tempAt // make assignment of fncall to tempAt
tmp := typecheck.Temp(t) tmp := typecheck.Temp(t)
@ -786,21 +770,19 @@ func walkSlice(n *ir.SliceExpr, init *ir.Nodes) ir.Node {
n.X = walkExpr(n.X, init) n.X = walkExpr(n.X, init)
} }
low, high, max := n.SliceBounds() n.Low = walkExpr(n.Low, init)
low = walkExpr(low, init) if n.Low != nil && ir.IsZero(n.Low) {
if low != nil && ir.IsZero(low) {
// Reduce x[0:j] to x[:j] and x[0:j:k] to x[:j:k]. // Reduce x[0:j] to x[:j] and x[0:j:k] to x[:j:k].
low = nil n.Low = nil
} }
high = walkExpr(high, init) n.High = walkExpr(n.High, init)
max = walkExpr(max, init) n.Max = walkExpr(n.Max, init)
n.SetSliceBounds(low, high, max)
if checkSlice { if checkSlice {
n.X = walkCheckPtrAlignment(n.X.(*ir.ConvExpr), init, max) n.X = walkCheckPtrAlignment(n.X.(*ir.ConvExpr), init, n.Max)
} }
if n.Op().IsSlice3() { if n.Op().IsSlice3() {
if max != nil && max.Op() == ir.OCAP && ir.SameSafeExpr(n.X, max.(*ir.UnaryExpr).X) { if n.Max != nil && n.Max.Op() == ir.OCAP && ir.SameSafeExpr(n.X, n.Max.(*ir.UnaryExpr).X) {
// Reduce x[i:j:cap(x)] to x[i:j]. // Reduce x[i:j:cap(x)] to x[i:j].
if n.Op() == ir.OSLICE3 { if n.Op() == ir.OSLICE3 {
n.SetOp(ir.OSLICE) n.SetOp(ir.OSLICE)
@ -817,20 +799,18 @@ func walkSlice(n *ir.SliceExpr, init *ir.Nodes) ir.Node {
// walkSliceHeader walks an OSLICEHEADER node. // walkSliceHeader walks an OSLICEHEADER node.
func walkSliceHeader(n *ir.SliceHeaderExpr, init *ir.Nodes) ir.Node { func walkSliceHeader(n *ir.SliceHeaderExpr, init *ir.Nodes) ir.Node {
n.Ptr = walkExpr(n.Ptr, init) n.Ptr = walkExpr(n.Ptr, init)
n.LenCap[0] = walkExpr(n.LenCap[0], init) n.Len = walkExpr(n.Len, init)
n.LenCap[1] = walkExpr(n.LenCap[1], init) n.Cap = walkExpr(n.Cap, init)
return n return n
} }
// TODO(josharian): combine this with its caller and simplify // TODO(josharian): combine this with its caller and simplify
func reduceSlice(n *ir.SliceExpr) ir.Node { func reduceSlice(n *ir.SliceExpr) ir.Node {
low, high, max := n.SliceBounds() if n.High != nil && n.High.Op() == ir.OLEN && ir.SameSafeExpr(n.X, n.High.(*ir.UnaryExpr).X) {
if high != nil && high.Op() == ir.OLEN && ir.SameSafeExpr(n.X, high.(*ir.UnaryExpr).X) {
// Reduce x[i:len(x)] to x[i:]. // Reduce x[i:len(x)] to x[i:].
high = nil n.High = nil
} }
n.SetSliceBounds(low, high, max) if (n.Op() == ir.OSLICE || n.Op() == ir.OSLICESTR) && n.Low == nil && n.High == nil {
if (n.Op() == ir.OSLICE || n.Op() == ir.OSLICESTR) && low == nil && high == nil {
// Reduce x[:] to x. // Reduce x[:] to x.
if base.Debug.Slice > 0 { if base.Debug.Slice > 0 {
base.Warn("slice: omit slice operation") base.Warn("slice: omit slice operation")
@ -969,22 +949,13 @@ func usefield(n *ir.SelectorExpr) {
case ir.ODOT, ir.ODOTPTR: case ir.ODOT, ir.ODOTPTR:
break break
} }
if n.Sel == nil {
// No field name. This DOTPTR was built by the compiler for access
// to runtime data structures. Ignore.
return
}
t := n.X.Type()
if t.IsPtr() {
t = t.Elem()
}
field := n.Selection field := n.Selection
if field == nil { if field == nil {
base.Fatalf("usefield %v %v without paramfld", n.X.Type(), n.Sel) base.Fatalf("usefield %v %v without paramfld", n.X.Type(), n.Sel)
} }
if field.Sym != n.Sel || field.Offset != n.Offset { if field.Sym != n.Sel {
base.Fatalf("field inconsistency: %v,%v != %v,%v", field.Sym, field.Offset, n.Sel, n.Offset) base.Fatalf("field inconsistency: %v != %v", field.Sym, n.Sel)
} }
if !strings.Contains(field.Note, "go:\"track\"") { if !strings.Contains(field.Note, "go:\"track\"") {
return return

View File

@ -235,7 +235,7 @@ func (o *orderState) safeExpr(n ir.Node) ir.Node {
// because we emit explicit VARKILL instructions marking the end of those // because we emit explicit VARKILL instructions marking the end of those
// temporaries' lifetimes. // temporaries' lifetimes.
func isaddrokay(n ir.Node) bool { func isaddrokay(n ir.Node) bool {
return ir.IsAssignable(n) && (n.Op() != ir.ONAME || n.(*ir.Name).Class_ == ir.PEXTERN || ir.IsAutoTmp(n)) return ir.IsAddressable(n) && (n.Op() != ir.ONAME || n.(*ir.Name).Class_ == ir.PEXTERN || ir.IsAutoTmp(n))
} }
// addrTemp ensures that n is okay to pass by address to runtime routines. // addrTemp ensures that n is okay to pass by address to runtime routines.
@ -843,12 +843,13 @@ func (o *orderState) stmt(n ir.Node) {
n.X = o.expr(n.X, nil) n.X = o.expr(n.X, nil)
orderBody := true orderBody := true
switch n.Type().Kind() { xt := typecheck.RangeExprType(n.X.Type())
switch xt.Kind() {
default: default:
base.Fatalf("order.stmt range %v", n.Type()) base.Fatalf("order.stmt range %v", n.Type())
case types.TARRAY, types.TSLICE: case types.TARRAY, types.TSLICE:
if len(n.Vars) < 2 || ir.IsBlank(n.Vars[1]) { if n.Value == nil || ir.IsBlank(n.Value) {
// for i := range x will only use x once, to compute len(x). // for i := range x will only use x once, to compute len(x).
// No need to copy it. // No need to copy it.
break break
@ -885,9 +886,10 @@ func (o *orderState) stmt(n ir.Node) {
// n.Prealloc is the temp for the iterator. // n.Prealloc is the temp for the iterator.
// hiter contains pointers and needs to be zeroed. // hiter contains pointers and needs to be zeroed.
n.Prealloc = o.newTemp(reflectdata.MapIterType(n.Type()), true) n.Prealloc = o.newTemp(reflectdata.MapIterType(xt), true)
} }
o.exprListInPlace(n.Vars) n.Key = o.exprInPlace(n.Key)
n.Value = o.exprInPlace(n.Value)
if orderBody { if orderBody {
orderBlock(&n.Body, o.free) orderBlock(&n.Body, o.free)
} }
@ -912,7 +914,6 @@ func (o *orderState) stmt(n ir.Node) {
n := n.(*ir.SelectStmt) n := n.(*ir.SelectStmt)
t := o.markTemp() t := o.markTemp()
for _, ncas := range n.Cases { for _, ncas := range n.Cases {
ncas := ncas.(*ir.CaseStmt)
r := ncas.Comm r := ncas.Comm
ir.SetPos(ncas) ir.SetPos(ncas)
@ -994,7 +995,6 @@ func (o *orderState) stmt(n ir.Node) {
// Also insert any ninit queued during the previous loop. // Also insert any ninit queued during the previous loop.
// (The temporary cleaning must follow that ninit work.) // (The temporary cleaning must follow that ninit work.)
for _, cas := range n.Cases { for _, cas := range n.Cases {
cas := cas.(*ir.CaseStmt)
orderBlock(&cas.Body, o.free) orderBlock(&cas.Body, o.free)
cas.Body.Prepend(o.cleanTempNoPop(t)...) cas.Body.Prepend(o.cleanTempNoPop(t)...)
@ -1034,13 +1034,12 @@ func (o *orderState) stmt(n ir.Node) {
n := n.(*ir.SwitchStmt) n := n.(*ir.SwitchStmt)
if base.Debug.Libfuzzer != 0 && !hasDefaultCase(n) { if base.Debug.Libfuzzer != 0 && !hasDefaultCase(n) {
// Add empty "default:" case for instrumentation. // Add empty "default:" case for instrumentation.
n.Cases.Append(ir.NewCaseStmt(base.Pos, nil, nil)) n.Cases = append(n.Cases, ir.NewCaseStmt(base.Pos, nil, nil))
} }
t := o.markTemp() t := o.markTemp()
n.Tag = o.expr(n.Tag, nil) n.Tag = o.expr(n.Tag, nil)
for _, ncas := range n.Cases { for _, ncas := range n.Cases {
ncas := ncas.(*ir.CaseStmt)
o.exprListInPlace(ncas.List) o.exprListInPlace(ncas.List)
orderBlock(&ncas.Body, o.free) orderBlock(&ncas.Body, o.free)
} }
@ -1054,7 +1053,6 @@ func (o *orderState) stmt(n ir.Node) {
func hasDefaultCase(n *ir.SwitchStmt) bool { func hasDefaultCase(n *ir.SwitchStmt) bool {
for _, ncas := range n.Cases { for _, ncas := range n.Cases {
ncas := ncas.(*ir.CaseStmt)
if len(ncas.List) == 0 { if len(ncas.List) == 0 {
return true return true
} }
@ -1296,14 +1294,9 @@ func (o *orderState) expr1(n, lhs ir.Node) ir.Node {
case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR: case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
n := n.(*ir.SliceExpr) n := n.(*ir.SliceExpr)
n.X = o.expr(n.X, nil) n.X = o.expr(n.X, nil)
low, high, max := n.SliceBounds() n.Low = o.cheapExpr(o.expr(n.Low, nil))
low = o.expr(low, nil) n.High = o.cheapExpr(o.expr(n.High, nil))
low = o.cheapExpr(low) n.Max = o.cheapExpr(o.expr(n.Max, nil))
high = o.expr(high, nil)
high = o.cheapExpr(high)
max = o.expr(max, nil)
max = o.cheapExpr(max)
n.SetSliceBounds(low, high, max)
if lhs == nil || lhs.Op() != ir.ONAME && !ir.SameSafeExpr(lhs, n.X) { if lhs == nil || lhs.Op() != ir.ONAME && !ir.SameSafeExpr(lhs, n.X) {
return o.copyExpr(n) return o.copyExpr(n)
} }

View File

@ -56,20 +56,11 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
// hb: hidden bool // hb: hidden bool
// a, v1, v2: not hidden aggregate, val 1, 2 // a, v1, v2: not hidden aggregate, val 1, 2
t := nrange.Type()
a := nrange.X a := nrange.X
t := typecheck.RangeExprType(a.Type())
lno := ir.SetPos(a) lno := ir.SetPos(a)
var v1, v2 ir.Node v1, v2 := nrange.Key, nrange.Value
l := len(nrange.Vars)
if l > 0 {
v1 = nrange.Vars[0]
}
if l > 1 {
v2 = nrange.Vars[1]
}
if ir.IsBlank(v2) { if ir.IsBlank(v2) {
v2 = nil v2 = nil
@ -121,7 +112,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
} }
// for v1, v2 := range ha { body } // for v1, v2 := range ha { body }
if cheapComputableIndex(nrange.Type().Elem().Width) { if cheapComputableIndex(t.Elem().Width) {
// v1, v2 = hv1, ha[hv1] // v1, v2 = hv1, ha[hv1]
tmp := ir.NewIndexExpr(base.Pos, ha, hv1) tmp := ir.NewIndexExpr(base.Pos, ha, hv1)
tmp.SetBounded(true) tmp.SetBounded(true)
@ -150,7 +141,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
ifGuard.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, hv1, hn) ifGuard.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, hv1, hn)
nfor.SetOp(ir.OFORUNTIL) nfor.SetOp(ir.OFORUNTIL)
hp := typecheck.Temp(types.NewPtr(nrange.Type().Elem())) hp := typecheck.Temp(types.NewPtr(t.Elem()))
tmp := ir.NewIndexExpr(base.Pos, ha, ir.NewInt(0)) tmp := ir.NewIndexExpr(base.Pos, ha, ir.NewInt(0))
tmp.SetBounded(true) tmp.SetBounded(true)
init = append(init, ir.NewAssignStmt(base.Pos, hp, typecheck.NodAddr(tmp))) init = append(init, ir.NewAssignStmt(base.Pos, hp, typecheck.NodAddr(tmp)))
@ -343,15 +334,12 @@ func isMapClear(n *ir.RangeStmt) bool {
return false return false
} }
if n.Op() != ir.ORANGE || n.Type().Kind() != types.TMAP || len(n.Vars) != 1 { t := n.X.Type()
return false if n.Op() != ir.ORANGE || t.Kind() != types.TMAP || n.Key == nil || n.Value != nil {
}
k := n.Vars[0]
if k == nil || ir.IsBlank(k) {
return false return false
} }
k := n.Key
// Require k to be a new variable name. // Require k to be a new variable name.
if !ir.DeclaredBy(k, n) { if !ir.DeclaredBy(k, n) {
return false return false
@ -372,7 +360,7 @@ func isMapClear(n *ir.RangeStmt) bool {
} }
// Keys where equality is not reflexive can not be deleted from maps. // Keys where equality is not reflexive can not be deleted from maps.
if !types.IsReflexive(m.Type().Key()) { if !types.IsReflexive(t.Key()) {
return false return false
} }
@ -428,7 +416,7 @@ func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
return nil return nil
} }
elemsize := loop.Type().Elem().Width elemsize := typecheck.RangeExprType(loop.X.Type()).Elem().Width
if elemsize <= 0 || !ir.IsZero(stmt.Y) { if elemsize <= 0 || !ir.IsZero(stmt.Y) {
return nil return nil
} }

View File

@ -21,7 +21,7 @@ func walkSelect(sel *ir.SelectStmt) {
sel.PtrInit().Set(nil) sel.PtrInit().Set(nil)
init = append(init, walkSelectCases(sel.Cases)...) init = append(init, walkSelectCases(sel.Cases)...)
sel.Cases = ir.Nodes{} sel.Cases = nil
sel.Compiled.Set(init) sel.Compiled.Set(init)
walkStmtList(sel.Compiled) walkStmtList(sel.Compiled)
@ -29,7 +29,7 @@ func walkSelect(sel *ir.SelectStmt) {
base.Pos = lno base.Pos = lno
} }
func walkSelectCases(cases ir.Nodes) []ir.Node { func walkSelectCases(cases []*ir.CommClause) []ir.Node {
ncas := len(cases) ncas := len(cases)
sellineno := base.Pos sellineno := base.Pos
@ -40,7 +40,7 @@ func walkSelectCases(cases ir.Nodes) []ir.Node {
// optimization: one-case select: single op. // optimization: one-case select: single op.
if ncas == 1 { if ncas == 1 {
cas := cases[0].(*ir.CaseStmt) cas := cases[0]
ir.SetPos(cas) ir.SetPos(cas)
l := cas.Init() l := cas.Init()
if cas.Comm != nil { // not default: if cas.Comm != nil { // not default:
@ -73,9 +73,8 @@ func walkSelectCases(cases ir.Nodes) []ir.Node {
// convert case value arguments to addresses. // convert case value arguments to addresses.
// this rewrite is used by both the general code and the next optimization. // this rewrite is used by both the general code and the next optimization.
var dflt *ir.CaseStmt var dflt *ir.CommClause
for _, cas := range cases { for _, cas := range cases {
cas := cas.(*ir.CaseStmt)
ir.SetPos(cas) ir.SetPos(cas)
n := cas.Comm n := cas.Comm
if n == nil { if n == nil {
@ -99,9 +98,9 @@ func walkSelectCases(cases ir.Nodes) []ir.Node {
// optimization: two-case select but one is default: single non-blocking op. // optimization: two-case select but one is default: single non-blocking op.
if ncas == 2 && dflt != nil { if ncas == 2 && dflt != nil {
cas := cases[0].(*ir.CaseStmt) cas := cases[0]
if cas == dflt { if cas == dflt {
cas = cases[1].(*ir.CaseStmt) cas = cases[1]
} }
n := cas.Comm n := cas.Comm
@ -147,7 +146,7 @@ func walkSelectCases(cases ir.Nodes) []ir.Node {
if dflt != nil { if dflt != nil {
ncas-- ncas--
} }
casorder := make([]*ir.CaseStmt, ncas) casorder := make([]*ir.CommClause, ncas)
nsends, nrecvs := 0, 0 nsends, nrecvs := 0, 0
var init []ir.Node var init []ir.Node
@ -170,7 +169,6 @@ func walkSelectCases(cases ir.Nodes) []ir.Node {
// register cases // register cases
for _, cas := range cases { for _, cas := range cases {
cas := cas.(*ir.CaseStmt)
ir.SetPos(cas) ir.SetPos(cas)
init = append(init, cas.Init()...) init = append(init, cas.Init()...)
@ -244,7 +242,7 @@ func walkSelectCases(cases ir.Nodes) []ir.Node {
} }
// dispatch cases // dispatch cases
dispatch := func(cond ir.Node, cas *ir.CaseStmt) { dispatch := func(cond ir.Node, cas *ir.CommClause) {
cond = typecheck.Expr(cond) cond = typecheck.Expr(cond)
cond = typecheck.DefaultLit(cond, nil) cond = typecheck.DefaultLit(cond, nil)
@ -287,9 +285,9 @@ var scase *types.Type
// Keep in sync with src/runtime/select.go. // Keep in sync with src/runtime/select.go.
func scasetype() *types.Type { func scasetype() *types.Type {
if scase == nil { if scase == nil {
scase = typecheck.NewStructType([]*ir.Field{ scase = types.NewStruct(types.NoPkg, []*types.Field{
ir.NewField(base.Pos, typecheck.Lookup("c"), nil, types.Types[types.TUNSAFEPTR]), types.NewField(base.Pos, typecheck.Lookup("c"), types.Types[types.TUNSAFEPTR]),
ir.NewField(base.Pos, typecheck.Lookup("elem"), nil, types.Types[types.TUNSAFEPTR]), types.NewField(base.Pos, typecheck.Lookup("elem"), types.Types[types.TUNSAFEPTR]),
}) })
scase.SetNoalg(true) scase.SetNoalg(true)
} }

View File

@ -71,7 +71,6 @@ func walkSwitchExpr(sw *ir.SwitchStmt) {
var defaultGoto ir.Node var defaultGoto ir.Node
var body ir.Nodes var body ir.Nodes
for _, ncase := range sw.Cases { for _, ncase := range sw.Cases {
ncase := ncase.(*ir.CaseStmt)
label := typecheck.AutoLabel(".s") label := typecheck.AutoLabel(".s")
jmp := ir.NewBranchStmt(ncase.Pos(), ir.OGOTO, label) jmp := ir.NewBranchStmt(ncase.Pos(), ir.OGOTO, label)
@ -96,7 +95,7 @@ func walkSwitchExpr(sw *ir.SwitchStmt) {
body.Append(br) body.Append(br)
} }
} }
sw.Cases.Set(nil) sw.Cases = nil
if defaultGoto == nil { if defaultGoto == nil {
br := ir.NewBranchStmt(base.Pos, ir.OBREAK, nil) br := ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)
@ -259,7 +258,6 @@ func allCaseExprsAreSideEffectFree(sw *ir.SwitchStmt) bool {
// enough. // enough.
for _, ncase := range sw.Cases { for _, ncase := range sw.Cases {
ncase := ncase.(*ir.CaseStmt)
for _, v := range ncase.List { for _, v := range ncase.List {
if v.Op() != ir.OLITERAL { if v.Op() != ir.OLITERAL {
return false return false
@ -318,26 +316,14 @@ func walkSwitchType(sw *ir.SwitchStmt) {
sw.Compiled.Append(ifNil) sw.Compiled.Append(ifNil)
// Load hash from type or itab. // Load hash from type or itab.
dotHash := ir.NewSelectorExpr(base.Pos, ir.ODOTPTR, itab, nil) dotHash := typeHashFieldOf(base.Pos, itab)
dotHash.SetType(types.Types[types.TUINT32])
dotHash.SetTypecheck(1)
if s.facename.Type().IsEmptyInterface() {
dotHash.Offset = int64(2 * types.PtrSize) // offset of hash in runtime._type
} else {
dotHash.Offset = int64(2 * types.PtrSize) // offset of hash in runtime.itab
}
dotHash.SetBounded(true) // guaranteed not to fault
s.hashname = copyExpr(dotHash, dotHash.Type(), &sw.Compiled) s.hashname = copyExpr(dotHash, dotHash.Type(), &sw.Compiled)
br := ir.NewBranchStmt(base.Pos, ir.OBREAK, nil) br := ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)
var defaultGoto, nilGoto ir.Node var defaultGoto, nilGoto ir.Node
var body ir.Nodes var body ir.Nodes
for _, ncase := range sw.Cases { for _, ncase := range sw.Cases {
ncase := ncase.(*ir.CaseStmt) caseVar := ncase.Var
var caseVar ir.Node
if len(ncase.Vars) != 0 {
caseVar = ncase.Vars[0]
}
// For single-type cases with an interface type, // For single-type cases with an interface type,
// we initialize the case variable as part of the type assertion. // we initialize the case variable as part of the type assertion.
@ -395,7 +381,7 @@ func walkSwitchType(sw *ir.SwitchStmt) {
body.Append(ncase.Body...) body.Append(ncase.Body...)
body.Append(br) body.Append(br)
} }
sw.Cases.Set(nil) sw.Cases = nil
if defaultGoto == nil { if defaultGoto == nil {
defaultGoto = br defaultGoto = br
@ -412,6 +398,32 @@ func walkSwitchType(sw *ir.SwitchStmt) {
walkStmtList(sw.Compiled) walkStmtList(sw.Compiled)
} }
// typeHashFieldOf returns an expression to select the type hash field
// from an interface's descriptor word (whether a *runtime._type or
// *runtime.itab pointer).
func typeHashFieldOf(pos src.XPos, itab *ir.UnaryExpr) *ir.SelectorExpr {
if itab.Op() != ir.OITAB {
base.Fatalf("expected OITAB, got %v", itab.Op())
}
var hashField *types.Field
if itab.X.Type().IsEmptyInterface() {
// runtime._type's hash field
if rtypeHashField == nil {
rtypeHashField = runtimeField("hash", int64(2*types.PtrSize), types.Types[types.TUINT32])
}
hashField = rtypeHashField
} else {
// runtime.itab's hash field
if itabHashField == nil {
itabHashField = runtimeField("hash", int64(2*types.PtrSize), types.Types[types.TUINT32])
}
hashField = itabHashField
}
return boundedDotPtr(pos, itab, hashField)
}
var rtypeHashField, itabHashField *types.Field
// A typeSwitch walks a type switch. // A typeSwitch walks a type switch.
type typeSwitch struct { type typeSwitch struct {
// Temporary variables (i.e., ONAMEs) used by type switch dispatch logic: // Temporary variables (i.e., ONAMEs) used by type switch dispatch logic:

View File

@ -539,12 +539,30 @@ func calcHasCall(n ir.Node) bool {
// itabType loads the _type field from a runtime.itab struct. // itabType loads the _type field from a runtime.itab struct.
func itabType(itab ir.Node) ir.Node { func itabType(itab ir.Node) ir.Node {
typ := ir.NewSelectorExpr(base.Pos, ir.ODOTPTR, itab, nil) if itabTypeField == nil {
typ.SetType(types.NewPtr(types.Types[types.TUINT8])) // runtime.itab's _type field
typ.SetTypecheck(1) itabTypeField = runtimeField("_type", int64(types.PtrSize), types.NewPtr(types.Types[types.TUINT8]))
typ.Offset = int64(types.PtrSize) // offset of _type in runtime.itab }
typ.SetBounded(true) // guaranteed not to fault return boundedDotPtr(base.Pos, itab, itabTypeField)
return typ }
var itabTypeField *types.Field
// boundedDotPtr returns a selector expression representing ptr.field
// and omits nil-pointer checks for ptr.
func boundedDotPtr(pos src.XPos, ptr ir.Node, field *types.Field) *ir.SelectorExpr {
sel := ir.NewSelectorExpr(pos, ir.ODOTPTR, ptr, field.Sym)
sel.Selection = field
sel.SetType(field.Type)
sel.SetTypecheck(1)
sel.SetBounded(true) // guaranteed not to fault
return sel
}
func runtimeField(name string, offset int64, typ *types.Type) *types.Field {
f := types.NewField(src.NoXPos, ir.Pkgs.Runtime.Lookup(name), typ)
f.Offset = offset
return f
} }
// ifaceData loads the data field from an interface. // ifaceData loads the data field from an interface.

View File

@ -1192,6 +1192,7 @@
// Require []Require // Require []Require
// Exclude []Module // Exclude []Module
// Replace []Replace // Replace []Replace
// Retract []Retract
// } // }
// //
// type Require struct { // type Require struct {

View File

@ -95,6 +95,7 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
Require []Require Require []Require
Exclude []Module Exclude []Module
Replace []Replace Replace []Replace
Retract []Retract
} }
type Require struct { type Require struct {

View File

@ -28,6 +28,11 @@ import (
// //
var buildList []module.Version var buildList []module.Version
// additionalExplicitRequirements is a list of modules paths for which
// WriteGoMod should record explicit requirements, even if they would be
// selected without those requirements. Each path must also appear in buildList.
var additionalExplicitRequirements []string
// capVersionSlice returns s with its cap reduced to its length. // capVersionSlice returns s with its cap reduced to its length.
func capVersionSlice(s []module.Version) []module.Version { func capVersionSlice(s []module.Version) []module.Version {
return s[:len(s):len(s)] return s[:len(s):len(s)]
@ -121,6 +126,12 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error
if !inconsistent { if !inconsistent {
buildList = final buildList = final
additionalExplicitRequirements = make([]string, 0, len(mustSelect))
for _, m := range mustSelect {
if m.Version != "none" {
additionalExplicitRequirements = append(additionalExplicitRequirements, m.Path)
}
}
return nil return nil
} }

View File

@ -15,6 +15,7 @@ import (
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"sort"
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
@ -27,6 +28,7 @@ import (
"cmd/go/internal/modfetch" "cmd/go/internal/modfetch"
"cmd/go/internal/mvs" "cmd/go/internal/mvs"
"cmd/go/internal/search" "cmd/go/internal/search"
"cmd/go/internal/str"
"golang.org/x/mod/modfile" "golang.org/x/mod/modfile"
"golang.org/x/mod/module" "golang.org/x/mod/module"
@ -845,13 +847,15 @@ func AllowWriteGoMod() {
// MinReqs returns a Reqs with minimal additional dependencies of Target, // MinReqs returns a Reqs with minimal additional dependencies of Target,
// as will be written to go.mod. // as will be written to go.mod.
func MinReqs() mvs.Reqs { func MinReqs() mvs.Reqs {
var retain []string retain := append([]string{}, additionalExplicitRequirements...)
for _, m := range buildList[1:] { for _, m := range buildList[1:] {
_, explicit := index.require[m] _, explicit := index.require[m]
if explicit || loaded.direct[m.Path] { if explicit || loaded.direct[m.Path] {
retain = append(retain, m.Path) retain = append(retain, m.Path)
} }
} }
sort.Strings(retain)
str.Uniq(&retain)
min, err := mvs.Req(Target, retain, &mvsReqs{buildList: buildList}) min, err := mvs.Req(Target, retain, &mvsReqs{buildList: buildList})
if err != nil { if err != nil {
base.Fatalf("go: %v", err) base.Fatalf("go: %v", err)

View File

@ -863,12 +863,21 @@ func loadFromRoots(params loaderParams) *loader {
for _, pkg := range ld.pkgs { for _, pkg := range ld.pkgs {
if pkg.mod == Target { if pkg.mod == Target {
for _, dep := range pkg.imports { for _, dep := range pkg.imports {
if dep.mod.Path != "" { if dep.mod.Path != "" && dep.mod.Path != Target.Path && index != nil {
_, explicit := index.require[dep.mod]
if allowWriteGoMod && cfg.BuildMod == "readonly" && !explicit {
// TODO(#40775): attach error to package instead of using
// base.Errorf. Ideally, 'go list' should not fail because of this,
// but today, LoadPackages calls WriteGoMod unconditionally, which
// would fail with a less clear message.
base.Errorf("go: %[1]s: package %[2]s imported from implicitly required module; try 'go get -d %[1]s' to add missing requirements", pkg.path, dep.path)
}
ld.direct[dep.mod.Path] = true ld.direct[dep.mod.Path] = true
} }
} }
} }
} }
base.ExitIfErrors()
// If we didn't scan all of the imports from the main module, or didn't use // If we didn't scan all of the imports from the main module, or didn't use
// imports.AnyTags, then we didn't necessarily load every package that // imports.AnyTags, then we didn't necessarily load every package that

View File

@ -21,6 +21,7 @@ import (
"cmd/go/internal/imports" "cmd/go/internal/imports"
"cmd/go/internal/modfetch" "cmd/go/internal/modfetch"
"cmd/go/internal/search" "cmd/go/internal/search"
"cmd/go/internal/str"
"cmd/go/internal/trace" "cmd/go/internal/trace"
"golang.org/x/mod/module" "golang.org/x/mod/module"
@ -1005,13 +1006,8 @@ func (rr *replacementRepo) Versions(prefix string) ([]string, error) {
sort.Slice(versions, func(i, j int) bool { sort.Slice(versions, func(i, j int) bool {
return semver.Compare(versions[i], versions[j]) < 0 return semver.Compare(versions[i], versions[j]) < 0
}) })
uniq := versions[:1] str.Uniq(&versions)
for _, v := range versions { return versions, nil
if v != uniq[len(uniq)-1] {
uniq = append(uniq, v)
}
}
return uniq, nil
} }
func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) { func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {

View File

@ -96,6 +96,20 @@ func Contains(x []string, s string) bool {
return false return false
} }
// Uniq removes consecutive duplicate strings from ss.
func Uniq(ss *[]string) {
if len(*ss) <= 1 {
return
}
uniq := (*ss)[:1]
for _, s := range *ss {
if s != uniq[len(uniq)-1] {
uniq = append(uniq, s)
}
}
*ss = uniq
}
func isSpaceByte(c byte) bool { func isSpaceByte(c byte) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r' return c == ' ' || c == '\t' || c == '\n' || c == '\r'
} }

View File

@ -0,0 +1,88 @@
cp go.mod.orig go.mod
# If we list a package in an implicit dependency imported from the main module,
# we should get an error because the dependency should have an explicit
# requirement.
go list -m indirect-with-pkg
stdout '^indirect-with-pkg v1.0.0 => ./indirect-with-pkg$'
! go list ./use-indirect
stderr '^go: m/use-indirect: package indirect-with-pkg imported from implicitly required module; try ''go get -d m/use-indirect'' to add missing requirements$'
# We can promote the implicit requirement by getting the importing package,
# as hinted.
go get -d m/use-indirect
cmp go.mod go.mod.use
cp go.mod.orig go.mod
# We can also promote implicit requirements using 'go get' on them, or their
# packages. This gives us "// indirect" requirements, since 'go get' doesn't
# know they're needed by the main module. See #43131 for the rationale.
go get -d indirect-with-pkg indirect-without-pkg
cmp go.mod go.mod.indirect
-- go.mod.orig --
module m
go 1.16
require direct v1.0.0
replace (
direct v1.0.0 => ./direct
indirect-with-pkg v1.0.0 => ./indirect-with-pkg
indirect-without-pkg v1.0.0 => ./indirect-without-pkg
)
-- go.mod.use --
module m
go 1.16
require (
direct v1.0.0
indirect-with-pkg v1.0.0
)
replace (
direct v1.0.0 => ./direct
indirect-with-pkg v1.0.0 => ./indirect-with-pkg
indirect-without-pkg v1.0.0 => ./indirect-without-pkg
)
-- go.mod.indirect --
module m
go 1.16
require (
direct v1.0.0
indirect-with-pkg v1.0.0 // indirect
indirect-without-pkg v1.0.0 // indirect
)
replace (
direct v1.0.0 => ./direct
indirect-with-pkg v1.0.0 => ./indirect-with-pkg
indirect-without-pkg v1.0.0 => ./indirect-without-pkg
)
-- use-indirect/use-indirect.go --
package use
import _ "indirect-with-pkg"
-- direct/go.mod --
module direct
go 1.16
require (
indirect-with-pkg v1.0.0
indirect-without-pkg v1.0.0
)
-- indirect-with-pkg/go.mod --
module indirect-with-pkg
go 1.16
-- indirect-with-pkg/p.go --
package p
-- indirect-without-pkg/go.mod --
module indirect-without-pkg
go 1.16

View File

@ -107,8 +107,8 @@ func TestDateParsing(t *testing.T) {
time.Date(1997, 11, 20, 9, 55, 6, 0, time.FixedZone("", -6*60*60)), time.Date(1997, 11, 20, 9, 55, 6, 0, time.FixedZone("", -6*60*60)),
}, },
{ {
"Thu, 20 Nov 1997 09:55:06 MDT (MDT)", "Thu, 20 Nov 1997 09:55:06 GMT (GMT)",
time.Date(1997, 11, 20, 9, 55, 6, 0, time.FixedZone("MDT", 0)), time.Date(1997, 11, 20, 9, 55, 6, 0, time.UTC),
}, },
{ {
"Fri, 21 Nov 1997 09:55:06 +1300 (TOT)", "Fri, 21 Nov 1997 09:55:06 +1300 (TOT)",
@ -278,8 +278,8 @@ func TestDateParsingCFWS(t *testing.T) {
true, true,
}, },
{ {
"Fri, 21 Nov 1997 09:55:06 MDT (MDT)", "Fri, 21 Nov 1997 09:55:06 GMT (GMT)",
time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("MDT", 0)), time.Date(1997, 11, 21, 9, 55, 6, 0, time.UTC),
true, true,
}, },
} }

View File

@ -0,0 +1,42 @@
// Copyright 2020 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.
// +build linux
package signal
import (
"os"
"syscall"
"testing"
"time"
)
const prSetKeepCaps = 8
// This test validates that syscall.AllThreadsSyscall() can reliably
// reach all 'm' (threads) of the nocgo runtime even when one thread
// is blocked waiting to receive signals from the kernel. This monitors
// for a regression vs. the fix for #43149.
func TestAllThreadsSyscallSignals(t *testing.T) {
if _, _, err := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, prSetKeepCaps, 0, 0); err == syscall.ENOTSUP {
t.Skip("AllThreadsSyscall disabled with cgo")
}
sig := make(chan os.Signal, 1)
Notify(sig, os.Interrupt)
for i := 0; i <= 100; i++ {
if _, _, errno := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, prSetKeepCaps, uintptr(i&1), 0); errno != 0 {
t.Fatalf("[%d] failed to set KEEP_CAPS=%d: %v", i, i&1, errno)
}
}
select {
case <-time.After(10 * time.Millisecond):
case <-sig:
t.Fatal("unexpected signal")
}
Stop(sig)
}

View File

@ -12,7 +12,7 @@ static void *threadentry(void*);
static void (*setg_gcc)(void*); static void (*setg_gcc)(void*);
// This will be set in gcc_android.c for android-specific customization. // This will be set in gcc_android.c for android-specific customization.
void (*x_cgo_inittls)(void **tlsg, void **tlsbase); void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
void void
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)

View File

@ -14,7 +14,7 @@ static void* threadentry(void*);
static void (*setg_gcc)(void*); static void (*setg_gcc)(void*);
// This will be set in gcc_android.c for android-specific customization. // This will be set in gcc_android.c for android-specific customization.
void (*x_cgo_inittls)(void **tlsg, void **tlsbase); void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
void void
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase) x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)

View File

@ -10,7 +10,7 @@
static void *threadentry(void*); static void *threadentry(void*);
void (*x_cgo_inittls)(void **tlsg, void **tlsbase); void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
static void (*setg_gcc)(void*); static void (*setg_gcc)(void*);
void void

View File

@ -12,7 +12,7 @@
static void *threadentry(void*); static void *threadentry(void*);
void (*x_cgo_inittls)(void **tlsg, void **tlsbase); void (*x_cgo_inittls)(void **tlsg, void **tlsbase) __attribute__((common));
static void (*setg_gcc)(void*); static void (*setg_gcc)(void*);
void void

View File

@ -1201,12 +1201,12 @@ type TimeHistogram timeHistogram
// Counts returns the counts for the given bucket, subBucket indices. // Counts returns the counts for the given bucket, subBucket indices.
// Returns true if the bucket was valid, otherwise returns the counts // Returns true if the bucket was valid, otherwise returns the counts
// for the overflow bucket and false. // for the underflow bucket and false.
func (th *TimeHistogram) Count(bucket, subBucket uint) (uint64, bool) { func (th *TimeHistogram) Count(bucket, subBucket uint) (uint64, bool) {
t := (*timeHistogram)(th) t := (*timeHistogram)(th)
i := bucket*TimeHistNumSubBuckets + subBucket i := bucket*TimeHistNumSubBuckets + subBucket
if i >= uint(len(t.counts)) { if i >= uint(len(t.counts)) {
return t.overflow, false return t.underflow, false
} }
return t.counts[i], true return t.counts[i], true
} }

View File

@ -69,17 +69,15 @@ const (
// for concurrent use. It is also safe to read all the values // for concurrent use. It is also safe to read all the values
// atomically. // atomically.
type timeHistogram struct { type timeHistogram struct {
counts [timeHistNumSuperBuckets * timeHistNumSubBuckets]uint64 counts [timeHistNumSuperBuckets * timeHistNumSubBuckets]uint64
overflow uint64 underflow uint64
} }
// record adds the given duration to the distribution. // record adds the given duration to the distribution.
//
// Although the duration is an int64 to facilitate ease-of-use
// with e.g. nanotime, the duration must be non-negative.
func (h *timeHistogram) record(duration int64) { func (h *timeHistogram) record(duration int64) {
if duration < 0 { if duration < 0 {
throw("timeHistogram encountered negative duration") atomic.Xadd64(&h.underflow, 1)
return
} }
// The index of the exponential bucket is just the index // The index of the exponential bucket is just the index
// of the highest set bit adjusted for how many bits we // of the highest set bit adjusted for how many bits we
@ -92,15 +90,17 @@ func (h *timeHistogram) record(duration int64) {
superBucket = uint(sys.Len64(uint64(duration))) - timeHistSubBucketBits superBucket = uint(sys.Len64(uint64(duration))) - timeHistSubBucketBits
if superBucket*timeHistNumSubBuckets >= uint(len(h.counts)) { if superBucket*timeHistNumSubBuckets >= uint(len(h.counts)) {
// The bucket index we got is larger than what we support, so // The bucket index we got is larger than what we support, so
// add into the special overflow bucket. // include this count in the highest bucket, which extends to
atomic.Xadd64(&h.overflow, 1) // infinity.
return superBucket = timeHistNumSuperBuckets - 1
subBucket = timeHistNumSubBuckets - 1
} else {
// The linear subbucket index is just the timeHistSubBucketsBits
// bits after the top bit. To extract that value, shift down
// the duration such that we leave the top bit and the next bits
// intact, then extract the index.
subBucket = uint((duration >> (superBucket - 1)) % timeHistNumSubBuckets)
} }
// The linear subbucket index is just the timeHistSubBucketsBits
// bits after the top bit. To extract that value, shift down
// the duration such that we leave the top bit and the next bits
// intact, then extract the index.
subBucket = uint((duration >> (superBucket - 1)) % timeHistNumSubBuckets)
} else { } else {
subBucket = uint(duration) subBucket = uint(duration)
} }
@ -128,7 +128,7 @@ func timeHistogramMetricsBuckets() []float64 {
// index to combine it with the bucketMin. // index to combine it with the bucketMin.
subBucketShift := uint(0) subBucketShift := uint(0)
if i > 1 { if i > 1 {
// The first two buckets are exact with respect to integers, // The first two super buckets are exact with respect to integers,
// so we'll never have to shift the sub-bucket index. Thereafter, // so we'll never have to shift the sub-bucket index. Thereafter,
// we shift up by 1 with each subsequent bucket. // we shift up by 1 with each subsequent bucket.
subBucketShift = uint(i - 2) subBucketShift = uint(i - 2)

View File

@ -5,6 +5,7 @@
package runtime_test package runtime_test
import ( import (
"math"
. "runtime" . "runtime"
"testing" "testing"
) )
@ -32,8 +33,8 @@ func TestTimeHistogram(t *testing.T) {
h.Record(base + v) h.Record(base + v)
} }
} }
// Hit the overflow bucket. // Hit the underflow bucket.
h.Record(int64(^uint64(0) >> 1)) h.Record(int64(-1))
// Check to make sure there's exactly one count in each // Check to make sure there's exactly one count in each
// bucket. // bucket.
@ -41,7 +42,7 @@ func TestTimeHistogram(t *testing.T) {
for j := uint(0); j < TimeHistNumSubBuckets; j++ { for j := uint(0); j < TimeHistNumSubBuckets; j++ {
c, ok := h.Count(i, j) c, ok := h.Count(i, j)
if !ok { if !ok {
t.Errorf("hit overflow bucket unexpectedly: (%d, %d)", i, j) t.Errorf("hit underflow bucket unexpectedly: (%d, %d)", i, j)
} else if c != 1 { } else if c != 1 {
t.Errorf("bucket (%d, %d) has count that is not 1: %d", i, j, c) t.Errorf("bucket (%d, %d) has count that is not 1: %d", i, j, c)
} }
@ -49,10 +50,21 @@ func TestTimeHistogram(t *testing.T) {
} }
c, ok := h.Count(TimeHistNumSuperBuckets, 0) c, ok := h.Count(TimeHistNumSuperBuckets, 0)
if ok { if ok {
t.Errorf("expected to hit overflow bucket: (%d, %d)", TimeHistNumSuperBuckets, 0) t.Errorf("expected to hit underflow bucket: (%d, %d)", TimeHistNumSuperBuckets, 0)
} }
if c != 1 { if c != 1 {
t.Errorf("overflow bucket has count that is not 1: %d", c) t.Errorf("underflow bucket has count that is not 1: %d", c)
} }
// Check overflow behavior.
// By hitting a high value, we should just be adding into the highest bucket.
h.Record(math.MaxInt64)
c, ok = h.Count(TimeHistNumSuperBuckets-1, TimeHistNumSubBuckets-1)
if !ok {
t.Error("hit underflow bucket in highest bucket unexpectedly")
} else if c != 2 {
t.Errorf("highest has count that is not 2: %d", c)
}
dummyTimeHistogram = TimeHistogram{} dummyTimeHistogram = TimeHistogram{}
} }

View File

@ -43,7 +43,18 @@ func initMetrics() {
} }
sizeClassBuckets = make([]float64, _NumSizeClasses) sizeClassBuckets = make([]float64, _NumSizeClasses)
for i := range sizeClassBuckets { for i := range sizeClassBuckets {
sizeClassBuckets[i] = float64(class_to_size[i]) // Size classes have an inclusive upper-bound
// and exclusive lower bound (e.g. 48-byte size class is
// (32, 48]) whereas we want and inclusive lower-bound
// and exclusive upper-bound (e.g. 48-byte size class is
// [33, 49). We can achieve this by shifting all bucket
// boundaries up by 1.
//
// Also, a float64 can precisely represent integers with
// value up to 2^53 and size classes are relatively small
// (nowhere near 2^48 even) so this will give us exact
// boundaries.
sizeClassBuckets[i] = float64(class_to_size[i] + 1)
} }
timeHistBuckets = timeHistogramMetricsBuckets() timeHistBuckets = timeHistogramMetricsBuckets()
metrics = map[string]metricData{ metrics = map[string]metricData{
@ -105,9 +116,9 @@ func initMetrics() {
"/gc/pauses:seconds": { "/gc/pauses:seconds": {
compute: func(_ *statAggregate, out *metricValue) { compute: func(_ *statAggregate, out *metricValue) {
hist := out.float64HistOrInit(timeHistBuckets) hist := out.float64HistOrInit(timeHistBuckets)
hist.counts[len(hist.counts)-1] = atomic.Load64(&memstats.gcPauseDist.overflow) hist.counts[0] = atomic.Load64(&memstats.gcPauseDist.underflow)
for i := range hist.buckets { for i := range hist.buckets {
hist.counts[i] = atomic.Load64(&memstats.gcPauseDist.counts[i]) hist.counts[i+1] = atomic.Load64(&memstats.gcPauseDist.counts[i])
} }
}, },
}, },

View File

@ -154,6 +154,12 @@ func TestReadMetricsConsistency(t *testing.T) {
if totalVirtual.got != totalVirtual.want { if totalVirtual.got != totalVirtual.want {
t.Errorf(`"/memory/classes/total:bytes" does not match sum of /memory/classes/**: got %d, want %d`, totalVirtual.got, totalVirtual.want) t.Errorf(`"/memory/classes/total:bytes" does not match sum of /memory/classes/**: got %d, want %d`, totalVirtual.got, totalVirtual.want)
} }
if objects.alloc.Counts[0] > 0 {
t.Error("found counts for objects of non-positive size in allocs-by-size")
}
if objects.free.Counts[0] > 0 {
t.Error("found counts for objects of non-positive size in frees-by-size")
}
if len(objects.alloc.Buckets) != len(objects.free.Buckets) { if len(objects.alloc.Buckets) != len(objects.free.Buckets) {
t.Error("allocs-by-size and frees-by-size buckets don't match in length") t.Error("allocs-by-size and frees-by-size buckets don't match in length")
} else if len(objects.alloc.Counts) != len(objects.free.Counts) { } else if len(objects.alloc.Counts) != len(objects.free.Counts) {

View File

@ -101,8 +101,7 @@ func gcMarkRootPrepare() {
// Gs may be created after this point, but it's okay that we // Gs may be created after this point, but it's okay that we
// ignore them because they begin life without any roots, so // ignore them because they begin life without any roots, so
// there's nothing to scan, and any roots they create during // there's nothing to scan, and any roots they create during
// the concurrent phase will be scanned during mark // the concurrent phase will be caught by the write barrier.
// termination.
work.nStackRoots = int(atomic.Loaduintptr(&allglen)) work.nStackRoots = int(atomic.Loaduintptr(&allglen))
work.markrootNext = 0 work.markrootNext = 0

View File

@ -72,7 +72,7 @@ func clearSignalHandlers() {
} }
//go:nosplit //go:nosplit
func sigblock() { func sigblock(exiting bool) {
} }
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).

View File

@ -301,6 +301,24 @@ func getHugePageSize() uintptr {
func osinit() { func osinit() {
ncpu = getproccount() ncpu = getproccount()
physHugePageSize = getHugePageSize() physHugePageSize = getHugePageSize()
if iscgo {
// #42494 glibc and musl reserve some signals for
// internal use and require they not be blocked by
// the rest of a normal C runtime. When the go runtime
// blocks...unblocks signals, temporarily, the blocked
// interval of time is generally very short. As such,
// these expectations of *libc code are mostly met by
// the combined go+cgo system of threads. However,
// when go causes a thread to exit, via a return from
// mstart(), the combined runtime can deadlock if
// these signals are blocked. Thus, don't block these
// signals when exiting threads.
// - glibc: SIGCANCEL (32), SIGSETXID (33)
// - musl: SIGTIMER (32), SIGCANCEL (33), SIGSYNCCALL (34)
sigdelset(&sigsetAllExiting, 32)
sigdelset(&sigsetAllExiting, 33)
sigdelset(&sigsetAllExiting, 34)
}
osArchInit() osArchInit()
} }

View File

@ -195,7 +195,7 @@ func msigrestore(sigmask sigset) {
func clearSignalHandlers() { func clearSignalHandlers() {
} }
func sigblock() { func sigblock(exiting bool) {
} }
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).

View File

@ -886,7 +886,7 @@ func clearSignalHandlers() {
} }
//go:nosplit //go:nosplit
func sigblock() { func sigblock(exiting bool) {
} }
// Called to initialize a new m (including the bootstrap m). // Called to initialize a new m (including the bootstrap m).

View File

@ -1313,7 +1313,7 @@ func mexit(osStack bool) {
throw("locked m0 woke up") throw("locked m0 woke up")
} }
sigblock() sigblock(true)
unminit() unminit()
// Free the gsignal stack. // Free the gsignal stack.
@ -1515,6 +1515,7 @@ func syscall_runtime_doAllThreadsSyscall(fn func(bool) bool) {
if netpollinited() { if netpollinited() {
netpollBreak() netpollBreak()
} }
sigRecvPrepareForFixup()
_g_ := getg() _g_ := getg()
if raceenabled { if raceenabled {
// For m's running without racectx, we loan out the // For m's running without racectx, we loan out the
@ -1754,7 +1755,7 @@ func needm() {
// starting a new m to run Go code via newosproc. // starting a new m to run Go code via newosproc.
var sigmask sigset var sigmask sigset
sigsave(&sigmask) sigsave(&sigmask)
sigblock() sigblock(false)
// Lock extra list, take head, unlock popped list. // Lock extra list, take head, unlock popped list.
// nilokay=false is safe here because of the invariant above, // nilokay=false is safe here because of the invariant above,
@ -1903,7 +1904,7 @@ func dropm() {
// Setg(nil) clears g, which is the signal handler's cue not to run Go handlers. // Setg(nil) clears g, which is the signal handler's cue not to run Go handlers.
// It's important not to try to handle a signal between those two steps. // It's important not to try to handle a signal between those two steps.
sigmask := mp.sigmask sigmask := mp.sigmask
sigblock() sigblock(false)
unminit() unminit()
mnext := lockextra(true) mnext := lockextra(true)
@ -3776,7 +3777,7 @@ func beforefork() {
// group. See issue #18600. // group. See issue #18600.
gp.m.locks++ gp.m.locks++
sigsave(&gp.m.sigmask) sigsave(&gp.m.sigmask)
sigblock() sigblock(false)
// This function is called before fork in syscall package. // This function is called before fork in syscall package.
// Code between fork and exec must not allocate memory nor even try to grow stack. // Code between fork and exec must not allocate memory nor even try to grow stack.

View File

@ -1042,15 +1042,26 @@ func msigrestore(sigmask sigset) {
sigprocmask(_SIG_SETMASK, &sigmask, nil) sigprocmask(_SIG_SETMASK, &sigmask, nil)
} }
// sigblock blocks all signals in the current thread's signal mask. // sigsetAllExiting is used by sigblock(true) when a thread is
// exiting. sigset_all is defined in OS specific code, and per GOOS
// behavior may override this default for sigsetAllExiting: see
// osinit().
var sigsetAllExiting = sigset_all
// sigblock blocks signals in the current thread's signal mask.
// This is used to block signals while setting up and tearing down g // This is used to block signals while setting up and tearing down g
// when a non-Go thread calls a Go function. // when a non-Go thread calls a Go function. When a thread is exiting
// The OS-specific code is expected to define sigset_all. // we use the sigsetAllExiting value, otherwise the OS specific
// definition of sigset_all is used.
// This is nosplit and nowritebarrierrec because it is called by needm // This is nosplit and nowritebarrierrec because it is called by needm
// which may be called on a non-Go thread with no g available. // which may be called on a non-Go thread with no g available.
//go:nosplit //go:nosplit
//go:nowritebarrierrec //go:nowritebarrierrec
func sigblock() { func sigblock(exiting bool) {
if exiting {
sigprocmask(_SIG_SETMASK, &sigsetAllExiting, nil)
return
}
sigprocmask(_SIG_SETMASK, &sigset_all, nil) sigprocmask(_SIG_SETMASK, &sigset_all, nil)
} }

View File

@ -12,12 +12,16 @@
// sigsend is called by the signal handler to queue a new signal. // sigsend is called by the signal handler to queue a new signal.
// signal_recv is called by the Go program to receive a newly queued signal. // signal_recv is called by the Go program to receive a newly queued signal.
// Synchronization between sigsend and signal_recv is based on the sig.state // Synchronization between sigsend and signal_recv is based on the sig.state
// variable. It can be in 3 states: sigIdle, sigReceiving and sigSending. // variable. It can be in 4 states: sigIdle, sigReceiving, sigSending and sigFixup.
// sigReceiving means that signal_recv is blocked on sig.Note and there are no // sigReceiving means that signal_recv is blocked on sig.Note and there are no
// new pending signals. // new pending signals.
// sigSending means that sig.mask *may* contain new pending signals, // sigSending means that sig.mask *may* contain new pending signals,
// signal_recv can't be blocked in this state. // signal_recv can't be blocked in this state.
// sigIdle means that there are no new pending signals and signal_recv is not blocked. // sigIdle means that there are no new pending signals and signal_recv is not blocked.
// sigFixup is a transient state that can only exist as a short
// transition from sigReceiving and then on to sigIdle: it is
// used to ensure the AllThreadsSyscall()'s mDoFixup() operation
// occurs on the sleeping m, waiting to receive a signal.
// Transitions between states are done atomically with CAS. // Transitions between states are done atomically with CAS.
// When signal_recv is unblocked, it resets sig.Note and rechecks sig.mask. // When signal_recv is unblocked, it resets sig.Note and rechecks sig.mask.
// If several sigsends and signal_recv execute concurrently, it can lead to // If several sigsends and signal_recv execute concurrently, it can lead to
@ -59,6 +63,7 @@ const (
sigIdle = iota sigIdle = iota
sigReceiving sigReceiving
sigSending sigSending
sigFixup
) )
// sigsend delivers a signal from sighandler to the internal signal delivery queue. // sigsend delivers a signal from sighandler to the internal signal delivery queue.
@ -112,6 +117,9 @@ Send:
notewakeup(&sig.note) notewakeup(&sig.note)
break Send break Send
} }
case sigFixup:
// nothing to do - we need to wait for sigIdle.
osyield()
} }
} }
@ -119,6 +127,19 @@ Send:
return true return true
} }
// sigRecvPrepareForFixup is used to temporarily wake up the
// signal_recv() running thread while it is blocked waiting for the
// arrival of a signal. If it causes the thread to wake up, the
// sig.state travels through this sequence: sigReceiving -> sigFixup
// -> sigIdle -> sigReceiving and resumes. (This is only called while
// GC is disabled.)
//go:nosplit
func sigRecvPrepareForFixup() {
if atomic.Cas(&sig.state, sigReceiving, sigFixup) {
notewakeup(&sig.note)
}
}
// Called to receive the next queued signal. // Called to receive the next queued signal.
// Must only be called from a single goroutine at a time. // Must only be called from a single goroutine at a time.
//go:linkname signal_recv os/signal.signal_recv //go:linkname signal_recv os/signal.signal_recv
@ -146,7 +167,16 @@ func signal_recv() uint32 {
} }
notetsleepg(&sig.note, -1) notetsleepg(&sig.note, -1)
noteclear(&sig.note) noteclear(&sig.note)
break Receive if !atomic.Cas(&sig.state, sigFixup, sigIdle) {
break Receive
}
// Getting here, the code will
// loop around again to sleep
// in state sigReceiving. This
// path is taken when
// sigRecvPrepareForFixup()
// has been called by another
// thread.
} }
case sigSending: case sigSending:
if atomic.Cas(&sig.state, sigSending, sigIdle) { if atomic.Cas(&sig.state, sigSending, sigIdle) {

View File

@ -92,6 +92,13 @@ func sendNote(s *byte) bool {
return true return true
} }
// sigRecvPrepareForFixup is a no-op on plan9. (This would only be
// called while GC is disabled.)
//
//go:nosplit
func sigRecvPrepareForFixup() {
}
// Called to receive the next queued signal. // Called to receive the next queued signal.
// Must only be called from a single goroutine at a time. // Must only be called from a single goroutine at a time.
//go:linkname signal_recv os/signal.signal_recv //go:linkname signal_recv os/signal.signal_recv

View File

@ -597,6 +597,14 @@ func compareStatus(filter, expect string) error {
return nil return nil
} }
// killAThread locks the goroutine to an OS thread and exits; this
// causes an OS thread to terminate.
func killAThread(c <-chan struct{}) {
runtime.LockOSThread()
<-c
return
}
// TestSetuidEtc performs tests on all of the wrapped system calls // TestSetuidEtc performs tests on all of the wrapped system calls
// that mirror to the 9 glibc syscalls with POSIX semantics. The test // that mirror to the 9 glibc syscalls with POSIX semantics. The test
// here is considered authoritative and should compile and run // here is considered authoritative and should compile and run
@ -647,6 +655,11 @@ func TestSetuidEtc(t *testing.T) {
} }
for i, v := range vs { for i, v := range vs {
// Generate some thread churn as we execute the tests.
c := make(chan struct{})
go killAThread(c)
close(c)
if err := v.fn(); err != nil { if err := v.fn(); err != nil {
t.Errorf("[%d] %q failed: %v", i, v.call, err) t.Errorf("[%d] %q failed: %v", i, v.call, err)
continue continue

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ package main
var a = twoResults() // ERROR "assignment mismatch: 1 variable but twoResults returns 2 values|2\-valued" var a = twoResults() // ERROR "assignment mismatch: 1 variable but twoResults returns 2 values|2\-valued"
var b, c, d = twoResults() // ERROR "assignment mismatch: 3 variables but twoResults returns 2 values|cannot initialize" var b, c, d = twoResults() // ERROR "assignment mismatch: 3 variables but twoResults returns 2 values|cannot initialize"
var e, f = oneResult() // ERROR "assignment mismatch: 2 variables but oneResult returns 1 values|cannot initialize" var e, f = oneResult() // ERROR "assignment mismatch: 2 variables but oneResult returns 1 value|cannot initialize"
func twoResults() (int, int) { func twoResults() (int, int) {
return 1, 2 return 1, 2

View File

@ -7,9 +7,9 @@
package main package main
func main() { func main() {
var a, b = 1 // ERROR "assignment mismatch: 2 variables but 1 values|wrong number of initializations|cannot initialize" var a, b = 1 // ERROR "assignment mismatch: 2 variables but 1 value|wrong number of initializations|cannot initialize"
_ = 1, 2 // ERROR "assignment mismatch: 1 variables but 2 values|number of variables does not match|cannot assign" _ = 1, 2 // ERROR "assignment mismatch: 1 variable but 2 values|number of variables does not match|cannot assign"
c, d := 1 // ERROR "assignment mismatch: 2 variables but 1 values|wrong number of initializations|cannot initialize" c, d := 1 // ERROR "assignment mismatch: 2 variables but 1 value|wrong number of initializations|cannot initialize"
e, f := 1, 2, 3 // ERROR "assignment mismatch: 2 variables but 3 values|wrong number of initializations|cannot initialize" e, f := 1, 2, 3 // ERROR "assignment mismatch: 2 variables but 3 values|wrong number of initializations|cannot initialize"
_, _, _, _ = c, d, e, f _, _, _, _ = c, d, e, f
} }

View File

@ -35,8 +35,8 @@ func main() {
_ = f.Exported _ = f.Exported
_ = f.exported // ERROR "f.exported undefined .type f1.Foo has no field or method exported, but does have Exported." _ = f.exported // ERROR "f.exported undefined .type f1.Foo has no field or method exported, but does have Exported."
_ = f.Unexported // ERROR "f.Unexported undefined .type f1.Foo has no field or method Unexported." _ = f.Unexported // ERROR "f.Unexported undefined .type f1.Foo has no field or method Unexported."
_ = f.unexported // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported." _ = f.unexported // ERROR "f.unexported undefined .cannot refer to unexported field or method unexported."
f.unexported = 10 // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported." f.unexported = 10 // ERROR "f.unexported undefined .cannot refer to unexported field or method unexported."
f.unexported() // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported." f.unexported() // ERROR "f.unexported undefined .cannot refer to unexported field or method unexported."
_ = f.hook // ERROR "f.hook undefined .cannot refer to unexported field or method hook." _ = f.hook // ERROR "f.hook undefined .cannot refer to unexported field or method hook."
} }

View File

@ -63,6 +63,7 @@ func _() {
_ = f1() // ok _ = f1() // ok
_, _ = f2() // ok _, _ = f2() // ok
_ = f2() // ERROR "assignment mismatch: 1 variable but f2 returns 2 values|cannot assign" _ = f2() // ERROR "assignment mismatch: 1 variable but f2 returns 2 values|cannot assign"
_ = f1(), 0 // ERROR "assignment mismatch: 1 variable but 2 values|cannot assign"
T.M0 // ERROR "T.M0 .* not used" T.M0 // ERROR "T.M0 .* not used"
t.M0 // ERROR "t.M0 .* not used" t.M0 // ERROR "t.M0 .* not used"
cap // ERROR "use of builtin cap not in function call|must be called" cap // ERROR "use of builtin cap not in function call|must be called"