1
0
mirror of https://github.com/golang/go synced 2024-11-22 02:54:39 -07:00

gc: fix recursion loop in interface comparison

iant's idea.

Fixes #2745.

R=iant, dsymonds
CC=golang-dev
https://golang.org/cl/5536085
This commit is contained in:
Russ Cox 2012-01-23 09:19:02 -05:00
parent 2a9c012498
commit 427b5bddcd
2 changed files with 81 additions and 10 deletions

View File

@ -986,6 +986,25 @@ eqnote(Strlit *a, Strlit *b)
return memcmp(a->s, b->s, a->len) == 0;
}
typedef struct TypePairList TypePairList;
struct TypePairList
{
Type *t1;
Type *t2;
TypePairList *next;
};
static int
onlist(TypePairList *l, Type *t1, Type *t2)
{
for(; l; l=l->next)
if((l->t1 == t1 && l->t2 == t2) || (l->t1 == t2 && l->t2 == t1))
return 1;
return 0;
}
static int eqtype1(Type*, Type*, TypePairList*);
// Return 1 if t1 and t2 are identical, following the spec rules.
//
// Any cyclic type must go through a named type, and if one is
@ -995,6 +1014,14 @@ eqnote(Strlit *a, Strlit *b)
int
eqtype(Type *t1, Type *t2)
{
return eqtype1(t1, t2, nil);
}
static int
eqtype1(Type *t1, Type *t2, TypePairList *assumed_equal)
{
TypePairList l;
if(t1 == t2)
return 1;
if(t1 == T || t2 == T || t1->etype != t2->etype)
@ -1016,16 +1043,24 @@ eqtype(Type *t1, Type *t2)
return 0;
}
if(onlist(assumed_equal, t1, t2))
return 1;
l.next = assumed_equal;
l.t1 = t1;
l.t2 = t2;
switch(t1->etype) {
case TINTER:
case TSTRUCT:
for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
if(t1->etype != TFIELD || t2->etype != TFIELD)
fatal("struct/interface missing field: %T %T", t1, t2);
if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type) || !eqnote(t1->note, t2->note))
return 0;
if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype1(t1->type, t2->type, &l) || !eqnote(t1->note, t2->note))
goto no;
}
return t1 == T && t2 == T;
if(t1 == T && t2 == T)
goto yes;
goto no;
case TFUNC:
// Loop over structs: receiver, in, out.
@ -1039,26 +1074,38 @@ eqtype(Type *t1, Type *t2)
for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
if(ta->etype != TFIELD || tb->etype != TFIELD)
fatal("func struct missing field: %T %T", ta, tb);
if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type))
return 0;
if(ta->isddd != tb->isddd || !eqtype1(ta->type, tb->type, &l))
goto no;
}
if(ta != T || tb != T)
return 0;
goto no;
}
return t1 == T && t2 == T;
if(t1 == T && t2 == T)
goto yes;
goto no;
case TARRAY:
if(t1->bound != t2->bound)
return 0;
goto no;
break;
case TCHAN:
if(t1->chan != t2->chan)
return 0;
goto no;
break;
}
return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type);
if(eqtype1(t1->down, t2->down, &l) && eqtype1(t1->type, t2->type, &l))
goto yes;
goto no;
yes:
assumed_equal = l.next;
return 1;
no:
assumed_equal = l.next;
return 0;
}
// Are t1 and t2 equal struct types when field names are ignored?

24
test/fixedbugs/bug398.go Normal file
View File

@ -0,0 +1,24 @@
// $G $D/$F.go
// Copyright 2012 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.
// Used to crash compiler in interface type equality check.
package p
type I1 interface {
F() interface{I1}
}
type I2 interface {
F() interface{I2}
}
var v1 I1
var v2 I2
func f() bool {
return v1 == v2
}