From 6688b01dc12ebe2d769dc9ce59e5de8a47be0db3 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 9 Sep 2013 16:41:46 -0700 Subject: [PATCH] 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 --- go/types/conversions.go | 21 ++++++++++++--------- go/types/testdata/conversions.src | 10 +++++++++- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/go/types/conversions.go b/go/types/conversions.go index 3645ee17..a32b8dc3 100644 --- a/go/types/conversions.go +++ b/go/types/conversions.go @@ -11,12 +11,13 @@ import "code.google.com/p/go.tools/go/exact" // Conversion type-checks the conversion T(x). // The result is in x. func (check *checker) conversion(x *operand, T Type) { + var ok bool switch { case x.mode == constant && isConstType(T): // constant conversion switch t := T.Underlying().(*Basic); { case isRepresentableConst(x.val, check.conf, t.kind, &x.val): - // nothing to do + ok = true case x.isInteger() && isString(t): codepoint := int64(-1) 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 // value - let string(codepoint) do the work. x.val = exact.MakeString(string(codepoint)) - default: - x.mode = invalid + ok = true } case x.isConvertible(check.conf, T): // non-constant conversion x.mode = value - default: - x.mode = invalid + ok = true } - if x.mode == invalid { + if !ok { check.errorf(x.pos(), "cannot convert %s to %s", x, T) + x.mode = invalid return } @@ -116,17 +116,20 @@ func (x *operand) isConvertible(conf *Config, T Type) bool { } func isUintptr(typ Type) bool { - t, ok := typ.(*Basic) + t, ok := typ.Underlying().(*Basic) return ok && t.kind == Uintptr } 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 } func isPointer(typ Type) bool { - _, ok := typ.(*Pointer) + _, ok := typ.Underlying().(*Pointer) return ok } diff --git a/go/types/testdata/conversions.src b/go/types/testdata/conversions.src index 7bc4c26c..42514246 100644 --- a/go/types/testdata/conversions.src +++ b/go/types/testdata/conversions.src @@ -6,6 +6,8 @@ package conversions +import "unsafe" + // argument count var ( _ = int() /* ERROR "missing argument" */ @@ -77,4 +79,10 @@ func interface_conversions() { _ = I3(i3) // TODO(gri) add more tests, improve error message -} \ No newline at end of file +} + +func issue6326() { + type T unsafe.Pointer + var x T + _ = uintptr(x) // see issue 6326 +}