Commit c4c92ebe authored by Russ Cox's avatar Russ Cox

cmd/gc: fix comparison of struct with _ field

Fixes #2989.

R=ken2
CC=golang-dev
https://golang.org/cl/5674091
parent ce020ffa
...@@ -1172,6 +1172,7 @@ int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr); ...@@ -1172,6 +1172,7 @@ int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr);
void importdot(Pkg *opkg, Node *pack); void importdot(Pkg *opkg, Node *pack);
int is64(Type *t); int is64(Type *t);
int isblank(Node *n); int isblank(Node *n);
int isblanksym(Sym *s);
int isfixedarray(Type *t); int isfixedarray(Type *t);
int isideal(Type *t); int isideal(Type *t);
int isinter(Type *t); int isinter(Type *t);
......
...@@ -571,6 +571,8 @@ algtype1(Type *t, Type **bad) ...@@ -571,6 +571,8 @@ algtype1(Type *t, Type **bad)
} }
ret = AMEM; ret = AMEM;
for(t1=t->type; t1!=T; t1=t1->down) { for(t1=t->type; t1!=T; t1=t1->down) {
if(isblanksym(t1->sym))
continue;
a = algtype1(t1->type, bad); a = algtype1(t1->type, bad);
if(a == ANOEQ) if(a == ANOEQ)
return ANOEQ; // not comparable return ANOEQ; // not comparable
...@@ -887,12 +889,20 @@ isslice(Type *t) ...@@ -887,12 +889,20 @@ isslice(Type *t)
int int
isblank(Node *n) isblank(Node *n)
{
if(n == N)
return 0;
return isblanksym(n->sym);
}
int
isblanksym(Sym *s)
{ {
char *p; char *p;
if(n == N || n->sym == S) if(s == S)
return 0; return 0;
p = n->sym->name; p = s->name;
if(p == nil) if(p == nil)
return 0; return 0;
return p[0] == '_' && p[1] == '\0'; return p[0] == '_' && p[1] == '\0';
...@@ -2652,12 +2662,14 @@ genhash(Sym *sym, Type *t) ...@@ -2652,12 +2662,14 @@ genhash(Sym *sym, Type *t)
// and calling specific hash functions for the others. // and calling specific hash functions for the others.
first = T; first = T;
for(t1=t->type;; t1=t1->down) { for(t1=t->type;; t1=t1->down) {
if(t1 != T && algtype1(t1->type, nil) == AMEM) { if(t1 != T && (isblanksym(t1->sym) || algtype1(t1->type, nil) == AMEM)) {
if(first == T) if(first == T)
first = t1; first = t1;
continue; continue;
} }
// Run memhash for fields up to this one. // Run memhash for fields up to this one.
while(first != T && isblanksym(first->sym))
first = first->down;
if(first != T) { if(first != T) {
if(first->down == t1) if(first->down == t1)
size = first->type->width; size = first->type->width;
...@@ -2867,7 +2879,7 @@ geneq(Sym *sym, Type *t) ...@@ -2867,7 +2879,7 @@ geneq(Sym *sym, Type *t)
// and calling specific equality tests for the others. // and calling specific equality tests for the others.
first = T; first = T;
for(t1=t->type;; t1=t1->down) { for(t1=t->type;; t1=t1->down) {
if(t1 != T && algtype1(t1->type, nil) == AMEM) { if(t1 != T && (isblanksym(t1->sym) || algtype1(t1->type, nil) == AMEM)) {
if(first == T) if(first == T)
first = t1; first = t1;
continue; continue;
...@@ -2875,12 +2887,15 @@ geneq(Sym *sym, Type *t) ...@@ -2875,12 +2887,15 @@ geneq(Sym *sym, Type *t)
// Run memequal for fields up to this one. // Run memequal for fields up to this one.
// TODO(rsc): All the calls to newname are wrong for // TODO(rsc): All the calls to newname are wrong for
// cross-package unexported fields. // cross-package unexported fields.
while(first != T && isblanksym(first->sym))
first = first->down;
if(first != T) { if(first != T) {
if(first->down == t1) { if(first->down == t1) {
fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
} else if(first->down->down == t1) { } else if(first->down->down == t1) {
fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
first = first->down; first = first->down;
if(!isblanksym(first->sym))
fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
} else { } else {
// More than two fields: use memequal. // More than two fields: use memequal.
......
...@@ -282,6 +282,25 @@ func main() { ...@@ -282,6 +282,25 @@ func main() {
isfalse(iz != x) isfalse(iz != x)
} }
// structs with _ fields
{
var x = struct {
x int
_ []int
y float64
_ float64
z int
}{
x: 1, y: 2, z: 3,
}
var ix interface{} = x
istrue(x == x)
istrue(x == ix)
istrue(ix == x)
istrue(ix == ix)
}
// arrays // arrays
{ {
var x = [2]string{"1", "hi"} var x = [2]string{"1", "hi"}
......
...@@ -15,6 +15,10 @@ type T3 struct{ z []int } ...@@ -15,6 +15,10 @@ type T3 struct{ z []int }
var t3 T3 var t3 T3
type T4 struct { _ []int; a float64 }
var t4 T4
func main() { func main() {
// Arguments to comparison must be // Arguments to comparison must be
// assignable one to the other (or vice versa) // assignable one to the other (or vice versa)
...@@ -46,6 +50,7 @@ func main() { ...@@ -46,6 +50,7 @@ func main() {
// Comparison of structs should have a good message // Comparison of structs should have a good message
use(t3 == t3) // ERROR "struct|expected" use(t3 == t3) // ERROR "struct|expected"
use(t4 == t4) // ok; the []int is a blank field
// Slices, functions, and maps too. // Slices, functions, and maps too.
var x []int var x []int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment