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() {
|
||||
// []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
|
||||
|
|
|
|||
16
ssa/emit.go
16
ssa/emit.go
|
|
@ -218,15 +218,21 @@ 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 {
|
||||
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.
|
||||
c := &Convert{X: val}
|
||||
c.setType(typ)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
17
ssa/ssa.go
17
ssa/ssa.go
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue