[dev.regabi] cmd/compile: arrange for typecheck1 to end in switch

Ending typecheck1 in the switch makes it safe for each case
to do an appropriate type assertion. The main change is dropping
the computation of "ok" and using the syntax nodes themselves
to decide what's OK.

Passes buildall w/ toolstash -cmp.

Change-Id: I2a1873a51e3f1194d74bb87a6653cb9857a02a1b
Reviewed-on: https://go-review.googlesource.com/c/go/+/275444
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Russ Cox 2020-12-04 11:37:54 -05:00
parent dcc640e839
commit ef5964dd6b
6 changed files with 195 additions and 175 deletions

View File

@ -307,17 +307,91 @@ func typecheck(n ir.Node, top int) (res ir.Node) {
return n return n
} }
n.SetTypecheck(2)
typecheck_tcstack = append(typecheck_tcstack, n) typecheck_tcstack = append(typecheck_tcstack, n)
n = typecheck1(n, top)
n.SetTypecheck(2)
n = typecheck1(n, top)
n.SetTypecheck(1) n.SetTypecheck(1)
last := len(typecheck_tcstack) - 1 last := len(typecheck_tcstack) - 1
typecheck_tcstack[last] = nil typecheck_tcstack[last] = nil
typecheck_tcstack = typecheck_tcstack[:last] typecheck_tcstack = typecheck_tcstack[:last]
_, isExpr := n.(ir.Expr)
_, isStmt := n.(ir.Stmt)
isMulti := false
switch n.Op() {
case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH:
if t := n.Left().Type(); t != nil && t.Kind() == types.TFUNC {
nr := t.NumResults()
isMulti = nr > 1
if nr == 0 {
isExpr = false
}
}
case ir.OAPPEND:
// Must be used (and not BinaryExpr/UnaryExpr).
isStmt = false
case ir.OCLOSE, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.OVARKILL, ir.OVARLIVE:
// Must not be used.
isExpr = false
isStmt = true
case ir.OCOPY, ir.ORECOVER, ir.ORECV:
// Can be used or not.
isStmt = true
}
t := n.Type()
if t != nil && !t.IsFuncArgStruct() && n.Op() != ir.OTYPE {
switch t.Kind() {
case types.TFUNC, // might have TANY; wait until it's called
types.TANY, types.TFORW, types.TIDEAL, types.TNIL, types.TBLANK:
break
default:
checkwidth(t)
}
}
if t != nil {
n = evalConst(n)
t = n.Type()
}
// TODO(rsc): Lots of the complexity here is because typecheck can
// see OTYPE, ONAME, and OLITERAL nodes multiple times.
// Once we make the IR a proper tree, we should be able to simplify
// this code a bit, especially the final case.
switch {
case top&(ctxStmt|ctxExpr) == ctxExpr && !isExpr && n.Op() != ir.OTYPE && !isMulti:
if !n.Diag() {
base.Errorf("%v used as value", n)
n.SetDiag(true)
}
if t != nil {
n.SetType(nil)
}
case top&ctxType == 0 && n.Op() == ir.OTYPE && t != nil:
if !n.Type().Broke() {
base.Errorf("type %v is not an expression", n.Type())
}
n.SetType(nil)
case top&(ctxStmt|ctxExpr) == ctxStmt && !isStmt && t != nil:
if !n.Diag() {
base.Errorf("%v evaluated but not used", n)
n.SetDiag(true)
}
n.SetType(nil)
case top&(ctxType|ctxExpr) == ctxType && n.Op() != ir.OTYPE && n.Op() != ir.ONONAME && (t != nil || n.Op() == ir.ONAME):
base.Errorf("%v is not a type", n)
if t != nil {
n.SetType(nil)
}
}
base.Pos = lno base.Pos = lno
return n return n
} }
@ -335,8 +409,7 @@ func indexlit(n ir.Node) ir.Node {
return n return n
} }
// The result of typecheck1 MUST be assigned back to n, e.g. // typecheck1 should ONLY be called from typecheck.
// n.Left = typecheck1(n.Left, top)
func typecheck1(n ir.Node, top int) (res ir.Node) { func typecheck1(n ir.Node, top int) (res ir.Node) {
if enableTrace && base.Flag.LowerT { if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheck1", n)(&res) defer tracePrint("typecheck1", n)(&res)
@ -345,7 +418,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
switch n.Op() { switch n.Op() {
case ir.OLITERAL, ir.ONAME, ir.ONONAME, ir.OTYPE: case ir.OLITERAL, ir.ONAME, ir.ONONAME, ir.OTYPE:
if n.Sym() == nil { if n.Sym() == nil {
break return n
} }
if n.Op() == ir.ONAME && n.SubOp() != 0 && top&ctxCallee == 0 { if n.Op() == ir.ONAME && n.SubOp() != 0 && top&ctxCallee == 0 {
@ -361,34 +434,29 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
} }
ok := 0
switch n.Op() { switch n.Op() {
// until typecheck is complete, do nothing.
default: default:
ir.Dump("typecheck", n) ir.Dump("typecheck", n)
base.Fatalf("typecheck %v", n.Op()) base.Fatalf("typecheck %v", n.Op())
panic("unreachable")
// names // names
case ir.OLITERAL: case ir.OLITERAL:
ok |= ctxExpr
if n.Type() == nil && n.Val().Kind() == constant.String { if n.Type() == nil && n.Val().Kind() == constant.String {
base.Fatalf("string literal missing type") base.Fatalf("string literal missing type")
} }
return n
case ir.ONIL, ir.ONONAME: case ir.ONIL, ir.ONONAME:
ok |= ctxExpr return n
case ir.ONAME: case ir.ONAME:
if n.Name().Decldepth == 0 { if n.Name().Decldepth == 0 {
n.Name().Decldepth = decldepth n.Name().Decldepth = decldepth
} }
if n.SubOp() != 0 { if n.SubOp() != 0 {
ok |= ctxCallee return n
break
} }
if top&ctxAssign == 0 { if top&ctxAssign == 0 {
// not a write to the variable // not a write to the variable
if ir.IsBlank(n) { if ir.IsBlank(n) {
@ -396,11 +464,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n.SetType(nil) n.SetType(nil)
return n return n
} }
n.Name().SetUsed(true) n.Name().SetUsed(true)
} }
return n
ok |= ctxExpr
case ir.OPACK: case ir.OPACK:
base.Errorf("use of package %v without selector", n.Sym()) base.Errorf("use of package %v without selector", n.Sym())
@ -409,14 +475,12 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// types (ODEREF is with exprs) // types (ODEREF is with exprs)
case ir.OTYPE: case ir.OTYPE:
ok |= ctxType
if n.Type() == nil { if n.Type() == nil {
return n return n
} }
return n
case ir.OTSLICE: case ir.OTSLICE:
ok |= ctxType
n := n.(*ir.SliceType) n := n.(*ir.SliceType)
n.Elem = typecheck(n.Elem, ctxType) n.Elem = typecheck(n.Elem, ctxType)
if n.Elem.Type() == nil { if n.Elem.Type() == nil {
@ -425,9 +489,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
t := types.NewSlice(n.Elem.Type()) t := types.NewSlice(n.Elem.Type())
n.SetOTYPE(t) n.SetOTYPE(t)
checkwidth(t) checkwidth(t)
return n
case ir.OTARRAY: case ir.OTARRAY:
ok |= ctxType
n := n.(*ir.ArrayType) n := n.(*ir.ArrayType)
n.Elem = typecheck(n.Elem, ctxType) n.Elem = typecheck(n.Elem, ctxType)
if n.Elem.Type() == nil { if n.Elem.Type() == nil {
@ -469,9 +533,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
t := types.NewArray(n.Elem.Type(), bound) t := types.NewArray(n.Elem.Type(), bound)
n.SetOTYPE(t) n.SetOTYPE(t)
checkwidth(t) checkwidth(t)
return n
case ir.OTMAP: case ir.OTMAP:
ok |= ctxType
n := n.(*ir.MapType) n := n.(*ir.MapType)
n.Key = typecheck(n.Key, ctxType) n.Key = typecheck(n.Key, ctxType)
n.Elem = typecheck(n.Elem, ctxType) n.Elem = typecheck(n.Elem, ctxType)
@ -488,9 +552,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
n.SetOTYPE(types.NewMap(l.Type(), r.Type())) n.SetOTYPE(types.NewMap(l.Type(), r.Type()))
mapqueue = append(mapqueue, n) // check map keys when all types are settled mapqueue = append(mapqueue, n) // check map keys when all types are settled
return n
case ir.OTCHAN: case ir.OTCHAN:
ok |= ctxType
n := n.(*ir.ChanType) n := n.(*ir.ChanType)
n.Elem = typecheck(n.Elem, ctxType) n.Elem = typecheck(n.Elem, ctxType)
l := n.Elem l := n.Elem
@ -501,21 +565,22 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
base.Errorf("chan of incomplete (or unallocatable) type not allowed") base.Errorf("chan of incomplete (or unallocatable) type not allowed")
} }
n.SetOTYPE(types.NewChan(l.Type(), n.Dir)) n.SetOTYPE(types.NewChan(l.Type(), n.Dir))
return n
case ir.OTSTRUCT: case ir.OTSTRUCT:
ok |= ctxType
n := n.(*ir.StructType) n := n.(*ir.StructType)
n.SetOTYPE(tostruct(n.Fields)) n.SetOTYPE(tostruct(n.Fields))
return n
case ir.OTINTER: case ir.OTINTER:
ok |= ctxType
n := n.(*ir.InterfaceType) n := n.(*ir.InterfaceType)
n.SetOTYPE(tointerface(n.Methods)) n.SetOTYPE(tointerface(n.Methods))
return n
case ir.OTFUNC: case ir.OTFUNC:
ok |= ctxType
n := n.(*ir.FuncType) n := n.(*ir.FuncType)
n.SetOTYPE(functype(n.Recv, n.Params, n.Results)) n.SetOTYPE(functype(n.Recv, n.Params, n.Results))
return n
// type or expr // type or expr
case ir.ODEREF: case ir.ODEREF:
@ -528,11 +593,10 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
} }
if l.Op() == ir.OTYPE { if l.Op() == ir.OTYPE {
ok |= ctxType
n.SetOTYPE(types.NewPtr(l.Type())) n.SetOTYPE(types.NewPtr(l.Type()))
// Ensure l.Type gets dowidth'd for the backend. Issue 20174. // Ensure l.Type gets dowidth'd for the backend. Issue 20174.
checkwidth(l.Type()) checkwidth(l.Type())
break return n
} }
if !t.IsPtr() { if !t.IsPtr() {
@ -541,12 +605,12 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n.SetType(nil) n.SetType(nil)
return n return n
} }
base.Errorf("%v is not a type", l)
break return n
} }
ok |= ctxExpr
n.SetType(t.Elem()) n.SetType(t.Elem())
return n
// arithmetic exprs // arithmetic exprs
case ir.OASOP, case ir.OASOP,
@ -573,7 +637,6 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
var op ir.Op var op ir.Op
var r ir.Node var r ir.Node
if n.Op() == ir.OASOP { if n.Op() == ir.OASOP {
ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetRight(typecheck(n.Right(), ctxExpr)) n.SetRight(typecheck(n.Right(), ctxExpr))
l = n.Left() l = n.Left()
@ -591,7 +654,6 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// TODO(marvin): Fix Node.EType type union. // TODO(marvin): Fix Node.EType type union.
op = n.SubOp() op = n.SubOp()
} else { } else {
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetRight(typecheck(n.Right(), ctxExpr)) n.SetRight(typecheck(n.Right(), ctxExpr))
l = n.Left() l = n.Left()
@ -629,8 +691,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
if (l.Type() == types.UntypedFloat || l.Type() == types.UntypedComplex) && r.Op() == ir.OLITERAL { if (l.Type() == types.UntypedFloat || l.Type() == types.UntypedComplex) && r.Op() == ir.OLITERAL {
n.SetType(types.UntypedInt) n.SetType(types.UntypedInt)
} }
return n
break
} }
// For "x == x && len(s)", it's better to report that "len(s)" (type int) // For "x == x && len(s)", it's better to report that "len(s)" (type int)
@ -815,9 +876,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
n.SetType(t) n.SetType(t)
return n
case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS: case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
l := n.Left() l := n.Left()
t := l.Type() t := l.Type()
@ -832,11 +893,10 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
n.SetType(t) n.SetType(t)
return n
// exprs // exprs
case ir.OADDR: case ir.OADDR:
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
if n.Left().Type() == nil { if n.Left().Type() == nil {
n.SetType(nil) n.SetType(nil)
@ -871,13 +931,10 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
n.SetType(types.NewPtr(n.Left().Type())) n.SetType(types.NewPtr(n.Left().Type()))
return n
case ir.OCOMPLIT: case ir.OCOMPLIT:
ok |= ctxExpr return typecheckcomplit(n)
n = typecheckcomplit(n)
if n.Type() == nil {
return n
}
case ir.OXDOT, ir.ODOT: case ir.OXDOT, ir.ODOT:
if n.Op() == ir.OXDOT { if n.Op() == ir.OXDOT {
@ -903,12 +960,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
s := n.Sym() s := n.Sym()
if n.Left().Op() == ir.OTYPE { if n.Left().Op() == ir.OTYPE {
n = typecheckMethodExpr(n) return typecheckMethodExpr(n)
if n.Type() == nil {
return n
}
ok = ctxExpr
break
} }
if t.IsPtr() && !t.Elem().IsInterface() { if t.IsPtr() && !t.Elem().IsInterface() {
@ -952,21 +1004,12 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
} }
switch n.Op() { if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
case ir.ODOTINTER, ir.ODOTMETH: n = typecheckpartialcall(n, s)
if top&ctxCallee != 0 {
ok |= ctxCallee
} else {
n = typecheckpartialcall(n, s)
ok |= ctxExpr
}
default:
ok |= ctxExpr
} }
return n
case ir.ODOTTYPE: case ir.ODOTTYPE:
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
l := n.Left() l := n.Left()
@ -1009,9 +1052,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
} }
} }
return n
case ir.OINDEX: case ir.OINDEX:
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
n.SetLeft(implicitstar(n.Left())) n.SetLeft(implicitstar(n.Left()))
@ -1045,7 +1088,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
if n.Right().Type() != nil && !n.Right().Type().IsInteger() { if n.Right().Type() != nil && !n.Right().Type().IsInteger() {
base.Errorf("non-integer %s index %v", why, n.Right()) base.Errorf("non-integer %s index %v", why, n.Right())
break return n
} }
if !n.Bounded() && ir.IsConst(n.Right(), constant.Int) { if !n.Bounded() && ir.IsConst(n.Right(), constant.Int) {
@ -1067,9 +1110,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n.SetOp(ir.OINDEXMAP) n.SetOp(ir.OINDEXMAP)
n.SetIndexMapLValue(false) n.SetIndexMapLValue(false)
} }
return n
case ir.ORECV: case ir.ORECV:
ok |= ctxStmt | ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
l := n.Left() l := n.Left()
@ -1091,9 +1134,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
n.SetType(t.Elem()) n.SetType(t.Elem())
return n
case ir.OSEND: case ir.OSEND:
ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetRight(typecheck(n.Right(), ctxExpr)) n.SetRight(typecheck(n.Right(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
@ -1115,14 +1158,13 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
if n.Right().Type() == nil { if n.Right().Type() == nil {
return n return n
} }
return n
case ir.OSLICEHEADER: case ir.OSLICEHEADER:
// Errors here are Fatalf instead of Errorf because only the compiler // Errors here are Fatalf instead of Errorf because only the compiler
// can construct an OSLICEHEADER node. // can construct an OSLICEHEADER node.
// Components used in OSLICEHEADER that are supplied by parsed source code // Components used in OSLICEHEADER that are supplied by parsed source code
// have already been typechecked in e.g. OMAKESLICE earlier. // have already been typechecked in e.g. OMAKESLICE earlier.
ok |= ctxExpr
t := n.Type() t := n.Type()
if t == nil { if t == nil {
base.Fatalf("no type specified for OSLICEHEADER") base.Fatalf("no type specified for OSLICEHEADER")
@ -1160,14 +1202,13 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n.List().SetFirst(l) n.List().SetFirst(l)
n.List().SetSecond(c) n.List().SetSecond(c)
return n
case ir.OMAKESLICECOPY: case ir.OMAKESLICECOPY:
// Errors here are Fatalf instead of Errorf because only the compiler // Errors here are Fatalf instead of Errorf because only the compiler
// can construct an OMAKESLICECOPY node. // can construct an OMAKESLICECOPY node.
// Components used in OMAKESCLICECOPY that are supplied by parsed source code // Components used in OMAKESCLICECOPY that are supplied by parsed source code
// have already been typechecked in OMAKE and OCOPY earlier. // have already been typechecked in OMAKE and OCOPY earlier.
ok |= ctxExpr
t := n.Type() t := n.Type()
if t == nil { if t == nil {
@ -1203,9 +1244,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
base.Fatalf("len for OMAKESLICECOPY must be non-negative") base.Fatalf("len for OMAKESLICECOPY must be non-negative")
} }
} }
return n
case ir.OSLICE, ir.OSLICE3: case ir.OSLICE, ir.OSLICE3:
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
low, high, max := n.SliceBounds() low, high, max := n.SliceBounds()
hasmax := n.Op().IsSlice3() hasmax := n.Op().IsSlice3()
@ -1277,6 +1318,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n.SetType(nil) n.SetType(nil)
return n return n
} }
return n
// call and call like // call and call like
case ir.OCALL: case ir.OCALL:
@ -1306,6 +1348,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER: case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
n.SetOp(l.SubOp()) n.SetOp(l.SubOp())
n.SetLeft(nil) n.SetLeft(nil)
n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL: case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
typecheckargs(n) typecheckargs(n)
@ -1331,8 +1374,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n = ir.NodAt(n.Pos(), l.SubOp(), arg1, arg2) n = ir.NodAt(n.Pos(), l.SubOp(), arg1, arg2)
n = initExpr(old.Init().Slice(), n) // typecheckargs can add to old.Init n = initExpr(old.Init().Slice(), n) // typecheckargs can add to old.Init
} }
n = typecheck1(n, top) return typecheck(n, top)
return n
} }
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
@ -1346,8 +1388,6 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
// pick off before type-checking arguments // pick off before type-checking arguments
ok |= ctxExpr
arg, ok := needOneArg(n, "conversion to %v", l.Type()) arg, ok := needOneArg(n, "conversion to %v", l.Type())
if !ok { if !ok {
n.SetType(nil) n.SetType(nil)
@ -1356,8 +1396,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n = ir.NodAt(n.Pos(), ir.OCONV, arg, nil) n = ir.NodAt(n.Pos(), ir.OCONV, arg, nil)
n.SetType(l.Type()) n.SetType(l.Type())
n = typecheck1(n, top) return typecheck1(n, top)
return n
} }
typecheckargs(n) typecheckargs(n)
@ -1403,11 +1442,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
typecheckaste(ir.OCALL, n.Left(), n.IsDDD(), t.Params(), n.List(), func() string { return fmt.Sprintf("argument to %v", n.Left()) }) typecheckaste(ir.OCALL, n.Left(), n.IsDDD(), t.Params(), n.List(), func() string { return fmt.Sprintf("argument to %v", n.Left()) })
ok |= ctxStmt
if t.NumResults() == 0 { if t.NumResults() == 0 {
break return n
} }
ok |= ctxExpr
if t.NumResults() == 1 { if t.NumResults() == 1 {
n.SetType(l.Type().Results().Field(0).Type) n.SetType(l.Type().Results().Field(0).Type)
@ -1420,24 +1457,23 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// and we want to avoid the temporaries, so we do the rewrite earlier than is typical. // and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
n.SetOp(ir.OGETG) n.SetOp(ir.OGETG)
} }
return n
break
} }
// multiple return // multiple return
if top&(ctxMultiOK|ctxStmt) == 0 { if top&(ctxMultiOK|ctxStmt) == 0 {
base.Errorf("multiple-value %v() in single-value context", l) base.Errorf("multiple-value %v() in single-value context", l)
break return n
} }
n.SetType(l.Type().Results()) n.SetType(l.Type().Results())
return n
case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF: case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
ok |= ctxExpr
n.SetType(types.Types[types.TUINTPTR]) n.SetType(types.Types[types.TUINTPTR])
return n
case ir.OCAP, ir.OLEN: case ir.OCAP, ir.OLEN:
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
n.SetLeft(implicitstar(n.Left())) n.SetLeft(implicitstar(n.Left()))
@ -1461,9 +1497,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
n.SetType(types.Types[types.TINT]) n.SetType(types.Types[types.TINT])
return n
case ir.OREAL, ir.OIMAG: case ir.OREAL, ir.OIMAG:
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
l := n.Left() l := n.Left()
t := l.Type() t := l.Type()
@ -1485,9 +1521,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n.SetType(nil) n.SetType(nil)
return n return n
} }
return n
case ir.OCOMPLEX: case ir.OCOMPLEX:
ok |= ctxExpr
l := typecheck(n.Left(), ctxExpr) l := typecheck(n.Left(), ctxExpr)
r := typecheck(n.Right(), ctxExpr) r := typecheck(n.Right(), ctxExpr)
if l.Type() == nil || r.Type() == nil { if l.Type() == nil || r.Type() == nil {
@ -1525,6 +1561,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
t = types.Types[types.TCOMPLEX128] t = types.Types[types.TCOMPLEX128]
} }
n.SetType(t) n.SetType(t)
return n
case ir.OCLOSE: case ir.OCLOSE:
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
@ -1546,11 +1583,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n.SetType(nil) n.SetType(nil)
return n return n
} }
return n
ok |= ctxStmt
case ir.ODELETE: case ir.ODELETE:
ok |= ctxStmt
typecheckargs(n) typecheckargs(n)
args := n.List() args := n.List()
if args.Len() == 0 { if args.Len() == 0 {
@ -1580,9 +1615,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
args.SetSecond(assignconv(r, l.Type().Key(), "delete")) args.SetSecond(assignconv(r, l.Type().Key(), "delete"))
return n
case ir.OAPPEND: case ir.OAPPEND:
ok |= ctxExpr
typecheckargs(n) typecheckargs(n)
args := n.List() args := n.List()
if args.Len() == 0 { if args.Len() == 0 {
@ -1625,11 +1660,11 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
if t.Elem().IsKind(types.TUINT8) && args.Second().Type().IsString() { if t.Elem().IsKind(types.TUINT8) && args.Second().Type().IsString() {
args.SetSecond(defaultlit(args.Second(), types.Types[types.TSTRING])) args.SetSecond(defaultlit(args.Second(), types.Types[types.TSTRING]))
break return n
} }
args.SetSecond(assignconv(args.Second(), t.Underlying(), "append")) args.SetSecond(assignconv(args.Second(), t.Underlying(), "append"))
break return n
} }
as := args.Slice()[1:] as := args.Slice()[1:]
@ -1640,9 +1675,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
as[i] = assignconv(n, t.Elem(), "append") as[i] = assignconv(n, t.Elem(), "append")
checkwidth(as[i].Type()) // ensure width is calculated for backend checkwidth(as[i].Type()) // ensure width is calculated for backend
} }
return n
case ir.OCOPY: case ir.OCOPY:
ok |= ctxStmt | ctxExpr
n.SetType(types.Types[types.TINT]) n.SetType(types.Types[types.TINT])
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
@ -1656,7 +1691,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// copy([]byte, string) // copy([]byte, string)
if n.Left().Type().IsSlice() && n.Right().Type().IsString() { if n.Left().Type().IsSlice() && n.Right().Type().IsString() {
if types.Identical(n.Left().Type().Elem(), types.ByteType) { if types.Identical(n.Left().Type().Elem(), types.ByteType) {
break return n
} }
base.Errorf("arguments to copy have different element types: %L and string", n.Left().Type()) base.Errorf("arguments to copy have different element types: %L and string", n.Left().Type())
n.SetType(nil) n.SetType(nil)
@ -1680,9 +1715,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
n.SetType(nil) n.SetType(nil)
return n return n
} }
return n
case ir.OCONV: case ir.OCONV:
ok |= ctxExpr
checkwidth(n.Type()) // ensure width is calculated for backend checkwidth(n.Type()) // ensure width is calculated for backend
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(convlit1(n.Left(), n.Type(), true, nil)) n.SetLeft(convlit1(n.Left(), n.Type(), true, nil))
@ -1717,16 +1752,16 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// do not convert to []byte literal. See CL 125796. // do not convert to []byte literal. See CL 125796.
// generated code and compiler memory footprint is better without it. // generated code and compiler memory footprint is better without it.
case ir.OSTR2BYTES: case ir.OSTR2BYTES:
break // ok
case ir.OSTR2RUNES: case ir.OSTR2RUNES:
if n.Left().Op() == ir.OLITERAL { if n.Left().Op() == ir.OLITERAL {
n = stringtoruneslit(n) n = stringtoruneslit(n)
} }
} }
return n
case ir.OMAKE: case ir.OMAKE:
ok |= ctxExpr
args := n.List().Slice() args := n.List().Slice()
if len(args) == 0 { if len(args) == 0 {
base.Errorf("missing argument to make") base.Errorf("missing argument to make")
@ -1832,9 +1867,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
nn.SetType(t) nn.SetType(t)
n = nn n = nn
return n
case ir.ONEW: case ir.ONEW:
ok |= ctxExpr
if n.Left() == nil { if n.Left() == nil {
// Fatalf because the OCALL above checked for us, // Fatalf because the OCALL above checked for us,
// so this must be an internally-generated mistake. // so this must be an internally-generated mistake.
@ -1849,9 +1884,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
n.SetLeft(l) n.SetLeft(l)
n.SetType(types.NewPtr(t)) n.SetType(types.NewPtr(t))
return n
case ir.OPRINT, ir.OPRINTN: case ir.OPRINT, ir.OPRINTN:
ok |= ctxStmt
typecheckargs(n) typecheckargs(n)
ls := n.List().Slice() ls := n.List().Slice()
for i1, n1 := range ls { for i1, n1 := range ls {
@ -1862,18 +1897,18 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
ls[i1] = defaultlit(ls[i1], nil) ls[i1] = defaultlit(ls[i1], nil)
} }
} }
return n
case ir.OPANIC: case ir.OPANIC:
ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), types.Types[types.TINTER])) n.SetLeft(defaultlit(n.Left(), types.Types[types.TINTER]))
if n.Left().Type() == nil { if n.Left().Type() == nil {
n.SetType(nil) n.SetType(nil)
return n return n
} }
return n
case ir.ORECOVER: case ir.ORECOVER:
ok |= ctxExpr | ctxStmt
if n.List().Len() != 0 { if n.List().Len() != 0 {
base.Errorf("too many arguments to recover") base.Errorf("too many arguments to recover")
n.SetType(nil) n.SetType(nil)
@ -1881,16 +1916,16 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
n.SetType(types.Types[types.TINTER]) n.SetType(types.Types[types.TINTER])
return n
case ir.OCLOSURE: case ir.OCLOSURE:
ok |= ctxExpr
typecheckclosure(n, top) typecheckclosure(n, top)
if n.Type() == nil { if n.Type() == nil {
return n return n
} }
return n
case ir.OITAB: case ir.OITAB:
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
t := n.Left().Type() t := n.Left().Type()
if t == nil { if t == nil {
@ -1901,14 +1936,15 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
base.Fatalf("OITAB of %v", t) base.Fatalf("OITAB of %v", t)
} }
n.SetType(types.NewPtr(types.Types[types.TUINTPTR])) n.SetType(types.NewPtr(types.Types[types.TUINTPTR]))
return n
case ir.OIDATA: case ir.OIDATA:
// Whoever creates the OIDATA node must know a priori the concrete type at that moment, // Whoever creates the OIDATA node must know a priori the concrete type at that moment,
// usually by just having checked the OITAB. // usually by just having checked the OITAB.
base.Fatalf("cannot typecheck interface data %v", n) base.Fatalf("cannot typecheck interface data %v", n)
panic("unreachable")
case ir.OSPTR: case ir.OSPTR:
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
t := n.Left().Type() t := n.Left().Type()
if t == nil { if t == nil {
@ -1923,33 +1959,33 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} else { } else {
n.SetType(types.NewPtr(t.Elem())) n.SetType(types.NewPtr(t.Elem()))
} }
return n
case ir.OCLOSUREREAD: case ir.OCLOSUREREAD:
ok |= ctxExpr return n
case ir.OCFUNC: case ir.OCFUNC:
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetType(types.Types[types.TUINTPTR]) n.SetType(types.Types[types.TUINTPTR])
return n
case ir.OCONVNOP: case ir.OCONVNOP:
ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
return n
// statements // statements
case ir.OAS: case ir.OAS:
ok |= ctxStmt
typecheckas(n) typecheckas(n)
// Code that creates temps does not bother to set defn, so do it here. // Code that creates temps does not bother to set defn, so do it here.
if n.Left().Op() == ir.ONAME && ir.IsAutoTmp(n.Left()) { if n.Left().Op() == ir.ONAME && ir.IsAutoTmp(n.Left()) {
n.Left().Name().Defn = n n.Left().Name().Defn = n
} }
return n
case ir.OAS2: case ir.OAS2:
ok |= ctxStmt
typecheckas2(n) typecheckas2(n)
return n
case ir.OBREAK, case ir.OBREAK,
ir.OCONTINUE, ir.OCONTINUE,
@ -1958,14 +1994,13 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
ir.OFALL, ir.OFALL,
ir.OVARKILL, ir.OVARKILL,
ir.OVARLIVE: ir.OVARLIVE:
ok |= ctxStmt return n
case ir.OBLOCK: case ir.OBLOCK:
ok |= ctxStmt
typecheckslice(n.List().Slice(), ctxStmt) typecheckslice(n.List().Slice(), ctxStmt)
return n
case ir.OLABEL: case ir.OLABEL:
ok |= ctxStmt
decldepth++ decldepth++
if n.Sym().IsBlank() { if n.Sym().IsBlank() {
// Empty identifier is valid but useless. // Empty identifier is valid but useless.
@ -1973,21 +2008,21 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// See issues 7538, 11589, 11593. // See issues 7538, 11589, 11593.
n = ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil) n = ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil)
} }
return n
case ir.ODEFER: case ir.ODEFER:
ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr))
if !n.Left().Diag() { if !n.Left().Diag() {
checkdefergo(n) checkdefergo(n)
} }
return n
case ir.OGO: case ir.OGO:
ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr))
checkdefergo(n) checkdefergo(n)
return n
case ir.OFOR, ir.OFORUNTIL: case ir.OFOR, ir.OFORUNTIL:
ok |= ctxStmt
typecheckslice(n.Init().Slice(), ctxStmt) typecheckslice(n.Init().Slice(), ctxStmt)
decldepth++ decldepth++
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
@ -2004,9 +2039,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
typecheckslice(n.Body().Slice(), ctxStmt) typecheckslice(n.Body().Slice(), ctxStmt)
decldepth-- decldepth--
return n
case ir.OIF: case ir.OIF:
ok |= ctxStmt
typecheckslice(n.Init().Slice(), ctxStmt) typecheckslice(n.Init().Slice(), ctxStmt)
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil)) n.SetLeft(defaultlit(n.Left(), nil))
@ -2018,9 +2053,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
typecheckslice(n.Body().Slice(), ctxStmt) typecheckslice(n.Body().Slice(), ctxStmt)
typecheckslice(n.Rlist().Slice(), ctxStmt) typecheckslice(n.Rlist().Slice(), ctxStmt)
return n
case ir.ORETURN: case ir.ORETURN:
ok |= ctxStmt
typecheckargs(n) typecheckargs(n)
if Curfn == nil { if Curfn == nil {
base.Errorf("return outside function") base.Errorf("return outside function")
@ -2029,24 +2064,25 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
} }
if hasNamedResults(Curfn) && n.List().Len() == 0 { if hasNamedResults(Curfn) && n.List().Len() == 0 {
break return n
} }
typecheckaste(ir.ORETURN, nil, false, Curfn.Type().Results(), n.List(), func() string { return "return argument" }) typecheckaste(ir.ORETURN, nil, false, Curfn.Type().Results(), n.List(), func() string { return "return argument" })
return n
case ir.ORETJMP: case ir.ORETJMP:
ok |= ctxStmt return n
case ir.OSELECT: case ir.OSELECT:
ok |= ctxStmt
typecheckselect(n) typecheckselect(n)
return n
case ir.OSWITCH: case ir.OSWITCH:
ok |= ctxStmt
typecheckswitch(n) typecheckswitch(n)
return n
case ir.ORANGE: case ir.ORANGE:
ok |= ctxStmt
typecheckrange(n) typecheckrange(n)
return n
case ir.OTYPESW: case ir.OTYPESW:
base.Errorf("use of .(type) outside type switch") base.Errorf("use of .(type) outside type switch")
@ -2054,64 +2090,22 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n return n
case ir.ODCLFUNC: case ir.ODCLFUNC:
ok |= ctxStmt
typecheckfunc(n.(*ir.Func)) typecheckfunc(n.(*ir.Func))
return n
case ir.ODCLCONST: case ir.ODCLCONST:
ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxExpr)) n.SetLeft(typecheck(n.Left(), ctxExpr))
return n
case ir.ODCLTYPE: case ir.ODCLTYPE:
ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxType)) n.SetLeft(typecheck(n.Left(), ctxType))
checkwidth(n.Left().Type()) checkwidth(n.Left().Type())
}
t := n.Type()
if t != nil && !t.IsFuncArgStruct() && n.Op() != ir.OTYPE {
switch t.Kind() {
case types.TFUNC, // might have TANY; wait until it's called
types.TANY, types.TFORW, types.TIDEAL, types.TNIL, types.TBLANK:
break
default:
checkwidth(t)
}
}
n = evalConst(n)
if n.Op() == ir.OTYPE && top&ctxType == 0 {
if !n.Type().Broke() {
base.Errorf("type %v is not an expression", n.Type())
}
n.SetType(nil)
return n return n
} }
if top&(ctxExpr|ctxType) == ctxType && n.Op() != ir.OTYPE { // No return n here!
base.Errorf("%v is not a type", n) // Individual cases can type-assert n, introducing a new one.
n.SetType(nil) // Each must execute its own return n.
return n
}
// TODO(rsc): simplify
if (top&(ctxCallee|ctxExpr|ctxType) != 0) && top&ctxStmt == 0 && ok&(ctxExpr|ctxType|ctxCallee) == 0 {
base.Errorf("%v used as value", n)
n.SetType(nil)
return n
}
if (top&ctxStmt != 0) && top&(ctxCallee|ctxExpr|ctxType) == 0 && ok&ctxStmt == 0 {
if !n.Diag() {
base.Errorf("%v evaluated but not used", n)
n.SetDiag(true)
}
n.SetType(nil)
return n
}
return n
} }
func typecheckargs(n ir.Node) { func typecheckargs(n ir.Node) {

View File

@ -32,7 +32,13 @@ func maybeEdit(x Node, edit func(Node) Node) Node {
return edit(x) return edit(x)
} }
// A miniStmt is a miniNode with extra fields common to expressions. // An Expr is a Node that can appear as an expression.
type Expr interface {
Node
isExpr()
}
// A miniExpr is a miniNode with extra fields common to expressions.
// TODO(rsc): Once we are sure about the contents, compact the bools // TODO(rsc): Once we are sure about the contents, compact the bools
// into a bit field and leave extra bits available for implementations // into a bit field and leave extra bits available for implementations
// embedding miniExpr. Right now there are ~60 unused bits sitting here. // embedding miniExpr. Right now there are ~60 unused bits sitting here.
@ -52,6 +58,8 @@ const (
miniExprBounded miniExprBounded
) )
func (*miniExpr) isExpr() {}
func (n *miniExpr) Type() *types.Type { return n.typ } func (n *miniExpr) Type() *types.Type { return n.typ }
func (n *miniExpr) SetType(x *types.Type) { n.typ = x } func (n *miniExpr) SetType(x *types.Type) { n.typ = x }
func (n *miniExpr) Opt() interface{} { return n.opt } func (n *miniExpr) Opt() interface{} { return n.opt }
@ -192,6 +200,8 @@ func NewCallExpr(pos src.XPos, fun Node, args []Node) *CallExpr {
return n return n
} }
func (*CallExpr) isStmt() {}
func (n *CallExpr) Orig() Node { return n.orig } func (n *CallExpr) Orig() Node { return n.orig }
func (n *CallExpr) SetOrig(x Node) { n.orig = x } func (n *CallExpr) SetOrig(x Node) { n.orig = x }
func (n *CallExpr) Left() Node { return n.X } func (n *CallExpr) Left() Node { return n.X }

View File

@ -114,6 +114,8 @@ func NewFunc(pos src.XPos) *Func {
return f return f
} }
func (f *Func) isStmt() {}
func (f *Func) Func() *Func { return f } func (f *Func) Func() *Func { return f }
func (f *Func) Body() Nodes { return f.body } func (f *Func) Body() Nodes { return f.body }
func (f *Func) PtrBody() *Nodes { return &f.body } func (f *Func) PtrBody() *Nodes { return &f.body }

View File

@ -121,6 +121,8 @@ type Name struct {
Outer *Name Outer *Name
} }
func (n *Name) isExpr() {}
// NewNameAt returns a new ONAME Node associated with symbol s at position pos. // NewNameAt returns a new ONAME Node associated with symbol s at position pos.
// The caller is responsible for setting Curfn. // The caller is responsible for setting Curfn.
func NewNameAt(pos src.XPos, sym *types.Sym) *Name { func NewNameAt(pos src.XPos, sym *types.Sym) *Name {

View File

@ -27,15 +27,26 @@ func NewDecl(pos src.XPos, op Op, x Node) *Decl {
return n return n
} }
func (*Decl) isStmt() {}
func (n *Decl) Left() Node { return n.X } func (n *Decl) Left() Node { return n.X }
func (n *Decl) SetLeft(x Node) { n.X = x } func (n *Decl) SetLeft(x Node) { n.X = x }
// A Stmt is a Node that can appear as a statement.
// This includes statement-like expressions such as <-c and f().
type Stmt interface {
Node
isStmt()
}
// A miniStmt is a miniNode with extra fields common to statements. // A miniStmt is a miniNode with extra fields common to statements.
type miniStmt struct { type miniStmt struct {
miniNode miniNode
init Nodes init Nodes
} }
func (*miniStmt) isStmt() {}
func (n *miniStmt) Init() Nodes { return n.init } func (n *miniStmt) Init() Nodes { return n.init }
func (n *miniStmt) SetInit(x Nodes) { n.init = x } func (n *miniStmt) SetInit(x Nodes) { n.init = x }
func (n *miniStmt) PtrInit() *Nodes { return &n.init } func (n *miniStmt) PtrInit() *Nodes { return &n.init }

View File

@ -10,7 +10,7 @@ import "unsafe"
const C = 1 const C = 1
var x1, x int var x, x1, x2 int
var b bool var b bool
var s string var s string
var c chan int var c chan int
@ -120,7 +120,6 @@ func _() {
_ = print(1) // ERROR "print\(1\) used as value" _ = print(1) // ERROR "print\(1\) used as value"
println(1) // ok println(1) // ok
_ = println(1) // ERROR "println\(1\) used as value" _ = println(1) // ERROR "println\(1\) used as value"
(x) // ERROR "x evaluated but not used"
c <- 1 // ok c <- 1 // ok
slice[1:1] // ERROR "slice\[1:1\] evaluated but not used" slice[1:1] // ERROR "slice\[1:1\] evaluated but not used"
array[1:1] // ERROR "array\[1:1\] evaluated but not used" array[1:1] // ERROR "array\[1:1\] evaluated but not used"
@ -137,6 +136,8 @@ func _() {
unsafe.Alignof(t.X) // ERROR "unsafe.Alignof\(t.X\) evaluated but not used" unsafe.Alignof(t.X) // ERROR "unsafe.Alignof\(t.X\) evaluated but not used"
unsafe.Offsetof(t.X) // ERROR "unsafe.Offsetof\(t.X\) evaluated but not used" unsafe.Offsetof(t.X) // ERROR "unsafe.Offsetof\(t.X\) evaluated but not used"
unsafe.Sizeof(t) // ERROR "unsafe.Sizeof\(t\) evaluated but not used" unsafe.Sizeof(t) // ERROR "unsafe.Sizeof\(t\) evaluated but not used"
_ = new(x) // ERROR "x is not a type"
_ = int // ERROR "type int is not an expression" _ = int // ERROR "type int is not an expression"
(x) // ERROR "x evaluated but not used"
_ = new(x2) // ERROR "x2 is not a type"
_ = new(1 + 1) // ERROR "1 \+ 1 is not a type"
} }