mirror of
https://github.com/golang/go
synced 2024-10-01 01:48:32 -06:00
go.tools/ssa: fix crash on (new)(T) due to missing unparen() call.
Audited codebase for other occurrences, found two more. Added test coverage for all of them. R=gri CC=golang-dev https://golang.org/cl/14698043
This commit is contained in:
parent
4a813e4058
commit
bac7098173
@ -457,7 +457,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
|
||||
// in an addressable location.
|
||||
//
|
||||
func (b *builder) exprInPlace(fn *Function, loc lvalue, e ast.Expr) {
|
||||
if e, ok := e.(*ast.CompositeLit); ok {
|
||||
if e, ok := unparen(e).(*ast.CompositeLit); ok {
|
||||
// A CompositeLit never evaluates to a pointer,
|
||||
// so if the type of the location is a pointer,
|
||||
// an &-operation is implied.
|
||||
@ -476,7 +476,9 @@ func (b *builder) exprInPlace(fn *Function, loc lvalue, e ast.Expr) {
|
||||
// Can't in-place initialize an interface value.
|
||||
// Fall back to copying.
|
||||
} else {
|
||||
b.compLit(fn, loc.address(fn), e, typ) // in place
|
||||
addr := loc.address(fn)
|
||||
b.compLit(fn, addr, e, typ) // in place
|
||||
emitDebugRef(fn, e, addr, true)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -551,7 +553,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
||||
return y
|
||||
}
|
||||
// Call to "intrinsic" built-ins, e.g. new, make, panic.
|
||||
if id, ok := e.Fun.(*ast.Ident); ok {
|
||||
if id, ok := unparen(e.Fun).(*ast.Ident); ok {
|
||||
if obj, ok := fn.Pkg.objectOf(id).(*types.Builtin); ok {
|
||||
if v := b.builtin(fn, obj, e.Args, typ, e.Lparen); v != nil {
|
||||
return v
|
||||
|
@ -45,6 +45,7 @@ func emitDebugRef(f *Function, e ast.Expr, v Value, isAddr bool) {
|
||||
panic("nil")
|
||||
}
|
||||
var obj types.Object
|
||||
e = unparen(e)
|
||||
if id, ok := e.(*ast.Ident); ok {
|
||||
if isBlankIdent(id) {
|
||||
return
|
||||
@ -57,7 +58,7 @@ func emitDebugRef(f *Function, e ast.Expr, v Value, isAddr bool) {
|
||||
}
|
||||
f.emit(&DebugRef{
|
||||
X: v,
|
||||
Expr: unparen(e),
|
||||
Expr: e,
|
||||
IsAddr: isAddr,
|
||||
object: obj,
|
||||
})
|
||||
|
7
ssa/interp/testdata/coverage.go
vendored
7
ssa/interp/testdata/coverage.go
vendored
@ -279,6 +279,13 @@ func main() {
|
||||
_ = map[int]*struct{}{0: {}}
|
||||
}
|
||||
|
||||
// Parens should not prevent intrinsic treatment of built-ins.
|
||||
// (Regression test for a crash.)
|
||||
func init() {
|
||||
_ = (new)(int)
|
||||
_ = (make)([]int, 0)
|
||||
}
|
||||
|
||||
type mybool bool
|
||||
|
||||
func (mybool) f() {}
|
||||
|
@ -99,7 +99,7 @@ type Value interface {
|
||||
// Instruction.
|
||||
//
|
||||
// This is the same as the source name for Parameters,
|
||||
// Builtins, Functions, Captures, Globals and some Allocs.
|
||||
// Builtins, Functions, Captures, Globals.
|
||||
// For constants, it is a representation of the constant's value
|
||||
// and type. For all other Values this is the name of the
|
||||
// virtual register defined by the instruction.
|
||||
@ -115,7 +115,7 @@ type Value interface {
|
||||
String() string
|
||||
|
||||
// Type returns the type of this value. Many instructions
|
||||
// (e.g. IndexAddr) change the behaviour depending on the
|
||||
// (e.g. IndexAddr) change their behaviour depending on the
|
||||
// types of their operands.
|
||||
Type() types.Type
|
||||
|
||||
@ -186,6 +186,7 @@ type Instruction interface {
|
||||
|
||||
// SetBlock sets the basic block to which this instruction
|
||||
// belongs.
|
||||
// TODO(adonovan): unexport this.
|
||||
SetBlock(*BasicBlock)
|
||||
|
||||
// Operands returns the operands of this instruction: the
|
||||
|
71
ssa/testdata/valueforexpr.go
vendored
71
ssa/testdata/valueforexpr.go
vendored
@ -33,12 +33,12 @@ func f(spilled, unspilled int) {
|
||||
_ = /*@Phi*/ (y)
|
||||
map1 := /*@MakeMap*/ (make(map[string]string))
|
||||
_ = map1
|
||||
_ = /*@MakeMap*/ (map[string]string{"": ""})
|
||||
_ = /*@MakeSlice*/ (make([]int, 0))
|
||||
_ = /*@MakeClosure*/ (func() { print(spilled) })
|
||||
sl := /*@Slice*/ ([]int{})
|
||||
_ = /*@Alloc*/ (&struct{}{})
|
||||
|
||||
sl := []int{}
|
||||
_ = /*@Slice*/ (sl[:0])
|
||||
|
||||
_ = /*@<nil>*/ (new(int)) // optimized away
|
||||
tmp := /*@Alloc*/ (new(int))
|
||||
_ = tmp
|
||||
@ -66,6 +66,71 @@ func f(spilled, unspilled int) {
|
||||
/*@UnOp*/ (n) = /*@UnOp*/ (**n)
|
||||
}
|
||||
|
||||
func complit() {
|
||||
// Composite literals.
|
||||
// We get different results for
|
||||
// - composite literal as value (e.g. operand to print)
|
||||
// - composite literal initializer for addressable value
|
||||
// - composite literal value assigned to blank var
|
||||
|
||||
// 1. Slices
|
||||
print( /*@Slice*/ ([]int{}))
|
||||
print( /*@Alloc*/ (&[]int{}))
|
||||
print(& /*@Alloc*/ ([]int{}))
|
||||
|
||||
sl1 := /*@Slice*/ ([]int{})
|
||||
sl2 := /*@Alloc*/ (&[]int{})
|
||||
sl3 := & /*@Alloc*/ ([]int{})
|
||||
_, _, _ = sl1, sl2, sl3
|
||||
|
||||
_ = /*@Slice*/ ([]int{})
|
||||
_ = /*@<nil>*/ (& /*@Slice*/ ([]int{})) // & optimized away
|
||||
_ = & /*@Slice*/ ([]int{})
|
||||
|
||||
// 2. Arrays
|
||||
print( /*@UnOp*/ ([1]int{}))
|
||||
print( /*@Alloc*/ (&[1]int{}))
|
||||
print(& /*@Alloc*/ ([1]int{}))
|
||||
|
||||
arr1 := /*@Alloc*/ ([1]int{})
|
||||
arr2 := /*@Alloc*/ (&[1]int{})
|
||||
arr3 := & /*@Alloc*/ ([1]int{})
|
||||
_, _, _ = arr1, arr2, arr3
|
||||
|
||||
_ = /*@UnOp*/ ([1]int{})
|
||||
_ = /*@Alloc*/ (& /*@Alloc*/ ([1]int{})) // & optimized away
|
||||
_ = & /*@Alloc*/ ([1]int{})
|
||||
|
||||
// 3. Maps
|
||||
type M map[int]int
|
||||
print( /*@MakeMap*/ (M{}))
|
||||
print( /*@Alloc*/ (&M{}))
|
||||
print(& /*@Alloc*/ (M{}))
|
||||
|
||||
m1 := /*@MakeMap*/ (M{})
|
||||
m2 := /*@Alloc*/ (&M{})
|
||||
m3 := & /*@Alloc*/ (M{})
|
||||
_, _, _ = m1, m2, m3
|
||||
|
||||
_ = /*@MakeMap*/ (M{})
|
||||
_ = /*@<nil>*/ (& /*@MakeMap*/ (M{})) // & optimized away
|
||||
_ = & /*@MakeMap*/ (M{})
|
||||
|
||||
// 4. Structs
|
||||
print( /*@UnOp*/ (struct{}{}))
|
||||
print( /*@Alloc*/ (&struct{}{}))
|
||||
print(& /*@Alloc*/ (struct{}{}))
|
||||
|
||||
s1 := /*@Alloc*/ (struct{}{})
|
||||
s2 := /*@Alloc*/ (&struct{}{})
|
||||
s3 := & /*@Alloc*/ (struct{}{})
|
||||
_, _, _ = s1, s2, s3
|
||||
|
||||
_ = /*@UnOp*/ (struct{}{})
|
||||
_ = /*@Alloc*/ (& /*@Alloc*/ (struct{}{}))
|
||||
_ = & /*@Alloc*/ (struct{}{})
|
||||
}
|
||||
|
||||
type t struct{ x int }
|
||||
|
||||
// Ensure we can locate methods of named types.
|
||||
|
Loading…
Reference in New Issue
Block a user