mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
[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:
commit
a800acaae1
@ -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).
|
||||
|
||||
<pre>
|
||||
$ cd $GODIR/src/hash/sha1
|
||||
$ cd $GODIR/src/crypto/sha1
|
||||
$ [make changes...]
|
||||
$ $GODIR/bin/go test .
|
||||
</pre>
|
||||
|
@ -8,8 +8,8 @@
|
||||
# Consult https://www.iana.org/time-zones for the latest versions.
|
||||
|
||||
# Versions to use.
|
||||
CODE=2020d
|
||||
DATA=2020d
|
||||
CODE=2020e
|
||||
DATA=2020e
|
||||
|
||||
set -e
|
||||
rm -rf work
|
||||
|
Binary file not shown.
85
src/cmd/compile/internal/devirtualize/devirtualize.go
Normal file
85
src/cmd/compile/internal/devirtualize/devirtualize.go
Normal 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())
|
||||
}
|
||||
}
|
@ -347,21 +347,19 @@ func (e *escape) stmt(n ir.Node) {
|
||||
e.loopDepth--
|
||||
|
||||
case ir.ORANGE:
|
||||
// for List = range Right { Nbody }
|
||||
// for Key, Value = range X { Body }
|
||||
n := n.(*ir.RangeStmt)
|
||||
e.loopDepth++
|
||||
ks := e.addrs(n.Vars)
|
||||
e.addr(n.Key)
|
||||
k := e.addr(n.Value)
|
||||
e.block(n.Body)
|
||||
e.loopDepth--
|
||||
|
||||
// Right is evaluated outside the loop.
|
||||
k := e.discardHole()
|
||||
if len(ks) >= 2 {
|
||||
// X is evaluated outside the loop.
|
||||
if n.X.Type().IsArray() {
|
||||
k = ks[1].note(n, "range")
|
||||
k = k.note(n, "range")
|
||||
} else {
|
||||
k = ks[1].deref(n, "range-deref")
|
||||
}
|
||||
k = k.deref(n, "range-deref")
|
||||
}
|
||||
e.expr(e.later(k), n.X)
|
||||
|
||||
@ -371,9 +369,8 @@ func (e *escape) stmt(n ir.Node) {
|
||||
|
||||
var ks []hole
|
||||
for _, cas := range n.Cases { // cases
|
||||
cas := cas.(*ir.CaseStmt)
|
||||
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.
|
||||
if cv.Type().HasPointers() {
|
||||
ks = append(ks, k.dotType(cv.Type(), cas, "switch case"))
|
||||
@ -393,7 +390,6 @@ func (e *escape) stmt(n ir.Node) {
|
||||
case ir.OSELECT:
|
||||
n := n.(*ir.SelectStmt)
|
||||
for _, cas := range n.Cases {
|
||||
cas := cas.(*ir.CaseStmt)
|
||||
e.stmt(cas.Comm)
|
||||
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:
|
||||
n := n.(*ir.SliceExpr)
|
||||
e.expr(k.note(n, "slice"), n.X)
|
||||
low, high, max := n.SliceBounds()
|
||||
e.discard(low)
|
||||
e.discard(high)
|
||||
e.discard(max)
|
||||
e.discard(n.Low)
|
||||
e.discard(n.High)
|
||||
e.discard(n.Max)
|
||||
|
||||
case ir.OCONV, ir.OCONVNOP:
|
||||
n := n.(*ir.ConvExpr)
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/devirtualize"
|
||||
"cmd/compile/internal/dwarfgen"
|
||||
"cmd/compile/internal/escape"
|
||||
"cmd/compile/internal/inline"
|
||||
@ -243,7 +244,7 @@ func Main(archInit func(*ssagen.ArchInfo)) {
|
||||
// Devirtualize.
|
||||
for _, n := range typecheck.Target.Decls {
|
||||
if n.Op() == ir.ODCLFUNC {
|
||||
inline.Devirtualize(n.(*ir.Func))
|
||||
devirtualize.Func(n.(*ir.Func))
|
||||
}
|
||||
}
|
||||
ir.CurFunc = nil
|
||||
|
@ -324,9 +324,8 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
|
||||
if t == nil {
|
||||
base.Fatalf("no function type for [%p] %+v\n", n.X, n.X)
|
||||
}
|
||||
if types.IsRuntimePkg(n.X.Sym().Pkg) {
|
||||
fn := n.X.Sym().Name
|
||||
if fn == "heapBits.nextArena" {
|
||||
fn := ir.MethodExprName(n.X).Func
|
||||
if types.IsRuntimePkg(fn.Sym().Pkg) && fn.Sym().Name == "heapBits.nextArena" {
|
||||
// Special case: explicitly allow
|
||||
// mid-stack inlining of
|
||||
// runtime.heapBits.next even though
|
||||
@ -334,9 +333,8 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
|
||||
// runtime.heapBits.nextArena.
|
||||
break
|
||||
}
|
||||
}
|
||||
if inlfn := ir.MethodExprName(n.X).Func; inlfn.Inl != nil {
|
||||
v.budget -= inlfn.Inl.Cost
|
||||
if fn.Inl != nil {
|
||||
v.budget -= fn.Inl.Cost
|
||||
break
|
||||
}
|
||||
// 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,
|
||||
// even when package reflect was compiled without it (#35073).
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -1203,73 +1201,6 @@ func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
|
||||
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.
|
||||
func numNonClosures(list []*ir.Func) int {
|
||||
count := 0
|
||||
|
@ -572,14 +572,12 @@ type SelectorExpr struct {
|
||||
miniExpr
|
||||
X Node
|
||||
Sel *types.Sym
|
||||
Offset int64
|
||||
Selection *types.Field
|
||||
}
|
||||
|
||||
func NewSelectorExpr(pos src.XPos, op Op, x Node, sel *types.Sym) *SelectorExpr {
|
||||
n := &SelectorExpr{X: x, Sel: sel}
|
||||
n.pos = pos
|
||||
n.Offset = types.BADWIDTH
|
||||
n.SetOp(op)
|
||||
return n
|
||||
}
|
||||
@ -596,6 +594,7 @@ func (n *SelectorExpr) SetOp(op Op) {
|
||||
func (n *SelectorExpr) Sym() *types.Sym { return n.Sel }
|
||||
func (n *SelectorExpr) Implicit() bool { return n.flags&miniExprImplicit != 0 }
|
||||
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.
|
||||
// After type-checking it becomes a Name.
|
||||
@ -605,11 +604,13 @@ func (*SelectorExpr) CanBeNtype() {}
|
||||
type SliceExpr struct {
|
||||
miniExpr
|
||||
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 {
|
||||
n := &SliceExpr{X: x}
|
||||
func NewSliceExpr(pos src.XPos, op Op, x, low, high, max Node) *SliceExpr {
|
||||
n := &SliceExpr{X: x, Low: low, High: high, Max: max}
|
||||
n.pos = pos
|
||||
n.op = op
|
||||
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).
|
||||
// o must be a slicing op.
|
||||
func (o Op) IsSlice3() bool {
|
||||
@ -696,15 +642,15 @@ func (o Op) IsSlice3() bool {
|
||||
type SliceHeaderExpr struct {
|
||||
miniExpr
|
||||
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 {
|
||||
n := &SliceHeaderExpr{Ptr: ptr}
|
||||
n := &SliceHeaderExpr{Ptr: ptr, Len: len, Cap: cap}
|
||||
n.pos = pos
|
||||
n.op = OSLICEHEADER
|
||||
n.typ = typ
|
||||
n.LenCap = []Node{len, cap}
|
||||
return n
|
||||
}
|
||||
|
||||
@ -829,12 +775,12 @@ func IsZero(n Node) bool {
|
||||
}
|
||||
|
||||
// lvalue etc
|
||||
func IsAssignable(n Node) bool {
|
||||
func IsAddressable(n Node) bool {
|
||||
switch n.Op() {
|
||||
case OINDEX:
|
||||
n := n.(*IndexExpr)
|
||||
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() {
|
||||
return false
|
||||
@ -845,7 +791,7 @@ func IsAssignable(n Node) bool {
|
||||
|
||||
case ODOT:
|
||||
n := n.(*SelectorExpr)
|
||||
return IsAssignable(n.X)
|
||||
return IsAddressable(n.X)
|
||||
|
||||
case ONAME:
|
||||
n := n.(*Name)
|
||||
|
@ -444,12 +444,15 @@ func stmtFmt(n Node, s fmt.State) {
|
||||
break
|
||||
}
|
||||
|
||||
if len(n.Vars) == 0 {
|
||||
fmt.Fprintf(s, "for range %v { %v }", n.X, n.Body)
|
||||
break
|
||||
fmt.Fprint(s, "for")
|
||||
if n.Key != nil {
|
||||
fmt.Fprintf(s, " %v", n.Key)
|
||||
if n.Value != nil {
|
||||
fmt.Fprintf(s, ", %v", n.Value)
|
||||
}
|
||||
|
||||
fmt.Fprintf(s, "for %.v = range %v { %v }", n.Vars, n.X, n.Body)
|
||||
fmt.Fprint(s, " =")
|
||||
}
|
||||
fmt.Fprintf(s, " range %v { %v }", n.X, n.Body)
|
||||
|
||||
case OSELECT:
|
||||
n := n.(*SelectStmt)
|
||||
@ -475,7 +478,7 @@ func stmtFmt(n Node, s fmt.State) {
|
||||
fmt.Fprintf(s, " { %v }", n.Cases)
|
||||
|
||||
case OCASE:
|
||||
n := n.(*CaseStmt)
|
||||
n := n.(*CaseClause)
|
||||
if len(n.List) != 0 {
|
||||
fmt.Fprintf(s, "case %.v", n.List)
|
||||
} else {
|
||||
@ -753,7 +756,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
|
||||
fmt.Fprint(s, ".<nil>")
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(s, ".%s", types.SymMethodName(n.Method.Sym))
|
||||
fmt.Fprintf(s, ".%s", n.Method.Sym.Name)
|
||||
|
||||
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
||||
n := n.(*SelectorExpr)
|
||||
@ -762,7 +765,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
|
||||
fmt.Fprint(s, ".<nil>")
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(s, ".%s", types.SymMethodName(n.Sel))
|
||||
fmt.Fprintf(s, ".%s", n.Sel.Name)
|
||||
|
||||
case ODOTTYPE, ODOTTYPE2:
|
||||
n := n.(*TypeAssertExpr)
|
||||
@ -782,28 +785,24 @@ func exprFmt(n Node, s fmt.State, prec int) {
|
||||
n := n.(*SliceExpr)
|
||||
exprFmt(n.X, s, nprec)
|
||||
fmt.Fprint(s, "[")
|
||||
low, high, max := n.SliceBounds()
|
||||
if low != nil {
|
||||
fmt.Fprint(s, low)
|
||||
if n.Low != nil {
|
||||
fmt.Fprint(s, n.Low)
|
||||
}
|
||||
fmt.Fprint(s, ":")
|
||||
if high != nil {
|
||||
fmt.Fprint(s, high)
|
||||
if n.High != nil {
|
||||
fmt.Fprint(s, n.High)
|
||||
}
|
||||
if n.Op().IsSlice3() {
|
||||
fmt.Fprint(s, ":")
|
||||
if max != nil {
|
||||
fmt.Fprint(s, max)
|
||||
if n.Max != nil {
|
||||
fmt.Fprint(s, n.Max)
|
||||
}
|
||||
}
|
||||
fmt.Fprint(s, "]")
|
||||
|
||||
case OSLICEHEADER:
|
||||
n := n.(*SliceHeaderExpr)
|
||||
if len(n.LenCap) != 2 {
|
||||
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])
|
||||
fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Ptr, n.Len, n.Cap)
|
||||
|
||||
case OCOMPLEX, OCOPY:
|
||||
n := n.(*BinaryExpr)
|
||||
|
@ -206,50 +206,22 @@ func (f *Func) SetWBPos(pos src.XPos) {
|
||||
}
|
||||
|
||||
// funcname returns the name (without the package) of the function n.
|
||||
func FuncName(n Node) 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
|
||||
}
|
||||
func FuncName(f *Func) string {
|
||||
if f == nil || f.Nname == 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.
|
||||
// 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
|
||||
// if the compilation package is actually the empty string.
|
||||
func PkgFuncName(n Node) string {
|
||||
var s *types.Sym
|
||||
if n == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
if n.Op() == ONAME {
|
||||
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
|
||||
}
|
||||
func PkgFuncName(f *Func) string {
|
||||
if f == nil || f.Nname == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
s = f.Nname.Sym()
|
||||
}
|
||||
s := f.Sym()
|
||||
pkg := s.Pkg
|
||||
|
||||
p := base.Ctxt.Pkgpath
|
||||
|
@ -37,6 +37,8 @@ func main() {
|
||||
nodeType := lookup("Node")
|
||||
ntypeType := lookup("Ntype")
|
||||
nodesType := lookup("Nodes")
|
||||
slicePtrCaseClauseType := types.NewSlice(types.NewPointer(lookup("CaseClause")))
|
||||
slicePtrCommClauseType := types.NewSlice(types.NewPointer(lookup("CommClause")))
|
||||
ptrFieldType := types.NewPointer(lookup("Field"))
|
||||
slicePtrFieldType := types.NewSlice(ptrFieldType)
|
||||
ptrIdentType := types.NewPointer(lookup("Ident"))
|
||||
@ -76,6 +78,10 @@ func main() {
|
||||
switch {
|
||||
case is(nodesType):
|
||||
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):
|
||||
fmt.Fprintf(&buf, "if c.%s != nil { c.%s = c.%s.copy() }\n", name, name, name)
|
||||
case is(slicePtrFieldType):
|
||||
@ -94,6 +100,10 @@ func main() {
|
||||
fmt.Fprintf(&buf, "err = maybeDo(n.%s, err, do)\n", name)
|
||||
case is(nodesType):
|
||||
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):
|
||||
fmt.Fprintf(&buf, "err = maybeDoField(n.%s, err, do)\n", name)
|
||||
case is(slicePtrFieldType):
|
||||
@ -113,6 +123,10 @@ func main() {
|
||||
fmt.Fprintf(&buf, "n.%s = toNtype(maybeEdit(n.%s, edit))\n", name, name)
|
||||
case is(nodesType):
|
||||
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):
|
||||
fmt.Fprintf(&buf, "editField(n.%s, edit)\n", name)
|
||||
case is(slicePtrFieldType):
|
||||
@ -155,10 +169,6 @@ func forNodeFields(typName string, typ *types.Struct, f func(name string, is fun
|
||||
case "orig":
|
||||
continue
|
||||
}
|
||||
switch typName + "." + v.Name() {
|
||||
case "AddStringExpr.Alloc":
|
||||
continue
|
||||
}
|
||||
f(v.Name(), func(t types.Type) bool { return types.Identical(t, v.Type()) })
|
||||
}
|
||||
}
|
||||
|
@ -268,7 +268,6 @@ const (
|
||||
nameInlLocal // PAUTO created by inliner, derived from callee local
|
||||
nameOpenDeferSlot // if temporary var storing info for open-coded defers
|
||||
nameLibfuzzerExtraCounter // if PEXTERN should be assigned to __libfuzzer_extra_counters section
|
||||
nameIsDDD // is function argument a ...
|
||||
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) OpenDeferSlot() bool { return n.flags&nameOpenDeferSlot != 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) 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) SetOpenDeferSlot(b bool) { n.flags.set(nameOpenDeferSlot, 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.
|
||||
func (n *Name) MarkReadonly() {
|
||||
|
@ -226,29 +226,26 @@ func (n *CallPartExpr) editChildren(edit func(Node) Node) {
|
||||
n.X = maybeEdit(n.X, edit)
|
||||
}
|
||||
|
||||
func (n *CaseStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
|
||||
func (n *CaseStmt) copy() Node {
|
||||
func (n *CaseClause) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
|
||||
func (n *CaseClause) copy() Node {
|
||||
c := *n
|
||||
c.init = c.init.Copy()
|
||||
c.Vars = c.Vars.Copy()
|
||||
c.List = c.List.Copy()
|
||||
c.Body = c.Body.Copy()
|
||||
return &c
|
||||
}
|
||||
func (n *CaseStmt) doChildren(do func(Node) error) error {
|
||||
func (n *CaseClause) doChildren(do func(Node) error) error {
|
||||
var err error
|
||||
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 = maybeDo(n.Comm, err, do)
|
||||
err = maybeDoList(n.Body, err, do)
|
||||
return err
|
||||
}
|
||||
func (n *CaseStmt) editChildren(edit func(Node) Node) {
|
||||
func (n *CaseClause) editChildren(edit func(Node) Node) {
|
||||
editList(n.init, edit)
|
||||
editList(n.Vars, edit)
|
||||
n.Var = maybeEdit(n.Var, edit)
|
||||
editList(n.List, edit)
|
||||
n.Comm = maybeEdit(n.Comm, edit)
|
||||
editList(n.Body, edit)
|
||||
}
|
||||
|
||||
@ -296,6 +293,26 @@ func (n *ClosureReadExpr) editChildren(edit func(Node) Node) {
|
||||
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) copy() Node {
|
||||
c := *n
|
||||
@ -725,22 +742,23 @@ func (n *RangeStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
|
||||
func (n *RangeStmt) copy() Node {
|
||||
c := *n
|
||||
c.init = c.init.Copy()
|
||||
c.Vars = c.Vars.Copy()
|
||||
c.Body = c.Body.Copy()
|
||||
return &c
|
||||
}
|
||||
func (n *RangeStmt) doChildren(do func(Node) error) error {
|
||||
var err error
|
||||
err = maybeDoList(n.init, err, do)
|
||||
err = maybeDoList(n.Vars, 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)
|
||||
return err
|
||||
}
|
||||
func (n *RangeStmt) editChildren(edit func(Node) Node) {
|
||||
editList(n.init, edit)
|
||||
editList(n.Vars, edit)
|
||||
n.X = maybeEdit(n.X, edit)
|
||||
n.Key = maybeEdit(n.Key, edit)
|
||||
n.Value = maybeEdit(n.Value, 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 {
|
||||
c := *n
|
||||
c.init = c.init.Copy()
|
||||
c.Cases = c.Cases.Copy()
|
||||
c.Cases = copyComms(c.Cases)
|
||||
c.Compiled = c.Compiled.Copy()
|
||||
return &c
|
||||
}
|
||||
func (n *SelectStmt) doChildren(do func(Node) error) error {
|
||||
var err error
|
||||
err = maybeDoList(n.init, err, do)
|
||||
err = maybeDoList(n.Cases, err, do)
|
||||
err = maybeDoComms(n.Cases, err, do)
|
||||
err = maybeDoList(n.Compiled, err, do)
|
||||
return err
|
||||
}
|
||||
func (n *SelectStmt) editChildren(edit func(Node) Node) {
|
||||
editList(n.init, edit)
|
||||
editList(n.Cases, edit)
|
||||
editComms(n.Cases, 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 {
|
||||
c := *n
|
||||
c.init = c.init.Copy()
|
||||
c.List = c.List.Copy()
|
||||
return &c
|
||||
}
|
||||
func (n *SliceExpr) doChildren(do func(Node) error) error {
|
||||
var err error
|
||||
err = maybeDoList(n.init, 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
|
||||
}
|
||||
func (n *SliceExpr) editChildren(edit func(Node) Node) {
|
||||
editList(n.init, 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) copy() Node {
|
||||
c := *n
|
||||
c.init = c.init.Copy()
|
||||
c.LenCap = c.LenCap.Copy()
|
||||
return &c
|
||||
}
|
||||
func (n *SliceHeaderExpr) doChildren(do func(Node) error) error {
|
||||
var err error
|
||||
err = maybeDoList(n.init, 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
|
||||
}
|
||||
func (n *SliceHeaderExpr) editChildren(edit func(Node) Node) {
|
||||
editList(n.init, 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) }
|
||||
@ -941,7 +963,7 @@ func (n *SwitchStmt) Format(s fmt.State, verb rune) { FmtNode(n, s, verb) }
|
||||
func (n *SwitchStmt) copy() Node {
|
||||
c := *n
|
||||
c.init = c.init.Copy()
|
||||
c.Cases = c.Cases.Copy()
|
||||
c.Cases = copyCases(c.Cases)
|
||||
c.Compiled = c.Compiled.Copy()
|
||||
return &c
|
||||
}
|
||||
@ -949,14 +971,14 @@ func (n *SwitchStmt) doChildren(do func(Node) error) error {
|
||||
var err error
|
||||
err = maybeDoList(n.init, 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)
|
||||
return err
|
||||
}
|
||||
func (n *SwitchStmt) editChildren(edit func(Node) Node) {
|
||||
editList(n.init, edit)
|
||||
n.Tag = maybeEdit(n.Tag, edit)
|
||||
editList(n.Cases, edit)
|
||||
editCases(n.Cases, edit)
|
||||
editList(n.Compiled, edit)
|
||||
}
|
||||
|
||||
|
@ -76,48 +76,27 @@ func (v *bottomUpVisitor) visit(n *Func) uint32 {
|
||||
min := v.visitgen
|
||||
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) {
|
||||
switch n.Op() {
|
||||
case ONAME:
|
||||
n := n.(*Name)
|
||||
if n.Class_ == PFUNC {
|
||||
if n != nil && n.Name().Defn != nil {
|
||||
if m := v.visit(n.Name().Defn.(*Func)); m < min {
|
||||
min = m
|
||||
}
|
||||
}
|
||||
}
|
||||
case OMETHEXPR:
|
||||
n := n.(*MethodExpr)
|
||||
fn := MethodExprName(n)
|
||||
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
|
||||
}
|
||||
if n := n.(*Name); n.Class_ == PFUNC {
|
||||
do(n.Defn)
|
||||
}
|
||||
case ODOTMETH, OCALLPART, OMETHEXPR:
|
||||
if fn := MethodExprName(n); fn != nil {
|
||||
do(fn.Defn)
|
||||
}
|
||||
case OCLOSURE:
|
||||
n := n.(*ClosureExpr)
|
||||
if m := v.visit(n.Func); m < min {
|
||||
min = m
|
||||
}
|
||||
do(n.Func)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -173,24 +173,94 @@ func NewBranchStmt(pos src.XPos, op Op, label *types.Sym) *BranchStmt {
|
||||
|
||||
func (n *BranchStmt) Sym() *types.Sym { return n.Label }
|
||||
|
||||
// A CaseStmt is a case statement in a switch or select: case List: Body.
|
||||
type CaseStmt struct {
|
||||
// A CaseClause is a case statement in a switch or select: case List: Body.
|
||||
type CaseClause struct {
|
||||
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
|
||||
Comm Node // communication case (Exprs[0]) after select is type-checked
|
||||
Body Nodes
|
||||
}
|
||||
|
||||
func NewCaseStmt(pos src.XPos, list, body []Node) *CaseStmt {
|
||||
n := &CaseStmt{}
|
||||
func NewCaseStmt(pos src.XPos, list, body []Node) *CaseClause {
|
||||
n := &CaseClause{List: list, Body: body}
|
||||
n.pos = pos
|
||||
n.op = OCASE
|
||||
n.List.Set(list)
|
||||
n.Body.Set(body)
|
||||
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 }
|
||||
// Op can be OFOR or OFORUNTIL (!Cond).
|
||||
type ForStmt struct {
|
||||
@ -203,11 +273,13 @@ type ForStmt struct {
|
||||
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.pos = pos
|
||||
n.op = OFOR
|
||||
n.init.Set(init)
|
||||
if init != nil {
|
||||
n.init = []Node{init}
|
||||
}
|
||||
n.Body.Set(body)
|
||||
return n
|
||||
}
|
||||
@ -290,32 +362,27 @@ func NewLabelStmt(pos src.XPos, label *types.Sym) *LabelStmt {
|
||||
|
||||
func (n *LabelStmt) Sym() *types.Sym { return n.Label }
|
||||
|
||||
// A RangeStmt is a range loop: for Vars = range X { Stmts }
|
||||
// Op can be OFOR or OFORUNTIL (!Cond).
|
||||
// A RangeStmt is a range loop: for Key, Value = range X { Body }
|
||||
type RangeStmt struct {
|
||||
miniStmt
|
||||
Label *types.Sym
|
||||
Vars Nodes // TODO(rsc): Replace with Key, Value Node
|
||||
Def bool
|
||||
X Node
|
||||
Key Node
|
||||
Value Node
|
||||
Body Nodes
|
||||
HasBreak bool
|
||||
typ *types.Type // TODO(rsc): Remove - use X.Type() instead
|
||||
Prealloc *Name
|
||||
}
|
||||
|
||||
func NewRangeStmt(pos src.XPos, vars []Node, x Node, body []Node) *RangeStmt {
|
||||
n := &RangeStmt{X: x}
|
||||
func NewRangeStmt(pos src.XPos, key, value, x Node, body []Node) *RangeStmt {
|
||||
n := &RangeStmt{X: x, Key: key, Value: value}
|
||||
n.pos = pos
|
||||
n.op = ORANGE
|
||||
n.Vars.Set(vars)
|
||||
n.Body.Set(body)
|
||||
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.
|
||||
type ReturnStmt struct {
|
||||
miniStmt
|
||||
@ -339,18 +406,17 @@ func (n *ReturnStmt) SetOrig(x Node) { n.orig = x }
|
||||
type SelectStmt struct {
|
||||
miniStmt
|
||||
Label *types.Sym
|
||||
Cases Nodes
|
||||
Cases []*CommClause
|
||||
HasBreak bool
|
||||
|
||||
// TODO(rsc): Instead of recording here, replace with a block?
|
||||
Compiled Nodes // compiled form, after walkswitch
|
||||
}
|
||||
|
||||
func NewSelectStmt(pos src.XPos, cases []Node) *SelectStmt {
|
||||
n := &SelectStmt{}
|
||||
func NewSelectStmt(pos src.XPos, cases []*CommClause) *SelectStmt {
|
||||
n := &SelectStmt{Cases: cases}
|
||||
n.pos = pos
|
||||
n.op = OSELECT
|
||||
n.Cases.Set(cases)
|
||||
return n
|
||||
}
|
||||
|
||||
@ -372,7 +438,7 @@ func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt {
|
||||
type SwitchStmt struct {
|
||||
miniStmt
|
||||
Tag Node
|
||||
Cases Nodes // list of *CaseStmt
|
||||
Cases []*CaseClause
|
||||
Label *types.Sym
|
||||
HasBreak bool
|
||||
|
||||
@ -380,11 +446,10 @@ type SwitchStmt struct {
|
||||
Compiled Nodes // compiled form, after walkswitch
|
||||
}
|
||||
|
||||
func NewSwitchStmt(pos src.XPos, tag Node, cases []Node) *SwitchStmt {
|
||||
n := &SwitchStmt{Tag: tag}
|
||||
func NewSwitchStmt(pos src.XPos, tag Node, cases []*CaseClause) *SwitchStmt {
|
||||
n := &SwitchStmt{Tag: tag, Cases: cases}
|
||||
n.pos = pos
|
||||
n.op = OSWITCH
|
||||
n.Cases.Set(cases)
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -115,14 +115,6 @@ func (n *StructType) SetOTYPE(t *types.Type) {
|
||||
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.
|
||||
type InterfaceType struct {
|
||||
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.
|
||||
// If DDD is true, it's the ...Elem at the end of a function list.
|
||||
type SliceType struct {
|
||||
|
@ -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.
|
||||
// If x's children should be processed, edit(x) must call EditChildren(x, edit) itself.
|
||||
func editList(list Nodes, edit func(Node) Node) {
|
||||
s := list
|
||||
for i, x := range list {
|
||||
if x != nil {
|
||||
s[i] = edit(x)
|
||||
list[i] = edit(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/objw"
|
||||
"cmd/compile/internal/ssa"
|
||||
"cmd/compile/internal/typebits"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
@ -179,11 +180,7 @@ type progeffectscache struct {
|
||||
// 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 the fake PAUTOHEAP variables.
|
||||
func ShouldTrack(nn ir.Node) bool {
|
||||
if nn.Op() != ir.ONAME {
|
||||
return false
|
||||
}
|
||||
n := nn.(*ir.Name)
|
||||
func ShouldTrack(n *ir.Name) bool {
|
||||
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.
|
||||
// If v does not affect any tracked variables, it returns -1, 0.
|
||||
func (lv *liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
|
||||
n, e := affectedNode(v)
|
||||
if e == 0 || n == nil || n.Op() != ir.ONAME { // cheapest checks first
|
||||
n, e := affectedVar(v)
|
||||
if e == 0 || n == nil { // cheapest checks first
|
||||
return -1, 0
|
||||
}
|
||||
|
||||
nn := n.(*ir.Name)
|
||||
// AllocFrame has dropped unused variables from
|
||||
// lv.fn.Func.Dcl, but they might still be referenced by
|
||||
// OpVarFoo pseudo-ops. Ignore them to prevent "lost track of
|
||||
// variable" ICEs (issue 19632).
|
||||
switch v.Op {
|
||||
case ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive:
|
||||
if !nn.Name().Used() {
|
||||
if !n.Name().Used() {
|
||||
return -1, 0
|
||||
}
|
||||
}
|
||||
@ -283,14 +278,14 @@ func (lv *liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
|
||||
return -1, 0
|
||||
}
|
||||
|
||||
if pos, ok := lv.idx[nn]; ok {
|
||||
if pos, ok := lv.idx[n]; ok {
|
||||
return pos, effect
|
||||
}
|
||||
return -1, 0
|
||||
}
|
||||
|
||||
// affectedNode returns the *Node affected by v
|
||||
func affectedNode(v *ssa.Value) (ir.Node, ssa.SymEffect) {
|
||||
// affectedVar returns the *ir.Name node affected by v
|
||||
func affectedVar(v *ssa.Value) (*ir.Name, ssa.SymEffect) {
|
||||
// Special cases.
|
||||
switch v.Op {
|
||||
case ssa.OpLoadReg:
|
||||
@ -381,82 +376,6 @@ func (lv *liveness) blockEffects(b *ssa.Block) *blockEffects {
|
||||
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
|
||||
// this argument and the in arguments are always assumed live. The vars
|
||||
// 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]
|
||||
switch node.Class_ {
|
||||
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:
|
||||
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))
|
||||
|
||||
if ir.IsMethod(fn) {
|
||||
SetTypeBits(fn.Type().Recvs(), 0, bv)
|
||||
typebits.Set(fn.Type().Recvs(), 0, bv)
|
||||
}
|
||||
if fn.Type().NumParams() > 0 {
|
||||
SetTypeBits(fn.Type().Params(), 0, bv)
|
||||
typebits.Set(fn.Type().Params(), 0, bv)
|
||||
}
|
||||
off = objw.BitVec(lsym, off, bv)
|
||||
|
||||
if fn.Type().NumResults() > 0 {
|
||||
SetTypeBits(fn.Type().Results(), 0, bv)
|
||||
typebits.Set(fn.Type().Results(), 0, bv)
|
||||
off = objw.BitVec(lsym, off, bv)
|
||||
}
|
||||
|
||||
|
@ -510,11 +510,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
|
||||
func (p *noder) varDecl(decl *syntax.VarDecl) []ir.Node {
|
||||
names := p.declNames(ir.ONAME, decl.NameList)
|
||||
typ := p.typeExprOrNil(decl.Type)
|
||||
|
||||
var exprs []ir.Node
|
||||
if decl.Values != nil {
|
||||
exprs = p.exprList(decl.Values)
|
||||
}
|
||||
exprs := p.exprList(decl.Values)
|
||||
|
||||
if pragma, ok := decl.Pragma.(*pragmas); ok {
|
||||
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 {
|
||||
if list, ok := expr.(*syntax.ListExpr); ok {
|
||||
return p.exprs(list.ElemList)
|
||||
}
|
||||
switch expr := expr.(type) {
|
||||
case nil:
|
||||
return nil
|
||||
case *syntax.ListExpr:
|
||||
return p.exprs(expr.ElemList)
|
||||
default:
|
||||
return []ir.Node{p.expr(expr)}
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
return p.mkname(expr)
|
||||
case *syntax.BasicLit:
|
||||
n := ir.NewLiteral(p.basicLit(expr))
|
||||
n := ir.NewBasicLit(p.pos(expr), p.basicLit(expr))
|
||||
if expr.Kind == syntax.RuneLit {
|
||||
n.SetType(types.UntypedRune)
|
||||
}
|
||||
n.SetDiag(expr.Bad) // avoid follow-on errors if there was a syntax error
|
||||
return n
|
||||
case *syntax.CompositeLit:
|
||||
n := ir.NewCompLitExpr(p.pos(expr), ir.OCOMPLIT, nil, nil)
|
||||
if expr.Type != nil {
|
||||
n.Ntype = ir.Node(p.expr(expr.Type)).(ir.Ntype)
|
||||
}
|
||||
n := ir.NewCompLitExpr(p.pos(expr), ir.OCOMPLIT, p.typeExpr(expr.Type), nil)
|
||||
l := p.exprs(expr.ElemList)
|
||||
for i, e := range l {
|
||||
l[i] = p.wrapname(expr.ElemList[i], e)
|
||||
@ -818,17 +815,16 @@ func (p *noder) expr(expr syntax.Expr) ir.Node {
|
||||
if expr.Full {
|
||||
op = ir.OSLICE3
|
||||
}
|
||||
n := ir.NewSliceExpr(p.pos(expr), op, p.expr(expr.X))
|
||||
x := p.expr(expr.X)
|
||||
var index [3]ir.Node
|
||||
for i, x := range &expr.Index {
|
||||
if x != nil {
|
||||
index[i] = p.expr(x)
|
||||
for i, n := range &expr.Index {
|
||||
if n != nil {
|
||||
index[i] = p.expr(n)
|
||||
}
|
||||
}
|
||||
n.SetSliceBounds(index[0], index[1], index[2])
|
||||
return n
|
||||
return ir.NewSliceExpr(p.pos(expr), op, x, index[0], index[1], index[2])
|
||||
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:
|
||||
if expr.Op == syntax.Add && expr.Y != nil {
|
||||
return p.sum(expr)
|
||||
@ -852,8 +848,7 @@ func (p *noder) expr(expr syntax.Expr) ir.Node {
|
||||
}
|
||||
return ir.NewBinaryExpr(pos, op, x, y)
|
||||
case *syntax.CallExpr:
|
||||
n := ir.NewCallExpr(p.pos(expr), ir.OCALL, p.expr(expr.Fun), nil)
|
||||
n.Args.Set(p.exprs(expr.ArgList))
|
||||
n := ir.NewCallExpr(p.pos(expr), ir.OCALL, p.expr(expr.Fun), p.exprs(expr.ArgList))
|
||||
n.IsDDD = expr.HasDots
|
||||
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 {
|
||||
p.setlineno(stmt)
|
||||
switch stmt := stmt.(type) {
|
||||
case *syntax.EmptyStmt:
|
||||
case nil, *syntax.EmptyStmt:
|
||||
return nil
|
||||
case *syntax.LabeledStmt:
|
||||
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))
|
||||
case *syntax.ReturnStmt:
|
||||
var results []ir.Node
|
||||
if stmt.Results != nil {
|
||||
results = p.exprList(stmt.Results)
|
||||
}
|
||||
n := ir.NewReturnStmt(p.pos(stmt), nil)
|
||||
n.Results.Set(results)
|
||||
n := ir.NewReturnStmt(p.pos(stmt), p.exprList(stmt.Results))
|
||||
if len(n.Results) == 0 && ir.CurFunc != nil {
|
||||
for _, ln := range ir.CurFunc.Dcl {
|
||||
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 {
|
||||
p.openScope(stmt.Pos())
|
||||
n := ir.NewIfStmt(p.pos(stmt), nil, nil, nil)
|
||||
if stmt.Init != nil {
|
||||
*n.PtrInit() = []ir.Node{p.stmt(stmt.Init)}
|
||||
init := p.stmt(stmt.Init)
|
||||
n := ir.NewIfStmt(p.pos(stmt), p.expr(stmt.Cond), p.blockStmt(stmt.Then), nil)
|
||||
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 {
|
||||
e := p.stmt(stmt.Else)
|
||||
if e.Op() == ir.OBLOCK {
|
||||
@ -1320,53 +1307,46 @@ func (p *noder) forStmt(stmt *syntax.ForStmt) ir.Node {
|
||||
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 {
|
||||
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))
|
||||
p.closeAnotherScope()
|
||||
return n
|
||||
}
|
||||
|
||||
n := ir.NewForStmt(p.pos(stmt), nil, nil, nil, nil)
|
||||
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))
|
||||
n := ir.NewForStmt(p.pos(stmt), p.stmt(stmt.Init), p.expr(stmt.Cond), p.stmt(stmt.Post), p.blockStmt(stmt.Body))
|
||||
p.closeAnotherScope()
|
||||
return n
|
||||
}
|
||||
|
||||
func (p *noder) switchStmt(stmt *syntax.SwitchStmt) ir.Node {
|
||||
p.openScope(stmt.Pos())
|
||||
n := ir.NewSwitchStmt(p.pos(stmt), nil, nil)
|
||||
if stmt.Init != nil {
|
||||
*n.PtrInit() = []ir.Node{p.stmt(stmt.Init)}
|
||||
}
|
||||
if stmt.Tag != nil {
|
||||
n.Tag = p.expr(stmt.Tag)
|
||||
|
||||
init := p.stmt(stmt.Init)
|
||||
n := ir.NewSwitchStmt(p.pos(stmt), p.expr(stmt.Tag), nil)
|
||||
if init != nil {
|
||||
*n.PtrInit() = []ir.Node{init}
|
||||
}
|
||||
|
||||
var tswitch *ir.TypeSwitchGuard
|
||||
if l := n.Tag; l != nil && l.Op() == ir.OTYPESW {
|
||||
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)
|
||||
return n
|
||||
}
|
||||
|
||||
func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.TypeSwitchGuard, rbrace syntax.Pos) []ir.Node {
|
||||
nodes := make([]ir.Node, 0, len(clauses))
|
||||
func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.TypeSwitchGuard, rbrace syntax.Pos) []*ir.CaseClause {
|
||||
nodes := make([]*ir.CaseClause, 0, len(clauses))
|
||||
for i, clause := range clauses {
|
||||
p.setlineno(clause)
|
||||
if i > 0 {
|
||||
@ -1374,14 +1354,11 @@ func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *ir.TypeSwitch
|
||||
}
|
||||
p.openScope(clause.Pos())
|
||||
|
||||
n := ir.NewCaseStmt(p.pos(clause), nil, nil)
|
||||
if clause.Cases != nil {
|
||||
n.List.Set(p.exprList(clause.Cases))
|
||||
}
|
||||
n := ir.NewCaseStmt(p.pos(clause), p.exprList(clause.Cases), nil)
|
||||
if tswitch != nil && tswitch.Tag != nil {
|
||||
nn := typecheck.NewName(tswitch.Tag.Sym())
|
||||
typecheck.Declare(nn, typecheck.DeclContext)
|
||||
n.Vars = []ir.Node{nn}
|
||||
n.Var = nn
|
||||
// keep track of the instances for reporting unused
|
||||
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 {
|
||||
n := ir.NewSelectStmt(p.pos(stmt), nil)
|
||||
n.Cases.Set(p.commClauses(stmt.Body, stmt.Rbrace))
|
||||
return n
|
||||
return ir.NewSelectStmt(p.pos(stmt), p.commClauses(stmt.Body, stmt.Rbrace))
|
||||
}
|
||||
|
||||
func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []ir.Node {
|
||||
nodes := make([]ir.Node, 0, len(clauses))
|
||||
func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []*ir.CommClause {
|
||||
nodes := make([]*ir.CommClause, len(clauses))
|
||||
for i, clause := range clauses {
|
||||
p.setlineno(clause)
|
||||
if i > 0 {
|
||||
@ -1430,12 +1405,7 @@ func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []i
|
||||
}
|
||||
p.openScope(clause.Pos())
|
||||
|
||||
n := ir.NewCaseStmt(p.pos(clause), nil, nil)
|
||||
if clause.Comm != nil {
|
||||
n.List = []ir.Node{p.stmt(clause.Comm)}
|
||||
}
|
||||
n.Body.Set(p.stmts(clause.Body))
|
||||
nodes = append(nodes, n)
|
||||
nodes[i] = ir.NewCommStmt(p.pos(clause), p.stmt(clause.Comm), p.stmts(clause.Body))
|
||||
}
|
||||
if len(clauses) > 0 {
|
||||
p.closeScope(rbrace)
|
||||
@ -2001,7 +1971,6 @@ func oldname(s *types.Sym) ir.Node {
|
||||
c = typecheck.NewName(s)
|
||||
c.Class_ = ir.PAUTOHEAP
|
||||
c.SetIsClosureVar(true)
|
||||
c.SetIsDDD(n.IsDDD())
|
||||
c.Defn = n
|
||||
|
||||
// Link into list of active closure variables.
|
||||
|
@ -33,7 +33,6 @@ package objw
|
||||
import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/ssa"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/objabi"
|
||||
"cmd/internal/src"
|
||||
@ -173,7 +172,7 @@ func (pp *Progs) Prog(as obj.As) *obj.Prog {
|
||||
p.Pos = pp.Pos
|
||||
if pp.Pos.IsStmt() == src.PosIsStmt {
|
||||
// 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
|
||||
}
|
||||
pp.Pos = pp.Pos.WithNotStmt()
|
||||
@ -216,3 +215,12 @@ func (pp *Progs) SetText(fn *ir.Func) {
|
||||
ptxt.From.Name = obj.NAME_EXTERN
|
||||
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
|
||||
}
|
||||
|
@ -289,10 +289,6 @@ func (d *initDeps) inspectList(l ir.Nodes) { ir.VisitList(l, d.cachedVisit()) }
|
||||
// referenced by n, if any.
|
||||
func (d *initDeps) visit(n ir.Node) {
|
||||
switch n.Op() {
|
||||
case ir.OMETHEXPR:
|
||||
n := n.(*ir.MethodExpr)
|
||||
d.foundDep(ir.MethodExprName(n))
|
||||
|
||||
case ir.ONAME:
|
||||
n := n.(*ir.Name)
|
||||
switch n.Class_ {
|
||||
@ -304,7 +300,7 @@ func (d *initDeps) visit(n ir.Node) {
|
||||
n := n.(*ir.ClosureExpr)
|
||||
d.inspectList(n.Func.Body)
|
||||
|
||||
case ir.ODOTMETH, ir.OCALLPART:
|
||||
case ir.ODOTMETH, ir.OCALLPART, ir.OMETHEXPR:
|
||||
d.foundDep(ir.MethodExprName(n))
|
||||
}
|
||||
}
|
||||
|
@ -289,11 +289,11 @@ func hashfor(t *types.Type) ir.Node {
|
||||
|
||||
n := typecheck.NewName(sym)
|
||||
ir.MarkFunc(n)
|
||||
n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
|
||||
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
|
||||
}, []*ir.Field{
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
|
||||
n.SetType(types.NewSignature(types.NoPkg, nil, []*types.Field{
|
||||
types.NewField(base.Pos, nil, types.NewPtr(t)),
|
||||
types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
|
||||
}, []*types.Field{
|
||||
types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
|
||||
}))
|
||||
return n
|
||||
}
|
||||
@ -777,12 +777,12 @@ func hashmem(t *types.Type) ir.Node {
|
||||
|
||||
n := typecheck.NewName(sym)
|
||||
ir.MarkFunc(n)
|
||||
n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
|
||||
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
|
||||
}, []*ir.Field{
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
|
||||
n.SetType(types.NewSignature(types.NoPkg, nil, []*types.Field{
|
||||
types.NewField(base.Pos, nil, types.NewPtr(t)),
|
||||
types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
|
||||
types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
|
||||
}, []*types.Field{
|
||||
types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
|
||||
}))
|
||||
return n
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ import (
|
||||
"cmd/compile/internal/escape"
|
||||
"cmd/compile/internal/inline"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/liveness"
|
||||
"cmd/compile/internal/objw"
|
||||
"cmd/compile/internal/typebits"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/gcprog"
|
||||
@ -835,6 +835,9 @@ func TypeSym(t *types.Type) *types.Sym {
|
||||
if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
|
||||
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)
|
||||
signatmu.Lock()
|
||||
NeedRuntimeType(t)
|
||||
@ -1419,7 +1422,11 @@ func WriteBasicTypes() {
|
||||
// The latter is the type of an auto-generated wrapper.
|
||||
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.
|
||||
dimportpath(ir.Pkgs.Runtime)
|
||||
@ -1545,7 +1552,7 @@ func fillptrmask(t *types.Type, ptrmask []byte) {
|
||||
}
|
||||
|
||||
vec := bitvec.New(8 * int32(len(ptrmask)))
|
||||
liveness.SetTypeBits(t, 0, vec)
|
||||
typebits.Set(t, 0, vec)
|
||||
|
||||
nptr := types.PtrDataSize(t) / int64(types.PtrSize)
|
||||
for i := int64(0); i < nptr; i++ {
|
||||
@ -1856,7 +1863,7 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) {
|
||||
r.Sym = tsym
|
||||
// dot.Xoffset is the method index * Widthptr (the offset of code pointer
|
||||
// in itab).
|
||||
midx := dot.Offset / int64(types.PtrSize)
|
||||
midx := dot.Offset() / int64(types.PtrSize)
|
||||
r.Add = InterfaceMethodOffset(ityp, midx)
|
||||
r.Type = objabi.R_USEIFACEMETHOD
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
package ssa
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/src"
|
||||
"fmt"
|
||||
"sort"
|
||||
@ -23,15 +22,6 @@ func isPoorStatementOp(op Op) bool {
|
||||
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
|
||||
// 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
|
||||
|
@ -214,10 +214,7 @@ func InitConfig() {
|
||||
func getParam(n *ir.CallExpr, i int) *types.Field {
|
||||
t := n.X.Type()
|
||||
if n.Op() == ir.OCALLMETH {
|
||||
if i == 0 {
|
||||
return t.Recv()
|
||||
}
|
||||
return t.Params().Field(i - 1)
|
||||
base.Fatalf("OCALLMETH missed by walkCall")
|
||||
}
|
||||
return t.Params().Field(i)
|
||||
}
|
||||
@ -1166,7 +1163,7 @@ func (s *state) stmt(n ir.Node) {
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case ir.OCALLMETH, ir.OCALLINTER:
|
||||
case ir.OCALLINTER:
|
||||
n := n.(*ir.CallExpr)
|
||||
s.callResult(n, callNormal)
|
||||
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.
|
||||
// Don't write back fields we aren't changing. See issue #14855.
|
||||
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) {
|
||||
// [0:...] is the same as [:...]
|
||||
i = nil
|
||||
@ -2111,10 +2108,6 @@ func (s *state) expr(n ir.Node) *ssa.Value {
|
||||
n := n.(*ir.UnaryExpr)
|
||||
aux := n.X.Sym().Linksym()
|
||||
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:
|
||||
n := n.(*ir.Name)
|
||||
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
|
||||
// prevents false memory dependencies in race/msan
|
||||
// instrumentation.
|
||||
if ir.IsAssignable(n) && !s.canSSA(n) {
|
||||
if ir.IsAddressable(n) && !s.canSSA(n) {
|
||||
p := s.addr(n)
|
||||
return s.load(n.Type(), p)
|
||||
}
|
||||
@ -2746,7 +2739,7 @@ func (s *state) expr(n ir.Node) *ssa.Value {
|
||||
case ir.ODOTPTR:
|
||||
n := n.(*ir.SelectorExpr)
|
||||
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)
|
||||
|
||||
case ir.OINDEX:
|
||||
@ -2844,23 +2837,22 @@ func (s *state) expr(n ir.Node) *ssa.Value {
|
||||
case ir.OSLICEHEADER:
|
||||
n := n.(*ir.SliceHeaderExpr)
|
||||
p := s.expr(n.Ptr)
|
||||
l := s.expr(n.LenCap[0])
|
||||
c := s.expr(n.LenCap[1])
|
||||
l := s.expr(n.Len)
|
||||
c := s.expr(n.Cap)
|
||||
return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
|
||||
|
||||
case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
|
||||
n := n.(*ir.SliceExpr)
|
||||
v := s.expr(n.X)
|
||||
var i, j, k *ssa.Value
|
||||
low, high, max := n.SliceBounds()
|
||||
if low != nil {
|
||||
i = s.expr(low)
|
||||
if n.Low != nil {
|
||||
i = s.expr(n.Low)
|
||||
}
|
||||
if high != nil {
|
||||
j = s.expr(high)
|
||||
if n.High != nil {
|
||||
j = s.expr(n.High)
|
||||
}
|
||||
if max != nil {
|
||||
k = s.expr(max)
|
||||
if n.Max != nil {
|
||||
k = s.expr(n.Max)
|
||||
}
|
||||
p, l, c := s.slice(v, i, j, k, n.Bounded())
|
||||
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)
|
||||
v := s.expr(n.X)
|
||||
var i, j *ssa.Value
|
||||
low, high, _ := n.SliceBounds()
|
||||
if low != nil {
|
||||
i = s.expr(low)
|
||||
if n.Low != nil {
|
||||
i = s.expr(n.Low)
|
||||
}
|
||||
if high != nil {
|
||||
j = s.expr(high)
|
||||
if n.High != nil {
|
||||
j = s.expr(n.High)
|
||||
}
|
||||
p, l, _ := s.slice(v, i, j, nil, n.Bounded())
|
||||
return s.newValue2(ssa.OpStringMake, n.Type(), p, l)
|
||||
@ -4398,16 +4389,7 @@ func (s *state) openDeferRecord(n *ir.CallExpr) {
|
||||
opendefer.closure = closure
|
||||
}
|
||||
} else if n.Op() == ir.OCALLMETH {
|
||||
if fn.Op() != ir.ODOTMETH {
|
||||
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)
|
||||
base.Fatalf("OCALLMETH missed by walkCall")
|
||||
} else {
|
||||
if fn.Op() != ir.ODOTINTER {
|
||||
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)
|
||||
}
|
||||
case ir.OCALLMETH:
|
||||
if fn.Op() != ir.ODOTMETH {
|
||||
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.
|
||||
base.Fatalf("OCALLMETH missed by walkCall")
|
||||
case ir.OCALLINTER:
|
||||
if fn.Op() != ir.ODOTINTER {
|
||||
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).
|
||||
if n.Op() == ir.OCALLMETH {
|
||||
f := ft.Recv()
|
||||
s.storeArgWithBase(args[0], f.Type, addr, off+f.Offset)
|
||||
args = args[1:]
|
||||
base.Fatalf("OCALLMETH missed by walkCall")
|
||||
}
|
||||
// Set other args.
|
||||
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()
|
||||
args := n.Rargs
|
||||
if n.Op() == ir.OCALLMETH {
|
||||
f := t.Recv()
|
||||
ACArg, arg := s.putArg(args[0], f.Type, argStart+f.Offset, testLateExpansion)
|
||||
ACArgs = append(ACArgs, ACArg)
|
||||
callArgs = append(callArgs, arg)
|
||||
args = args[1:]
|
||||
base.Fatalf("OCALLMETH missed by walkCall")
|
||||
}
|
||||
for i, n := range args {
|
||||
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
|
||||
// interface call
|
||||
func (s *state) getClosureAndRcvr(fn *ir.SelectorExpr) (*ssa.Value, *ssa.Value) {
|
||||
i := s.expr(fn.X)
|
||||
itab := s.newValue1(ssa.OpITab, types.Types[types.TUINTPTR], i)
|
||||
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)
|
||||
rcvr := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, i)
|
||||
return closure, rcvr
|
||||
@ -5075,11 +5024,11 @@ func (s *state) addr(n ir.Node) *ssa.Value {
|
||||
case ir.ODOT:
|
||||
n := n.(*ir.SelectorExpr)
|
||||
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:
|
||||
n := n.(*ir.SelectorExpr)
|
||||
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:
|
||||
n := n.(*ir.ClosureReadExpr)
|
||||
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)
|
||||
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)
|
||||
return s.callAddr(n, callNormal)
|
||||
case ir.ODOTTYPE:
|
||||
@ -6328,7 +6277,7 @@ type State struct {
|
||||
// Prog appends a new Prog.
|
||||
func (s *State) Prog(as obj.As) *obj.Prog {
|
||||
p := s.pp.Prog(as)
|
||||
if ssa.LosesStmtMark(as) {
|
||||
if objw.LosesStmtMark(as) {
|
||||
return p
|
||||
}
|
||||
// Float a statement start to the beginning of any same-line run.
|
||||
@ -7116,22 +7065,18 @@ func (s *State) UseArgs(n int64) {
|
||||
// fieldIdx finds the index of the field referred to by the ODOT node n.
|
||||
func fieldIdx(n *ir.SelectorExpr) int {
|
||||
t := n.X.Type()
|
||||
f := n.Sel
|
||||
if !t.IsStruct() {
|
||||
panic("ODOT's LHS is not a struct")
|
||||
}
|
||||
|
||||
var i int
|
||||
for _, t1 := range t.Fields().Slice() {
|
||||
if t1.Sym != f {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if t1.Offset != n.Offset {
|
||||
for i, f := range t.Fields().Slice() {
|
||||
if f.Sym == n.Sel {
|
||||
if f.Offset != n.Offset() {
|
||||
panic("field offset doesn't match")
|
||||
}
|
||||
return i
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("can't find field in expr %v\n", n))
|
||||
|
||||
// TODO: keep the result of this function somewhere in the ODOT Node
|
||||
|
@ -469,7 +469,7 @@ func StaticLoc(n ir.Node) (name *ir.Name, offset int64, ok bool) {
|
||||
if name, offset, ok = StaticLoc(n.X); !ok {
|
||||
break
|
||||
}
|
||||
offset += n.Offset
|
||||
offset += n.Offset()
|
||||
return name, offset, true
|
||||
|
||||
case ir.OINDEX:
|
||||
|
87
src/cmd/compile/internal/typebits/typebits.go
Normal file
87
src/cmd/compile/internal/typebits/typebits.go
Normal 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)
|
||||
}
|
||||
}
|
@ -3,9 +3,8 @@
|
||||
package typecheck
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/base"
|
||||
"cmd/compile/internal/ir"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/src"
|
||||
)
|
||||
|
||||
var runtimeDecls = [...]struct {
|
||||
@ -212,133 +211,133 @@ func runtimeTypes() []*types.Type {
|
||||
typs[1] = types.NewPtr(typs[0])
|
||||
typs[2] = types.Types[types.TANY]
|
||||
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[6] = types.Types[types.TBOOL]
|
||||
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[9] = NewFuncType(nil, nil, nil)
|
||||
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] = types.NewSignature(types.NoPkg, nil, nil, nil)
|
||||
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[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[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[18] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[17]), ir.NewField(base.Pos, nil, nil, typs[15])}, nil)
|
||||
typs[19] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}, 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] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[6])}, nil)
|
||||
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[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[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[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[29] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, nil)
|
||||
typs[30] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, nil)
|
||||
typs[31] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
|
||||
typs[29] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[28])}, nil)
|
||||
typs[30] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[2])}, 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[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[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[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[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[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] = 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] = 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] = 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[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[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[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] = 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[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[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[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[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] = 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] = 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[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[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[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[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[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[56] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, 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[58] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, 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[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[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[62] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1])}, nil)
|
||||
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] = 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] = 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] = 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] = 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] = 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] = 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] = 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] = 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] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1])}, nil)
|
||||
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[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[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[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[70] = NewFuncType(nil, nil, []*ir.Field{ir.NewField(base.Pos, nil, 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[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[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[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[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[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[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[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[79] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, 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[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] = 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] = types.NewSignature(types.NoPkg, nil, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[67])})
|
||||
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] = 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] = 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] = 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] = 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] = 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] = 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] = 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] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[3])}, 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[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[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[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] = 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[85] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[84]), ir.NewField(base.Pos, nil, 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[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] = 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[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[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[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[92] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, 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[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[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[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] = 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] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[1]), types.NewField(src.NoXPos, nil, typs[3])}, nil)
|
||||
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] = 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] = 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[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[98] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, 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[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[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[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[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] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[63])}, nil)
|
||||
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] = 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] = 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] = 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[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[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[106] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, 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[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[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[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[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[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[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[114] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, 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[116] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, 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[118] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}, []*ir.Field{ir.NewField(base.Pos, nil, 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[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[121] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, 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[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[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] = 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] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[7]), types.NewField(src.NoXPos, nil, typs[5])}, nil)
|
||||
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] = 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] = 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] = 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] = 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] = 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] = 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] = 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] = 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] = 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] = 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] = 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] = 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] = 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] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[5]), types.NewField(src.NoXPos, 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] = 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[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[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[129] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[128]), ir.NewField(base.Pos, nil, 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[131] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24]), ir.NewField(base.Pos, nil, nil, typs[24])}, 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] = types.NewSignature(types.NoPkg, nil, []*types.Field{types.NewField(src.NoXPos, nil, typs[65]), types.NewField(src.NoXPos, nil, typs[65])}, 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[:]
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
)
|
||||
|
||||
func TestBuiltin(t *testing.T) {
|
||||
t.Skip("mkbuiltin needs fixing")
|
||||
testenv.MustHaveGoRun(t)
|
||||
t.Parallel()
|
||||
|
||||
|
@ -929,7 +929,7 @@ func evalunsafe(n ir.Node) int64 {
|
||||
fallthrough
|
||||
case ir.ODOT:
|
||||
r := r.(*ir.SelectorExpr)
|
||||
v += r.Offset
|
||||
v += r.Offset()
|
||||
next = r.X
|
||||
default:
|
||||
ir.Dump("unsafenmagic", tsel)
|
||||
|
@ -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.
|
||||
// - msym is the method symbol
|
||||
// - 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)
|
||||
n.Decl = name
|
||||
name.Ntype = n.Ntype
|
||||
name.SetIsDDD(n.IsDDD)
|
||||
Declare(name, ctxt)
|
||||
|
||||
vargen++
|
||||
@ -527,7 +460,6 @@ func funcarg2(f *types.Field, ctxt ir.Class) {
|
||||
n := ir.NewNameAt(f.Pos, f.Sym)
|
||||
f.Nname = n
|
||||
n.SetType(f.Type)
|
||||
n.SetIsDDD(f.IsDDD())
|
||||
Declare(n, ctxt)
|
||||
}
|
||||
|
||||
@ -604,27 +536,6 @@ func initname(s string) bool {
|
||||
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
|
||||
|
||||
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 {
|
||||
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{
|
||||
Name: autotmpname(len(curfn.Dcl)),
|
||||
@ -676,30 +590,26 @@ func autotmpname(n int) string {
|
||||
|
||||
// f is method type, with receiver.
|
||||
// return function type, receiver as first argument (or not).
|
||||
func NewMethodType(f *types.Type, receiver *types.Type) *types.Type {
|
||||
inLen := f.Params().Fields().Len()
|
||||
if receiver != nil {
|
||||
inLen++
|
||||
}
|
||||
in := make([]*ir.Field, 0, inLen)
|
||||
|
||||
if receiver != nil {
|
||||
d := ir.NewField(base.Pos, nil, nil, receiver)
|
||||
in = append(in, d)
|
||||
func NewMethodType(sig *types.Type, recv *types.Type) *types.Type {
|
||||
nrecvs := 0
|
||||
if recv != nil {
|
||||
nrecvs++
|
||||
}
|
||||
|
||||
for _, t := range f.Params().Fields().Slice() {
|
||||
d := ir.NewField(base.Pos, nil, nil, t.Type)
|
||||
d.IsDDD = t.IsDDD()
|
||||
in = append(in, d)
|
||||
params := make([]*types.Field, nrecvs+sig.Params().Fields().Len())
|
||||
if recv != nil {
|
||||
params[0] = types.NewField(base.Pos, nil, recv)
|
||||
}
|
||||
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()
|
||||
out := make([]*ir.Field, 0, outLen)
|
||||
for _, t := range f.Results().Fields().Slice() {
|
||||
d := ir.NewField(base.Pos, nil, nil, t.Type)
|
||||
out = append(out, d)
|
||||
results := make([]*types.Field, sig.Results().Fields().Len())
|
||||
for i, t := range sig.Results().Fields().Slice() {
|
||||
results[i] = types.NewField(base.Pos, nil, t.Type)
|
||||
}
|
||||
|
||||
return NewFuncType(nil, in, out)
|
||||
return types.NewSignature(types.LocalPkg, nil, params, results)
|
||||
}
|
||||
|
@ -571,7 +571,6 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
|
||||
}
|
||||
|
||||
n.X = typecheck(n.X, ctxExpr|ctxType)
|
||||
|
||||
n.X = DefaultLit(n.X, nil)
|
||||
|
||||
t := n.X.Type()
|
||||
@ -581,8 +580,6 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
|
||||
return n
|
||||
}
|
||||
|
||||
s := n.Sel
|
||||
|
||||
if n.X.Op() == ir.OTYPE {
|
||||
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 {
|
||||
return tcCallPart(n, s)
|
||||
// Create top-level function.
|
||||
fn := makepartialcall(n)
|
||||
|
||||
return ir.NewCallPartExpr(n.Pos(), n.X, n.Selection, fn)
|
||||
}
|
||||
return n
|
||||
}
|
||||
@ -831,24 +831,18 @@ func tcSPtr(n *ir.UnaryExpr) ir.Node {
|
||||
|
||||
// tcSlice typechecks an OSLICE or OSLICE3 node.
|
||||
func tcSlice(n *ir.SliceExpr) ir.Node {
|
||||
n.X = Expr(n.X)
|
||||
low, high, max := n.SliceBounds()
|
||||
n.X = DefaultLit(Expr(n.X), nil)
|
||||
n.Low = indexlit(Expr(n.Low))
|
||||
n.High = indexlit(Expr(n.High))
|
||||
n.Max = indexlit(Expr(n.Max))
|
||||
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
|
||||
if l.Type() == nil {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
if l.Type().IsArray() {
|
||||
if !ir.IsAssignable(n.X) {
|
||||
if !ir.IsAddressable(n.X) {
|
||||
base.Errorf("invalid operation %v (slice of unaddressable value)", n)
|
||||
n.SetType(nil)
|
||||
return n
|
||||
@ -886,19 +880,19 @@ func tcSlice(n *ir.SliceExpr) ir.Node {
|
||||
return n
|
||||
}
|
||||
|
||||
if low != nil && !checksliceindex(l, low, tp) {
|
||||
if n.Low != nil && !checksliceindex(l, n.Low, tp) {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
if high != nil && !checksliceindex(l, high, tp) {
|
||||
if n.High != nil && !checksliceindex(l, n.High, tp) {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
if max != nil && !checksliceindex(l, max, tp) {
|
||||
if n.Max != nil && !checksliceindex(l, n.Max, tp) {
|
||||
n.SetType(nil)
|
||||
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)
|
||||
return n
|
||||
}
|
||||
@ -924,30 +918,22 @@ func tcSliceHeader(n *ir.SliceHeaderExpr) ir.Node {
|
||||
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)
|
||||
l := Expr(n.LenCap[0])
|
||||
c := Expr(n.LenCap[1])
|
||||
l = DefaultLit(l, types.Types[types.TINT])
|
||||
c = DefaultLit(c, types.Types[types.TINT])
|
||||
n.Len = DefaultLit(Expr(n.Len), types.Types[types.TINT])
|
||||
n.Cap = DefaultLit(Expr(n.Cap), 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")
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
n.LenCap[0] = l
|
||||
n.LenCap[1] = c
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -73,17 +73,17 @@ func ClosureType(clo *ir.ClosureExpr) *types.Type {
|
||||
// The information appears in the binary in the form of type descriptors;
|
||||
// the struct is unnamed so that closures in multiple packages with the
|
||||
// same struct type can share the descriptor.
|
||||
fields := []*ir.Field{
|
||||
ir.NewField(base.Pos, Lookup(".F"), nil, types.Types[types.TUINTPTR]),
|
||||
fields := []*types.Field{
|
||||
types.NewField(base.Pos, Lookup(".F"), types.Types[types.TUINTPTR]),
|
||||
}
|
||||
for _, v := range clo.Func.ClosureVars {
|
||||
typ := v.Type()
|
||||
if !v.Byval() {
|
||||
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)
|
||||
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).
|
||||
// The address of a variable of the returned type can be cast to a func.
|
||||
func PartialCallType(n *ir.CallPartExpr) *types.Type {
|
||||
t := NewStructType([]*ir.Field{
|
||||
ir.NewField(base.Pos, Lookup("F"), nil, types.Types[types.TUINTPTR]),
|
||||
ir.NewField(base.Pos, Lookup("R"), nil, n.X.Type()),
|
||||
t := types.NewStruct(types.NoPkg, []*types.Field{
|
||||
types.NewField(base.Pos, Lookup("F"), types.Types[types.TUINTPTR]),
|
||||
types.NewField(base.Pos, Lookup("R"), n.X.Type()),
|
||||
})
|
||||
t.SetNoalg(true)
|
||||
return t
|
||||
@ -249,7 +249,9 @@ var globClosgen int32
|
||||
|
||||
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
|
||||
// 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()
|
||||
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
|
||||
|
||||
// Set line number equal to the line number where the method is declared.
|
||||
var m *types.Field
|
||||
if lookdot0(meth, rcvrtype, &m, false) == 1 && m.Pos.IsKnown() {
|
||||
base.Pos = m.Pos
|
||||
if pos := dot.Selection.Pos; pos.IsKnown() {
|
||||
base.Pos = 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
|
||||
// built-in error type is one such method. We leave the line
|
||||
// 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.SetDupok(true)
|
||||
fn.SetNeedctxt(true)
|
||||
fn.SetWrapper(true)
|
||||
|
||||
// Declare and initialize variable holding receiver.
|
||||
cr := ir.NewClosureRead(rcvrtype, types.Rnd(int64(types.PtrSize), int64(rcvrtype.Align)))
|
||||
ptr := NewName(Lookup(".this"))
|
||||
Declare(ptr, ir.PAUTO)
|
||||
ptr.SetUsed(true)
|
||||
var ptr *ir.Name
|
||||
var body []ir.Node
|
||||
if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
|
||||
ptr.SetType(rcvrtype)
|
||||
ptr = Temp(rcvrtype)
|
||||
body = append(body, ir.NewAssignStmt(base.Pos, ptr, cr))
|
||||
} else {
|
||||
ptr.SetType(types.NewPtr(rcvrtype))
|
||||
ptr = Temp(types.NewPtr(rcvrtype))
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
// To be called by typecheck, not directly.
|
||||
// (Call typecheckFunc instead.)
|
||||
@ -542,9 +525,7 @@ func tcCall(n *ir.CallExpr, top int) ir.Node {
|
||||
default:
|
||||
n.SetOp(ir.OCALLFUNC)
|
||||
if t.Kind() != types.TFUNC {
|
||||
// TODO(mdempsky): Remove "o.Sym() != nil" once we stop
|
||||
// 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 {
|
||||
if o := ir.Orig(l); o.Name() != nil && types.BuiltinPkg.Lookup(o.Sym().Name).Def != nil {
|
||||
// be more specific when the non-function
|
||||
// name matches a predeclared function
|
||||
base.Errorf("cannot call non-function %L, declared at %s",
|
||||
|
@ -594,23 +594,15 @@ func (w *exportWriter) selector(s *types.Sym) {
|
||||
base.Fatalf("missing currPkg")
|
||||
}
|
||||
|
||||
// Method selectors are rewritten into method symbols (of the
|
||||
// form T.M) during typechecking, but we want to write out
|
||||
// just the bare method name.
|
||||
name := s.Name
|
||||
if i := strings.LastIndex(name, "."); i >= 0 {
|
||||
name = name[i+1:]
|
||||
} else {
|
||||
pkg := w.currPkg
|
||||
if types.IsExported(name) {
|
||||
if types.IsExported(s.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) {
|
||||
@ -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
|
||||
// of type typ. As a special case, 8-bit types are always encoded as a
|
||||
// single byte.
|
||||
//
|
||||
// TODO(mdempsky): Is this level of complexity really worthwhile?
|
||||
func (w *exportWriter) mpint(x constant.Value, typ *types.Type) {
|
||||
signed, maxBytes := intSize(typ)
|
||||
|
||||
@ -1145,7 +1135,7 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||
n := n.(*ir.RangeStmt)
|
||||
w.op(ir.ORANGE)
|
||||
w.pos(n.Pos())
|
||||
w.stmtList(n.Vars)
|
||||
w.exprsOrNil(n.Key, n.Value)
|
||||
w.expr(n.X)
|
||||
w.stmtList(n.Body)
|
||||
|
||||
@ -1154,8 +1144,7 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
w.stmtList(n.Init())
|
||||
w.exprsOrNil(nil, nil) // TODO(rsc): Delete (and fix importer).
|
||||
w.caseList(n)
|
||||
w.commList(n.Cases)
|
||||
|
||||
case ir.OSWITCH:
|
||||
n := n.(*ir.SwitchStmt)
|
||||
@ -1163,7 +1152,7 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||
w.pos(n.Pos())
|
||||
w.stmtList(n.Init())
|
||||
w.exprsOrNil(n.Tag, nil)
|
||||
w.caseList(n)
|
||||
w.caseList(n.Cases, isNamedTypeSwitch(n.Tag))
|
||||
|
||||
// case OCASE:
|
||||
// handled by caseList
|
||||
@ -1187,39 +1176,32 @@ func (w *exportWriter) stmt(n ir.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
func isNamedTypeSwitch(n ir.Node) bool {
|
||||
if n.Op() != ir.OSWITCH {
|
||||
return false
|
||||
}
|
||||
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 isNamedTypeSwitch(x ir.Node) bool {
|
||||
guard, ok := x.(*ir.TypeSwitchGuard)
|
||||
return ok && guard.Tag != nil
|
||||
}
|
||||
|
||||
func (w *exportWriter) caseList(sw ir.Node) {
|
||||
namedTypeSwitch := isNamedTypeSwitch(sw)
|
||||
|
||||
var cases []ir.Node
|
||||
if sw.Op() == ir.OSWITCH {
|
||||
cases = sw.(*ir.SwitchStmt).Cases
|
||||
} else {
|
||||
cases = sw.(*ir.SelectStmt).Cases
|
||||
}
|
||||
func (w *exportWriter) caseList(cases []*ir.CaseClause, namedTypeSwitch bool) {
|
||||
w.uint64(uint64(len(cases)))
|
||||
for _, cas := range cases {
|
||||
cas := cas.(*ir.CaseStmt)
|
||||
w.pos(cas.Pos())
|
||||
w.stmtList(cas.List)
|
||||
if namedTypeSwitch {
|
||||
w.localName(cas.Vars[0].(*ir.Name))
|
||||
w.localName(cas.Var.(*ir.Name))
|
||||
}
|
||||
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) {
|
||||
for _, n := range list {
|
||||
w.expr(n)
|
||||
@ -1313,7 +1295,7 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
s = n.Tag.Sym()
|
||||
}
|
||||
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:
|
||||
// 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)
|
||||
w.op(ir.OKEY)
|
||||
w.pos(n.Pos())
|
||||
w.exprsOrNil(n.Key, n.Value)
|
||||
w.expr(n.Key)
|
||||
w.expr(n.Value)
|
||||
|
||||
// case OSTRUCTKEY:
|
||||
// unreachable - handled in case OSTRUCTLIT by elemList
|
||||
@ -1387,17 +1370,15 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
w.op(ir.OSLICE)
|
||||
w.pos(n.Pos())
|
||||
w.expr(n.X)
|
||||
low, high, _ := n.SliceBounds()
|
||||
w.exprsOrNil(low, high)
|
||||
w.exprsOrNil(n.Low, n.High)
|
||||
|
||||
case ir.OSLICE3, ir.OSLICE3ARR:
|
||||
n := n.(*ir.SliceExpr)
|
||||
w.op(ir.OSLICE3)
|
||||
w.pos(n.Pos())
|
||||
w.expr(n.X)
|
||||
low, high, max := n.SliceBounds()
|
||||
w.exprsOrNil(low, high)
|
||||
w.expr(max)
|
||||
w.exprsOrNil(n.Low, n.High)
|
||||
w.expr(n.Max)
|
||||
|
||||
case ir.OCOPY, ir.OCOMPLEX:
|
||||
// treated like other builtin calls (see e.g., OREAL)
|
||||
@ -1412,8 +1393,8 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
n := n.(*ir.ConvExpr)
|
||||
w.op(ir.OCONV)
|
||||
w.pos(n.Pos())
|
||||
w.expr(n.X)
|
||||
w.typ(n.Type())
|
||||
w.expr(n.X)
|
||||
|
||||
case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
|
||||
n := n.(*ir.UnaryExpr)
|
||||
@ -1544,6 +1525,7 @@ func (w *exportWriter) fieldList(list ir.Nodes) {
|
||||
w.uint64(uint64(len(list)))
|
||||
for _, n := range list {
|
||||
n := n.(*ir.StructKeyExpr)
|
||||
w.pos(n.Pos())
|
||||
w.selector(n.Field)
|
||||
w.expr(n.Value)
|
||||
}
|
||||
|
@ -71,7 +71,12 @@ func ImportBody(fn *ir.Func) {
|
||||
base.Fatalf("missing import reader for %v", fn)
|
||||
}
|
||||
|
||||
if inimport {
|
||||
base.Fatalf("recursive inimport")
|
||||
}
|
||||
inimport = true
|
||||
r.doInline(fn)
|
||||
inimport = false
|
||||
}
|
||||
|
||||
func importReaderFor(sym *types.Sym, importers map[*types.Sym]iimporterAndOffset) *importReader {
|
||||
@ -767,10 +772,10 @@ func (r *importReader) stmtList() []ir.Node {
|
||||
return list
|
||||
}
|
||||
|
||||
func (r *importReader) caseList(sw ir.Node) []ir.Node {
|
||||
namedTypeSwitch := isNamedTypeSwitch(sw)
|
||||
func (r *importReader) caseList(switchExpr ir.Node) []*ir.CaseClause {
|
||||
namedTypeSwitch := isNamedTypeSwitch(switchExpr)
|
||||
|
||||
cases := make([]ir.Node, r.uint64())
|
||||
cases := make([]*ir.CaseClause, r.uint64())
|
||||
for i := range cases {
|
||||
cas := ir.NewCaseStmt(r.pos(), nil, nil)
|
||||
cas.List.Set(r.stmtList())
|
||||
@ -780,8 +785,8 @@ func (r *importReader) caseList(sw ir.Node) []ir.Node {
|
||||
// Sym for diagnostics anyway.
|
||||
caseVar := ir.NewNameAt(cas.Pos(), r.ident())
|
||||
Declare(caseVar, DeclContext)
|
||||
cas.Vars = []ir.Node{caseVar}
|
||||
caseVar.Defn = sw.(*ir.SwitchStmt).Tag
|
||||
cas.Var = caseVar
|
||||
caseVar.Defn = switchExpr
|
||||
}
|
||||
cas.Body.Set(r.stmtList())
|
||||
cases[i] = cas
|
||||
@ -789,6 +794,14 @@ func (r *importReader) caseList(sw ir.Node) []ir.Node {
|
||||
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 {
|
||||
var list []ir.Node
|
||||
for {
|
||||
@ -821,7 +834,7 @@ func (r *importReader) node() ir.Node {
|
||||
pos := r.pos()
|
||||
typ := r.typ()
|
||||
|
||||
n := npos(pos, NodNil())
|
||||
n := ir.NewNilExpr(pos)
|
||||
n.SetType(typ)
|
||||
return n
|
||||
|
||||
@ -829,7 +842,7 @@ func (r *importReader) node() ir.Node {
|
||||
pos := r.pos()
|
||||
typ := r.typ()
|
||||
|
||||
n := npos(pos, ir.NewLiteral(r.value(typ)))
|
||||
n := ir.NewBasicLit(pos, r.value(typ))
|
||||
n.SetType(typ)
|
||||
return n
|
||||
|
||||
@ -851,8 +864,7 @@ func (r *importReader) node() ir.Node {
|
||||
if s := r.ident(); s != nil {
|
||||
tag = ir.NewIdent(pos, s)
|
||||
}
|
||||
expr, _ := r.exprsOrNil()
|
||||
return ir.NewTypeSwitchGuard(pos, tag, expr)
|
||||
return ir.NewTypeSwitchGuard(pos, tag, r.expr())
|
||||
|
||||
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
|
||||
// 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
|
||||
|
||||
case ir.OSTRUCTLIT:
|
||||
// TODO(mdempsky): Export position information for OSTRUCTKEY nodes.
|
||||
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
|
||||
return ir.NewCompLitExpr(r.pos(), ir.OCOMPLIT, ir.TypeNode(r.typ()), r.fieldList())
|
||||
|
||||
// case OARRAYLIT, OSLICELIT, OMAPLIT:
|
||||
// unreachable - mapped to case OCOMPLIT below by exporter
|
||||
|
||||
case ir.OCOMPLIT:
|
||||
n := ir.NewCompLitExpr(r.pos(), ir.OCOMPLIT, ir.TypeNode(r.typ()).(ir.Ntype), nil)
|
||||
n.List.Set(r.exprList())
|
||||
return n
|
||||
return ir.NewCompLitExpr(r.pos(), ir.OCOMPLIT, ir.TypeNode(r.typ()), r.exprList())
|
||||
|
||||
case ir.OKEY:
|
||||
pos := r.pos()
|
||||
left, right := r.exprsOrNil()
|
||||
return ir.NewKeyExpr(pos, left, right)
|
||||
return ir.NewKeyExpr(r.pos(), r.expr(), r.expr())
|
||||
|
||||
// case OSTRUCTKEY:
|
||||
// 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())
|
||||
|
||||
case ir.OSLICE, ir.OSLICE3:
|
||||
n := ir.NewSliceExpr(r.pos(), op, r.expr())
|
||||
pos, x := r.pos(), r.expr()
|
||||
low, high := r.exprsOrNil()
|
||||
var max ir.Node
|
||||
if n.Op().IsSlice3() {
|
||||
if op.IsSlice3() {
|
||||
max = r.expr()
|
||||
}
|
||||
n.SetSliceBounds(low, high, max)
|
||||
return n
|
||||
return ir.NewSliceExpr(pos, op, x, low, high, max)
|
||||
|
||||
// case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR:
|
||||
// unreachable - mapped to OCONV case below by exporter
|
||||
|
||||
case ir.OCONV:
|
||||
n := ir.NewConvExpr(r.pos(), ir.OCONV, nil, r.expr())
|
||||
n.SetType(r.typ())
|
||||
return n
|
||||
return ir.NewConvExpr(r.pos(), ir.OCONV, r.typ(), r.expr())
|
||||
|
||||
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)
|
||||
@ -942,10 +941,10 @@ func (r *importReader) node() ir.Node {
|
||||
// unreachable - mapped to OCALL case below by exporter
|
||||
|
||||
case ir.OCALL:
|
||||
n := ir.NewCallExpr(r.pos(), ir.OCALL, nil, nil)
|
||||
n.PtrInit().Set(r.stmtList())
|
||||
n.X = r.expr()
|
||||
n.Args.Set(r.exprList())
|
||||
pos := r.pos()
|
||||
init := r.stmtList()
|
||||
n := ir.NewCallExpr(pos, ir.OCALL, r.expr(), r.exprList())
|
||||
n.PtrInit().Set(init)
|
||||
n.IsDDD = r.bool()
|
||||
return n
|
||||
|
||||
@ -979,7 +978,7 @@ func (r *importReader) node() ir.Node {
|
||||
case ir.OADDSTR:
|
||||
pos := r.pos()
|
||||
list := r.exprList()
|
||||
x := npos(pos, list[0])
|
||||
x := list[0]
|
||||
for _, y := range list[1:] {
|
||||
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())
|
||||
|
||||
case ir.OASOP:
|
||||
n := ir.NewAssignOpStmt(r.pos(), ir.OXXX, nil, nil)
|
||||
n.AsOp = r.op()
|
||||
n.X = r.expr()
|
||||
n := ir.NewAssignOpStmt(r.pos(), r.op(), r.expr(), nil)
|
||||
if !r.bool() {
|
||||
n.Y = ir.NewInt(1)
|
||||
n.IncDec = true
|
||||
@ -1021,15 +1018,10 @@ func (r *importReader) node() ir.Node {
|
||||
// unreachable - mapped to OAS2 case below by exporter
|
||||
|
||||
case ir.OAS2:
|
||||
n := ir.NewAssignListStmt(r.pos(), ir.OAS2, nil, nil)
|
||||
n.Lhs.Set(r.exprList())
|
||||
n.Rhs.Set(r.exprList())
|
||||
return n
|
||||
return ir.NewAssignListStmt(r.pos(), ir.OAS2, r.exprList(), r.exprList())
|
||||
|
||||
case ir.ORETURN:
|
||||
n := ir.NewReturnStmt(r.pos(), nil)
|
||||
n.Results.Set(r.exprList())
|
||||
return n
|
||||
return ir.NewReturnStmt(r.pos(), r.exprList())
|
||||
|
||||
// case ORETJMP:
|
||||
// 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())
|
||||
|
||||
case ir.OIF:
|
||||
n := ir.NewIfStmt(r.pos(), nil, nil, nil)
|
||||
n.PtrInit().Set(r.stmtList())
|
||||
n.Cond = r.expr()
|
||||
n.Body.Set(r.stmtList())
|
||||
n.Else.Set(r.stmtList())
|
||||
pos, init := r.pos(), r.stmtList()
|
||||
n := ir.NewIfStmt(pos, r.expr(), r.stmtList(), r.stmtList())
|
||||
n.PtrInit().Set(init)
|
||||
return n
|
||||
|
||||
case ir.OFOR:
|
||||
n := ir.NewForStmt(r.pos(), nil, nil, nil, nil)
|
||||
n.PtrInit().Set(r.stmtList())
|
||||
left, right := r.exprsOrNil()
|
||||
n.Cond = left
|
||||
n.Post = right
|
||||
n.Body.Set(r.stmtList())
|
||||
pos, init := r.pos(), r.stmtList()
|
||||
cond, post := r.exprsOrNil()
|
||||
n := ir.NewForStmt(pos, nil, cond, post, r.stmtList())
|
||||
n.PtrInit().Set(init)
|
||||
return n
|
||||
|
||||
case ir.ORANGE:
|
||||
n := ir.NewRangeStmt(r.pos(), nil, nil, nil)
|
||||
n.Vars.Set(r.stmtList())
|
||||
n.X = r.expr()
|
||||
n.Body.Set(r.stmtList())
|
||||
return n
|
||||
pos := r.pos()
|
||||
k, v := r.exprsOrNil()
|
||||
return ir.NewRangeStmt(pos, k, v, r.expr(), r.stmtList())
|
||||
|
||||
case ir.OSELECT:
|
||||
n := ir.NewSelectStmt(r.pos(), nil)
|
||||
n.PtrInit().Set(r.stmtList())
|
||||
r.exprsOrNil() // TODO(rsc): Delete (and fix exporter). These are always nil.
|
||||
n.Cases.Set(r.caseList(n))
|
||||
pos := r.pos()
|
||||
init := r.stmtList()
|
||||
n := ir.NewSelectStmt(pos, r.commList())
|
||||
n.PtrInit().Set(init)
|
||||
return n
|
||||
|
||||
case ir.OSWITCH:
|
||||
n := ir.NewSwitchStmt(r.pos(), nil, nil)
|
||||
n.PtrInit().Set(r.stmtList())
|
||||
left, _ := r.exprsOrNil()
|
||||
n.Tag = left
|
||||
n.Cases.Set(r.caseList(n))
|
||||
pos := r.pos()
|
||||
init := r.stmtList()
|
||||
x, _ := r.exprsOrNil()
|
||||
n := ir.NewSwitchStmt(pos, x, r.caseList(x))
|
||||
n.PtrInit().Set(init)
|
||||
return n
|
||||
|
||||
// case OCASE:
|
||||
// handled by caseList
|
||||
|
||||
case ir.OFALL:
|
||||
n := ir.NewBranchStmt(r.pos(), ir.OFALL, nil)
|
||||
return n
|
||||
return ir.NewBranchStmt(r.pos(), ir.OFALL, nil)
|
||||
|
||||
// case OEMPTY:
|
||||
// unreachable - not emitted by exporter
|
||||
|
||||
case ir.OBREAK, ir.OCONTINUE, ir.OGOTO:
|
||||
var sym *types.Sym
|
||||
pos := r.pos()
|
||||
var sym *types.Sym
|
||||
if label := r.string(); label != "" {
|
||||
sym = Lookup(label)
|
||||
}
|
||||
@ -1111,12 +1096,10 @@ func (r *importReader) op() ir.Op {
|
||||
return ir.Op(r.uint64())
|
||||
}
|
||||
|
||||
func (r *importReader) elemList() []ir.Node {
|
||||
c := r.uint64()
|
||||
list := make([]ir.Node, c)
|
||||
func (r *importReader) fieldList() []ir.Node {
|
||||
list := make([]ir.Node, r.uint64())
|
||||
for i := range list {
|
||||
s := r.ident()
|
||||
list[i] = ir.NewStructKeyExpr(base.Pos, s, r.expr())
|
||||
list[i] = ir.NewStructKeyExpr(r.pos(), r.ident(), r.expr())
|
||||
}
|
||||
return list
|
||||
}
|
||||
@ -1135,8 +1118,3 @@ func (r *importReader) exprsOrNil() (a, b ir.Node) {
|
||||
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)
|
||||
}
|
||||
|
||||
func npos(pos src.XPos, n ir.Node) ir.Node {
|
||||
n.SetPos(pos)
|
||||
return n
|
||||
}
|
||||
|
@ -36,8 +36,8 @@ func main() {
|
||||
fmt.Fprintln(&b, "package typecheck")
|
||||
fmt.Fprintln(&b)
|
||||
fmt.Fprintln(&b, `import (`)
|
||||
fmt.Fprintln(&b, ` "cmd/compile/internal/ir"`)
|
||||
fmt.Fprintln(&b, ` "cmd/compile/internal/types"`)
|
||||
fmt.Fprintln(&b, ` "cmd/internal/src"`)
|
||||
fmt.Fprintln(&b, `)`)
|
||||
|
||||
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)
|
||||
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:
|
||||
if len(t.Methods.List) != 0 {
|
||||
log.Fatal("non-empty interfaces unsupported")
|
||||
@ -180,7 +180,7 @@ func (i *typeInterner) mktype(t ast.Expr) string {
|
||||
case *ast.StarExpr:
|
||||
return fmt.Sprintf("types.NewPtr(%s)", i.subtype(t.X))
|
||||
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:
|
||||
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 {
|
||||
typ := i.subtype(f.Type)
|
||||
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 {
|
||||
for _, name := range f.Names {
|
||||
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 {
|
||||
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 {
|
||||
|
@ -11,27 +11,29 @@ import (
|
||||
"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) {
|
||||
n.X = Expr(n.X)
|
||||
|
||||
t := n.X.Type()
|
||||
if t == nil {
|
||||
if n.X.Type() == nil {
|
||||
return
|
||||
}
|
||||
|
||||
t := RangeExprType(n.X.Type())
|
||||
// delicate little dance. see typecheckas2
|
||||
ls := n.Vars
|
||||
for i1, n1 := range ls {
|
||||
if !ir.DeclaredBy(n1, n) {
|
||||
ls[i1] = AssignExpr(ls[i1])
|
||||
if n.Key != nil && !ir.DeclaredBy(n.Key, n) {
|
||||
n.Key = AssignExpr(n.Key)
|
||||
}
|
||||
if n.Value != nil && !ir.DeclaredBy(n.Value, n) {
|
||||
n.Value = AssignExpr(n.Value)
|
||||
}
|
||||
|
||||
if t.IsPtr() && t.Elem().IsArray() {
|
||||
t = t.Elem()
|
||||
}
|
||||
n.SetType(t)
|
||||
|
||||
var t1, t2 *types.Type
|
||||
var tk, tv *types.Type
|
||||
toomany := false
|
||||
switch t.Kind() {
|
||||
default:
|
||||
@ -39,12 +41,12 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
|
||||
return
|
||||
|
||||
case types.TARRAY, types.TSLICE:
|
||||
t1 = types.Types[types.TINT]
|
||||
t2 = t.Elem()
|
||||
tk = types.Types[types.TINT]
|
||||
tv = t.Elem()
|
||||
|
||||
case types.TMAP:
|
||||
t1 = t.Key()
|
||||
t2 = t.Elem()
|
||||
tk = t.Key()
|
||||
tv = t.Elem()
|
||||
|
||||
case types.TCHAN:
|
||||
if !t.ChanDir().CanRecv() {
|
||||
@ -52,61 +54,35 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
|
||||
return
|
||||
}
|
||||
|
||||
t1 = t.Elem()
|
||||
t2 = nil
|
||||
if len(n.Vars) == 2 {
|
||||
tk = t.Elem()
|
||||
tv = nil
|
||||
if n.Value != nil {
|
||||
toomany = true
|
||||
}
|
||||
|
||||
case types.TSTRING:
|
||||
t1 = types.Types[types.TINT]
|
||||
t2 = types.RuneType
|
||||
tk = types.Types[types.TINT]
|
||||
tv = types.RuneType
|
||||
}
|
||||
|
||||
if len(n.Vars) > 2 || toomany {
|
||||
if toomany {
|
||||
base.ErrorfAt(n.Pos(), "too many variables in range")
|
||||
}
|
||||
|
||||
var v1, v2 ir.Node
|
||||
if len(n.Vars) != 0 {
|
||||
v1 = n.Vars[0]
|
||||
}
|
||||
if len(n.Vars) > 1 {
|
||||
v2 = n.Vars[1]
|
||||
}
|
||||
|
||||
// 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)
|
||||
do := func(nn ir.Node, t *types.Type) {
|
||||
if nn != nil {
|
||||
if ir.DeclaredBy(nn, n) {
|
||||
nn.SetType(t)
|
||||
} else if nn.Type() != nil {
|
||||
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)
|
||||
}
|
||||
}
|
||||
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, nn)
|
||||
}
|
||||
}
|
||||
checkassign(n, v2)
|
||||
}
|
||||
do(n.Key, tk)
|
||||
do(n.Value, tv)
|
||||
}
|
||||
|
||||
// type check assignment.
|
||||
@ -117,47 +93,16 @@ func tcAssign(n *ir.AssignStmt) {
|
||||
defer tracePrint("typecheckas", n)(nil)
|
||||
}
|
||||
|
||||
// delicate little dance.
|
||||
// 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 {
|
||||
if n.Y == nil {
|
||||
n.X = AssignExpr(n.X)
|
||||
return
|
||||
}
|
||||
|
||||
// Use ctxMultiOK so we can emit an "N variables but M values" error
|
||||
// to be consistent with typecheckas2 (#26616).
|
||||
n.Y = typecheck(n.Y, ctxExpr|ctxMultiOK)
|
||||
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")
|
||||
}
|
||||
}
|
||||
lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
|
||||
assign(n, lhs, rhs)
|
||||
n.X, n.Y = lhs[0], rhs[0]
|
||||
|
||||
if ir.DeclaredBy(n.X, n) && n.X.Name().Ntype == nil {
|
||||
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)
|
||||
}
|
||||
// TODO(mdempsky): This seems out of place.
|
||||
if !ir.IsBlank(n.X) {
|
||||
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)
|
||||
}
|
||||
|
||||
ls := n.Lhs
|
||||
for i1, n1 := range ls {
|
||||
assign(n, n.Lhs, n.Rhs)
|
||||
}
|
||||
|
||||
func assign(stmt ir.Node, lhs, rhs []ir.Node) {
|
||||
// delicate little dance.
|
||||
n1 = Resolve(n1)
|
||||
ls[i1] = n1
|
||||
// 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).
|
||||
|
||||
if !ir.DeclaredBy(n1, n) || n1.Name().Ntype != nil {
|
||||
ls[i1] = AssignExpr(ls[i1])
|
||||
}
|
||||
}
|
||||
|
||||
cl := len(n.Lhs)
|
||||
cr := len(n.Rhs)
|
||||
if cl > 1 && cr == 1 {
|
||||
n.Rhs[0] = typecheck(n.Rhs[0], ctxExpr|ctxMultiOK)
|
||||
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 {
|
||||
Exprs(n.Rhs)
|
||||
base.Errorf("use of untyped nil")
|
||||
}
|
||||
}
|
||||
if lhs[i].Typecheck() == 0 {
|
||||
lhs[i] = AssignExpr(lhs[i])
|
||||
}
|
||||
checkassign(stmt, lhs[i])
|
||||
}
|
||||
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())
|
||||
assignType := func(i int, typ *types.Type) {
|
||||
checkLHS(i, typ)
|
||||
if typ != nil {
|
||||
checkassignto(typ, lhs[i])
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
cr := len(rhs)
|
||||
if len(rhs) == 1 {
|
||||
rhs[0] = typecheck(rhs[0], ctxExpr|ctxMultiOK)
|
||||
if rtyp := rhs[0].Type(); rtyp != nil && rtyp.IsFuncArgStruct() {
|
||||
cr = rtyp.NumFields()
|
||||
}
|
||||
} else {
|
||||
Exprs(rhs)
|
||||
}
|
||||
|
||||
// x, ok = y
|
||||
if cl == 2 && cr == 1 {
|
||||
if r.Type() == nil {
|
||||
goto out
|
||||
}
|
||||
switch r.Op() {
|
||||
case ir.OINDEXMAP, ir.ORECV, ir.ODOTTYPE:
|
||||
assignOK:
|
||||
for len(lhs) == 2 && cr == 1 {
|
||||
stmt := stmt.(*ir.AssignListStmt)
|
||||
r := rhs[0]
|
||||
|
||||
switch r.Op() {
|
||||
case ir.OINDEXMAP:
|
||||
n.SetOp(ir.OAS2MAPR)
|
||||
stmt.SetOp(ir.OAS2MAPR)
|
||||
case ir.ORECV:
|
||||
n.SetOp(ir.OAS2RECV)
|
||||
stmt.SetOp(ir.OAS2RECV)
|
||||
case ir.ODOTTYPE:
|
||||
r := r.(*ir.TypeAssertExpr)
|
||||
n.SetOp(ir.OAS2DOTTYPE)
|
||||
stmt.SetOp(ir.OAS2DOTTYPE)
|
||||
r.SetOp(ir.ODOTTYPE2)
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
mismatch:
|
||||
switch r.Op() {
|
||||
default:
|
||||
base.Errorf("assignment mismatch: %d variables but %d values", cl, cr)
|
||||
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
|
||||
r := r.(*ir.CallExpr)
|
||||
base.Errorf("assignment mismatch: %d variables but %v returns %d values", cl, r.X, cr)
|
||||
break assignOK
|
||||
}
|
||||
|
||||
// second half of dance
|
||||
out:
|
||||
n.SetTypecheck(1)
|
||||
ls = n.Lhs
|
||||
for i1, n1 := range ls {
|
||||
if n1.Typecheck() == 0 {
|
||||
ls[i1] = AssignExpr(ls[i1])
|
||||
assignType(0, r.Type())
|
||||
assignType(1, types.UntypedBool)
|
||||
return
|
||||
}
|
||||
|
||||
if len(lhs) != cr {
|
||||
if r, ok := rhs[0].(*ir.CallExpr); ok && len(rhs) == 1 {
|
||||
if r.Type() != nil {
|
||||
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))
|
||||
}
|
||||
} else {
|
||||
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
|
||||
}
|
||||
|
||||
// x,y,z = f()
|
||||
if cr > len(rhs) {
|
||||
stmt := stmt.(*ir.AssignListStmt)
|
||||
stmt.SetOp(ir.OAS2FUNC)
|
||||
r := rhs[0].(*ir.CallExpr)
|
||||
r.Use = ir.CallUseList
|
||||
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.
|
||||
func tcFor(n *ir.ForStmt) ir.Node {
|
||||
Stmts(n.Init())
|
||||
@ -399,11 +330,11 @@ func tcRange(n *ir.RangeStmt) {
|
||||
|
||||
// second half of dance, the first half being typecheckrangeExpr
|
||||
n.SetTypecheck(1)
|
||||
ls := n.Vars
|
||||
for i1, n1 := range ls {
|
||||
if n1.Typecheck() == 0 {
|
||||
ls[i1] = AssignExpr(ls[i1])
|
||||
if n.Key != nil && n.Key.Typecheck() == 0 {
|
||||
n.Key = AssignExpr(n.Key)
|
||||
}
|
||||
if n.Value != nil && n.Value.Typecheck() == 0 {
|
||||
n.Value = AssignExpr(n.Value)
|
||||
}
|
||||
|
||||
decldepth++
|
||||
@ -429,31 +360,23 @@ func tcReturn(n *ir.ReturnStmt) ir.Node {
|
||||
|
||||
// select
|
||||
func tcSelect(sel *ir.SelectStmt) {
|
||||
var def ir.Node
|
||||
var def *ir.CommClause
|
||||
lno := ir.SetPos(sel)
|
||||
Stmts(sel.Init())
|
||||
for _, ncase := range sel.Cases {
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
|
||||
if len(ncase.List) == 0 {
|
||||
if ncase.Comm == nil {
|
||||
// default
|
||||
if def != nil {
|
||||
base.ErrorfAt(ncase.Pos(), "multiple defaults in select (first at %v)", ir.Line(def))
|
||||
} else {
|
||||
def = ncase
|
||||
}
|
||||
} else if len(ncase.List) > 1 {
|
||||
base.ErrorfAt(ncase.Pos(), "select cases cannot be lists")
|
||||
} else {
|
||||
ncase.List[0] = Stmt(ncase.List[0])
|
||||
n := ncase.List[0]
|
||||
n := Stmt(ncase.Comm)
|
||||
ncase.Comm = n
|
||||
ncase.List.Set(nil)
|
||||
oselrecv2 := func(dst, recv ir.Node, colas bool) {
|
||||
n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, nil, nil)
|
||||
n.Lhs = []ir.Node{dst, ir.BlankNode}
|
||||
n.Rhs = []ir.Node{recv}
|
||||
n.Def = colas
|
||||
oselrecv2 := func(dst, recv ir.Node, def bool) {
|
||||
n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
|
||||
n.Def = def
|
||||
n.SetTypecheck(1)
|
||||
ncase.Comm = n
|
||||
}
|
||||
@ -577,7 +500,6 @@ func tcSwitchExpr(n *ir.SwitchStmt) {
|
||||
var defCase ir.Node
|
||||
var cs constSet
|
||||
for _, ncase := range n.Cases {
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
ls := ncase.List
|
||||
if len(ls) == 0 { // default:
|
||||
if defCase != nil {
|
||||
@ -646,7 +568,6 @@ func tcSwitchType(n *ir.SwitchStmt) {
|
||||
var defCase, nilCase ir.Node
|
||||
var ts typeSet
|
||||
for _, ncase := range n.Cases {
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
ls := ncase.List
|
||||
if len(ls) == 0 { // default:
|
||||
if defCase != nil {
|
||||
@ -694,7 +615,7 @@ func tcSwitchType(n *ir.SwitchStmt) {
|
||||
ts.add(ncase.Pos(), n1.Type())
|
||||
}
|
||||
|
||||
if len(ncase.Vars) != 0 {
|
||||
if ncase.Var != nil {
|
||||
// Assign the clause variable's type.
|
||||
vt := t
|
||||
if len(ls) == 1 {
|
||||
@ -707,7 +628,7 @@ func tcSwitchType(n *ir.SwitchStmt) {
|
||||
}
|
||||
}
|
||||
|
||||
nvar := ncase.Vars[0]
|
||||
nvar := ncase.Var
|
||||
nvar.SetType(vt)
|
||||
if vt != nil {
|
||||
nvar = AssignExpr(nvar)
|
||||
@ -716,7 +637,7 @@ func tcSwitchType(n *ir.SwitchStmt) {
|
||||
nvar.SetTypecheck(1)
|
||||
nvar.SetWalkdef(1)
|
||||
}
|
||||
ncase.Vars[0] = nvar
|
||||
ncase.Var = nvar
|
||||
}
|
||||
|
||||
Stmts(ncase.Body)
|
||||
|
@ -73,13 +73,42 @@ func tcChanType(n *ir.ChanType) ir.Node {
|
||||
|
||||
// tcFuncType typechecks an OTFUNC 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
|
||||
}
|
||||
|
||||
// tcInterfaceType typechecks an OTINTER 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
|
||||
}
|
||||
|
||||
@ -117,6 +146,43 @@ func tcSliceType(n *ir.SliceType) ir.Node {
|
||||
|
||||
// tcStructType typechecks an OTSTRUCT 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
@ -251,13 +251,7 @@ func Resolve(n ir.Node) (res ir.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
if inimport {
|
||||
base.Fatalf("recursive inimport")
|
||||
}
|
||||
inimport = true
|
||||
n = expandDecl(n)
|
||||
inimport = false
|
||||
return n
|
||||
return expandDecl(n)
|
||||
}
|
||||
|
||||
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 {
|
||||
base.Fatalf("lookdot badwidth %v %p", f1, f1)
|
||||
}
|
||||
n.Offset = f1.Offset
|
||||
n.Selection = f1
|
||||
n.SetType(f1.Type)
|
||||
if t.IsInterface() {
|
||||
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.Selection = f1
|
||||
return f1
|
||||
}
|
||||
|
||||
@ -1298,11 +1291,9 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
|
||||
return nil
|
||||
}
|
||||
|
||||
n.Sel = ir.MethodSym(n.X.Type(), f2.Sym)
|
||||
n.Offset = f2.Offset
|
||||
n.Selection = f2
|
||||
n.SetType(f2.Type)
|
||||
n.SetOp(ir.ODOTMETH)
|
||||
n.Selection = f2
|
||||
|
||||
return f2
|
||||
}
|
||||
@ -1638,7 +1629,7 @@ func nonexported(sym *types.Sym) bool {
|
||||
}
|
||||
|
||||
func checklvalue(n ir.Node, verb string) {
|
||||
if !ir.IsAssignable(n) {
|
||||
if !ir.IsAddressable(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
|
||||
}
|
||||
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) {
|
||||
// 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 {
|
||||
base.Errorf("cannot assign %v to %L in multiple assignment%s", src, dst, why)
|
||||
return
|
||||
@ -2101,7 +2097,6 @@ func isTermNode(n ir.Node) bool {
|
||||
}
|
||||
def := false
|
||||
for _, cas := range n.Cases {
|
||||
cas := cas.(*ir.CaseStmt)
|
||||
if !isTermNodes(cas.Body) {
|
||||
return false
|
||||
}
|
||||
@ -2117,7 +2112,6 @@ func isTermNode(n ir.Node) bool {
|
||||
return false
|
||||
}
|
||||
for _, cas := range n.Cases {
|
||||
cas := cas.(*ir.CaseStmt)
|
||||
if !isTermNodes(cas.Body) {
|
||||
return false
|
||||
}
|
||||
@ -2216,9 +2210,6 @@ func deadcodeslice(nn *ir.Nodes) {
|
||||
case ir.OBLOCK:
|
||||
n := n.(*ir.BlockStmt)
|
||||
deadcodeslice(&n.List)
|
||||
case ir.OCASE:
|
||||
n := n.(*ir.CaseStmt)
|
||||
deadcodeslice(&n.Body)
|
||||
case ir.OFOR:
|
||||
n := n.(*ir.ForStmt)
|
||||
deadcodeslice(&n.Body)
|
||||
@ -2231,10 +2222,14 @@ func deadcodeslice(nn *ir.Nodes) {
|
||||
deadcodeslice(&n.Body)
|
||||
case ir.OSELECT:
|
||||
n := n.(*ir.SelectStmt)
|
||||
deadcodeslice(&n.Cases)
|
||||
for _, cas := range n.Cases {
|
||||
deadcodeslice(&cas.Body)
|
||||
}
|
||||
case ir.OSWITCH:
|
||||
n := n.(*ir.SwitchStmt)
|
||||
deadcodeslice(&n.Cases)
|
||||
for _, cas := range n.Cases {
|
||||
deadcodeslice(&cas.Body)
|
||||
}
|
||||
}
|
||||
|
||||
if cut {
|
||||
|
@ -10,7 +10,7 @@ import "cmd/compile/internal/base"
|
||||
// hashing a Type.
|
||||
type AlgKind int
|
||||
|
||||
//go:generate stringer -type AlgKind -trimprefix A
|
||||
//go:generate stringer -type AlgKind -trimprefix A alg.go
|
||||
|
||||
const (
|
||||
// These values are known by runtime.
|
||||
|
@ -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
|
||||
|
||||
|
@ -180,15 +180,6 @@ func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
|
||||
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
|
||||
|
||||
var BasicTypeNames = []string{
|
||||
@ -595,7 +586,10 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
|
||||
if funarg != FunargNone {
|
||||
name = fmt.Sprint(f.Nname)
|
||||
} else if verb == 'L' {
|
||||
name = SymMethodName(s)
|
||||
name = s.Name
|
||||
if name == ".F" {
|
||||
name = "F" // Hack for toolstash -cmp.
|
||||
}
|
||||
if !IsExported(name) && mode != fmtTypeIDName {
|
||||
name = sconv(s, 0, mode) // qualify non-exported names (used on structs, not on funarg)
|
||||
}
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run mkbuiltin.go
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
|
@ -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
|
||||
|
||||
@ -48,13 +48,13 @@ func _() {
|
||||
_ = 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 {
|
||||
if i >= Kind(len(_EType_index)-1) {
|
||||
return "EType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
if i >= Kind(len(_Kind_index)-1) {
|
||||
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]]
|
||||
}
|
@ -33,9 +33,9 @@ type VarObject interface {
|
||||
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
|
||||
|
||||
const (
|
||||
|
@ -297,54 +297,6 @@ func fncall(l ir.Node, rt *types.Type) bool {
|
||||
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
|
||||
// an expression list. called in
|
||||
// expr-list = func()
|
||||
@ -387,39 +339,79 @@ func ascompatet(nl ir.Nodes, nr *types.Type) []ir.Node {
|
||||
return append(nn, mm...)
|
||||
}
|
||||
|
||||
// reorder3
|
||||
// from ascompatee
|
||||
// a,b = c,d
|
||||
// simultaneous assignment. there cannot
|
||||
// be later use of an earlier lvalue.
|
||||
//
|
||||
// function calls have been removed.
|
||||
func reorder3(all []*ir.AssignStmt) []ir.Node {
|
||||
// check assign expression list to
|
||||
// an expression list. called in
|
||||
// expr-list = expr-list
|
||||
func ascompatee(op ir.Op, nl, nr []ir.Node, init *ir.Nodes) []ir.Node {
|
||||
// cannot happen: should have been rejected during type checking
|
||||
if len(nl) != len(nr) {
|
||||
base.Fatalf("assignment operands mismatch: %+v / %+v", ir.Nodes(nl), ir.Nodes(nr))
|
||||
}
|
||||
|
||||
// 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
|
||||
// earlier assignment, make an early copy of that
|
||||
// expression and use the copy instead.
|
||||
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
|
||||
for i, n := range all {
|
||||
l := n.X
|
||||
var late []ir.Node
|
||||
for i, l := range nl {
|
||||
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.
|
||||
// Drill through non-dereferences.
|
||||
for {
|
||||
switch ll := l; ll.Op() {
|
||||
case ir.ODOT:
|
||||
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)
|
||||
switch ll := l.(type) {
|
||||
case *ir.IndexExpr:
|
||||
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
|
||||
continue
|
||||
}
|
||||
@ -427,143 +419,50 @@ func reorder3(all []*ir.AssignStmt) []ir.Node {
|
||||
break
|
||||
}
|
||||
|
||||
var name *ir.Name
|
||||
switch l.Op() {
|
||||
default:
|
||||
base.Fatalf("reorder3 unexpected lvalue %v", l.Op())
|
||||
|
||||
base.Fatalf("unexpected lvalue %v", l.Op())
|
||||
case ir.ONAME:
|
||||
break
|
||||
|
||||
name = l.(*ir.Name)
|
||||
case ir.OINDEX, ir.OINDEXMAP:
|
||||
l := l.(*ir.IndexExpr)
|
||||
l.X = reorder3save(l.X, all, i, &early)
|
||||
l.Index = reorder3save(l.Index, all, i, &early)
|
||||
if l.Op() == ir.OINDEXMAP {
|
||||
all[i] = convas(all[i], &mapinit)
|
||||
}
|
||||
|
||||
save(&l.X)
|
||||
save(&l.Index)
|
||||
case ir.ODEREF:
|
||||
l := l.(*ir.StarExpr)
|
||||
l.X = reorder3save(l.X, all, i, &early)
|
||||
save(&l.X)
|
||||
case ir.ODOTPTR:
|
||||
l := l.(*ir.SelectorExpr)
|
||||
l.X = reorder3save(l.X, all, i, &early)
|
||||
save(&l.X)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
early = append(mapinit, early...)
|
||||
for _, as := range all {
|
||||
early = append(early, as)
|
||||
}
|
||||
return early
|
||||
}
|
||||
|
||||
// if the evaluation of *np would be affected by the
|
||||
// assignments in all up to but not including the ith assignment,
|
||||
// copy into a temporary during *early and
|
||||
// replace *np with that temp.
|
||||
// The result of reorder3save MUST be assigned back to n, e.g.
|
||||
// n.Left = reorder3save(n.Left, all, i, early)
|
||||
func reorder3save(n ir.Node, all []*ir.AssignStmt, i int, early *[]ir.Node) ir.Node {
|
||||
if !aliased(n, all[:i]) {
|
||||
return n
|
||||
}
|
||||
|
||||
q := ir.Node(typecheck.Temp(n.Type()))
|
||||
as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, q, n))
|
||||
*early = append(*early, as)
|
||||
return q
|
||||
}
|
||||
|
||||
// Is it possible that the computation of r might be
|
||||
// affected by assignments in all?
|
||||
func aliased(r ir.Node, all []*ir.AssignStmt) bool {
|
||||
if r == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Treat all fields of a struct as referring to the whole struct.
|
||||
// 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 {
|
||||
if ir.IsBlank(name) {
|
||||
// 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
|
||||
assigned.Add(name)
|
||||
}
|
||||
|
||||
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 append(early, late...)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// readsMemory reports whether the evaluation n directly reads from
|
||||
// memory that might be written to indirectly.
|
||||
func readsMemory(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")
|
||||
return n.Class_ == ir.PEXTERN || n.Class_ == ir.PAUTOHEAP || n.Addrtaken()
|
||||
|
||||
case ir.OADD,
|
||||
ir.OAND,
|
||||
@ -574,6 +473,7 @@ func anyAddrTaken(n ir.Node) bool {
|
||||
ir.OCONVIFACE,
|
||||
ir.OCONVNOP,
|
||||
ir.ODIV,
|
||||
ir.ODOT,
|
||||
ir.ODOTTYPE,
|
||||
ir.OLITERAL,
|
||||
ir.OLSH,
|
||||
@ -590,65 +490,9 @@ func anyAddrTaken(n ir.Node) bool {
|
||||
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
|
||||
@ -700,17 +544,15 @@ func appendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||
nodes.Append(nif)
|
||||
|
||||
// s = s[:n]
|
||||
nt := ir.NewSliceExpr(base.Pos, ir.OSLICE, s)
|
||||
nt.SetSliceBounds(nil, nn, nil)
|
||||
nt := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, nil, nn, nil)
|
||||
nt.SetBounded(true)
|
||||
nodes.Append(ir.NewAssignStmt(base.Pos, s, nt))
|
||||
|
||||
var ncopy ir.Node
|
||||
if elemtype.HasPointers() {
|
||||
// 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.SetSliceBounds(ir.NewUnaryExpr(base.Pos, ir.OLEN, l1), nil, nil)
|
||||
|
||||
ir.CurFunc.SetWBPos(n.Pos())
|
||||
|
||||
@ -724,9 +566,8 @@ func appendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||
// rely on runtime to instrument:
|
||||
// copy(s[len(l1):], l2)
|
||||
// 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.SetSliceBounds(ir.NewUnaryExpr(base.Pos, ir.OLEN, l1), nil, nil)
|
||||
|
||||
ptr1, len1 := backingArrayPtrLen(cheapExpr(slice, &nodes))
|
||||
ptr2, len2 := backingArrayPtrLen(l2)
|
||||
@ -870,8 +711,7 @@ func extendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||
nodes = append(nodes, nif)
|
||||
|
||||
// s = s[:n]
|
||||
nt := ir.NewSliceExpr(base.Pos, ir.OSLICE, s)
|
||||
nt.SetSliceBounds(nil, nn, nil)
|
||||
nt := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, nil, nn, nil)
|
||||
nt.SetBounded(true)
|
||||
nodes = append(nodes, ir.NewAssignStmt(base.Pos, s, nt))
|
||||
|
||||
|
@ -95,8 +95,7 @@ func walkAppend(n *ir.CallExpr, init *ir.Nodes, dst ir.Node) ir.Node {
|
||||
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)
|
||||
|
||||
slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, ns) // ...s[:n+argc]
|
||||
slice.SetSliceBounds(nil, ir.NewBinaryExpr(base.Pos, ir.OADD, nn, na), nil)
|
||||
slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, ns, nil, ir.NewBinaryExpr(base.Pos, ir.OADD, nn, na), nil) // ...s[:n+argc]
|
||||
slice.SetBounded(true)
|
||||
l = append(l, ir.NewAssignStmt(base.Pos, ns, slice)) // s = s[:n+argc]
|
||||
|
||||
@ -408,8 +407,7 @@ func walkMakeSlice(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
|
||||
t = types.NewArray(t.Elem(), i) // [r]T
|
||||
var_ := typecheck.Temp(t)
|
||||
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil)) // zero temp
|
||||
r := ir.NewSliceExpr(base.Pos, ir.OSLICE, var_) // arr[:l]
|
||||
r.SetSliceBounds(nil, l, nil)
|
||||
r := ir.NewSliceExpr(base.Pos, ir.OSLICE, var_, nil, l, nil) // arr[:l]
|
||||
// The conv is necessary in case n.Type is named.
|
||||
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)
|
||||
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.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)
|
||||
}
|
||||
|
||||
@ -471,7 +470,8 @@ func walkMakeSliceCopy(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
|
||||
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.MarkNonNil()
|
||||
sh.LenCap = []ir.Node{length, length}
|
||||
sh.Len = length
|
||||
sh.Cap = length
|
||||
sh.SetType(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.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.LenCap = []ir.Node{length, length}
|
||||
s.Len = length
|
||||
s.Cap = length
|
||||
s.SetType(t)
|
||||
return walkExpr(typecheck.Expr(s), init)
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ func walkCompare(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
|
||||
// Chose not to inline. Call equality function directly.
|
||||
if !inline {
|
||||
// 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)
|
||||
}
|
||||
|
||||
@ -428,11 +428,11 @@ func eqFor(t *types.Type) (n ir.Node, needsize bool) {
|
||||
sym := reflectdata.TypeSymPrefix(".eq", t)
|
||||
n := typecheck.NewName(sym)
|
||||
ir.MarkFunc(n)
|
||||
n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
|
||||
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
|
||||
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
|
||||
}, []*ir.Field{
|
||||
ir.NewField(base.Pos, nil, nil, types.Types[types.TBOOL]),
|
||||
n.SetType(types.NewSignature(types.NoPkg, nil, []*types.Field{
|
||||
types.NewField(base.Pos, nil, types.NewPtr(t)),
|
||||
types.NewField(base.Pos, nil, types.NewPtr(t)),
|
||||
}, []*types.Field{
|
||||
types.NewField(base.Pos, nil, types.Types[types.TBOOL]),
|
||||
}))
|
||||
return n, false
|
||||
}
|
||||
|
@ -425,7 +425,7 @@ func slicelit(ctxt initContext, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes)
|
||||
}
|
||||
|
||||
// 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 = 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
|
||||
return false
|
||||
}
|
||||
x := n.X.(*ir.Name)
|
||||
if !types.Identical(n.X.Type(), n.Y.Type()) {
|
||||
// not a special composite literal assignment
|
||||
return false
|
||||
@ -640,7 +641,7 @@ func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
|
||||
return false
|
||||
|
||||
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
|
||||
return false
|
||||
}
|
||||
|
@ -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 non-interface cases, is not visible to order.stmt, so we
|
||||
// have to fall back on allocating a temp here.
|
||||
if !ir.IsAssignable(v) {
|
||||
if !ir.IsAddressable(v) {
|
||||
v = copyExpr(v, v.Type(), init)
|
||||
}
|
||||
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 := ir.NewSliceExpr(n.Pos(), ir.OSLICEARR, p)
|
||||
slice := ir.NewSliceExpr(n.Pos(), ir.OSLICEARR, p, nil, nil, nil)
|
||||
slice.SetType(n.Type())
|
||||
slice.SetTypecheck(1)
|
||||
return walkExpr(slice, init)
|
||||
|
@ -26,15 +26,6 @@ func walkExpr(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
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() {
|
||||
// not okay to use n->ninit when walking n,
|
||||
// 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)
|
||||
|
||||
// Expressions that are constant at run time but not
|
||||
// considered const by the language spec are not turned into
|
||||
// constants until walk. For example, if n is y%1 == 0, the
|
||||
// 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())
|
||||
// Eagerly compute sizes of all expressions for the back end.
|
||||
if typ := n.Type(); typ != nil && typ.Kind() != types.TBLANK && !typ.IsFuncArgStruct() {
|
||||
types.CheckSize(typ)
|
||||
}
|
||||
if n.Op() == ir.OLITERAL {
|
||||
n = typecheck.Expr(n)
|
||||
if ir.IsConst(n, constant.String) {
|
||||
// Emit string symbol now to avoid emitting
|
||||
// any concurrently during the backend.
|
||||
if v := n.Val(); v.Kind() == constant.String {
|
||||
_ = staticdata.StringSym(n.Pos(), constant.StringVal(v))
|
||||
}
|
||||
_ = staticdata.StringSym(n.Pos(), constant.StringVal(n.Val()))
|
||||
}
|
||||
|
||||
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())
|
||||
panic("unreachable")
|
||||
|
||||
case ir.ONONAME, ir.OGETG, ir.ONEWOBJ, ir.OMETHEXPR:
|
||||
case ir.ONONAME, ir.OGETG, ir.ONEWOBJ:
|
||||
return n
|
||||
|
||||
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.
|
||||
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:
|
||||
n := n.(*ir.UnaryExpr)
|
||||
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
|
||||
if ir.IsAssignable(n) {
|
||||
if ir.IsAddressable(n) {
|
||||
base.Fatalf("missing lvalue case in safeexpr: %v", n)
|
||||
}
|
||||
return cheapExpr(n, init)
|
||||
@ -535,22 +522,28 @@ func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
|
||||
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
|
||||
params := n.X.Type().Params()
|
||||
|
||||
n.X = walkExpr(n.X, 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,
|
||||
// store that argument into a temporary variable,
|
||||
// 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 {
|
||||
updateHasCall(arg)
|
||||
// Determine param type.
|
||||
var t *types.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
|
||||
}
|
||||
t := params.Field(i).Type
|
||||
if base.Flag.Cfg.Instrumenting || fncall(arg, t) {
|
||||
// make assignment of fncall to tempAt
|
||||
tmp := typecheck.Temp(t)
|
||||
@ -786,21 +770,19 @@ func walkSlice(n *ir.SliceExpr, init *ir.Nodes) ir.Node {
|
||||
n.X = walkExpr(n.X, init)
|
||||
}
|
||||
|
||||
low, high, max := n.SliceBounds()
|
||||
low = walkExpr(low, init)
|
||||
if low != nil && ir.IsZero(low) {
|
||||
n.Low = walkExpr(n.Low, init)
|
||||
if n.Low != nil && ir.IsZero(n.Low) {
|
||||
// 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)
|
||||
max = walkExpr(max, init)
|
||||
n.SetSliceBounds(low, high, max)
|
||||
n.High = walkExpr(n.High, init)
|
||||
n.Max = walkExpr(n.Max, init)
|
||||
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 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].
|
||||
if n.Op() == ir.OSLICE3 {
|
||||
n.SetOp(ir.OSLICE)
|
||||
@ -817,20 +799,18 @@ func walkSlice(n *ir.SliceExpr, init *ir.Nodes) ir.Node {
|
||||
// walkSliceHeader walks an OSLICEHEADER node.
|
||||
func walkSliceHeader(n *ir.SliceHeaderExpr, init *ir.Nodes) ir.Node {
|
||||
n.Ptr = walkExpr(n.Ptr, init)
|
||||
n.LenCap[0] = walkExpr(n.LenCap[0], init)
|
||||
n.LenCap[1] = walkExpr(n.LenCap[1], init)
|
||||
n.Len = walkExpr(n.Len, init)
|
||||
n.Cap = walkExpr(n.Cap, init)
|
||||
return n
|
||||
}
|
||||
|
||||
// TODO(josharian): combine this with its caller and simplify
|
||||
func reduceSlice(n *ir.SliceExpr) ir.Node {
|
||||
low, high, max := n.SliceBounds()
|
||||
if high != nil && high.Op() == ir.OLEN && ir.SameSafeExpr(n.X, high.(*ir.UnaryExpr).X) {
|
||||
if n.High != nil && n.High.Op() == ir.OLEN && ir.SameSafeExpr(n.X, n.High.(*ir.UnaryExpr).X) {
|
||||
// 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) && low == nil && high == nil {
|
||||
if (n.Op() == ir.OSLICE || n.Op() == ir.OSLICESTR) && n.Low == nil && n.High == nil {
|
||||
// Reduce x[:] to x.
|
||||
if base.Debug.Slice > 0 {
|
||||
base.Warn("slice: omit slice operation")
|
||||
@ -969,22 +949,13 @@ func usefield(n *ir.SelectorExpr) {
|
||||
case ir.ODOT, ir.ODOTPTR:
|
||||
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
|
||||
if field == nil {
|
||||
base.Fatalf("usefield %v %v without paramfld", n.X.Type(), n.Sel)
|
||||
}
|
||||
if field.Sym != n.Sel || field.Offset != n.Offset {
|
||||
base.Fatalf("field inconsistency: %v,%v != %v,%v", field.Sym, field.Offset, n.Sel, n.Offset)
|
||||
if field.Sym != n.Sel {
|
||||
base.Fatalf("field inconsistency: %v != %v", field.Sym, n.Sel)
|
||||
}
|
||||
if !strings.Contains(field.Note, "go:\"track\"") {
|
||||
return
|
||||
|
@ -235,7 +235,7 @@ func (o *orderState) safeExpr(n ir.Node) ir.Node {
|
||||
// because we emit explicit VARKILL instructions marking the end of those
|
||||
// temporaries' lifetimes.
|
||||
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.
|
||||
@ -843,12 +843,13 @@ func (o *orderState) stmt(n ir.Node) {
|
||||
n.X = o.expr(n.X, nil)
|
||||
|
||||
orderBody := true
|
||||
switch n.Type().Kind() {
|
||||
xt := typecheck.RangeExprType(n.X.Type())
|
||||
switch xt.Kind() {
|
||||
default:
|
||||
base.Fatalf("order.stmt range %v", n.Type())
|
||||
|
||||
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).
|
||||
// No need to copy it.
|
||||
break
|
||||
@ -885,9 +886,10 @@ func (o *orderState) stmt(n ir.Node) {
|
||||
|
||||
// n.Prealloc is the temp for the iterator.
|
||||
// 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 {
|
||||
orderBlock(&n.Body, o.free)
|
||||
}
|
||||
@ -912,7 +914,6 @@ func (o *orderState) stmt(n ir.Node) {
|
||||
n := n.(*ir.SelectStmt)
|
||||
t := o.markTemp()
|
||||
for _, ncas := range n.Cases {
|
||||
ncas := ncas.(*ir.CaseStmt)
|
||||
r := ncas.Comm
|
||||
ir.SetPos(ncas)
|
||||
|
||||
@ -994,7 +995,6 @@ func (o *orderState) stmt(n ir.Node) {
|
||||
// Also insert any ninit queued during the previous loop.
|
||||
// (The temporary cleaning must follow that ninit work.)
|
||||
for _, cas := range n.Cases {
|
||||
cas := cas.(*ir.CaseStmt)
|
||||
orderBlock(&cas.Body, o.free)
|
||||
cas.Body.Prepend(o.cleanTempNoPop(t)...)
|
||||
|
||||
@ -1034,13 +1034,12 @@ func (o *orderState) stmt(n ir.Node) {
|
||||
n := n.(*ir.SwitchStmt)
|
||||
if base.Debug.Libfuzzer != 0 && !hasDefaultCase(n) {
|
||||
// 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()
|
||||
n.Tag = o.expr(n.Tag, nil)
|
||||
for _, ncas := range n.Cases {
|
||||
ncas := ncas.(*ir.CaseStmt)
|
||||
o.exprListInPlace(ncas.List)
|
||||
orderBlock(&ncas.Body, o.free)
|
||||
}
|
||||
@ -1054,7 +1053,6 @@ func (o *orderState) stmt(n ir.Node) {
|
||||
|
||||
func hasDefaultCase(n *ir.SwitchStmt) bool {
|
||||
for _, ncas := range n.Cases {
|
||||
ncas := ncas.(*ir.CaseStmt)
|
||||
if len(ncas.List) == 0 {
|
||||
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:
|
||||
n := n.(*ir.SliceExpr)
|
||||
n.X = o.expr(n.X, nil)
|
||||
low, high, max := n.SliceBounds()
|
||||
low = o.expr(low, nil)
|
||||
low = o.cheapExpr(low)
|
||||
high = o.expr(high, nil)
|
||||
high = o.cheapExpr(high)
|
||||
max = o.expr(max, nil)
|
||||
max = o.cheapExpr(max)
|
||||
n.SetSliceBounds(low, high, max)
|
||||
n.Low = o.cheapExpr(o.expr(n.Low, nil))
|
||||
n.High = o.cheapExpr(o.expr(n.High, nil))
|
||||
n.Max = o.cheapExpr(o.expr(n.Max, nil))
|
||||
if lhs == nil || lhs.Op() != ir.ONAME && !ir.SameSafeExpr(lhs, n.X) {
|
||||
return o.copyExpr(n)
|
||||
}
|
||||
|
@ -56,20 +56,11 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
|
||||
// hb: hidden bool
|
||||
// a, v1, v2: not hidden aggregate, val 1, 2
|
||||
|
||||
t := nrange.Type()
|
||||
|
||||
a := nrange.X
|
||||
t := typecheck.RangeExprType(a.Type())
|
||||
lno := ir.SetPos(a)
|
||||
|
||||
var v1, v2 ir.Node
|
||||
l := len(nrange.Vars)
|
||||
if l > 0 {
|
||||
v1 = nrange.Vars[0]
|
||||
}
|
||||
|
||||
if l > 1 {
|
||||
v2 = nrange.Vars[1]
|
||||
}
|
||||
v1, v2 := nrange.Key, nrange.Value
|
||||
|
||||
if ir.IsBlank(v2) {
|
||||
v2 = nil
|
||||
@ -121,7 +112,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
|
||||
}
|
||||
|
||||
// for v1, v2 := range ha { body }
|
||||
if cheapComputableIndex(nrange.Type().Elem().Width) {
|
||||
if cheapComputableIndex(t.Elem().Width) {
|
||||
// v1, v2 = hv1, ha[hv1]
|
||||
tmp := ir.NewIndexExpr(base.Pos, ha, hv1)
|
||||
tmp.SetBounded(true)
|
||||
@ -150,7 +141,7 @@ func walkRange(nrange *ir.RangeStmt) ir.Node {
|
||||
ifGuard.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, hv1, hn)
|
||||
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.SetBounded(true)
|
||||
init = append(init, ir.NewAssignStmt(base.Pos, hp, typecheck.NodAddr(tmp)))
|
||||
@ -343,15 +334,12 @@ func isMapClear(n *ir.RangeStmt) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if n.Op() != ir.ORANGE || n.Type().Kind() != types.TMAP || len(n.Vars) != 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
k := n.Vars[0]
|
||||
if k == nil || ir.IsBlank(k) {
|
||||
t := n.X.Type()
|
||||
if n.Op() != ir.ORANGE || t.Kind() != types.TMAP || n.Key == nil || n.Value != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
k := n.Key
|
||||
// Require k to be a new variable name.
|
||||
if !ir.DeclaredBy(k, n) {
|
||||
return false
|
||||
@ -372,7 +360,7 @@ func isMapClear(n *ir.RangeStmt) bool {
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@ -428,7 +416,7 @@ func arrayClear(loop *ir.RangeStmt, v1, v2, a ir.Node) ir.Node {
|
||||
return nil
|
||||
}
|
||||
|
||||
elemsize := loop.Type().Elem().Width
|
||||
elemsize := typecheck.RangeExprType(loop.X.Type()).Elem().Width
|
||||
if elemsize <= 0 || !ir.IsZero(stmt.Y) {
|
||||
return nil
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ func walkSelect(sel *ir.SelectStmt) {
|
||||
sel.PtrInit().Set(nil)
|
||||
|
||||
init = append(init, walkSelectCases(sel.Cases)...)
|
||||
sel.Cases = ir.Nodes{}
|
||||
sel.Cases = nil
|
||||
|
||||
sel.Compiled.Set(init)
|
||||
walkStmtList(sel.Compiled)
|
||||
@ -29,7 +29,7 @@ func walkSelect(sel *ir.SelectStmt) {
|
||||
base.Pos = lno
|
||||
}
|
||||
|
||||
func walkSelectCases(cases ir.Nodes) []ir.Node {
|
||||
func walkSelectCases(cases []*ir.CommClause) []ir.Node {
|
||||
ncas := len(cases)
|
||||
sellineno := base.Pos
|
||||
|
||||
@ -40,7 +40,7 @@ func walkSelectCases(cases ir.Nodes) []ir.Node {
|
||||
|
||||
// optimization: one-case select: single op.
|
||||
if ncas == 1 {
|
||||
cas := cases[0].(*ir.CaseStmt)
|
||||
cas := cases[0]
|
||||
ir.SetPos(cas)
|
||||
l := cas.Init()
|
||||
if cas.Comm != nil { // not default:
|
||||
@ -73,9 +73,8 @@ func walkSelectCases(cases ir.Nodes) []ir.Node {
|
||||
|
||||
// convert case value arguments to addresses.
|
||||
// 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 {
|
||||
cas := cas.(*ir.CaseStmt)
|
||||
ir.SetPos(cas)
|
||||
n := cas.Comm
|
||||
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.
|
||||
if ncas == 2 && dflt != nil {
|
||||
cas := cases[0].(*ir.CaseStmt)
|
||||
cas := cases[0]
|
||||
if cas == dflt {
|
||||
cas = cases[1].(*ir.CaseStmt)
|
||||
cas = cases[1]
|
||||
}
|
||||
|
||||
n := cas.Comm
|
||||
@ -147,7 +146,7 @@ func walkSelectCases(cases ir.Nodes) []ir.Node {
|
||||
if dflt != nil {
|
||||
ncas--
|
||||
}
|
||||
casorder := make([]*ir.CaseStmt, ncas)
|
||||
casorder := make([]*ir.CommClause, ncas)
|
||||
nsends, nrecvs := 0, 0
|
||||
|
||||
var init []ir.Node
|
||||
@ -170,7 +169,6 @@ func walkSelectCases(cases ir.Nodes) []ir.Node {
|
||||
|
||||
// register cases
|
||||
for _, cas := range cases {
|
||||
cas := cas.(*ir.CaseStmt)
|
||||
ir.SetPos(cas)
|
||||
|
||||
init = append(init, cas.Init()...)
|
||||
@ -244,7 +242,7 @@ func walkSelectCases(cases ir.Nodes) []ir.Node {
|
||||
}
|
||||
|
||||
// dispatch cases
|
||||
dispatch := func(cond ir.Node, cas *ir.CaseStmt) {
|
||||
dispatch := func(cond ir.Node, cas *ir.CommClause) {
|
||||
cond = typecheck.Expr(cond)
|
||||
cond = typecheck.DefaultLit(cond, nil)
|
||||
|
||||
@ -287,9 +285,9 @@ var scase *types.Type
|
||||
// Keep in sync with src/runtime/select.go.
|
||||
func scasetype() *types.Type {
|
||||
if scase == nil {
|
||||
scase = typecheck.NewStructType([]*ir.Field{
|
||||
ir.NewField(base.Pos, typecheck.Lookup("c"), nil, types.Types[types.TUNSAFEPTR]),
|
||||
ir.NewField(base.Pos, typecheck.Lookup("elem"), nil, types.Types[types.TUNSAFEPTR]),
|
||||
scase = types.NewStruct(types.NoPkg, []*types.Field{
|
||||
types.NewField(base.Pos, typecheck.Lookup("c"), types.Types[types.TUNSAFEPTR]),
|
||||
types.NewField(base.Pos, typecheck.Lookup("elem"), types.Types[types.TUNSAFEPTR]),
|
||||
})
|
||||
scase.SetNoalg(true)
|
||||
}
|
||||
|
@ -71,7 +71,6 @@ func walkSwitchExpr(sw *ir.SwitchStmt) {
|
||||
var defaultGoto ir.Node
|
||||
var body ir.Nodes
|
||||
for _, ncase := range sw.Cases {
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
label := typecheck.AutoLabel(".s")
|
||||
jmp := ir.NewBranchStmt(ncase.Pos(), ir.OGOTO, label)
|
||||
|
||||
@ -96,7 +95,7 @@ func walkSwitchExpr(sw *ir.SwitchStmt) {
|
||||
body.Append(br)
|
||||
}
|
||||
}
|
||||
sw.Cases.Set(nil)
|
||||
sw.Cases = nil
|
||||
|
||||
if defaultGoto == nil {
|
||||
br := ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)
|
||||
@ -259,7 +258,6 @@ func allCaseExprsAreSideEffectFree(sw *ir.SwitchStmt) bool {
|
||||
// enough.
|
||||
|
||||
for _, ncase := range sw.Cases {
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
for _, v := range ncase.List {
|
||||
if v.Op() != ir.OLITERAL {
|
||||
return false
|
||||
@ -318,26 +316,14 @@ func walkSwitchType(sw *ir.SwitchStmt) {
|
||||
sw.Compiled.Append(ifNil)
|
||||
|
||||
// Load hash from type or itab.
|
||||
dotHash := ir.NewSelectorExpr(base.Pos, ir.ODOTPTR, itab, nil)
|
||||
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
|
||||
dotHash := typeHashFieldOf(base.Pos, itab)
|
||||
s.hashname = copyExpr(dotHash, dotHash.Type(), &sw.Compiled)
|
||||
|
||||
br := ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)
|
||||
var defaultGoto, nilGoto ir.Node
|
||||
var body ir.Nodes
|
||||
for _, ncase := range sw.Cases {
|
||||
ncase := ncase.(*ir.CaseStmt)
|
||||
var caseVar ir.Node
|
||||
if len(ncase.Vars) != 0 {
|
||||
caseVar = ncase.Vars[0]
|
||||
}
|
||||
caseVar := ncase.Var
|
||||
|
||||
// For single-type cases with an interface type,
|
||||
// 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(br)
|
||||
}
|
||||
sw.Cases.Set(nil)
|
||||
sw.Cases = nil
|
||||
|
||||
if defaultGoto == nil {
|
||||
defaultGoto = br
|
||||
@ -412,6 +398,32 @@ func walkSwitchType(sw *ir.SwitchStmt) {
|
||||
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.
|
||||
type typeSwitch struct {
|
||||
// Temporary variables (i.e., ONAMEs) used by type switch dispatch logic:
|
||||
|
@ -539,12 +539,30 @@ func calcHasCall(n ir.Node) bool {
|
||||
|
||||
// itabType loads the _type field from a runtime.itab struct.
|
||||
func itabType(itab ir.Node) ir.Node {
|
||||
typ := ir.NewSelectorExpr(base.Pos, ir.ODOTPTR, itab, nil)
|
||||
typ.SetType(types.NewPtr(types.Types[types.TUINT8]))
|
||||
typ.SetTypecheck(1)
|
||||
typ.Offset = int64(types.PtrSize) // offset of _type in runtime.itab
|
||||
typ.SetBounded(true) // guaranteed not to fault
|
||||
return typ
|
||||
if itabTypeField == nil {
|
||||
// runtime.itab's _type field
|
||||
itabTypeField = runtimeField("_type", int64(types.PtrSize), types.NewPtr(types.Types[types.TUINT8]))
|
||||
}
|
||||
return boundedDotPtr(base.Pos, itab, itabTypeField)
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -1192,6 +1192,7 @@
|
||||
// Require []Require
|
||||
// Exclude []Module
|
||||
// Replace []Replace
|
||||
// Retract []Retract
|
||||
// }
|
||||
//
|
||||
// type Require struct {
|
||||
|
@ -95,6 +95,7 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
|
||||
Require []Require
|
||||
Exclude []Module
|
||||
Replace []Replace
|
||||
Retract []Retract
|
||||
}
|
||||
|
||||
type Require struct {
|
||||
|
@ -28,6 +28,11 @@ import (
|
||||
//
|
||||
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.
|
||||
func capVersionSlice(s []module.Version) []module.Version {
|
||||
return s[:len(s):len(s)]
|
||||
@ -121,6 +126,12 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) error
|
||||
|
||||
if !inconsistent {
|
||||
buildList = final
|
||||
additionalExplicitRequirements = make([]string, 0, len(mustSelect))
|
||||
for _, m := range mustSelect {
|
||||
if m.Version != "none" {
|
||||
additionalExplicitRequirements = append(additionalExplicitRequirements, m.Path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -27,6 +28,7 @@ import (
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/mvs"
|
||||
"cmd/go/internal/search"
|
||||
"cmd/go/internal/str"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"golang.org/x/mod/module"
|
||||
@ -845,13 +847,15 @@ func AllowWriteGoMod() {
|
||||
// MinReqs returns a Reqs with minimal additional dependencies of Target,
|
||||
// as will be written to go.mod.
|
||||
func MinReqs() mvs.Reqs {
|
||||
var retain []string
|
||||
retain := append([]string{}, additionalExplicitRequirements...)
|
||||
for _, m := range buildList[1:] {
|
||||
_, explicit := index.require[m]
|
||||
if explicit || loaded.direct[m.Path] {
|
||||
retain = append(retain, m.Path)
|
||||
}
|
||||
}
|
||||
sort.Strings(retain)
|
||||
str.Uniq(&retain)
|
||||
min, err := mvs.Req(Target, retain, &mvsReqs{buildList: buildList})
|
||||
if err != nil {
|
||||
base.Fatalf("go: %v", err)
|
||||
|
@ -863,12 +863,21 @@ func loadFromRoots(params loaderParams) *loader {
|
||||
for _, pkg := range ld.pkgs {
|
||||
if pkg.mod == Target {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
base.ExitIfErrors()
|
||||
|
||||
// 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
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"cmd/go/internal/imports"
|
||||
"cmd/go/internal/modfetch"
|
||||
"cmd/go/internal/search"
|
||||
"cmd/go/internal/str"
|
||||
"cmd/go/internal/trace"
|
||||
|
||||
"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 {
|
||||
return semver.Compare(versions[i], versions[j]) < 0
|
||||
})
|
||||
uniq := versions[:1]
|
||||
for _, v := range versions {
|
||||
if v != uniq[len(uniq)-1] {
|
||||
uniq = append(uniq, v)
|
||||
}
|
||||
}
|
||||
return uniq, nil
|
||||
str.Uniq(&versions)
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
|
||||
|
@ -96,6 +96,20 @@ func Contains(x []string, s string) bool {
|
||||
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 {
|
||||
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
|
||||
}
|
||||
|
88
src/cmd/go/testdata/script/mod_get_promote_implicit.txt
vendored
Normal file
88
src/cmd/go/testdata/script/mod_get_promote_implicit.txt
vendored
Normal 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
|
@ -107,8 +107,8 @@ func TestDateParsing(t *testing.T) {
|
||||
time.Date(1997, 11, 20, 9, 55, 6, 0, time.FixedZone("", -6*60*60)),
|
||||
},
|
||||
{
|
||||
"Thu, 20 Nov 1997 09:55:06 MDT (MDT)",
|
||||
time.Date(1997, 11, 20, 9, 55, 6, 0, time.FixedZone("MDT", 0)),
|
||||
"Thu, 20 Nov 1997 09:55:06 GMT (GMT)",
|
||||
time.Date(1997, 11, 20, 9, 55, 6, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
"Fri, 21 Nov 1997 09:55:06 +1300 (TOT)",
|
||||
@ -278,8 +278,8 @@ func TestDateParsingCFWS(t *testing.T) {
|
||||
true,
|
||||
},
|
||||
{
|
||||
"Fri, 21 Nov 1997 09:55:06 MDT (MDT)",
|
||||
time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("MDT", 0)),
|
||||
"Fri, 21 Nov 1997 09:55:06 GMT (GMT)",
|
||||
time.Date(1997, 11, 21, 9, 55, 6, 0, time.UTC),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
42
src/os/signal/signal_linux_test.go
Normal file
42
src/os/signal/signal_linux_test.go
Normal 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)
|
||||
}
|
@ -12,7 +12,7 @@ static void *threadentry(void*);
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
// 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
|
||||
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
|
||||
|
@ -14,7 +14,7 @@ static void* threadentry(void*);
|
||||
static void (*setg_gcc)(void*);
|
||||
|
||||
// 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
|
||||
x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
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*);
|
||||
|
||||
void
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
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*);
|
||||
|
||||
void
|
||||
|
@ -1201,12 +1201,12 @@ type TimeHistogram timeHistogram
|
||||
|
||||
// Counts returns the counts for the given bucket, subBucket indices.
|
||||
// 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) {
|
||||
t := (*timeHistogram)(th)
|
||||
i := bucket*TimeHistNumSubBuckets + subBucket
|
||||
if i >= uint(len(t.counts)) {
|
||||
return t.overflow, false
|
||||
return t.underflow, false
|
||||
}
|
||||
return t.counts[i], true
|
||||
}
|
||||
|
@ -70,16 +70,14 @@ const (
|
||||
// atomically.
|
||||
type timeHistogram struct {
|
||||
counts [timeHistNumSuperBuckets * timeHistNumSubBuckets]uint64
|
||||
overflow uint64
|
||||
underflow uint64
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if duration < 0 {
|
||||
throw("timeHistogram encountered negative duration")
|
||||
atomic.Xadd64(&h.underflow, 1)
|
||||
return
|
||||
}
|
||||
// The index of the exponential bucket is just the index
|
||||
// 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
|
||||
if superBucket*timeHistNumSubBuckets >= uint(len(h.counts)) {
|
||||
// The bucket index we got is larger than what we support, so
|
||||
// add into the special overflow bucket.
|
||||
atomic.Xadd64(&h.overflow, 1)
|
||||
return
|
||||
}
|
||||
// include this count in the highest bucket, which extends to
|
||||
// infinity.
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
subBucket = uint(duration)
|
||||
}
|
||||
@ -128,7 +128,7 @@ func timeHistogramMetricsBuckets() []float64 {
|
||||
// index to combine it with the bucketMin.
|
||||
subBucketShift := uint(0)
|
||||
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,
|
||||
// we shift up by 1 with each subsequent bucket.
|
||||
subBucketShift = uint(i - 2)
|
||||
|
@ -5,6 +5,7 @@
|
||||
package runtime_test
|
||||
|
||||
import (
|
||||
"math"
|
||||
. "runtime"
|
||||
"testing"
|
||||
)
|
||||
@ -32,8 +33,8 @@ func TestTimeHistogram(t *testing.T) {
|
||||
h.Record(base + v)
|
||||
}
|
||||
}
|
||||
// Hit the overflow bucket.
|
||||
h.Record(int64(^uint64(0) >> 1))
|
||||
// Hit the underflow bucket.
|
||||
h.Record(int64(-1))
|
||||
|
||||
// Check to make sure there's exactly one count in each
|
||||
// bucket.
|
||||
@ -41,7 +42,7 @@ func TestTimeHistogram(t *testing.T) {
|
||||
for j := uint(0); j < TimeHistNumSubBuckets; j++ {
|
||||
c, ok := h.Count(i, j)
|
||||
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 {
|
||||
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)
|
||||
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 {
|
||||
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{}
|
||||
}
|
||||
|
@ -43,7 +43,18 @@ func initMetrics() {
|
||||
}
|
||||
sizeClassBuckets = make([]float64, _NumSizeClasses)
|
||||
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()
|
||||
metrics = map[string]metricData{
|
||||
@ -105,9 +116,9 @@ func initMetrics() {
|
||||
"/gc/pauses:seconds": {
|
||||
compute: func(_ *statAggregate, out *metricValue) {
|
||||
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 {
|
||||
hist.counts[i] = atomic.Load64(&memstats.gcPauseDist.counts[i])
|
||||
hist.counts[i+1] = atomic.Load64(&memstats.gcPauseDist.counts[i])
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -154,6 +154,12 @@ func TestReadMetricsConsistency(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
|
@ -101,8 +101,7 @@ func gcMarkRootPrepare() {
|
||||
// Gs may be created after this point, but it's okay that we
|
||||
// ignore them because they begin life without any roots, so
|
||||
// there's nothing to scan, and any roots they create during
|
||||
// the concurrent phase will be scanned during mark
|
||||
// termination.
|
||||
// the concurrent phase will be caught by the write barrier.
|
||||
work.nStackRoots = int(atomic.Loaduintptr(&allglen))
|
||||
|
||||
work.markrootNext = 0
|
||||
|
@ -72,7 +72,7 @@ func clearSignalHandlers() {
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func sigblock() {
|
||||
func sigblock(exiting bool) {
|
||||
}
|
||||
|
||||
// Called to initialize a new m (including the bootstrap m).
|
||||
|
@ -301,6 +301,24 @@ func getHugePageSize() uintptr {
|
||||
func osinit() {
|
||||
ncpu = getproccount()
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ func msigrestore(sigmask sigset) {
|
||||
func clearSignalHandlers() {
|
||||
}
|
||||
|
||||
func sigblock() {
|
||||
func sigblock(exiting bool) {
|
||||
}
|
||||
|
||||
// Called to initialize a new m (including the bootstrap m).
|
||||
|
@ -886,7 +886,7 @@ func clearSignalHandlers() {
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func sigblock() {
|
||||
func sigblock(exiting bool) {
|
||||
}
|
||||
|
||||
// Called to initialize a new m (including the bootstrap m).
|
||||
|
@ -1313,7 +1313,7 @@ func mexit(osStack bool) {
|
||||
throw("locked m0 woke up")
|
||||
}
|
||||
|
||||
sigblock()
|
||||
sigblock(true)
|
||||
unminit()
|
||||
|
||||
// Free the gsignal stack.
|
||||
@ -1515,6 +1515,7 @@ func syscall_runtime_doAllThreadsSyscall(fn func(bool) bool) {
|
||||
if netpollinited() {
|
||||
netpollBreak()
|
||||
}
|
||||
sigRecvPrepareForFixup()
|
||||
_g_ := getg()
|
||||
if raceenabled {
|
||||
// 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.
|
||||
var sigmask sigset
|
||||
sigsave(&sigmask)
|
||||
sigblock()
|
||||
sigblock(false)
|
||||
|
||||
// Lock extra list, take head, unlock popped list.
|
||||
// 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.
|
||||
// It's important not to try to handle a signal between those two steps.
|
||||
sigmask := mp.sigmask
|
||||
sigblock()
|
||||
sigblock(false)
|
||||
unminit()
|
||||
|
||||
mnext := lockextra(true)
|
||||
@ -3776,7 +3777,7 @@ func beforefork() {
|
||||
// group. See issue #18600.
|
||||
gp.m.locks++
|
||||
sigsave(&gp.m.sigmask)
|
||||
sigblock()
|
||||
sigblock(false)
|
||||
|
||||
// This function is called before fork in syscall package.
|
||||
// Code between fork and exec must not allocate memory nor even try to grow stack.
|
||||
|
@ -1042,15 +1042,26 @@ func msigrestore(sigmask sigset) {
|
||||
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
|
||||
// when a non-Go thread calls a Go function.
|
||||
// The OS-specific code is expected to define sigset_all.
|
||||
// when a non-Go thread calls a Go function. When a thread is exiting
|
||||
// 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
|
||||
// which may be called on a non-Go thread with no g available.
|
||||
//go:nosplit
|
||||
//go:nowritebarrierrec
|
||||
func sigblock() {
|
||||
func sigblock(exiting bool) {
|
||||
if exiting {
|
||||
sigprocmask(_SIG_SETMASK, &sigsetAllExiting, nil)
|
||||
return
|
||||
}
|
||||
sigprocmask(_SIG_SETMASK, &sigset_all, nil)
|
||||
}
|
||||
|
||||
|
@ -12,12 +12,16 @@
|
||||
// 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.
|
||||
// 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
|
||||
// new pending signals.
|
||||
// sigSending means that sig.mask *may* contain new pending signals,
|
||||
// signal_recv can't be blocked in this state.
|
||||
// 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.
|
||||
// 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
|
||||
@ -59,6 +63,7 @@ const (
|
||||
sigIdle = iota
|
||||
sigReceiving
|
||||
sigSending
|
||||
sigFixup
|
||||
)
|
||||
|
||||
// sigsend delivers a signal from sighandler to the internal signal delivery queue.
|
||||
@ -112,6 +117,9 @@ Send:
|
||||
notewakeup(&sig.note)
|
||||
break Send
|
||||
}
|
||||
case sigFixup:
|
||||
// nothing to do - we need to wait for sigIdle.
|
||||
osyield()
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,6 +127,19 @@ Send:
|
||||
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.
|
||||
// Must only be called from a single goroutine at a time.
|
||||
//go:linkname signal_recv os/signal.signal_recv
|
||||
@ -146,8 +167,17 @@ func signal_recv() uint32 {
|
||||
}
|
||||
notetsleepg(&sig.note, -1)
|
||||
noteclear(&sig.note)
|
||||
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:
|
||||
if atomic.Cas(&sig.state, sigSending, sigIdle) {
|
||||
break Receive
|
||||
|
@ -92,6 +92,13 @@ func sendNote(s *byte) bool {
|
||||
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.
|
||||
// Must only be called from a single goroutine at a time.
|
||||
//go:linkname signal_recv os/signal.signal_recv
|
||||
|
@ -597,6 +597,14 @@ func compareStatus(filter, expect string) error {
|
||||
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
|
||||
// that mirror to the 9 glibc syscalls with POSIX semantics. The test
|
||||
// here is considered authoritative and should compile and run
|
||||
@ -647,6 +655,11 @@ func TestSetuidEtc(t *testing.T) {
|
||||
}
|
||||
|
||||
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 {
|
||||
t.Errorf("[%d] %q failed: %v", i, v.call, err)
|
||||
continue
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@ package main
|
||||
|
||||
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 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) {
|
||||
return 1, 2
|
||||
|
@ -7,9 +7,9 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var a, b = 1 // ERROR "assignment mismatch: 2 variables but 1 values|wrong number of initializations|cannot initialize"
|
||||
_ = 1, 2 // ERROR "assignment mismatch: 1 variables 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"
|
||||
var a, b = 1 // ERROR "assignment mismatch: 2 variables but 1 value|wrong number of initializations|cannot initialize"
|
||||
_ = 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 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"
|
||||
_, _, _, _ = c, d, e, f
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ func main() {
|
||||
_ = f.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 .cannot refer to unexported field or method f1..\*Foo..unexported."
|
||||
f.unexported = 10 // 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 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 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."
|
||||
}
|
||||
|
@ -63,6 +63,7 @@ func _() {
|
||||
_ = f1() // ok
|
||||
_, _ = f2() // ok
|
||||
_ = 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"
|
||||
cap // ERROR "use of builtin cap not in function call|must be called"
|
||||
|
Loading…
x
Reference in New Issue
Block a user