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:
Alan Donovan 2014-01-13 16:45:46 -05:00
parent 29ac1365f4
commit f3eb05bcef
5 changed files with 33 additions and 47 deletions

View File

@ -14,10 +14,6 @@ func conv1() {
}
func conv2() {
// []byte/[]rune literal
print([]byte("foo")) // @pointsto "foo":[]byte
print([]rune("bar")) // @pointsto "bar":[]rune
// string -> []byte/[]rune conversion
s := "foo"
ba := []byte(s) // @line c2ba

View File

@ -218,13 +218,19 @@ func emitConv(f *Function, val Value, typ types.Type) Value {
return f.emit(mi)
}
// Conversion of a constant to a non-interface type results in
// 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.
// Conversion of a compile-time constant value?
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.

View File

@ -37,9 +37,7 @@ func constValue(c *ssa.Const) value {
return zero(c.Type()) // typed nil
}
// By destination type:
switch t := c.Type().Underlying().(type) {
case *types.Basic:
if t, ok := c.Type().Underlying().(*types.Basic); ok {
// TODO(adonovan): eliminate untyped constants from SSA form.
switch t.Kind() {
case types.Bool, types.UntypedBool:
@ -82,29 +80,6 @@ func constValue(c *ssa.Const) value {
return exact.StringVal(c.Value)
}
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
}
}
}

View File

@ -610,3 +610,17 @@ func init() {
_ = x
_ = 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)
}
}

View File

@ -95,7 +95,7 @@ type NamedConst struct {
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 {
// Name returns the name of this value, and determines how
// this Value appears when used as an operand of an
@ -232,7 +232,7 @@ type Instruction interface {
// or method.
//
// 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
// handle external functions specially.
//
@ -368,15 +368,10 @@ type Parameter struct {
// A Const represents the value of a constant expression.
//
// It may have a nil, boolean, string or numeric (integer, fraction or
// complex) value, or a []byte or []rune conversion of a string
// constant.
//
// 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".
// The underlying type of a constant may be any boolean, numeric, or
// string type. In addition, a Const may represent the nil value of
// any reference type: interface, map, channel, pointer, slice, or
// function---but not "untyped nil".
//
// All source-level constant expressions are represented by a Const
// of equal type and value.