mirror of
https://github.com/golang/go
synced 2024-11-18 17:14:45 -07:00
go/ssa/interp: delete SSA bodies from standalone functions in "reflect"
...like we do for "runtime" functions, so that they fail informatively if executed. They all need intrinsics, but only some are yet defined. Also: - added test for issue 9462 - "BUG" in test output is now a failure in all tests (not just $GOROOT tests) - added intrinsic for reflect.SliceOf - show dynamic type of panic value Fixes issue 9462 Change-Id: I3a504c7faeed81e922fedc7dd59222717f3a7e95 Reviewed-on: https://go-review.googlesource.com/2145 Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
ca3901c3d8
commit
4b1d99f7f3
@ -80,6 +80,7 @@ func init() {
|
||||
"math.Min": ext۰math۰Min,
|
||||
"os.runtime_args": ext۰os۰runtime_args,
|
||||
"reflect.New": ext۰reflect۰New,
|
||||
"reflect.SliceOf": ext۰reflect۰SliceOf,
|
||||
"reflect.TypeOf": ext۰reflect۰TypeOf,
|
||||
"reflect.ValueOf": ext۰reflect۰ValueOf,
|
||||
"reflect.init": ext۰reflect۰Init,
|
||||
|
@ -631,6 +631,20 @@ func init() {
|
||||
environ = append(environ, "GOARCH="+runtime.GOARCH)
|
||||
}
|
||||
|
||||
// deleteBodies delete the bodies of all standalone functions except the
|
||||
// specified ones. A missing intrinsic leads to a clear runtime error.
|
||||
func deleteBodies(pkg *ssa.Package, except ...string) {
|
||||
keep := make(map[string]bool)
|
||||
for _, e := range except {
|
||||
keep[e] = true
|
||||
}
|
||||
for _, mem := range pkg.Members {
|
||||
if fn, ok := mem.(*ssa.Function); ok && !keep[fn.Name()] {
|
||||
fn.Blocks = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interpret interprets the Go program whose main package is mainpkg.
|
||||
// mode specifies various interpreter options. filename and args are
|
||||
// the initial values of os.Args for the target program. sizes is the
|
||||
@ -676,22 +690,13 @@ func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename stri
|
||||
case "syscall":
|
||||
setGlobal(i, pkg, "envs", environ)
|
||||
|
||||
case "reflect":
|
||||
deleteBodies(pkg, "DeepEqual", "deepValueEqual")
|
||||
|
||||
case "runtime":
|
||||
sz := sizes.Sizeof(pkg.Object.Scope().Lookup("MemStats").Type())
|
||||
setGlobal(i, pkg, "sizeof_C_MStats", uintptr(sz))
|
||||
|
||||
// Delete the bodies of almost all "runtime" functions since they're magic.
|
||||
// A missing intrinsic leads to a very clear error.
|
||||
for _, mem := range pkg.Members {
|
||||
if fn, ok := mem.(*ssa.Function); ok {
|
||||
switch fn.Name() {
|
||||
case "GOROOT", "gogetenv":
|
||||
// keep
|
||||
default:
|
||||
fn.Blocks = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
deleteBodies(pkg, "GOROOT", "gogetenv")
|
||||
}
|
||||
}
|
||||
|
||||
@ -712,7 +717,7 @@ func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename stri
|
||||
case string:
|
||||
fmt.Fprintln(os.Stderr, "panic:", p)
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "panic: unexpected type: %T\n", p)
|
||||
fmt.Fprintf(os.Stderr, "panic: unexpected type: %T: %v\n", p, p)
|
||||
}
|
||||
|
||||
// TODO(adonovan): dump panicking interpreter goroutine?
|
||||
|
@ -146,6 +146,7 @@ var testdataTests = []string{
|
||||
"mrvchain.go",
|
||||
"range.go",
|
||||
"recover.go",
|
||||
"reflect.go",
|
||||
"static.go",
|
||||
"callstack.go",
|
||||
}
|
||||
@ -276,11 +277,13 @@ func printFailures(failures []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// The "normal" success predicate.
|
||||
func exitsZero(exitcode int, _ string) error {
|
||||
func success(exitcode int, output string) error {
|
||||
if exitcode != 0 {
|
||||
return fmt.Errorf("exit code was %d", exitcode)
|
||||
}
|
||||
if strings.Contains(output, "BUG") {
|
||||
return fmt.Errorf("exited zero but output contained 'BUG'")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -288,7 +291,7 @@ func exitsZero(exitcode int, _ string) error {
|
||||
func TestTestdataFiles(t *testing.T) {
|
||||
var failures []string
|
||||
for _, input := range testdataTests {
|
||||
if !run(t, "testdata"+slash, input, exitsZero) {
|
||||
if !run(t, "testdata"+slash, input, success) {
|
||||
failures = append(failures, input)
|
||||
}
|
||||
}
|
||||
@ -303,16 +306,6 @@ func TestGorootTest(t *testing.T) {
|
||||
|
||||
var failures []string
|
||||
|
||||
// $GOROOT/tests are also considered a failure if they print "BUG".
|
||||
success := func(exitcode int, output string) error {
|
||||
if exitcode != 0 {
|
||||
return fmt.Errorf("exit code was %d", exitcode)
|
||||
}
|
||||
if strings.Contains(output, "BUG") {
|
||||
return fmt.Errorf("exited zero but output contained 'BUG'")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
for _, input := range gorootTestTests {
|
||||
if !run(t, filepath.Join(build.Default.GOROOT, "test")+slash, input, success) {
|
||||
failures = append(failures, input)
|
||||
|
@ -150,8 +150,13 @@ func ext۰reflect۰New(fr *frame, args []value) value {
|
||||
return makeReflectValue(types.NewPointer(t), &alloc)
|
||||
}
|
||||
|
||||
func ext۰reflect۰SliceOf(fr *frame, args []value) value {
|
||||
// Signature: func (t reflect.rtype) Type
|
||||
return makeReflectType(rtype{types.NewSlice(args[0].(iface).v.(rtype).t)})
|
||||
}
|
||||
|
||||
func ext۰reflect۰TypeOf(fr *frame, args []value) value {
|
||||
// Signature: func (t reflect.rtype) string
|
||||
// Signature: func (t reflect.rtype) Type
|
||||
return makeReflectType(rtype{args[0].(iface).t})
|
||||
}
|
||||
|
||||
|
11
go/ssa/interp/testdata/reflect.go
vendored
Normal file
11
go/ssa/interp/testdata/reflect.go
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "reflect"
|
||||
|
||||
func main() {
|
||||
// Regression test for issue 9462.
|
||||
got := reflect.SliceOf(reflect.TypeOf(byte(0))).String()
|
||||
if got != "[]uint8" && got != "[]byte" { // result varies by toolchain
|
||||
println("BUG: " + got)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user