1
0
mirror of https://github.com/golang/go synced 2024-11-26 04:17:59 -07:00

[dev.regabi] cmd/compile: replace CTNIL with ONIL

Properly speaking, "nil" is a zero value, not a constant. So
go/constant does not have a representation for it. To allow replacing
Val with constant.Value, we split out ONIL separately from OLITERAL so
we can get rid of CTNIL.

Passes toolstash-check.

Change-Id: I4c8e60cae3b3c91bbac43b3b0cf2a4ade028d6cb
Reviewed-on: https://go-review.googlesource.com/c/go/+/272650
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Trust: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Matthew Dempsky 2020-11-13 20:38:21 -08:00
parent 4af2decf30
commit 88a9e2f9ad
18 changed files with 100 additions and 87 deletions

View File

@ -24,7 +24,6 @@ const (
CTCPLX
CTSTR
CTBOOL
CTNIL
)
type Val struct {
@ -34,7 +33,6 @@ type Val struct {
// *Mpflt float when Ctype() == CTFLT
// *Mpcplx pair of floats when Ctype() == CTCPLX
// string string when Ctype() == CTSTR
// *Nilval when Ctype() == CTNIL
U interface{}
}
@ -45,8 +43,6 @@ func (v Val) Ctype() Ctype {
panic("unreachable")
case nil:
return CTxxx
case *NilVal:
return CTNIL
case bool:
return CTBOOL
case *Mpint:
@ -71,8 +67,6 @@ func eqval(a, b Val) bool {
default:
Fatalf("unexpected Ctype for %T", a.U)
panic("unreachable")
case *NilVal:
return true
case bool:
y := b.U.(bool)
return x == y
@ -99,8 +93,6 @@ func (v Val) Interface() interface{} {
default:
Fatalf("unexpected Interface for %T", v.U)
panic("unreachable")
case *NilVal:
return nil
case bool, string:
return x
case *Mpint:
@ -112,8 +104,6 @@ func (v Val) Interface() interface{} {
}
}
type NilVal struct{}
// Int64Val returns n as an int64.
// n must be an integer or rune constant.
func (n *Node) Int64Val() int64 {
@ -245,7 +235,7 @@ func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Nod
return n
}
if n.Op == OLITERAL {
if n.Op == OLITERAL || n.Op == ONIL {
// Can't always set n.Type directly on OLITERAL nodes.
// See discussion on CL 20813.
n = n.rawcopy()
@ -253,6 +243,9 @@ func convlit1(n *Node, t *types.Type, explicit bool, context func() string) *Nod
// Nil is technically not a constant, so handle it specially.
if n.Type.Etype == TNIL {
if n.Op != ONIL {
Fatalf("unexpected op: %v (%v)", n, n.Op)
}
if t == nil {
yyerror("use of untyped nil")
n.SetDiag(true)
@ -1039,8 +1032,6 @@ func idealType(ct Ctype) *types.Type {
return types.UntypedFloat
case CTCPLX:
return types.UntypedComplex
case CTNIL:
return types.Types[TNIL]
}
Fatalf("unexpected Ctype: %v", ct)
return nil
@ -1189,7 +1180,7 @@ func indexconst(n *Node) int64 {
// Expressions derived from nil, like string([]byte(nil)), while they
// may be known at compile time, are not Go language constants.
func (n *Node) isGoConst() bool {
return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
return n.Op == OLITERAL
}
func hascallchan(n *Node) bool {

View File

@ -152,7 +152,7 @@ func mayAffectMemory(n *Node) bool {
// We're ignoring things like division by zero, index out of range,
// and nil pointer dereference here.
switch n.Op {
case ONAME, OCLOSUREVAR, OLITERAL:
case ONAME, OCLOSUREVAR, OLITERAL, ONIL:
return false
// Left+Right group.

View File

@ -476,7 +476,7 @@ func (e *Escape) exprSkipInit(k EscHole, n *Node) {
default:
Fatalf("unexpected expr: %v", n)
case OLITERAL, OGETG, OCLOSUREVAR, OTYPE:
case OLITERAL, ONIL, OGETG, OCLOSUREVAR, OTYPE:
// nop
case ONAME:

View File

@ -571,9 +571,6 @@ func (v Val) vconv(s fmt.State, flag FmtFlag) {
case bool:
fmt.Fprint(s, u)
case *NilVal:
fmt.Fprint(s, "nil")
default:
fmt.Fprintf(s, "<ctype=%d>", v.Ctype())
}
@ -1207,6 +1204,7 @@ var opprec = []int{
OMAPLIT: 8,
ONAME: 8,
ONEW: 8,
ONIL: 8,
ONONAME: 8,
OOFFSETOF: 8,
OPACK: 8,
@ -1323,6 +1321,9 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
case OPAREN:
mode.Fprintf(s, "(%v)", n.Left)
case ONIL:
fmt.Fprint(s, "nil")
case OLITERAL: // this is a bit of a mess
if mode == FErr {
if n.Orig != nil && n.Orig != n {
@ -1334,10 +1335,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
return
}
}
if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
n.Orig.exprfmt(s, prec, mode)
return
}
if n.Type != nil && !n.Type.IsUntyped() {
// Need parens when type begins with what might
// be misinterpreted as a unary operator: * or <-.

View File

@ -759,8 +759,6 @@ func constTypeOf(typ *types.Type) Ctype {
}
switch typ.Etype {
case TCHAN, TFUNC, TMAP, TNIL, TINTER, TPTR, TSLICE, TUNSAFEPTR:
return CTNIL
case TBOOL:
return CTBOOL
case TSTRING:
@ -790,9 +788,6 @@ func (w *exportWriter) value(typ *types.Type, v Val) {
// and provides a useful consistency check.
switch constTypeOf(typ) {
case CTNIL:
// Only one value; nothing to encode.
_ = v.U.(*NilVal)
case CTBOOL:
w.bool(v.U.(bool))
case CTSTR:
@ -1207,11 +1202,19 @@ func (w *exportWriter) expr(n *Node) {
switch op := n.Op; op {
// expressions
// (somewhat closely following the structure of exprfmt in fmt.go)
case OLITERAL:
if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
case ONIL:
if !n.Type.HasNil() {
Fatalf("unexpected type for nil: %v", n.Type)
}
if n.Orig != nil && n.Orig != n {
w.expr(n.Orig)
break
}
w.op(OLITERAL)
w.pos(n.Pos)
w.typ(n.Type)
case OLITERAL:
w.op(OLITERAL)
w.pos(n.Pos)
w.value(n.Type, n.Val())

View File

@ -293,7 +293,8 @@ func (r *importReader) doDecl(n *Node) {
importalias(r.p.ipkg, pos, n.Sym, typ)
case 'C':
typ, val := r.value()
typ := r.typ()
val := r.value(typ)
importconst(r.p.ipkg, pos, n.Sym, typ, val)
@ -354,12 +355,8 @@ func (r *importReader) doDecl(n *Node) {
}
}
func (p *importReader) value() (typ *types.Type, v Val) {
typ = p.typ()
func (p *importReader) value(typ *types.Type) (v Val) {
switch constTypeOf(typ) {
case CTNIL:
v.U = &NilVal{}
case CTBOOL:
v.U = p.bool()
case CTSTR:
@ -810,11 +807,20 @@ func (r *importReader) node() *Node {
// case OPAREN:
// unreachable - unpacked by exporter
// case ONIL:
// unreachable - mapped to OLITERAL
case OLITERAL:
pos := r.pos()
typ, val := r.value()
typ := r.typ()
n := npos(pos, nodlit(val))
var n *Node
if typ.HasNil() {
n = nodnil()
} else {
n = nodlit(r.value(typ))
}
n = npos(pos, n)
n.Type = typ
return n

View File

@ -459,7 +459,7 @@ func inlcopy(n *Node) *Node {
}
switch n.Op {
case ONAME, OTYPE, OLITERAL:
case ONAME, OTYPE, OLITERAL, ONIL:
return n
}
@ -1322,7 +1322,7 @@ func (subst *inlsubst) node(n *Node) *Node {
}
return n
case OLITERAL, OTYPE:
case OLITERAL, ONIL, OTYPE:
// If n is a named constant or type, we can continue
// using it in the inline copy. Otherwise, make a copy
// so we can update the line number.

View File

@ -591,12 +591,15 @@ func litsym(n, c *Node, wid int) {
if n.Op != ONAME {
Fatalf("litsym n op %v", n.Op)
}
if c.Op != OLITERAL {
Fatalf("litsym c op %v", c.Op)
}
if n.Sym == nil {
Fatalf("litsym nil n sym")
}
if c.Op == ONIL {
return
}
if c.Op != OLITERAL {
Fatalf("litsym c op %v", c.Op)
}
s := n.Sym.Linksym()
switch u := c.Val().U.(type) {
case bool:

View File

@ -119,7 +119,7 @@ func (o *Order) cheapExpr(n *Node) *Node {
}
switch n.Op {
case ONAME, OLITERAL:
case ONAME, OLITERAL, ONIL:
return n
case OLEN, OCAP:
l := o.cheapExpr(n.Left)
@ -143,7 +143,7 @@ func (o *Order) cheapExpr(n *Node) *Node {
// The intended use is to apply to x when rewriting x += y into x = x + y.
func (o *Order) safeExpr(n *Node) *Node {
switch n.Op {
case ONAME, OLITERAL:
case ONAME, OLITERAL, ONIL:
return n
case ODOT, OLEN, OCAP:
@ -202,7 +202,7 @@ func isaddrokay(n *Node) bool {
// The result of addrTemp MUST be assigned back to n, e.g.
// n.Left = o.addrTemp(n.Left)
func (o *Order) addrTemp(n *Node) *Node {
if consttype(n) != CTxxx {
if n.Op == OLITERAL || n.Op == ONIL {
// TODO: expand this to all static composite literal nodes?
n = defaultlit(n, nil)
dowidth(n.Type)

View File

@ -104,6 +104,9 @@ func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
s.append(nod(OAS, l, conv(r, l.Type)))
return true
case ONIL:
return true
case OLITERAL:
if isZero(r) {
return true
@ -139,7 +142,7 @@ func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
e := &p.E[i]
n.Xoffset = l.Xoffset + e.Xoffset
n.Type = e.Expr.Type
if e.Expr.Op == OLITERAL {
if e.Expr.Op == OLITERAL || e.Expr.Op == ONIL {
litsym(n, e.Expr, int(n.Type.Width))
continue
}
@ -171,6 +174,9 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
case ONAME:
return s.staticcopy(l, r)
case ONIL:
return true
case OLITERAL:
if isZero(r) {
return true
@ -232,7 +238,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
e := &p.E[i]
n.Xoffset = l.Xoffset + e.Xoffset
n.Type = e.Expr.Type
if e.Expr.Op == OLITERAL {
if e.Expr.Op == OLITERAL || e.Expr.Op == ONIL {
litsym(n, e.Expr, int(n.Type.Width))
continue
}
@ -269,13 +275,14 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
for val.Op == OCONVIFACE {
val = val.Left
}
if val.Type.IsInterface() {
// val is an interface type.
// If val is nil, we can statically initialize l;
// both words are zero and so there no work to do, so report success.
// If val is non-nil, we have no concrete type to record,
// and we won't be able to statically initialize its value, so report failure.
return Isconst(val, CTNIL)
return val.Op == ONIL
}
markTypeUsedInInterface(val.Type, l.Sym.Linksym())
@ -296,7 +303,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
// Emit data.
if isdirectiface(val.Type) {
if Isconst(val, CTNIL) {
if val.Op == ONIL {
// Nil is zero, nothing to do.
return true
}
@ -462,7 +469,7 @@ func isStaticCompositeLiteral(n *Node) bool {
}
}
return true
case OLITERAL:
case OLITERAL, ONIL:
return true
case OCONVIFACE:
// See staticassign's OCONVIFACE case for comments.
@ -471,9 +478,9 @@ func isStaticCompositeLiteral(n *Node) bool {
val = val.Left
}
if val.Type.IsInterface() {
return Isconst(val, CTNIL)
return val.Op == ONIL
}
if isdirectiface(val.Type) && Isconst(val, CTNIL) {
if isdirectiface(val.Type) && val.Op == ONIL {
return true
}
return isStaticCompositeLiteral(val)
@ -1105,13 +1112,14 @@ func (s *InitSchedule) addvalue(p *InitPlan, xoffset int64, n *Node) {
func isZero(n *Node) bool {
switch n.Op {
case ONIL:
return true
case OLITERAL:
switch u := n.Val().U.(type) {
default:
Dump("unexpected literal", n)
Fatalf("isZero")
case *NilVal:
return true
case string:
return u == ""
case bool:

View File

@ -1993,7 +1993,7 @@ func (s *state) ssaShiftOp(op Op, t *types.Type, u *types.Type) ssa.Op {
// expr converts the expression n to ssa, adds it to s and returns the ssa result.
func (s *state) expr(n *Node) *ssa.Value {
if !(n.Op == ONAME || n.Op == OLITERAL && n.Sym != nil) {
if hasUniquePos(n) {
// ONAMEs and named OLITERALs have the line number
// of the decl, not the use. See issue 14742.
s.pushLine(n.Pos)
@ -2029,6 +2029,16 @@ func (s *state) expr(n *Node) *ssa.Value {
case OCLOSUREVAR:
addr := s.addr(n)
return s.load(n.Type, addr)
case ONIL:
t := n.Type
switch {
case t.IsSlice():
return s.constSlice(t)
case t.IsInterface():
return s.constInterface(t)
default:
return s.constNil(t)
}
case OLITERAL:
switch u := n.Val().U.(type) {
case *Mpint:
@ -2053,16 +2063,6 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.entryNewValue0A(ssa.OpConstString, n.Type, u)
case bool:
return s.constBool(u)
case *NilVal:
t := n.Type
switch {
case t.IsSlice():
return s.constSlice(t)
case t.IsInterface():
return s.constInterface(t)
default:
return s.constNil(t)
}
case *Mpflt:
switch n.Type.Size() {
case 4:

View File

@ -41,7 +41,7 @@ func hasUniquePos(n *Node) bool {
switch n.Op {
case ONAME, OPACK:
return false
case OLITERAL, OTYPE:
case OLITERAL, ONIL, OTYPE:
if n.Sym != nil {
return false
}
@ -257,7 +257,9 @@ func nodintconst(v int64) *Node {
}
func nodnil() *Node {
return nodlit(Val{new(NilVal)})
n := nod(ONIL, nil, nil)
n.Type = types.Types[TNIL]
return n
}
func nodbool(b bool) *Node {
@ -298,7 +300,7 @@ func treecopy(n *Node, pos src.XPos) *Node {
// crashing (golang.org/issue/11361).
fallthrough
case ONAME, ONONAME, OLITERAL, OTYPE:
case ONAME, ONONAME, OLITERAL, ONIL, OTYPE:
return n
}
@ -308,7 +310,7 @@ func treecopy(n *Node, pos src.XPos) *Node {
func (n *Node) isNil() bool {
// Check n.Orig because constant propagation may produce typed nil constants,
// which don't exist in the Go spec.
return Isconst(n.Orig, CTNIL)
return n.Orig.Op == ONIL
}
func isptrto(t *types.Type, et types.EType) bool {
@ -807,7 +809,7 @@ func calcHasCall(n *Node) bool {
}
switch n.Op {
case OLITERAL, ONAME, OTYPE:
case OLITERAL, ONIL, ONAME, OTYPE:
if n.HasCall() {
Fatalf("OLITERAL/ONAME/OTYPE should never have calls: %+v", n)
}
@ -926,7 +928,7 @@ func safeexpr(n *Node, init *Nodes) *Node {
}
switch n.Op {
case ONAME, OLITERAL:
case ONAME, OLITERAL, ONIL:
return n
case ODOT, OLEN, OCAP:
@ -988,7 +990,7 @@ func copyexpr(n *Node, t *types.Type, init *Nodes) *Node {
// result may not be assignable.
func cheapexpr(n *Node, init *Nodes) *Node {
switch n.Op {
case ONAME, OLITERAL:
case ONAME, OLITERAL, ONIL:
return n
}

View File

@ -261,7 +261,7 @@ func walkExprSwitch(sw *Node) {
}
cond = walkexpr(cond, &sw.Ninit)
if cond.Op != OLITERAL {
if cond.Op != OLITERAL && cond.Op != ONIL {
cond = copyexpr(cond, cond.Type, &sw.Nbody)
}

View File

@ -294,7 +294,7 @@ func (n *Node) SetIota(x int64) {
// Extra care must be taken when mutating such a node.
func (n *Node) mayBeShared() bool {
switch n.Op {
case ONAME, OLITERAL, OTYPE:
case ONAME, OLITERAL, ONIL, OTYPE:
return true
}
return false

View File

@ -363,7 +363,7 @@ func typecheck1(n *Node, top int) (res *Node) {
n.Type = types.UntypedString
}
case ONONAME:
case ONIL, ONONAME:
ok |= ctxExpr
case ONAME:
@ -1590,7 +1590,7 @@ func typecheck1(n *Node, top int) (res *Node) {
n.Type = t
if !t.IsSlice() {
if Isconst(args.First(), CTNIL) {
if args.First().isNil() {
yyerror("first argument to append must be typed slice; have untyped nil")
n.Type = nil
return n
@ -3193,6 +3193,9 @@ func samesafeexpr(l *Node, r *Node) bool {
case OLITERAL:
return eqval(l.Val(), r.Val())
case ONIL:
return true
}
return false
@ -3596,7 +3599,7 @@ func typecheckdef(n *Node) {
}
if !e.isGoConst() {
if !e.Diag() {
if Isconst(e, CTNIL) {
if e.Op == ONIL {
yyerrorl(n.Pos, "const initializer cannot be nil")
} else {
yyerrorl(n.Pos, "const initializer %v is not a constant", e)

View File

@ -157,9 +157,7 @@ func lexinit() {
types.Types[TNIL] = types.New(TNIL)
s = builtinpkg.Lookup("nil")
var v Val
v.U = new(NilVal)
s.Def = asTypesNode(nodlit(v))
s.Def = asTypesNode(nodnil())
asNode(s.Def).Sym = s
asNode(s.Def).Name = new(Name)

View File

@ -465,7 +465,7 @@ opswitch:
case ONONAME, OEMPTY, OGETG, ONEWOBJ:
case OTYPE, ONAME, OLITERAL:
case OTYPE, ONAME, OLITERAL, ONIL:
// TODO(mdempsky): Just return n; see discussion on CL 38655.
// Perhaps refactor to use Node.mayBeShared for these instead.
// If these return early, make sure to still call
@ -2277,7 +2277,7 @@ func varexpr(n *Node) bool {
}
switch n.Op {
case OLITERAL:
case OLITERAL, ONIL:
return true
case ONAME:
@ -2332,7 +2332,7 @@ func vmatch2(l *Node, r *Node) bool {
case ONAME:
return l == r
case OLITERAL:
case OLITERAL, ONIL:
return false
}
@ -2373,7 +2373,7 @@ func vmatch1(l *Node, r *Node) bool {
return vmatch2(l, r)
case OLITERAL:
case OLITERAL, ONIL:
return false
}
@ -3190,7 +3190,7 @@ func eqfor(t *types.Type) (n *Node, needsize bool) {
// The result of walkcompare MUST be assigned back to n, e.g.
// n.Left = walkcompare(n.Left, init)
func walkcompare(n *Node, init *Nodes) *Node {
if n.Left.Type.IsInterface() && n.Right.Type.IsInterface() && n.Left.Op != OLITERAL && n.Right.Op != OLITERAL {
if n.Left.Type.IsInterface() && n.Right.Type.IsInterface() && n.Left.Op != ONIL && n.Right.Op != ONIL {
return walkcompareInterface(n, init)
}
@ -3788,6 +3788,7 @@ func candiscard(n *Node) bool {
OTYPE,
OPACK,
OLITERAL,
ONIL,
OADD,
OSUB,
OOR,

View File

@ -1265,7 +1265,7 @@ func (t *Type) IsPtrShaped() bool {
// HasNil reports whether the set of values determined by t includes nil.
func (t *Type) HasNil() bool {
switch t.Etype {
case TCHAN, TFUNC, TINTER, TMAP, TPTR, TSLICE, TUNSAFEPTR:
case TCHAN, TFUNC, TINTER, TMAP, TNIL, TPTR, TSLICE, TUNSAFEPTR:
return true
}
return false