go.tools/ssa: eliminate (non-nil) slice constants.
go/types no longer reports a constant value for a slice,
e.g. []byte("foo").
ssa.Const no longer support slice constants, only
bool/string/numeric and nil.
emitConv emits a Convert instruction for string->[]byte
conversions.
Added regression test for bug 6949.
R=gri
CC=golang-codereviews
https://golang.org/cl/50590043
This commit is contained in:
parent
29ac1365f4
commit
f3eb05bcef
|
|
@ -14,10 +14,6 @@ func conv1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func conv2() {
|
func conv2() {
|
||||||
// []byte/[]rune literal
|
|
||||||
print([]byte("foo")) // @pointsto "foo":[]byte
|
|
||||||
print([]rune("bar")) // @pointsto "bar":[]rune
|
|
||||||
|
|
||||||
// string -> []byte/[]rune conversion
|
// string -> []byte/[]rune conversion
|
||||||
s := "foo"
|
s := "foo"
|
||||||
ba := []byte(s) // @line c2ba
|
ba := []byte(s) // @line c2ba
|
||||||
|
|
|
||||||
18
ssa/emit.go
18
ssa/emit.go
|
|
@ -218,13 +218,19 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
|
||||||
return f.emit(mi)
|
return f.emit(mi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conversion of a constant to a non-interface type results in
|
// Conversion of a compile-time constant value?
|
||||||
// a new constant of the destination type and (initially) the
|
|
||||||
// same abstract value. We don't compute the representation
|
|
||||||
// change yet; this defers the point at which the number of
|
|
||||||
// possible representations explodes.
|
|
||||||
if c, ok := val.(*Const); ok {
|
if c, ok := val.(*Const); ok {
|
||||||
return NewConst(c.Value, typ)
|
if _, ok := ut_dst.(*types.Basic); ok || c.IsNil() {
|
||||||
|
// Conversion of a compile-time constant to
|
||||||
|
// another constant type results in a new
|
||||||
|
// constant of the destination type and
|
||||||
|
// (initially) the same abstract value.
|
||||||
|
// We don't truncate the value yet.
|
||||||
|
return NewConst(c.Value, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're converting from constant to non-constant type,
|
||||||
|
// e.g. string -> []byte/[]rune.
|
||||||
}
|
}
|
||||||
|
|
||||||
// A representation-changing conversion.
|
// A representation-changing conversion.
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,7 @@ func constValue(c *ssa.Const) value {
|
||||||
return zero(c.Type()) // typed nil
|
return zero(c.Type()) // typed nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// By destination type:
|
if t, ok := c.Type().Underlying().(*types.Basic); ok {
|
||||||
switch t := c.Type().Underlying().(type) {
|
|
||||||
case *types.Basic:
|
|
||||||
// TODO(adonovan): eliminate untyped constants from SSA form.
|
// TODO(adonovan): eliminate untyped constants from SSA form.
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case types.Bool, types.UntypedBool:
|
case types.Bool, types.UntypedBool:
|
||||||
|
|
@ -82,29 +80,6 @@ func constValue(c *ssa.Const) value {
|
||||||
return exact.StringVal(c.Value)
|
return exact.StringVal(c.Value)
|
||||||
}
|
}
|
||||||
return string(rune(c.Int64()))
|
return string(rune(c.Int64()))
|
||||||
case types.UnsafePointer:
|
|
||||||
panic("unsafe.Pointer constant") // not possible
|
|
||||||
case types.UntypedNil:
|
|
||||||
// nil was handled above.
|
|
||||||
}
|
|
||||||
|
|
||||||
case *types.Slice:
|
|
||||||
switch et := t.Elem().Underlying().(type) {
|
|
||||||
case *types.Basic:
|
|
||||||
switch et.Kind() {
|
|
||||||
case types.Byte: // string -> []byte
|
|
||||||
var v []value
|
|
||||||
for _, b := range []byte(exact.StringVal(c.Value)) {
|
|
||||||
v = append(v, b)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
case types.Rune: // string -> []rune
|
|
||||||
var v []value
|
|
||||||
for _, r := range []rune(exact.StringVal(c.Value)) {
|
|
||||||
v = append(v, r)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -610,3 +610,17 @@ func init() {
|
||||||
_ = x
|
_ = x
|
||||||
_ = y
|
_ = y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Regression test for issue 6949:
|
||||||
|
// []byte("foo") is not a constant since it allocates memory.
|
||||||
|
func init() {
|
||||||
|
var r string
|
||||||
|
for i, b := range "ABC" {
|
||||||
|
x := []byte("abc")
|
||||||
|
x[i] = byte(b)
|
||||||
|
r += string(x)
|
||||||
|
}
|
||||||
|
if r != "AbcaBcabC" {
|
||||||
|
panic(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
17
ssa/ssa.go
17
ssa/ssa.go
|
|
@ -95,7 +95,7 @@ type NamedConst struct {
|
||||||
pkg *Package
|
pkg *Package
|
||||||
}
|
}
|
||||||
|
|
||||||
// An SSA value that can be referenced by an instruction.
|
// A Value is an SSA value that can be referenced by an instruction.
|
||||||
type Value interface {
|
type Value interface {
|
||||||
// Name returns the name of this value, and determines how
|
// Name returns the name of this value, and determines how
|
||||||
// this Value appears when used as an operand of an
|
// this Value appears when used as an operand of an
|
||||||
|
|
@ -232,7 +232,7 @@ type Instruction interface {
|
||||||
// or method.
|
// or method.
|
||||||
//
|
//
|
||||||
// If Blocks is nil, this indicates an external function for which no
|
// If Blocks is nil, this indicates an external function for which no
|
||||||
// Go source code is available. In this case, Captures and Locals
|
// Go source code is available. In this case, FreeVars and Locals
|
||||||
// will be nil too. Clients performing whole-program analysis must
|
// will be nil too. Clients performing whole-program analysis must
|
||||||
// handle external functions specially.
|
// handle external functions specially.
|
||||||
//
|
//
|
||||||
|
|
@ -368,15 +368,10 @@ type Parameter struct {
|
||||||
|
|
||||||
// A Const represents the value of a constant expression.
|
// A Const represents the value of a constant expression.
|
||||||
//
|
//
|
||||||
// It may have a nil, boolean, string or numeric (integer, fraction or
|
// The underlying type of a constant may be any boolean, numeric, or
|
||||||
// complex) value, or a []byte or []rune conversion of a string
|
// string type. In addition, a Const may represent the nil value of
|
||||||
// constant.
|
// any reference type: interface, map, channel, pointer, slice, or
|
||||||
//
|
// function---but not "untyped nil".
|
||||||
// Consts may be of named types. A constant's underlying type can be
|
|
||||||
// a basic type, possibly one of the "untyped" types, or a slice type
|
|
||||||
// whose elements' underlying type is byte or rune. A nil constant can
|
|
||||||
// have any reference type: interface, map, channel, pointer, slice,
|
|
||||||
// or function---but not "untyped nil".
|
|
||||||
//
|
//
|
||||||
// All source-level constant expressions are represented by a Const
|
// All source-level constant expressions are represented by a Const
|
||||||
// of equal type and value.
|
// of equal type and value.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue