1
0
mirror of https://github.com/golang/go synced 2024-11-18 19:54:44 -07: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:
Alan Donovan 2013-10-29 11:07:09 -04:00
parent 4a813e4058
commit bac7098173
5 changed files with 85 additions and 9 deletions

View File

@ -457,7 +457,7 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
// in an addressable location. // in an addressable location.
// //
func (b *builder) exprInPlace(fn *Function, loc lvalue, e ast.Expr) { 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, // A CompositeLit never evaluates to a pointer,
// so if the type of the location is a pointer, // so if the type of the location is a pointer,
// an &-operation is implied. // 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. // Can't in-place initialize an interface value.
// Fall back to copying. // Fall back to copying.
} else { } 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 return
} }
} }
@ -551,7 +553,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
return y return y
} }
// Call to "intrinsic" built-ins, e.g. new, make, panic. // 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 obj, ok := fn.Pkg.objectOf(id).(*types.Builtin); ok {
if v := b.builtin(fn, obj, e.Args, typ, e.Lparen); v != nil { if v := b.builtin(fn, obj, e.Args, typ, e.Lparen); v != nil {
return v return v

View File

@ -45,6 +45,7 @@ func emitDebugRef(f *Function, e ast.Expr, v Value, isAddr bool) {
panic("nil") panic("nil")
} }
var obj types.Object var obj types.Object
e = unparen(e)
if id, ok := e.(*ast.Ident); ok { if id, ok := e.(*ast.Ident); ok {
if isBlankIdent(id) { if isBlankIdent(id) {
return return
@ -57,7 +58,7 @@ func emitDebugRef(f *Function, e ast.Expr, v Value, isAddr bool) {
} }
f.emit(&DebugRef{ f.emit(&DebugRef{
X: v, X: v,
Expr: unparen(e), Expr: e,
IsAddr: isAddr, IsAddr: isAddr,
object: obj, object: obj,
}) })

View File

@ -279,6 +279,13 @@ func main() {
_ = map[int]*struct{}{0: {}} _ = 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 type mybool bool
func (mybool) f() {} func (mybool) f() {}

View File

@ -99,7 +99,7 @@ type Value interface {
// Instruction. // Instruction.
// //
// This is the same as the source name for Parameters, // 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 // For constants, it is a representation of the constant's value
// and type. For all other Values this is the name of the // and type. For all other Values this is the name of the
// virtual register defined by the instruction. // virtual register defined by the instruction.
@ -115,7 +115,7 @@ type Value interface {
String() string String() string
// Type returns the type of this value. Many instructions // 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. // types of their operands.
Type() types.Type Type() types.Type
@ -186,6 +186,7 @@ type Instruction interface {
// SetBlock sets the basic block to which this instruction // SetBlock sets the basic block to which this instruction
// belongs. // belongs.
// TODO(adonovan): unexport this.
SetBlock(*BasicBlock) SetBlock(*BasicBlock)
// Operands returns the operands of this instruction: the // Operands returns the operands of this instruction: the

View File

@ -33,12 +33,12 @@ func f(spilled, unspilled int) {
_ = /*@Phi*/ (y) _ = /*@Phi*/ (y)
map1 := /*@MakeMap*/ (make(map[string]string)) map1 := /*@MakeMap*/ (make(map[string]string))
_ = map1 _ = map1
_ = /*@MakeMap*/ (map[string]string{"": ""})
_ = /*@MakeSlice*/ (make([]int, 0)) _ = /*@MakeSlice*/ (make([]int, 0))
_ = /*@MakeClosure*/ (func() { print(spilled) }) _ = /*@MakeClosure*/ (func() { print(spilled) })
sl := /*@Slice*/ ([]int{})
_ = /*@Alloc*/ (&struct{}{}) sl := []int{}
_ = /*@Slice*/ (sl[:0]) _ = /*@Slice*/ (sl[:0])
_ = /*@<nil>*/ (new(int)) // optimized away _ = /*@<nil>*/ (new(int)) // optimized away
tmp := /*@Alloc*/ (new(int)) tmp := /*@Alloc*/ (new(int))
_ = tmp _ = tmp
@ -66,6 +66,71 @@ func f(spilled, unspilled int) {
/*@UnOp*/ (n) = /*@UnOp*/ (**n) /*@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 } type t struct{ x int }
// Ensure we can locate methods of named types. // Ensure we can locate methods of named types.