1
0
mirror of https://github.com/golang/go synced 2024-11-21 17:34:40 -07:00

gc: fix smaller-than-pointer-sized receivers in interfaces

Fixes #812.

R=ken2
CC=golang-dev
https://golang.org/cl/1904041
This commit is contained in:
Russ Cox 2010-07-26 15:25:10 -07:00
parent 7b240e8135
commit 607eaea456
9 changed files with 121 additions and 18 deletions

View File

@ -705,7 +705,7 @@ out:
p->to.type = D_OREG;
p->to.reg = NREG;
p->to.name = D_EXTERN;
p->to.sym = methodsym(method->sym, ptrto(f->type));
p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
//print("4. %P\n", p);
pc->as = ARET; // overwrite AEND

View File

@ -732,7 +732,7 @@ out:
p = pc;
gins(AJMP, N, N);
p->to.type = D_EXTERN;
p->to.sym = methodsym(method->sym, ptrto(f->type));
p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
//print("6. %P\n", p);
pc->as = ARET; // overwrite AEND

View File

@ -739,7 +739,7 @@ out:
p = pc;
gins(AJMP, N, N);
p->to.type = D_EXTERN;
p->to.sym = methodsym(method->sym, ptrto(f->type));
p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
//print("6. %P\n", p);
pc->as = ARET; // overwrite AEND

View File

@ -1017,11 +1017,12 @@ functype(Node *this, NodeList *in, NodeList *out)
}
Sym*
methodsym(Sym *nsym, Type *t0)
methodsym(Sym *nsym, Type *t0, int iface)
{
Sym *s;
char *p;
Type *t;
char *suffix;
t = t0;
if(t == T)
@ -1043,7 +1044,13 @@ methodsym(Sym *nsym, Type *t0)
if(t != t0 && t0->sym)
t0 = ptrto(t);
p = smprint("%#hT·%s", t0, nsym->name);
suffix = "";
if(iface) {
dowidth(t0);
if(t0->width < types[tptr]->width)
suffix = "·i";
}
p = smprint("%#hT·%s%s", t0, nsym->name, suffix);
s = pkglookup(p, s->pkg);
free(p);
return s;
@ -1058,7 +1065,7 @@ methodname(Node *n, Type *t)
{
Sym *s;
s = methodsym(n->sym, t);
s = methodsym(n->sym, t, 0);
if(s == S)
return n;
return newname(s);

View File

@ -858,7 +858,7 @@ int isifacemethod(Type *f);
void markdcl(void);
Node* methodname(Node *n, Type *t);
Node* methodname1(Node *n, Node *t);
Sym* methodsym(Sym *nsym, Type *t0);
Sym* methodsym(Sym *nsym, Type *t0, int iface);
Node* newname(Sym *s);
Type* newtype(Sym *s);
Node* oldname(Sym *s);
@ -1061,7 +1061,7 @@ void flusherrors(void);
void frame(int context);
Type* funcfirst(Iter *s, Type *t);
Type* funcnext(Iter *s);
void genwrapper(Type *rcvr, Type *method, Sym *newnam);
void genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface);
Type** getinarg(Type *t);
Type* getinargx(Type *t);
Type** getoutarg(Type *t);

View File

@ -183,14 +183,14 @@ methods(Type *t)
a = b;
a->name = method->name;
a->isym = methodsym(method, it);
a->tsym = methodsym(method, t);
a->isym = methodsym(method, it, 1);
a->tsym = methodsym(method, t, 0);
a->type = methodfunc(f->type, 1);
a->mtype = methodfunc(f->type, 0);
if(!(a->isym->flags & SymSiggen)) {
a->isym->flags |= SymSiggen;
if(!eqtype(this, it)) {
if(!eqtype(this, it) || this->width < types[tptr]->width) {
if(oldlist == nil)
oldlist = pc;
// Is okay to call genwrapper here always,
@ -201,7 +201,7 @@ methods(Type *t)
&& f->embedded && !isifacemethod(f->type))
genembedtramp(it, f, a->isym);
else
genwrapper(it, f, a->isym);
genwrapper(it, f, a->isym, 1);
}
}
@ -214,7 +214,7 @@ methods(Type *t)
&& f->embedded && !isifacemethod(f->type))
genembedtramp(t, f, a->tsym);
else
genwrapper(t, f, a->tsym);
genwrapper(t, f, a->tsym, 0);
}
}
}

View File

@ -3043,10 +3043,11 @@ structargs(Type **tl, int mustname)
* newnam - the eventual mangled name of this function
*/
void
genwrapper(Type *rcvr, Type *method, Sym *newnam)
genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
{
Node *this, *fn, *call, *n, *t;
Node *this, *fn, *call, *n, *t, *pad;
NodeList *l, *args, *in, *out;
Type *tpad;
if(debug['r'])
print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
@ -3062,8 +3063,21 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
fn = nod(ODCLFUNC, N, N);
fn->nname = newname(newnam);
t = nod(OTFUNC, this, N);
t->list = in;
t = nod(OTFUNC, N, N);
l = list1(this);
if(iface && rcvr->width < types[tptr]->width) {
// Building method for interface table and receiver
// is smaller than the single pointer-sized word
// that the interface call will pass in.
// Add a dummy padding argument after the
// receiver to make up the difference.
tpad = typ(TARRAY);
tpad->type = types[TUINT8];
tpad->bound = types[tptr]->width - rcvr->width;
pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad));
l = list(l, pad);
}
t->list = concat(l, in);
t->rlist = out;
fn->nname->ntype = t;
funchdr(fn);

View File

@ -494,7 +494,7 @@ reswitch:
goto error;
}
n->op = ONAME;
n->sym = methodsym(sym, l->type);
n->sym = methodsym(sym, l->type, 0);
n->type = methodfunc(n->type, 1);
n->xoffset = 0;
getinargx(n->type)->type->type = l->type; // fix up receiver

82
test/fixedbugs/bug296.go Normal file
View File

@ -0,0 +1,82 @@
package main
type I interface {
m(a, b, c, d, e, f, g, h byte)
}
type Int8 int8
func (x Int8) m(a, b, c, d, e, f, g, h byte) {
check("Int8", int64(x), 0x01, a, b, c, d, e, f, g, h)
}
type Uint8 uint8
func (x Uint8) m(a, b, c, d, e, f, g, h byte) {
check("Uint8", int64(x), 0x01, a, b, c, d, e, f, g, h)
}
type Int16 int16
func (x Int16) m(a, b, c, d, e, f, g, h byte) {
check("Int16", int64(x), 0x0102, a, b, c, d, e, f, g, h)
}
type Uint16 uint16
func (x Uint16) m(a, b, c, d, e, f, g, h byte) {
check("Uint16", int64(x), 0x0102, a, b, c, d, e, f, g, h)
}
type Int32 int32
func (x Int32) m(a, b, c, d, e, f, g, h byte) {
check("Int32", int64(x), 0x01020304, a, b, c, d, e, f, g, h)
}
type Uint32 uint32
func (x Uint32) m(a, b, c, d, e, f, g, h byte) {
check("Uint32", int64(x), 0x01020304, a, b, c, d, e, f, g, h)
}
type Int64 int64
func (x Int64) m(a, b, c, d, e, f, g, h byte) {
check("Int64", int64(x), 0x0102030405060708, a, b, c, d, e, f, g, h)
}
type Uint64 uint64
func (x Uint64) m(a, b, c, d, e, f, g, h byte) {
check("Uint64", int64(x), 0x0102030405060708, a, b, c, d, e, f, g, h)
}
var test = []I{
Int8(0x01),
Uint8(0x01),
Int16(0x0102),
Uint16(0x0102),
Int32(0x01020304),
Uint32(0x01020304),
Int64(0x0102030405060708),
Uint64(0x0102030405060708),
}
func main() {
for _, t := range test {
t.m(0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17)
}
}
var bug = false
func check(desc string, have, want int64, a, b, c, d, e, f, g, h byte) {
if have != want || a != 0x10 || b != 0x11 || c != 0x12 || d != 0x13 || e != 0x14 || f != 0x15 || g != 0x16 || h != 0x17 {
if !bug {
bug = true
println("BUG")
}
println(desc, "check", have, want, a, b, c, d, e, f, g, h)
}
}