cmd/gc: fix comparison of struct with _ field

Fixes #2989.

R=ken2
CC=golang-dev
https://golang.org/cl/5674091
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index bb909b9..fcbea2c 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -1172,6 +1172,7 @@
 void	importdot(Pkg *opkg, Node *pack);
 int	is64(Type *t);
 int	isblank(Node *n);
+int	isblanksym(Sym *s);
 int	isfixedarray(Type *t);
 int	isideal(Type *t);
 int	isinter(Type *t);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 3fd5209..5621ed9 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -571,6 +571,8 @@
 		}
 		ret = AMEM;
 		for(t1=t->type; t1!=T; t1=t1->down) {
+			if(isblanksym(t1->sym))
+				continue;
 			a = algtype1(t1->type, bad);
 			if(a == ANOEQ)
 				return ANOEQ;  // not comparable
@@ -888,11 +890,19 @@
 int
 isblank(Node *n)
 {
+	if(n == N)
+		return 0;
+	return isblanksym(n->sym);
+}
+
+int
+isblanksym(Sym *s)
+{
 	char *p;
 
-	if(n == N || n->sym == S)
+	if(s == S)
 		return 0;
-	p = n->sym->name;
+	p = s->name;
 	if(p == nil)
 		return 0;
 	return p[0] == '_' && p[1] == '\0';
@@ -2652,12 +2662,14 @@
 		// and calling specific hash functions for the others.
 		first = T;
 		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)
 					first = t1;
 				continue;
 			}
 			// Run memhash for fields up to this one.
+			while(first != T && isblanksym(first->sym))
+				first = first->down;
 			if(first != T) {
 				if(first->down == t1)
 					size = first->type->width;
@@ -2867,7 +2879,7 @@
 		// and calling specific equality tests for the others.
 		first = T;
 		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)
 					first = t1;
 				continue;
@@ -2875,13 +2887,16 @@
 			// Run memequal for fields up to this one.
 			// TODO(rsc): All the calls to newname are wrong for
 			// cross-package unexported fields.
+			while(first != T && isblanksym(first->sym))
+				first = first->down;
 			if(first != T) {
 				if(first->down == t1) {
 					fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
 				} else if(first->down->down == t1) {
 					fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
 					first = first->down;
-					fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
+					if(!isblanksym(first->sym))
+						fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq));
 				} else {
 					// More than two fields: use memequal.
 					if(t1 == T)
diff --git a/test/cmp.go b/test/cmp.go
index 795245f..a9d0375 100644
--- a/test/cmp.go
+++ b/test/cmp.go
@@ -281,6 +281,25 @@
 		isfalse(ix != z)
 		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
 	{
diff --git a/test/cmp6.go b/test/cmp6.go
index 71f1284..1e28675 100644
--- a/test/cmp6.go
+++ b/test/cmp6.go
@@ -15,6 +15,10 @@
 
 var t3 T3
 
+type T4 struct { _ []int; a float64 }
+
+var t4 T4
+
 func main() {
 	// Arguments to comparison must be
 	// assignable one to the other (or vice versa)
@@ -46,6 +50,7 @@
 
 	// Comparison of structs should have a good message
 	use(t3 == t3) // ERROR "struct|expected"
+	use(t4 == t4) // ok; the []int is a blank field
 
 	// Slices, functions, and maps too.
 	var x []int