compiler: Prohibit comparisons of funcs, maps, and slices to non-nil.

From-SVN: r182703
This commit is contained in:
Ian Lance Taylor 2011-12-28 03:46:20 +00:00
parent 9437ab32a5
commit 1358551fc6
7 changed files with 25 additions and 160 deletions

View file

@ -6052,11 +6052,11 @@ Binary_expression::do_determine_type(const Type_context* context)
}
// Report an error if the binary operator OP does not support TYPE.
// Return whether the operation is OK. This should not be used for
// shift.
// OTYPE is the type of the other operand. Return whether the
// operation is OK. This should not be used for shift.
bool
Binary_expression::check_operator_type(Operator op, Type* type,
Binary_expression::check_operator_type(Operator op, Type* type, Type* otype,
Location location)
{
switch (op)
@ -6092,6 +6092,16 @@ Binary_expression::check_operator_type(Operator op, Type* type,
"or function type"));
return false;
}
if ((type->is_slice_type()
|| type->map_type() != NULL
|| type->function_type() != NULL)
&& !otype->is_nil_type())
{
error_at(location,
("slice, map, and function types may only "
"be compared to nil"));
return false;
}
break;
case OPERATOR_LT:
@ -6189,8 +6199,10 @@ Binary_expression::do_check_types(Gogo*)
return;
}
if (!Binary_expression::check_operator_type(this->op_, left_type,
right_type,
this->location())
|| !Binary_expression::check_operator_type(this->op_, right_type,
left_type,
this->location()))
{
this->set_is_error();
@ -6205,6 +6217,7 @@ Binary_expression::do_check_types(Gogo*)
return;
}
if (!Binary_expression::check_operator_type(this->op_, left_type,
right_type,
this->location()))
{
this->set_is_error();

View file

@ -1147,9 +1147,9 @@ class Binary_expression : public Expression
do_import(Import*);
// Report an error if OP can not be applied to TYPE. Return whether
// it can.
// it can. OTYPE is the type of the other operand.
static bool
check_operator_type(Operator op, Type* type, Location);
check_operator_type(Operator op, Type* type, Type* otype, Location);
protected:
int

View file

@ -1235,8 +1235,6 @@ Type::type_functions(const char** hash_fn, const char** equal_fn) const
case Type::TYPE_FLOAT:
case Type::TYPE_COMPLEX:
case Type::TYPE_POINTER:
case Type::TYPE_FUNCTION:
case Type::TYPE_MAP:
case Type::TYPE_CHANNEL:
*hash_fn = "__go_type_hash_identity";
*equal_fn = "__go_type_equal_identity";
@ -1249,6 +1247,8 @@ Type::type_functions(const char** hash_fn, const char** equal_fn) const
case Type::TYPE_STRUCT:
case Type::TYPE_ARRAY:
case Type::TYPE_FUNCTION:
case Type::TYPE_MAP:
// These types can not be hashed or compared.
*hash_fn = "__go_type_hash_error";
*equal_fn = "__go_type_equal_error";
@ -4731,7 +4731,9 @@ bool
Map_type::do_verify()
{
if (this->key_type_->struct_type() != NULL
|| this->key_type_->array_type() != NULL)
|| this->key_type_->array_type() != NULL
|| this->key_type_->function_type() != NULL
|| this->key_type_->map_type() != NULL)
{
error_at(this->location_, "invalid map key type");
return false;

View file

@ -76,7 +76,6 @@ func h() {
func newfunc() func(int) int { return func(x int) int { return x } }
func main() {
go f()
check([]int{1, 4, 5, 4})
@ -90,10 +89,6 @@ func main() {
check([]int{100, 200, 101, 201, 500, 101, 201, 500})
x, y := newfunc(), newfunc()
if x == y {
println("newfunc returned same func")
panic("fail")
}
if x(1) != 1 || y(2) != 2 {
println("newfunc returned broken funcs")
panic("fail")

View file

@ -1,130 +0,0 @@
// $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "unsafe"
func use(bool) {}
func stringptr(s string) uintptr { return *(*uintptr)(unsafe.Pointer(&s)) }
func isfalse(b bool) {
if b {
// stack will explain where
panic("wanted false, got true")
}
}
func istrue(b bool) {
if !b {
// stack will explain where
panic("wanted true, got false")
}
}
type T *int
func main() {
var a []int
var b map[string]int
var c string = "hello"
var d string = "hel" // try to get different pointer
d = d + "lo"
if stringptr(c) == stringptr(d) {
panic("compiler too smart -- got same string")
}
var e = make(chan int)
var ia interface{} = a
var ib interface{} = b
var ic interface{} = c
var id interface{} = d
var ie interface{} = e
// these comparisons are okay because
// string compare is okay and the others
// are comparisons where the types differ.
isfalse(ia == ib)
isfalse(ia == ic)
isfalse(ia == id)
isfalse(ib == ic)
isfalse(ib == id)
istrue(ic == id)
istrue(ie == ie)
// these are okay because one side of the
// comparison need only be assignable to the other.
isfalse(a == ib)
isfalse(a == ic)
isfalse(a == id)
isfalse(b == ic)
isfalse(b == id)
istrue(c == id)
istrue(e == ie)
isfalse(ia == b)
isfalse(ia == c)
isfalse(ia == d)
isfalse(ib == c)
isfalse(ib == d)
istrue(ic == d)
istrue(ie == e)
// 6g used to let this go through as true.
var g uint64 = 123
var h int64 = 123
var ig interface{} = g
var ih interface{} = h
isfalse(ig == ih)
// map of interface should use == on interface values,
// not memory.
// TODO: should m[c], m[d] be valid here?
var m = make(map[interface{}]int)
m[ic] = 1
m[id] = 2
if m[ic] != 2 {
println("m[ic] = ", m[ic])
panic("bad m[ic]")
}
// non-interface comparisons
{
c := make(chan int)
c1 := (<-chan int)(c)
c2 := (chan<- int)(c)
istrue(c == c1)
istrue(c == c2)
istrue(c1 == c)
istrue(c2 == c)
d := make(chan int)
isfalse(c == d)
isfalse(d == c)
isfalse(d == c1)
isfalse(d == c2)
isfalse(c1 == d)
isfalse(c2 == d)
}
// named types vs not
{
var x = new(int)
var y T
var z T = x
isfalse(x == y)
istrue(x == z)
isfalse(y == z)
isfalse(y == x)
istrue(z == x)
isfalse(z == y)
}
}

View file

@ -45,20 +45,6 @@ func main() {
mp[p] = 42
mp[&T{7}] = 42
type F func(x int)
f := func(x int) {}
mf := make(map[F]int)
mf[nil] = 42
mf[f] = 42
mf[func(x int) {}] = 42
type M map[int]int
m := make(M)
mm := make(map[M]int)
mm[nil] = 42
mm[m] = 42
mm[make(M)] = 42
type C chan int
c := make(C)
mc := make(map[C]int)

View file

@ -82,9 +82,9 @@ func main() {
case []int:
assert(x[3] == 3 && i == Array, "array")
case map[string]int:
assert(x == m && i == Map, "map")
assert(x != nil && i == Map, "map")
case func(i int) interface{}:
assert(x == f && i == Func, "fun")
assert(x != nil && i == Func, "fun")
default:
assert(false, "unknown")
}
@ -111,5 +111,4 @@ func main() {
default:
assert(false, "switch 4 unknown")
}
}