mirror of
https://github.com/golang/go
synced 2024-11-22 03:24:41 -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:
parent
2a9c012498
commit
427b5bddcd
@ -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
24
test/fixedbugs/bug398.go
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user