go.tools/go/types: fix unsafe.Pointer conversions

Make compliant with gc. Spec is not very clear.
Also: Fix error handling (don't destroy x before
using it in error message).

Fixes golang/go#6326.

R=adonovan
CC=golang-dev
https://golang.org/cl/13632043
This commit is contained in:
Robert Griesemer 2013-09-09 16:41:46 -07:00
parent 932a87ce16
commit 6688b01dc1
2 changed files with 21 additions and 10 deletions

View File

@ -11,12 +11,13 @@ import "code.google.com/p/go.tools/go/exact"
// Conversion type-checks the conversion T(x). // Conversion type-checks the conversion T(x).
// The result is in x. // The result is in x.
func (check *checker) conversion(x *operand, T Type) { func (check *checker) conversion(x *operand, T Type) {
var ok bool
switch { switch {
case x.mode == constant && isConstType(T): case x.mode == constant && isConstType(T):
// constant conversion // constant conversion
switch t := T.Underlying().(*Basic); { switch t := T.Underlying().(*Basic); {
case isRepresentableConst(x.val, check.conf, t.kind, &x.val): case isRepresentableConst(x.val, check.conf, t.kind, &x.val):
// nothing to do ok = true
case x.isInteger() && isString(t): case x.isInteger() && isString(t):
codepoint := int64(-1) codepoint := int64(-1)
if i, ok := exact.Int64Val(x.val); ok { if i, ok := exact.Int64Val(x.val); ok {
@ -26,18 +27,17 @@ func (check *checker) conversion(x *operand, T Type) {
// conversion. This is the same as converting any other out-of-range // conversion. This is the same as converting any other out-of-range
// value - let string(codepoint) do the work. // value - let string(codepoint) do the work.
x.val = exact.MakeString(string(codepoint)) x.val = exact.MakeString(string(codepoint))
default: ok = true
x.mode = invalid
} }
case x.isConvertible(check.conf, T): case x.isConvertible(check.conf, T):
// non-constant conversion // non-constant conversion
x.mode = value x.mode = value
default: ok = true
x.mode = invalid
} }
if x.mode == invalid { if !ok {
check.errorf(x.pos(), "cannot convert %s to %s", x, T) check.errorf(x.pos(), "cannot convert %s to %s", x, T)
x.mode = invalid
return return
} }
@ -116,17 +116,20 @@ func (x *operand) isConvertible(conf *Config, T Type) bool {
} }
func isUintptr(typ Type) bool { func isUintptr(typ Type) bool {
t, ok := typ.(*Basic) t, ok := typ.Underlying().(*Basic)
return ok && t.kind == Uintptr return ok && t.kind == Uintptr
} }
func isUnsafePointer(typ Type) bool { func isUnsafePointer(typ Type) bool {
t, ok := typ.(*Basic) // TODO(gri): Is this (typ.Underlying() instead of just typ) correct?
// The spec does't say so, but gc claims it is. See also
// issue 6326.
t, ok := typ.Underlying().(*Basic)
return ok && t.kind == UnsafePointer return ok && t.kind == UnsafePointer
} }
func isPointer(typ Type) bool { func isPointer(typ Type) bool {
_, ok := typ.(*Pointer) _, ok := typ.Underlying().(*Pointer)
return ok return ok
} }

View File

@ -6,6 +6,8 @@
package conversions package conversions
import "unsafe"
// argument count // argument count
var ( var (
_ = int() /* ERROR "missing argument" */ _ = int() /* ERROR "missing argument" */
@ -77,4 +79,10 @@ func interface_conversions() {
_ = I3(i3) _ = I3(i3)
// TODO(gri) add more tests, improve error message // TODO(gri) add more tests, improve error message
} }
func issue6326() {
type T unsafe.Pointer
var x T
_ = uintptr(x) // see issue 6326
}