mirror of
https://github.com/golang/go
synced 2024-11-13 16:30:25 -07:00
gc: fix infinite recursion for embedded interfaces
Fixes #1909 R=rsc, gri CC=golang-dev https://golang.org/cl/5523047
This commit is contained in:
parent
8e99016c80
commit
9523b4d59c
@ -940,12 +940,20 @@ interfacefield(Node *n)
|
|||||||
Type*
|
Type*
|
||||||
tointerface(NodeList *l)
|
tointerface(NodeList *l)
|
||||||
{
|
{
|
||||||
Type *t, *f, **tp, *t1;
|
Type *t, *f, **tp, **otp, *t1;
|
||||||
|
|
||||||
t = typ(TINTER);
|
t = typ(TINTER);
|
||||||
|
t->orig = typ(TINTER);
|
||||||
|
|
||||||
for(tp = &t->type; l; l=l->next) {
|
tp = &t->type;
|
||||||
|
otp = &t->orig->type;
|
||||||
|
|
||||||
|
for(; l; l=l->next) {
|
||||||
f = interfacefield(l->n);
|
f = interfacefield(l->n);
|
||||||
|
*otp = typ(TFIELD);
|
||||||
|
**otp = *f;
|
||||||
|
otp = &(*otp)->down;
|
||||||
|
|
||||||
if (l->n->left == N && f->type->etype == TINTER) {
|
if (l->n->left == N && f->type->etype == TINTER) {
|
||||||
// embedded interface, inline methods
|
// embedded interface, inline methods
|
||||||
for(t1=f->type->type; t1; t1=t1->down) {
|
for(t1=f->type->type; t1; t1=t1->down) {
|
||||||
@ -953,6 +961,7 @@ tointerface(NodeList *l)
|
|||||||
f->type = t1->type;
|
f->type = t1->type;
|
||||||
f->broke = t1->broke;
|
f->broke = t1->broke;
|
||||||
f->sym = t1->sym;
|
f->sym = t1->sym;
|
||||||
|
f->embedded = 1;
|
||||||
if(f->sym)
|
if(f->sym)
|
||||||
f->nname = newname(f->sym);
|
f->nname = newname(f->sym);
|
||||||
*tp = f;
|
*tp = f;
|
||||||
|
@ -241,6 +241,13 @@ dumpexporttype(Type *t)
|
|||||||
if(t->sym != S && t->etype != TFIELD)
|
if(t->sym != S && t->etype != TFIELD)
|
||||||
dumppkg(t->sym->pkg);
|
dumppkg(t->sym->pkg);
|
||||||
|
|
||||||
|
// fmt will print the ->orig of an interface, which has the original embedded interfaces.
|
||||||
|
// be sure to dump them here
|
||||||
|
if(t->etype == TINTER)
|
||||||
|
for(f=t->orig->type; f; f=f->down)
|
||||||
|
if(f->sym == S)
|
||||||
|
dumpexporttype(f->type);
|
||||||
|
|
||||||
dumpexporttype(t->type);
|
dumpexporttype(t->type);
|
||||||
dumpexporttype(t->down);
|
dumpexporttype(t->down);
|
||||||
|
|
||||||
@ -470,8 +477,8 @@ importtype(Type *pt, Type *t)
|
|||||||
pt->sym->lastlineno = parserline();
|
pt->sym->lastlineno = parserline();
|
||||||
declare(n, PEXTERN);
|
declare(n, PEXTERN);
|
||||||
checkwidth(pt);
|
checkwidth(pt);
|
||||||
} else if(!eqtype(pt->orig, t))
|
} else if(!eqtype(pt->orig, t->orig))
|
||||||
yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t);
|
yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t);
|
||||||
|
|
||||||
if(debug['E'])
|
if(debug['E'])
|
||||||
print("import type %T %lT\n", pt, t);
|
print("import type %T %lT\n", pt, t);
|
||||||
|
@ -195,6 +195,7 @@ goopnames[] =
|
|||||||
[OCONTINUE] = "continue",
|
[OCONTINUE] = "continue",
|
||||||
[OCOPY] = "copy",
|
[OCOPY] = "copy",
|
||||||
[ODEC] = "--",
|
[ODEC] = "--",
|
||||||
|
[ODELETE] = "delete",
|
||||||
[ODEFER] = "defer",
|
[ODEFER] = "defer",
|
||||||
[ODIV] = "/",
|
[ODIV] = "/",
|
||||||
[OEQ] = "==",
|
[OEQ] = "==",
|
||||||
@ -639,9 +640,15 @@ typefmt(Fmt *fp, Type *t)
|
|||||||
return fmtprint(fp, "map[%T]%T", t->down, t->type);
|
return fmtprint(fp, "map[%T]%T", t->down, t->type);
|
||||||
|
|
||||||
case TINTER:
|
case TINTER:
|
||||||
|
t = t->orig;
|
||||||
fmtstrcpy(fp, "interface {");
|
fmtstrcpy(fp, "interface {");
|
||||||
for(t1=t->type; t1!=T; t1=t1->down)
|
for(t1=t->type; t1!=T; t1=t1->down)
|
||||||
if(exportname(t1->sym->name)) {
|
if(!t1->sym) {
|
||||||
|
if(t1->down)
|
||||||
|
fmtprint(fp, " %T;", t1->type);
|
||||||
|
else
|
||||||
|
fmtprint(fp, " %T ", t1->type);
|
||||||
|
} else if(exportname(t1->sym->name)) {
|
||||||
if(t1->down)
|
if(t1->down)
|
||||||
fmtprint(fp, " %hS%hT;", t1->sym, t1->type);
|
fmtprint(fp, " %hS%hT;", t1->sym, t1->type);
|
||||||
else
|
else
|
||||||
@ -946,6 +953,7 @@ static int opprec[] = {
|
|||||||
[OCONVNOP] = 8,
|
[OCONVNOP] = 8,
|
||||||
[OCONV] = 8,
|
[OCONV] = 8,
|
||||||
[OCOPY] = 8,
|
[OCOPY] = 8,
|
||||||
|
[ODELETE] = 8,
|
||||||
[OLEN] = 8,
|
[OLEN] = 8,
|
||||||
[OLITERAL] = 8,
|
[OLITERAL] = 8,
|
||||||
[OMAKESLICE] = 8,
|
[OMAKESLICE] = 8,
|
||||||
@ -1010,6 +1018,7 @@ static int opprec[] = {
|
|||||||
[OGT] = 4,
|
[OGT] = 4,
|
||||||
[ONE] = 4,
|
[ONE] = 4,
|
||||||
[OCMPSTR] = 4,
|
[OCMPSTR] = 4,
|
||||||
|
[OCMPIFACE] = 4,
|
||||||
|
|
||||||
[OSEND] = 3,
|
[OSEND] = 3,
|
||||||
[OANDAND] = 2,
|
[OANDAND] = 2,
|
||||||
@ -1218,6 +1227,7 @@ exprfmt(Fmt *f, Node *n, int prec)
|
|||||||
case OAPPEND:
|
case OAPPEND:
|
||||||
case OCAP:
|
case OCAP:
|
||||||
case OCLOSE:
|
case OCLOSE:
|
||||||
|
case ODELETE:
|
||||||
case OLEN:
|
case OLEN:
|
||||||
case OMAKE:
|
case OMAKE:
|
||||||
case ONEW:
|
case ONEW:
|
||||||
@ -1288,6 +1298,7 @@ exprfmt(Fmt *f, Node *n, int prec)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case OCMPSTR:
|
case OCMPSTR:
|
||||||
|
case OCMPIFACE:
|
||||||
exprfmt(f, n->left, nprec);
|
exprfmt(f, n->left, nprec);
|
||||||
fmtprint(f, " %#O ", n->etype);
|
fmtprint(f, " %#O ", n->etype);
|
||||||
exprfmt(f, n->right, nprec+1);
|
exprfmt(f, n->right, nprec+1);
|
||||||
@ -1303,8 +1314,10 @@ nodefmt(Fmt *f, Node *n)
|
|||||||
Type *t;
|
Type *t;
|
||||||
|
|
||||||
t = n->type;
|
t = n->type;
|
||||||
if(n->orig == N)
|
if(n->orig == N) {
|
||||||
|
n->orig = n;
|
||||||
fatal("node with no orig %N", n);
|
fatal("node with no orig %N", n);
|
||||||
|
}
|
||||||
|
|
||||||
// we almost always want the original, except in export mode for literals
|
// we almost always want the original, except in export mode for literals
|
||||||
// this saves the importer some work, and avoids us having to redo some
|
// this saves the importer some work, and avoids us having to redo some
|
||||||
@ -1359,6 +1372,7 @@ nodedump(Fmt *fp, Node *n)
|
|||||||
indent(fp);
|
indent(fp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fmtprint(fp, "[%p]", n);
|
||||||
|
|
||||||
switch(n->op) {
|
switch(n->op) {
|
||||||
default:
|
default:
|
||||||
|
@ -1620,7 +1620,7 @@ non_dcl_stmt:
|
|||||||
$$->list = $2;
|
$$->list = $2;
|
||||||
if($$->list == nil && curfn != N) {
|
if($$->list == nil && curfn != N) {
|
||||||
NodeList *l;
|
NodeList *l;
|
||||||
|
|
||||||
for(l=curfn->dcl; l; l=l->next) {
|
for(l=curfn->dcl; l; l=l->next) {
|
||||||
if(l->n->class == PPARAM)
|
if(l->n->class == PPARAM)
|
||||||
continue;
|
continue;
|
||||||
@ -1953,6 +1953,10 @@ hidden_interfacedcl:
|
|||||||
{
|
{
|
||||||
$$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
|
$$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
|
||||||
}
|
}
|
||||||
|
| hidden_type
|
||||||
|
{
|
||||||
|
$$ = nod(ODCLFIELD, N, typenod($1));
|
||||||
|
}
|
||||||
|
|
||||||
ohidden_funres:
|
ohidden_funres:
|
||||||
{
|
{
|
||||||
|
@ -460,29 +460,32 @@ func (p *gcParser) parseSignature() *Func {
|
|||||||
return &Func{Params: params, Results: results, IsVariadic: isVariadic}
|
return &Func{Params: params, Results: results, IsVariadic: isVariadic}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MethodSpec = ( identifier | ExportedName ) Signature .
|
// MethodOrEmbedSpec = Name [ Signature ] .
|
||||||
//
|
//
|
||||||
func (p *gcParser) parseMethodSpec() *ast.Object {
|
func (p *gcParser) parseMethodOrEmbedSpec() *ast.Object {
|
||||||
if p.tok == scanner.Ident {
|
p.parseName()
|
||||||
p.expect(scanner.Ident)
|
if p.tok == '(' {
|
||||||
} else {
|
p.parseSignature()
|
||||||
p.parseExportedName()
|
// TODO(gri) compute method object
|
||||||
|
return ast.NewObj(ast.Fun, "_")
|
||||||
}
|
}
|
||||||
p.parseSignature()
|
// TODO lookup name and return that type
|
||||||
|
return ast.NewObj(ast.Typ, "_")
|
||||||
// TODO(gri) compute method object
|
|
||||||
return ast.NewObj(ast.Fun, "_")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterfaceType = "interface" "{" [ MethodList ] "}" .
|
// InterfaceType = "interface" "{" [ MethodOrEmbedList ] "}" .
|
||||||
// MethodList = MethodSpec { ";" MethodSpec } .
|
// MethodOrEmbedList = MethodOrEmbedSpec { ";" MethodOrEmbedSpec } .
|
||||||
//
|
//
|
||||||
func (p *gcParser) parseInterfaceType() Type {
|
func (p *gcParser) parseInterfaceType() Type {
|
||||||
var methods ObjList
|
var methods ObjList
|
||||||
|
|
||||||
parseMethod := func() {
|
parseMethod := func() {
|
||||||
meth := p.parseMethodSpec()
|
switch m := p.parseMethodOrEmbedSpec(); m.Kind {
|
||||||
methods = append(methods, meth)
|
case ast.Typ:
|
||||||
|
// TODO expand embedded methods
|
||||||
|
case ast.Fun:
|
||||||
|
methods = append(methods, m)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.expectKeyword("interface")
|
p.expectKeyword("interface")
|
||||||
|
15
test/fixedbugs/bug395.go
Normal file
15
test/fixedbugs/bug395.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// $G $D/$F.go || echo "Bug395"
|
||||||
|
|
||||||
|
// Copyright 2011 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.
|
||||||
|
|
||||||
|
// Issue 1909
|
||||||
|
// Would OOM due to exponential recursion on Foo's expanded methodset in nodefmt
|
||||||
|
package test
|
||||||
|
|
||||||
|
type Foo interface {
|
||||||
|
Bar() interface{Foo}
|
||||||
|
Baz() interface{Foo}
|
||||||
|
Bug() interface{Foo}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user