mirror of
https://github.com/golang/go
synced 2024-11-22 00:34:40 -07:00
forward declarations not necessary.
still to do: * initializer cycle detection * nicer error for type checking cycles R=ken OCL=32855 CL=32880
This commit is contained in:
parent
e98dde27ef
commit
b648716ee9
@ -18,7 +18,7 @@ OFILES=\
|
||||
align.$O\
|
||||
bits.$O\
|
||||
builtin.$O\
|
||||
compat.$O\
|
||||
closure.$O\
|
||||
const.$O\
|
||||
dcl.$O\
|
||||
export.$O\
|
||||
|
@ -61,10 +61,23 @@ widstruct(Type *t, uint32 o, int flag)
|
||||
if(f->etype != TFIELD)
|
||||
fatal("widstruct: not TFIELD: %lT", f);
|
||||
dowidth(f->type);
|
||||
if(f->type->width < 0 || f->type->width > 100000000)
|
||||
fatal("invalid width %lld", f->type->width);
|
||||
w = f->type->width;
|
||||
m = arrayelemwidth(f->type);
|
||||
o = rnd(o, m);
|
||||
f->width = o; // really offset for TFIELD
|
||||
if(f->nname != N) {
|
||||
// this same stackparam logic is in addrescapes
|
||||
// in typecheck.c. usually addrescapes runs after
|
||||
// widstruct, in which case we could drop this,
|
||||
// but function closure functions are the exception.
|
||||
if(f->nname->stackparam) {
|
||||
f->nname->stackparam->xoffset = o;
|
||||
f->nname->xoffset = 0;
|
||||
} else
|
||||
f->nname->xoffset = o;
|
||||
}
|
||||
o += w;
|
||||
}
|
||||
// final width is rounded
|
||||
@ -91,6 +104,9 @@ dowidth(Type *t)
|
||||
if(t == T)
|
||||
return;
|
||||
|
||||
if(t->width > 0)
|
||||
return;
|
||||
|
||||
if(t->width == -2) {
|
||||
yyerror("invalid recursive type %T", t);
|
||||
t->width = 0;
|
||||
@ -99,7 +115,6 @@ dowidth(Type *t)
|
||||
|
||||
t->width = -2;
|
||||
|
||||
|
||||
et = t->etype;
|
||||
switch(et) {
|
||||
case TFUNC:
|
||||
@ -165,13 +180,16 @@ dowidth(Type *t)
|
||||
break;
|
||||
case TFORW: // should have been filled in
|
||||
case TFORWSTRUCT:
|
||||
yyerror("incomplete type %T", t);
|
||||
yyerror("undefined type %T", t);
|
||||
w = widthptr;
|
||||
break;
|
||||
case TANY: // implemented as pointer
|
||||
w = widthptr;
|
||||
case TANY:
|
||||
// dummy type; should be replaced before use.
|
||||
fatal("dowidth any");
|
||||
break;
|
||||
case TSTRING:
|
||||
if(sizeof_String == 0)
|
||||
fatal("early dowidth string");
|
||||
w = sizeof_String;
|
||||
break;
|
||||
case TARRAY:
|
||||
@ -413,6 +431,9 @@ typeinit(void)
|
||||
|
||||
// string is same as slice wo the cap
|
||||
sizeof_String = rnd(Array_nel+types[TUINT32]->width, maxround);
|
||||
|
||||
dowidth(types[TSTRING]);
|
||||
dowidth(idealstring);
|
||||
}
|
||||
|
||||
/*
|
||||
|
194
src/cmd/gc/closure.c
Normal file
194
src/cmd/gc/closure.c
Normal file
@ -0,0 +1,194 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
/*
|
||||
* function literals aka closures
|
||||
*/
|
||||
|
||||
#include "go.h"
|
||||
|
||||
void
|
||||
closurehdr(Node *ntype)
|
||||
{
|
||||
Node *n, *name;
|
||||
NodeList *l;
|
||||
|
||||
n = nod(OCLOSURE, N, N);
|
||||
n->ntype = ntype;
|
||||
n->funcdepth = funcdepth;
|
||||
|
||||
funchdr(n);
|
||||
|
||||
// steal ntype's argument names and
|
||||
// leave a fresh copy in their place.
|
||||
// references to these variables need to
|
||||
// refer to the variables in the external
|
||||
// function declared below; see walkclosure.
|
||||
n->list = ntype->list;
|
||||
n->rlist = ntype->rlist;
|
||||
ntype->list = nil;
|
||||
ntype->rlist = nil;
|
||||
for(l=n->list; l; l=l->next) {
|
||||
name = l->n->left;
|
||||
if(name)
|
||||
name = newname(name->sym);
|
||||
ntype->list = list(ntype->list, nod(ODCLFIELD, name, l->n->right));
|
||||
}
|
||||
for(l=n->rlist; l; l=l->next) {
|
||||
name = l->n->left;
|
||||
if(name)
|
||||
name = newname(name->sym);
|
||||
ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right));
|
||||
}
|
||||
}
|
||||
|
||||
Node*
|
||||
closurebody(NodeList *body)
|
||||
{
|
||||
Node *func, *v;
|
||||
NodeList *l;
|
||||
|
||||
if(body == nil)
|
||||
body = list1(nod(OEMPTY, N, N));
|
||||
|
||||
func = curfn;
|
||||
l = func->dcl;
|
||||
func->nbody = body;
|
||||
funcbody(func);
|
||||
|
||||
// closure-specific variables are hanging off the
|
||||
// ordinary ones in the symbol table; see oldname.
|
||||
// unhook them.
|
||||
// make the list of pointers for the closure call.
|
||||
for(l=func->cvars; l; l=l->next) {
|
||||
v = l->n;
|
||||
v->closure->closure = v->outer;
|
||||
v->heapaddr = nod(OADDR, oldname(v->sym), N);
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
void
|
||||
typecheckclosure(Node *func)
|
||||
{
|
||||
Node *oldfn;
|
||||
NodeList *l;
|
||||
Node *v;
|
||||
|
||||
oldfn = curfn;
|
||||
typecheck(&func->ntype, Etype);
|
||||
func->type = func->ntype->type;
|
||||
if(func->type != T) {
|
||||
curfn = func;
|
||||
typechecklist(func->nbody, Etop);
|
||||
curfn = oldfn;
|
||||
}
|
||||
|
||||
// type check the & of closed variables outside the closure,
|
||||
// so that the outer frame also grabs them and knows they
|
||||
// escape.
|
||||
func->enter = nil;
|
||||
for(l=func->cvars; l; l=l->next) {
|
||||
v = l->n;
|
||||
if(v->type == T) {
|
||||
// if v->type is nil, it means v looked like it was
|
||||
// going to be used in the closure but wasn't.
|
||||
// this happens because when parsing a, b, c := f()
|
||||
// the a, b, c gets parsed as references to older
|
||||
// a, b, c before the parser figures out this is a
|
||||
// declaration.
|
||||
v->op = 0;
|
||||
continue;
|
||||
}
|
||||
typecheck(&v->heapaddr, Erv);
|
||||
func->enter = list(func->enter, v->heapaddr);
|
||||
v->heapaddr = N;
|
||||
}
|
||||
}
|
||||
|
||||
Node*
|
||||
walkclosure(Node *func, NodeList **init)
|
||||
{
|
||||
int narg;
|
||||
Node *xtype, *v, *addr, *xfunc, *call, *clos;
|
||||
NodeList *l, *in;
|
||||
static int closgen;
|
||||
|
||||
/*
|
||||
* wrap body in external function
|
||||
* with extra closure parameters.
|
||||
*/
|
||||
xtype = nod(OTFUNC, N, N);
|
||||
|
||||
// each closure variable has a corresponding
|
||||
// address parameter.
|
||||
narg = 0;
|
||||
for(l=func->cvars; l; l=l->next) {
|
||||
v = l->n;
|
||||
if(v->op == 0)
|
||||
continue;
|
||||
addr = nod(ONAME, N, N);
|
||||
snprint(namebuf, sizeof namebuf, "&%s", v->sym->name);
|
||||
addr->sym = lookup(namebuf);
|
||||
addr->ntype = nod(OIND, typenod(v->type), N);
|
||||
addr->class = PPARAM;
|
||||
addr->addable = 1;
|
||||
addr->ullman = 1;
|
||||
narg++;
|
||||
|
||||
v->heapaddr = addr;
|
||||
|
||||
xtype->list = list(xtype->list, nod(ODCLFIELD, addr, addr->ntype));
|
||||
}
|
||||
|
||||
// then a dummy arg where the closure's caller pc sits
|
||||
xtype->list = list(xtype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
|
||||
|
||||
// then the function arguments
|
||||
xtype->list = concat(xtype->list, func->list);
|
||||
xtype->rlist = concat(xtype->rlist, func->rlist);
|
||||
|
||||
// create the function
|
||||
xfunc = nod(ODCLFUNC, N, N);
|
||||
snprint(namebuf, sizeof namebuf, "_f%.3ld·%s", ++closgen, filename);
|
||||
xfunc->nname = newname(lookup(namebuf));
|
||||
xfunc->nname->ntype = xtype;
|
||||
declare(xfunc->nname, PFUNC);
|
||||
xfunc->nname->funcdepth = func->funcdepth;
|
||||
xfunc->funcdepth = func->funcdepth;
|
||||
xfunc->nbody = func->nbody;
|
||||
xfunc->dcl = func->dcl;
|
||||
if(xfunc->nbody == nil)
|
||||
fatal("empty body - won't generate any code");
|
||||
typecheck(&xfunc, Etop);
|
||||
closures = list(closures, xfunc);
|
||||
|
||||
// prepare call of sys.closure that turns external func into func literal value.
|
||||
clos = syslook("closure", 1);
|
||||
clos->type = T;
|
||||
clos->ntype = nod(OTFUNC, N, N);
|
||||
in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // siz
|
||||
in = list(in, nod(ODCLFIELD, N, xtype));
|
||||
for(l=func->cvars; l; l=l->next) {
|
||||
if(l->n->op == 0)
|
||||
continue;
|
||||
in = list(in, nod(ODCLFIELD, N, l->n->heapaddr->ntype));
|
||||
}
|
||||
clos->ntype->list = in;
|
||||
clos->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(func->type)));
|
||||
typecheck(&clos, Erv);
|
||||
|
||||
call = nod(OCALL, clos, N);
|
||||
if(narg*widthptr > 100)
|
||||
yyerror("closure needs too many variables; runtime will reject it");
|
||||
in = list1(nodintconst(narg*widthptr));
|
||||
in = list(in, xfunc->nname);
|
||||
in = concat(in, func->enter);
|
||||
call->list = in;
|
||||
|
||||
typecheck(&call, Erv);
|
||||
walkexpr(&call, init);
|
||||
return call;
|
||||
}
|
@ -337,6 +337,7 @@ evconst(Node *n)
|
||||
case OMAKEMAP:
|
||||
case OMAKESLICE:
|
||||
case OMAKECHAN:
|
||||
case ODCLCONST:
|
||||
return;
|
||||
}
|
||||
|
||||
|
759
src/cmd/gc/dcl.c
759
src/cmd/gc/dcl.c
@ -5,6 +5,8 @@
|
||||
#include "go.h"
|
||||
#include "y.tab.h"
|
||||
|
||||
static void funcargs(Node*);
|
||||
|
||||
int
|
||||
dflag(void)
|
||||
{
|
||||
@ -50,6 +52,8 @@ pushdcl(Sym *s)
|
||||
|
||||
d = push();
|
||||
dcopy(d, s);
|
||||
if(dflag())
|
||||
print("\t%L push %S %p\n", lineno, s, s->def);
|
||||
return d;
|
||||
}
|
||||
|
||||
@ -67,7 +71,7 @@ popdcl(void)
|
||||
s = pkglookup(d->name, d->package);
|
||||
dcopy(s, d);
|
||||
if(dflag())
|
||||
print("\t%L pop %S\n", lineno, s);
|
||||
print("\t%L pop %S %p\n", lineno, s, s->def);
|
||||
}
|
||||
if(d == S)
|
||||
fatal("popdcl: no mark");
|
||||
@ -157,15 +161,21 @@ declare(Node *n, int ctxt)
|
||||
gen = 0;
|
||||
if(ctxt == PEXTERN) {
|
||||
externdcl = list(externdcl, n);
|
||||
if(dflag())
|
||||
print("\t%L global decl %S %p\n", lineno, s, n);
|
||||
} else {
|
||||
if(autodcl != nil)
|
||||
autodcl = list(autodcl, n);
|
||||
if(curfn == nil && ctxt == PAUTO)
|
||||
fatal("automatic outside function");
|
||||
if(curfn != nil)
|
||||
curfn->dcl = list(curfn->dcl, n);
|
||||
if(n->op == OTYPE)
|
||||
gen = ++typegen;
|
||||
else if(n->op == ONAME)
|
||||
gen = ++vargen;
|
||||
pushdcl(s);
|
||||
}
|
||||
if(ctxt == PAUTO)
|
||||
n->xoffset = BADWIDTH;
|
||||
|
||||
if(s->block == block) {
|
||||
what = "???";
|
||||
@ -181,7 +191,7 @@ declare(Node *n, int ctxt)
|
||||
break;
|
||||
}
|
||||
|
||||
yyerror("%s %S redeclared in this block", what, s);
|
||||
yyerror("%s %S redeclared in this block %d", what, s, block);
|
||||
print("\tprevious declaration at %L\n", s->lastlineno);
|
||||
}
|
||||
s->block = block;
|
||||
@ -205,6 +215,7 @@ addvar(Node *n, Type *t, int ctxt)
|
||||
n->type = t;
|
||||
}
|
||||
|
||||
// TODO: cut use of below in sigtype and then delete
|
||||
void
|
||||
addtyp(Type *n, int ctxt)
|
||||
{
|
||||
@ -220,35 +231,11 @@ addtyp(Type *n, int ctxt)
|
||||
typelist = list(typelist, def);
|
||||
}
|
||||
|
||||
/*
|
||||
* declare (possible list) n of type t.
|
||||
* append ODCL nodes to *init
|
||||
*/
|
||||
void
|
||||
dodclvar(Node *n, Type *t, NodeList **init)
|
||||
{
|
||||
if(n == N)
|
||||
return;
|
||||
|
||||
if(t != T && (t->etype == TIDEAL || t->etype == TNIL))
|
||||
fatal("dodclvar %T", t);
|
||||
dowidth(t);
|
||||
|
||||
// in case of type checking error,
|
||||
// use "undefined" type for variable type,
|
||||
// to avoid fatal in addvar.
|
||||
if(t == T)
|
||||
t = typ(TFORW);
|
||||
|
||||
addvar(n, t, dclcontext);
|
||||
if(funcdepth > 0)
|
||||
*init = list(*init, nod(ODCL, n, N));
|
||||
}
|
||||
|
||||
/*
|
||||
* introduce a type named n
|
||||
* but it is an unknown type for now
|
||||
*/
|
||||
// TODO(rsc): cut use of this in sigtype and then delete
|
||||
Type*
|
||||
dodcltype(Type *n)
|
||||
{
|
||||
@ -282,6 +269,7 @@ found:
|
||||
/*
|
||||
* now we know what n is: it's t
|
||||
*/
|
||||
// TODO(rsc): cut use of this in sigtype and then delete
|
||||
void
|
||||
updatetype(Type *n, Type *t)
|
||||
{
|
||||
@ -409,7 +397,7 @@ constiter(NodeList *vl, Node *t, NodeList *cl)
|
||||
Node *v, *c;
|
||||
NodeList *vv;
|
||||
|
||||
vv = vl;
|
||||
vv = nil;
|
||||
if(cl == nil) {
|
||||
if(t != N)
|
||||
yyerror("constdcl cannot have type without expr");
|
||||
@ -435,6 +423,8 @@ constiter(NodeList *vl, Node *t, NodeList *cl)
|
||||
|
||||
v->ntype = t;
|
||||
v->defn = c;
|
||||
|
||||
vv = list(vv, nod(ODCLCONST, v, N));
|
||||
}
|
||||
if(cl != nil)
|
||||
yyerror("extra expr in const dcl");
|
||||
@ -451,6 +441,9 @@ newname(Sym *s)
|
||||
{
|
||||
Node *n;
|
||||
|
||||
if(s == S)
|
||||
fatal("newname nil");
|
||||
|
||||
n = nod(ONAME, N, N);
|
||||
n->sym = s;
|
||||
n->type = T;
|
||||
@ -473,14 +466,15 @@ dclname(Sym *s)
|
||||
// top-level name: might already have been
|
||||
// referred to, in which case s->def is already
|
||||
// set to an ONONAME.
|
||||
if(dclcontext == PEXTERN && s->block == 0) {
|
||||
if(dclcontext == PEXTERN && s->block <= 1) {
|
||||
// toss predefined name like "close"
|
||||
// TODO(rsc): put close in at the end.
|
||||
if(s->def != N && s->def->etype)
|
||||
s->def = N;
|
||||
if(s->def == N)
|
||||
oldname(s);
|
||||
return s->def;
|
||||
if(s->def->op == ONONAME)
|
||||
return s->def;
|
||||
}
|
||||
|
||||
n = newname(s);
|
||||
@ -524,20 +518,19 @@ oldname(Sym *s)
|
||||
// inner func is referring to var
|
||||
// in outer func.
|
||||
if(n->closure == N || n->closure->funcdepth != funcdepth) {
|
||||
typecheck(&n, Erv);
|
||||
// create new closure var.
|
||||
c = nod(ONAME, N, N);
|
||||
c->sym = s;
|
||||
c->class = PPARAMREF;
|
||||
c->type = n->type;
|
||||
c->defn = n;
|
||||
c->addable = 0;
|
||||
c->ullman = 2;
|
||||
c->funcdepth = funcdepth;
|
||||
c->outer = n->closure;
|
||||
n->closure = c;
|
||||
c->closure = n;
|
||||
if(funclit != N)
|
||||
funclit->cvars = list(funclit->cvars, c);
|
||||
c->xoffset = 0;
|
||||
curfn->cvars = list(curfn->cvars, c);
|
||||
}
|
||||
// return ref to closure var, not original
|
||||
return n->closure;
|
||||
@ -644,6 +637,231 @@ colas(NodeList *left, NodeList *right)
|
||||
return as;
|
||||
}
|
||||
|
||||
/*
|
||||
* declare the function proper
|
||||
* and declare the arguments.
|
||||
* called in extern-declaration context
|
||||
* returns in auto-declaration context.
|
||||
*/
|
||||
void
|
||||
funchdr(Node *n)
|
||||
{
|
||||
Node *nt;
|
||||
|
||||
if(n->nname != N) {
|
||||
// TODO(rsc): remove once forward declarations are gone
|
||||
if(n->nname->sym->def && n->nname->sym->def->class == PFUNC) {
|
||||
nt = n->nname->ntype;
|
||||
n->nname = n->nname->sym->def;
|
||||
n->nname->ntype = nt;
|
||||
n->nname->type = T;
|
||||
} else {
|
||||
n->nname->op = ONAME;
|
||||
declare(n->nname, PFUNC);
|
||||
}
|
||||
}
|
||||
|
||||
// change the declaration context from extern to auto
|
||||
if(funcdepth == 0 && dclcontext != PEXTERN)
|
||||
fatal("funchdr: dclcontext");
|
||||
|
||||
dclcontext = PAUTO;
|
||||
markdcl();
|
||||
funcdepth++;
|
||||
|
||||
n->outer = curfn;
|
||||
curfn = n;
|
||||
if(n->nname)
|
||||
funcargs(n->nname->ntype);
|
||||
else
|
||||
funcargs(n->ntype);
|
||||
}
|
||||
|
||||
static void
|
||||
funcargs(Node *nt)
|
||||
{
|
||||
Node *n;
|
||||
NodeList *l;
|
||||
|
||||
if(nt->op != OTFUNC)
|
||||
fatal("funcargs %O", nt->op);
|
||||
|
||||
// declare the receiver and in arguments.
|
||||
// no n->defn because type checking of func header
|
||||
// will fill in the types before we can demand them.
|
||||
if(nt->left != N) {
|
||||
n = nt->left;
|
||||
if(n->op != ODCLFIELD)
|
||||
fatal("funcargs1 %O", n->op);
|
||||
if(n->left != N) {
|
||||
n->left->op = ONAME;
|
||||
n->left->ntype = n->right;
|
||||
declare(n->left, PPARAM);
|
||||
}
|
||||
}
|
||||
for(l=nt->list; l; l=l->next) {
|
||||
n = l->n;
|
||||
if(n->op != ODCLFIELD)
|
||||
fatal("funcargs2 %O", n->op);
|
||||
if(n->left != N) {
|
||||
n->left->op = ONAME;
|
||||
n->left->ntype = n->right;
|
||||
declare(n->left, PPARAM);
|
||||
}
|
||||
}
|
||||
|
||||
// declare the out arguments.
|
||||
for(l=nt->rlist; l; l=l->next) {
|
||||
n = l->n;
|
||||
if(n->op != ODCLFIELD)
|
||||
fatal("funcargs3 %O", n->op);
|
||||
if(n->left != N) {
|
||||
n->left->op = ONAME;
|
||||
n->left->ntype = n->right;
|
||||
declare(n->left, PPARAMOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* finish the body.
|
||||
* called in auto-declaration context.
|
||||
* returns in extern-declaration context.
|
||||
*/
|
||||
void
|
||||
funcbody(Node *n)
|
||||
{
|
||||
// change the declaration context from auto to extern
|
||||
if(dclcontext != PAUTO)
|
||||
fatal("funcbody: dclcontext");
|
||||
popdcl();
|
||||
funcdepth--;
|
||||
curfn = n->outer;
|
||||
n->outer = N;
|
||||
if(funcdepth == 0)
|
||||
dclcontext = PEXTERN;
|
||||
}
|
||||
|
||||
/*
|
||||
* forward declarations of types
|
||||
* TODO(rsc): delete!
|
||||
*/
|
||||
|
||||
/*
|
||||
* new type being defined with name s.
|
||||
*/
|
||||
Node*
|
||||
typedcl0(Sym *s)
|
||||
{
|
||||
Node *o, *ot, *n;
|
||||
int et;
|
||||
|
||||
// TODO(rsc): throw away once forward declarations are gone
|
||||
if((o = s->def) != N && o != N && o->op == OTYPE && s->block == block) {
|
||||
if((ot = o->ntype) != N && ot->op == OTYPE && ot->type != T)
|
||||
if((et = ot->type->etype) == TFORWSTRUCT || et == TFORWINTER) {
|
||||
// local forward declaration exists!
|
||||
// use it instead of the node we just created.
|
||||
if(ot->walkdef || ot->typecheck)
|
||||
fatal("someone looked at the fwd decl");
|
||||
return o;
|
||||
}
|
||||
|
||||
if(o->type && ((et = o->type->etype) == TFORWSTRUCT || et == TFORWINTER)) {
|
||||
// imported forward declaration exists.
|
||||
// attach the fwd type to the node we just
|
||||
// created, so that when we define the type in walkdef
|
||||
// we will overwrite the fwd version.
|
||||
o->nincr = nod(OXXX, N, N);
|
||||
o->nincr->type = o->type;
|
||||
o->type = T;
|
||||
o->walkdef = 0;
|
||||
o->typecheck = 0;
|
||||
autoexport(o, PEXTERN);
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
// make a new one
|
||||
n = dclname(s);
|
||||
n->op = OTYPE;
|
||||
declare(n, dclcontext);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* node n, which was returned by typedcl0
|
||||
* is being declared to have uncompiled type t. if n was previously forward
|
||||
* declared, update the forward declaration and undo the dclname.
|
||||
* extra tricky because we have to deal with imported forward declarations.
|
||||
* return the ODCLTYPE node to use.
|
||||
*/
|
||||
Node*
|
||||
typedcl1(Node *n, Node *t, int local)
|
||||
{
|
||||
n->ntype = t;
|
||||
n->local = local;
|
||||
return nod(ODCLTYPE, n, N);
|
||||
}
|
||||
|
||||
/*
|
||||
* node n, which was returned by dclname (newname for imports)
|
||||
* is being forward declared as et (TFORWSTRUCT or TFORWINTER).
|
||||
* if n was previously forward declared, scream.
|
||||
* return the ODCLTYPE node to use.
|
||||
*/
|
||||
Node*
|
||||
fwdtype(Node *n, int et)
|
||||
{
|
||||
n->op = OTYPE;
|
||||
n->ntype = typenod(typ(et));
|
||||
return nod(ODCLTYPE, n, N);
|
||||
}
|
||||
|
||||
/*
|
||||
* typedcl1 but during imports
|
||||
*/
|
||||
void
|
||||
typedcl2(Type *pt, Type *t)
|
||||
{
|
||||
Node *n;
|
||||
|
||||
if(pt->etype == TFORW)
|
||||
goto ok;
|
||||
if(pt->etype == TFORWSTRUCT && t->etype == TSTRUCT)
|
||||
goto ok;
|
||||
if(pt->etype == TFORWINTER && t->etype == TINTER)
|
||||
goto ok;
|
||||
if(pt->etype == TSTRUCT && t->etype == TFORWSTRUCT)
|
||||
return;
|
||||
if(pt->etype == TINTER && t->etype == TFORWINTER)
|
||||
return;
|
||||
if(!cvttype(pt, t)) {
|
||||
yyerror("redeclaration of %T during imports\n\t%lT [%p]\n\t%lT [%p]", pt, pt, pt, t, t);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
ok:
|
||||
n = pt->nod;
|
||||
*pt = *t;
|
||||
pt->method = nil;
|
||||
pt->nod = n;
|
||||
pt->sym = n->sym;
|
||||
declare(n, PEXTERN);
|
||||
|
||||
switch(pt->etype) {
|
||||
case TFORWINTER:
|
||||
case TFORWSTRUCT:
|
||||
// allow re-export in case it gets defined
|
||||
pt->sym->flags &= ~(SymExport|SymPackage);
|
||||
pt->sym->flags &= ~SymImported;
|
||||
break;
|
||||
default:
|
||||
checkwidth(pt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* structs, functions, and methods.
|
||||
@ -675,6 +893,8 @@ stotype(NodeList *l, int et, Type **t)
|
||||
if(n->right != N) {
|
||||
typecheck(&n->right, Etype);
|
||||
n->type = n->right->type;
|
||||
if(n->left != N)
|
||||
n->left->type = n->type;
|
||||
n->right = N;
|
||||
if(n->embedded && n->type != T) {
|
||||
t1 = n->type;
|
||||
@ -791,14 +1011,15 @@ embedded(Sym *s)
|
||||
}
|
||||
|
||||
n = newname(lookup(name));
|
||||
n = nod(ODCLFIELD, n, N);
|
||||
n = nod(ODCLFIELD, n, oldname(s));
|
||||
n->embedded = 1;
|
||||
if(s == S)
|
||||
return n;
|
||||
n->right = oldname(s);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* check that the list of declarations is either all anonymous or all named
|
||||
*/
|
||||
|
||||
static Node*
|
||||
findtype(NodeList *l)
|
||||
{
|
||||
@ -808,59 +1029,11 @@ findtype(NodeList *l)
|
||||
return N;
|
||||
}
|
||||
|
||||
static Node*
|
||||
xanondcl(Node *nt)
|
||||
{
|
||||
Node *n;
|
||||
Type *t;
|
||||
|
||||
typecheck(&nt, Etype);
|
||||
t = nt->type;
|
||||
if(nt->op != OTYPE) {
|
||||
yyerror("%S is not a type", nt->sym);
|
||||
t = types[TINT32];
|
||||
}
|
||||
n = nod(ODCLFIELD, N, N);
|
||||
n->type = t;
|
||||
return n;
|
||||
}
|
||||
|
||||
static Node*
|
||||
namedcl(Node *nn, Node *nt)
|
||||
{
|
||||
Node *n;
|
||||
Type *t;
|
||||
|
||||
if(nn->op == OKEY)
|
||||
nn = nn->left;
|
||||
if(nn->sym == S) {
|
||||
typecheck(&nn, Etype);
|
||||
yyerror("cannot mix anonymous %T with named arguments", nn->type);
|
||||
return xanondcl(nn);
|
||||
}
|
||||
t = types[TINT32];
|
||||
if(nt == N)
|
||||
yyerror("missing type for argument %S", nn->sym);
|
||||
else {
|
||||
typecheck(&nt, Etype);
|
||||
if(nt->op != OTYPE)
|
||||
yyerror("%S is not a type", nt->sym);
|
||||
else
|
||||
t = nt->type;
|
||||
}
|
||||
n = nod(ODCLFIELD, newname(nn->sym), N);
|
||||
n->type = t;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* check that the list of declarations is either all anonymous or all named
|
||||
*/
|
||||
NodeList*
|
||||
checkarglist(NodeList *all)
|
||||
{
|
||||
int named;
|
||||
Node *r;
|
||||
Node *n, *t, *nextt;
|
||||
NodeList *l;
|
||||
|
||||
named = 0;
|
||||
@ -870,17 +1043,51 @@ checkarglist(NodeList *all)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(l=all; l; l=l->next) {
|
||||
if(named)
|
||||
l->n = namedcl(l->n, findtype(l));
|
||||
else
|
||||
l->n = xanondcl(l->n);
|
||||
if(l->next != nil) {
|
||||
r = l->n;
|
||||
if(r != N && r->type != T && r->type->etype == TDDD)
|
||||
yyerror("only last argument can have type ...");
|
||||
if(named) {
|
||||
n = N;
|
||||
for(l=all; l; l=l->next) {
|
||||
n = l->n;
|
||||
if(n->op != OKEY && n->sym == S) {
|
||||
yyerror("mixed named and unnamed function parameters");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(l == nil && n != N && n->op != OKEY)
|
||||
yyerror("final function parameter must have type");
|
||||
}
|
||||
|
||||
nextt = nil;
|
||||
for(l=all; l; l=l->next) {
|
||||
// can cache result from findtype to avoid
|
||||
// quadratic behavior here, but unlikely to matter.
|
||||
n = l->n;
|
||||
if(named) {
|
||||
if(n->op == OKEY) {
|
||||
t = n->right;
|
||||
n = n->left;
|
||||
nextt = nil;
|
||||
} else {
|
||||
if(nextt == nil)
|
||||
nextt = findtype(l);
|
||||
t = nextt;
|
||||
}
|
||||
} else {
|
||||
t = n;
|
||||
n = N;
|
||||
}
|
||||
if(n != N && n->sym == S) {
|
||||
t = n;
|
||||
n = N;
|
||||
}
|
||||
if(n != N) {
|
||||
if(n->op == ONONAME && n->sym->def == n)
|
||||
n->sym->def = N;
|
||||
n = newname(n->sym);
|
||||
}
|
||||
n = nod(ODCLFIELD, n, t);
|
||||
if(l->next != nil && n->right != N && n->right->op == OTYPE && isddd(n->right->type))
|
||||
yyerror("only last argument can have type ...");
|
||||
l->n = n;
|
||||
}
|
||||
return all;
|
||||
}
|
||||
@ -891,8 +1098,7 @@ fakethis(void)
|
||||
{
|
||||
Node *n;
|
||||
|
||||
n = nod(ODCLFIELD, N, N);
|
||||
n->type = ptrto(typ(TSTRUCT));
|
||||
n = nod(ODCLFIELD, N, typenod(ptrto(typ(TSTRUCT))));
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -943,8 +1149,8 @@ functype(Node *this, NodeList *in, NodeList *out)
|
||||
t->thistuple = 1;
|
||||
t->outtuple = count(out);
|
||||
t->intuple = count(in);
|
||||
t->outnamed = t->outtuple > 0 && out->n->left != N;
|
||||
|
||||
checkwidth(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -1003,7 +1209,6 @@ methodsym(Sym *nsym, Type *t0)
|
||||
t0 = ptrto(t);
|
||||
|
||||
snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name);
|
||||
//print("methodname %s\n", buf);
|
||||
return pkglookup(buf, s->package);
|
||||
|
||||
bad:
|
||||
@ -1022,42 +1227,52 @@ methodname(Node *n, Type *t)
|
||||
return newname(s);
|
||||
}
|
||||
|
||||
Node*
|
||||
methodname1(Node *n, Node *t)
|
||||
{
|
||||
char *star;
|
||||
char buf[NSYMB];
|
||||
|
||||
star = "";
|
||||
if(t->op == OIND) {
|
||||
star = "*";
|
||||
t = t->left;
|
||||
}
|
||||
if(t->sym == S)
|
||||
return n;
|
||||
snprint(buf, sizeof(buf), "%s%S·%S", star, t->sym, n->sym);
|
||||
return newname(pkglookup(buf, t->sym->package));
|
||||
}
|
||||
|
||||
/*
|
||||
* add a method, declared as a function,
|
||||
* n is fieldname, pa is base type, t is function type
|
||||
*/
|
||||
void
|
||||
addmethod(Node *n, Type *t, int local)
|
||||
addmethod(Sym *sf, Type *t, int local)
|
||||
{
|
||||
Type *f, *d, *pa;
|
||||
Sym *sf;
|
||||
Node *n;
|
||||
|
||||
pa = nil;
|
||||
sf = nil;
|
||||
|
||||
// get field sym
|
||||
if(n == N)
|
||||
goto bad;
|
||||
if(n->op != ONAME)
|
||||
goto bad;
|
||||
sf = n->sym;
|
||||
if(sf == S)
|
||||
goto bad;
|
||||
fatal("no method symbol");
|
||||
|
||||
// get parent type sym
|
||||
pa = *getthis(t); // ptr to this structure
|
||||
if(pa == T)
|
||||
goto bad;
|
||||
pa = pa->type; // ptr to this field
|
||||
if(pa == T)
|
||||
goto bad;
|
||||
pa = pa->type; // ptr to this type
|
||||
if(pa == T)
|
||||
goto bad;
|
||||
pa = getthisx(t)->type; // ptr to this structure
|
||||
if(pa == T) {
|
||||
yyerror("missing receiver");
|
||||
return;
|
||||
}
|
||||
|
||||
pa = pa->type;
|
||||
f = methtype(pa);
|
||||
if(f == T)
|
||||
goto bad;
|
||||
if(f == T) {
|
||||
yyerror("invalid receiver type %T", pa);
|
||||
return;
|
||||
}
|
||||
|
||||
pa = f;
|
||||
if(pkgimportname != S && !exportname(sf->name))
|
||||
@ -1093,295 +1308,35 @@ addmethod(Node *n, Type *t, int local)
|
||||
else
|
||||
stotype(list1(n), 0, &d->down);
|
||||
return;
|
||||
|
||||
bad:
|
||||
yyerror("invalid receiver type %T", pa);
|
||||
}
|
||||
|
||||
/*
|
||||
* declare the function proper.
|
||||
* and declare the arguments
|
||||
* called in extern-declaration context
|
||||
* returns in auto-declaration context.
|
||||
*/
|
||||
void
|
||||
funchdr(Node *n)
|
||||
funccompile(Node *n)
|
||||
{
|
||||
Node *on;
|
||||
Sym *s;
|
||||
stksize = BADWIDTH;
|
||||
maxarg = 0;
|
||||
|
||||
s = n->nname->sym;
|
||||
on = s->def;
|
||||
if(on != N && (on->op != ONAME || on->builtin))
|
||||
on = N;
|
||||
|
||||
// check for same types
|
||||
if(on != N) {
|
||||
if(eqtype(n->type, on->type)) {
|
||||
if(!eqargs(n->type, on->type)) {
|
||||
yyerror("function arg names changed: %S", s);
|
||||
print("\t%T\n\t%T\n", on->type, n->type);
|
||||
}
|
||||
} else {
|
||||
yyerror("function redeclared: %S", s);
|
||||
print("\t%T\n\t%T\n", on->type, n->type);
|
||||
on = N;
|
||||
}
|
||||
if(n->type == T) {
|
||||
if(nerrors == 0)
|
||||
fatal("funccompile missing type");
|
||||
return;
|
||||
}
|
||||
|
||||
// check for forward declaration
|
||||
if(on == N) {
|
||||
// initial declaration or redeclaration
|
||||
// declare fun name, argument types and argument names
|
||||
n->nname->type = n->type;
|
||||
if(n->type->thistuple == 0)
|
||||
addvar(n->nname, n->type, PFUNC);
|
||||
else
|
||||
n->nname->class = PFUNC;
|
||||
} else {
|
||||
// identical redeclaration
|
||||
// steal previous names
|
||||
n->nname = on;
|
||||
n->type = on->type;
|
||||
n->class = on->class;
|
||||
n->sym = s;
|
||||
}
|
||||
// assign parameter offsets
|
||||
checkwidth(n->type);
|
||||
|
||||
// change the declaration context from extern to auto
|
||||
autodcl = list1(nod(OXXX, N, N));
|
||||
|
||||
if(funcdepth == 0 && dclcontext != PEXTERN)
|
||||
fatal("funchdr: dclcontext");
|
||||
if(curfn)
|
||||
fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym);
|
||||
curfn = n;
|
||||
typechecklist(n->nbody, Etop);
|
||||
curfn = nil;
|
||||
|
||||
stksize = 0;
|
||||
dclcontext = PAUTO;
|
||||
markdcl();
|
||||
funcargs(n->type);
|
||||
}
|
||||
|
||||
void
|
||||
funcargs(Type *ft)
|
||||
{
|
||||
Type *t;
|
||||
Iter save;
|
||||
int all;
|
||||
|
||||
funcdepth++;
|
||||
|
||||
// declare the this/in arguments
|
||||
t = funcfirst(&save, ft);
|
||||
while(t != T) {
|
||||
if(t->nname != N) {
|
||||
t->nname->xoffset = t->width;
|
||||
addvar(t->nname, t->type, PPARAM);
|
||||
}
|
||||
t = funcnext(&save);
|
||||
}
|
||||
|
||||
// declare the outgoing arguments
|
||||
all = 0;
|
||||
t = structfirst(&save, getoutarg(ft));
|
||||
while(t != T) {
|
||||
if(t->nname != N)
|
||||
t->nname->xoffset = t->width;
|
||||
if(t->nname != N) {
|
||||
addvar(t->nname, t->type, PPARAMOUT);
|
||||
all |= 1;
|
||||
} else
|
||||
all |= 2;
|
||||
t = structnext(&save);
|
||||
}
|
||||
|
||||
// this test is remarkedly similar to checkarglist
|
||||
if(all == 3)
|
||||
yyerror("cannot mix anonymous and named output arguments");
|
||||
|
||||
ft->outnamed = 0;
|
||||
if(all == 1)
|
||||
ft->outnamed = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* compile the function.
|
||||
* called in auto-declaration context.
|
||||
* returns in extern-declaration context.
|
||||
*/
|
||||
void
|
||||
funcbody(Node *n)
|
||||
{
|
||||
|
||||
funcdepth = n->funcdepth + 1;
|
||||
compile(n);
|
||||
|
||||
// change the declaration context from auto to extern
|
||||
if(dclcontext != PAUTO)
|
||||
fatal("funcbody: dclcontext");
|
||||
popdcl();
|
||||
funcdepth--;
|
||||
if(funcdepth == 0)
|
||||
dclcontext = PEXTERN;
|
||||
curfn = nil;
|
||||
funcdepth = 0;
|
||||
dclcontext = PEXTERN;
|
||||
}
|
||||
|
||||
Node*
|
||||
funclit0(Node *t)
|
||||
{
|
||||
Node *n;
|
||||
|
||||
n = nod(OXXX, N, N);
|
||||
n->outer = funclit;
|
||||
n->dcl = autodcl;
|
||||
funclit = n;
|
||||
|
||||
// new declaration context
|
||||
autodcl = list1(nod(OEMPTY, N, N));
|
||||
|
||||
typecheck(&t, Etype);
|
||||
funcargs(t->type);
|
||||
return t;
|
||||
}
|
||||
|
||||
Node*
|
||||
funclit1(Node *ntype, NodeList *body)
|
||||
{
|
||||
Node *func;
|
||||
Type *type;
|
||||
Node *a, *d, *f, *n, *clos;
|
||||
Type *ft, *t;
|
||||
Iter save;
|
||||
int narg, shift;
|
||||
NodeList *args, *l, *in, *out;
|
||||
static int closgen;
|
||||
|
||||
type = ntype->type;
|
||||
popdcl();
|
||||
func = funclit;
|
||||
funclit = func->outer;
|
||||
|
||||
// build up type of func f that we're going to compile.
|
||||
// as we referred to variables from the outer function,
|
||||
// we accumulated a list of PHEAP names in func->cvars.
|
||||
narg = 0;
|
||||
// add PHEAP versions as function arguments.
|
||||
in = nil;
|
||||
for(l=func->cvars; l; l=l->next) {
|
||||
a = l->n;
|
||||
d = nod(ODCLFIELD, a, N);
|
||||
d->type = ptrto(a->type);
|
||||
in = list(in, d);
|
||||
|
||||
// while we're here, set up a->heapaddr for back end
|
||||
n = nod(ONAME, N, N);
|
||||
snprint(namebuf, sizeof namebuf, "&%s", a->sym->name);
|
||||
n->sym = lookup(namebuf);
|
||||
n->type = ptrto(a->type);
|
||||
n->class = PPARAM;
|
||||
n->xoffset = narg*types[tptr]->width;
|
||||
n->addable = 1;
|
||||
n->ullman = 1;
|
||||
narg++;
|
||||
a->heapaddr = n;
|
||||
|
||||
a->xoffset = 0;
|
||||
|
||||
// unlink from actual ONAME in symbol table
|
||||
a->closure->closure = a->outer;
|
||||
}
|
||||
|
||||
// add a dummy arg for the closure's caller pc
|
||||
d = nod(ODCLFIELD, N, N);
|
||||
d->type = types[TUINTPTR];
|
||||
in = list(in, d);
|
||||
|
||||
// slide param offset to make room for ptrs above.
|
||||
// narg+1 to skip over caller pc.
|
||||
shift = (narg+1)*types[tptr]->width;
|
||||
|
||||
// now the original arguments.
|
||||
for(t=structfirst(&save, getinarg(type)); t; t=structnext(&save)) {
|
||||
d = nod(ODCLFIELD, t->nname, N);
|
||||
d->type = t->type;
|
||||
in = list(in, d);
|
||||
|
||||
a = t->nname;
|
||||
if(a != N) {
|
||||
if(a->stackparam != N)
|
||||
a = a->stackparam;
|
||||
a->xoffset += shift;
|
||||
}
|
||||
}
|
||||
|
||||
// out arguments
|
||||
out = nil;
|
||||
for(t=structfirst(&save, getoutarg(type)); t; t=structnext(&save)) {
|
||||
d = nod(ODCLFIELD, t->nname, N);
|
||||
d->type = t->type;
|
||||
out = list(out, d);
|
||||
|
||||
a = t->nname;
|
||||
if(a != N) {
|
||||
if(a->stackparam != N)
|
||||
a = a->stackparam;
|
||||
a->xoffset += shift;
|
||||
}
|
||||
}
|
||||
|
||||
ft = functype(N, in, out);
|
||||
ft->outnamed = type->outnamed;
|
||||
|
||||
// declare function.
|
||||
snprint(namebuf, sizeof(namebuf), "_f%.3ld·%s", ++closgen, filename);
|
||||
f = newname(lookup(namebuf));
|
||||
addvar(f, ft, PFUNC);
|
||||
f->funcdepth = 0;
|
||||
|
||||
// compile function
|
||||
n = nod(ODCLFUNC, N, N);
|
||||
n->nname = f;
|
||||
n->type = ft;
|
||||
if(body == nil)
|
||||
body = list1(nod(OEMPTY, N, N));
|
||||
n->nbody = body;
|
||||
compile(n);
|
||||
funcdepth--;
|
||||
autodcl = func->dcl;
|
||||
|
||||
// build up type for this instance of the closure func.
|
||||
in = nil;
|
||||
d = nod(ODCLFIELD, N, N); // siz
|
||||
d->type = types[TINT];
|
||||
in = list(in, d);
|
||||
d = nod(ODCLFIELD, N, N); // f
|
||||
d->type = ft;
|
||||
in = list(in, d);
|
||||
for(l=func->cvars; l; l=l->next) {
|
||||
a = l->n;
|
||||
d = nod(ODCLFIELD, N, N); // arg
|
||||
d->type = ptrto(a->type);
|
||||
in = list(in, d);
|
||||
}
|
||||
|
||||
d = nod(ODCLFIELD, N, N);
|
||||
d->type = type;
|
||||
out = list1(d);
|
||||
|
||||
clos = syslook("closure", 1);
|
||||
clos->type = functype(N, in, out);
|
||||
|
||||
// literal expression is sys.closure(siz, f, arg0, arg1, ...)
|
||||
// which builds a function that calls f after filling in arg0,
|
||||
// arg1, ... for the PHEAP arguments above.
|
||||
args = nil;
|
||||
if(narg*widthptr > 100)
|
||||
yyerror("closure needs too many variables; runtime will reject it");
|
||||
a = nodintconst(narg*widthptr);
|
||||
args = list(args, a); // siz
|
||||
args = list(args, f); // f
|
||||
for(l=func->cvars; l; l=l->next) {
|
||||
a = l->n;
|
||||
d = oldname(a->sym);
|
||||
args = list(args, nod(OADDR, d, N));
|
||||
}
|
||||
typechecklist(args, Erv);
|
||||
|
||||
n = nod(OCALL, clos, N);
|
||||
n->list = args;
|
||||
return n;
|
||||
}
|
||||
|
@ -61,6 +61,8 @@ autoexport(Node *n, int ctxt)
|
||||
return;
|
||||
if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
|
||||
return;
|
||||
if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left) // method
|
||||
return;
|
||||
if(exportname(n->sym->name) || strcmp(n->sym->name, "init") == 0)
|
||||
exportsym(n);
|
||||
else
|
||||
@ -347,7 +349,6 @@ importvar(Sym *s, Type *t, int ctxt)
|
||||
warn("redeclare import var %S from %T to %T",
|
||||
s, s->def->type, t);
|
||||
}
|
||||
checkwidth(t);
|
||||
n = newname(s);
|
||||
n->type = t;
|
||||
declare(n, ctxt);
|
||||
@ -357,56 +358,19 @@ importvar(Sym *s, Type *t, int ctxt)
|
||||
}
|
||||
|
||||
void
|
||||
importtype(Sym *s, Type *t)
|
||||
importtype(Type *pt, Type *t)
|
||||
{
|
||||
Node *n;
|
||||
Type *tt;
|
||||
|
||||
importsym(s, OTYPE);
|
||||
n = s->def;
|
||||
if(n != N && n->op == OTYPE) {
|
||||
if(cvttype(t, n->type))
|
||||
return;
|
||||
if(t->etype == TFORWSTRUCT && n->type->etype == TSTRUCT)
|
||||
return;
|
||||
if(t->etype == TFORWINTER && n->type->etype == TINTER)
|
||||
return;
|
||||
if(n->type->etype != TFORW && n->type->etype != TFORWSTRUCT && n->type->etype != TFORWINTER) {
|
||||
yyerror("redeclare import type %S from %lT to %lT", s, n->type, t);
|
||||
n = s->def = typenod(typ(0));
|
||||
}
|
||||
}
|
||||
if(n == N || n->op != OTYPE) {
|
||||
tt = typ(0);
|
||||
tt->sym = s;
|
||||
n = typenod(tt);
|
||||
s->def = n;
|
||||
}
|
||||
if(n->type == T)
|
||||
n->type = typ(0);
|
||||
*n->type = *t;
|
||||
n->type->sym = s;
|
||||
n->type->nod = n;
|
||||
switch(n->type->etype) {
|
||||
case TFORWINTER:
|
||||
case TFORWSTRUCT:
|
||||
// allow re-export in case it gets defined
|
||||
s->flags &= ~(SymExport|SymPackage);
|
||||
s->flags &= ~SymImported;
|
||||
break;
|
||||
default:
|
||||
checkwidth(n->type);
|
||||
}
|
||||
typedcl2(pt, t);
|
||||
|
||||
if(debug['E'])
|
||||
print("import type %S %lT\n", s, t);
|
||||
print("import type %T %lT\n", pt, t);
|
||||
}
|
||||
|
||||
void
|
||||
importmethod(Sym *s, Type *t)
|
||||
{
|
||||
checkwidth(t);
|
||||
addmethod(newname(s), t, 0);
|
||||
addmethod(s, t, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
106
src/cmd/gc/gen.c
106
src/cmd/gc/gen.c
@ -25,14 +25,25 @@ allocparams(void)
|
||||
NodeList *l;
|
||||
Node *n;
|
||||
uint32 w;
|
||||
Sym *s;
|
||||
|
||||
if(stksize < 0)
|
||||
fatal("allocparams not during code generation");
|
||||
|
||||
/*
|
||||
* allocate (set xoffset) the stack
|
||||
* slots for all automatics.
|
||||
* allocated starting at -w down.
|
||||
*/
|
||||
for(l=autodcl; l; l=l->next) {
|
||||
for(l=curfn->dcl; l; l=l->next) {
|
||||
n = l->n;
|
||||
if(n->op == ONAME && n->class == PHEAP-1) {
|
||||
// heap address variable; finish the job
|
||||
// started in addrescapes.
|
||||
s = n->sym;
|
||||
tempname(n, n->type);
|
||||
n->sym = s;
|
||||
}
|
||||
if(n->op != ONAME || n->class != PAUTO)
|
||||
continue;
|
||||
typecheck(&n, Erv); // only needed for unused variables
|
||||
@ -42,9 +53,10 @@ allocparams(void)
|
||||
w = n->type->width;
|
||||
if(n->class & PHEAP)
|
||||
w = widthptr;
|
||||
if(w >= 100000000)
|
||||
fatal("bad width");
|
||||
stksize += w;
|
||||
stksize = rnd(stksize, w);
|
||||
|
||||
n->xoffset = -stksize;
|
||||
}
|
||||
}
|
||||
@ -161,6 +173,9 @@ gen(Node *n)
|
||||
case OFALL:
|
||||
case OXCASE:
|
||||
case OXFALL:
|
||||
case ODCLCONST:
|
||||
case ODCLFUNC:
|
||||
case ODCLTYPE:
|
||||
break;
|
||||
|
||||
case OEMPTY:
|
||||
@ -511,3 +526,90 @@ cgen_as(Node *nl, Node *nr)
|
||||
ret:
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* gather series of offsets
|
||||
* >=0 is direct addressed field
|
||||
* <0 is pointer to next field (+1)
|
||||
*/
|
||||
int
|
||||
dotoffset(Node *n, int *oary, Node **nn)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch(n->op) {
|
||||
case ODOT:
|
||||
if(n->xoffset == BADWIDTH) {
|
||||
dump("bad width in dotoffset", n);
|
||||
fatal("bad width in dotoffset");
|
||||
}
|
||||
i = dotoffset(n->left, oary, nn);
|
||||
if(i > 0) {
|
||||
if(oary[i-1] >= 0)
|
||||
oary[i-1] += n->xoffset;
|
||||
else
|
||||
oary[i-1] -= n->xoffset;
|
||||
break;
|
||||
}
|
||||
if(i < 10)
|
||||
oary[i++] = n->xoffset;
|
||||
break;
|
||||
|
||||
case ODOTPTR:
|
||||
if(n->xoffset == BADWIDTH) {
|
||||
dump("bad width in dotoffset", n);
|
||||
fatal("bad width in dotoffset");
|
||||
}
|
||||
i = dotoffset(n->left, oary, nn);
|
||||
if(i < 10)
|
||||
oary[i++] = -(n->xoffset+1);
|
||||
break;
|
||||
|
||||
default:
|
||||
*nn = n;
|
||||
return 0;
|
||||
}
|
||||
if(i >= 10)
|
||||
*nn = N;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* make a new off the books
|
||||
*/
|
||||
void
|
||||
tempname(Node *n, Type *t)
|
||||
{
|
||||
Sym *s;
|
||||
uint32 w;
|
||||
|
||||
if(stksize < 0)
|
||||
fatal("tempname not during code generation");
|
||||
|
||||
if(t == T) {
|
||||
yyerror("tempname called with nil type");
|
||||
t = types[TINT32];
|
||||
}
|
||||
|
||||
// give each tmp a different name so that there
|
||||
// a chance to registerizer them
|
||||
snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
|
||||
statuniqgen++;
|
||||
s = lookup(namebuf);
|
||||
|
||||
memset(n, 0, sizeof(*n));
|
||||
n->op = ONAME;
|
||||
n->sym = s;
|
||||
n->type = t;
|
||||
n->class = PAUTO;
|
||||
n->addable = 1;
|
||||
n->ullman = 1;
|
||||
n->noescape = 1;
|
||||
|
||||
dowidth(t);
|
||||
w = t->width;
|
||||
stksize += w;
|
||||
stksize = rnd(stksize, w);
|
||||
n->xoffset = -stksize;
|
||||
}
|
||||
|
||||
|
@ -144,6 +144,7 @@ struct Type
|
||||
uchar funarg;
|
||||
uchar copyany;
|
||||
uchar local; // created in this file
|
||||
uchar deferwidth;
|
||||
|
||||
Node* nod; // canonical OTYPE node
|
||||
|
||||
@ -195,6 +196,7 @@ struct Node
|
||||
uchar builtin; // built-in name, like len or close
|
||||
uchar walkdef;
|
||||
uchar typecheck;
|
||||
uchar local;
|
||||
|
||||
// most nodes
|
||||
Node* left;
|
||||
@ -217,17 +219,15 @@ struct Node
|
||||
|
||||
// func
|
||||
Node* nname;
|
||||
Node* shortname;
|
||||
NodeList* enter;
|
||||
NodeList* exit;
|
||||
NodeList* cvars; // closure params
|
||||
NodeList* dcl; // outer autodcl
|
||||
NodeList* dcl; // autodcl for this func/closure
|
||||
|
||||
// OLITERAL/OREGISTER
|
||||
Val val;
|
||||
|
||||
// OTFUNC
|
||||
Node* rcvr;
|
||||
|
||||
// ONAME
|
||||
Node* ntype;
|
||||
Node* defn;
|
||||
@ -250,7 +250,7 @@ struct Node
|
||||
};
|
||||
#define N ((Node*)0)
|
||||
|
||||
struct NodeList
|
||||
struct NodeList
|
||||
{
|
||||
Node* n;
|
||||
NodeList* next;
|
||||
@ -327,11 +327,12 @@ enum
|
||||
OCAP,
|
||||
OCLOSE,
|
||||
OCLOSED,
|
||||
OCLOSURE,
|
||||
OCMPIFACE, OCMPSTR,
|
||||
OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
|
||||
OCOMPSLICE, OCOMPMAP,
|
||||
OCONV, OCONVNOP, OCONVA2S, OCONVIFACE, OCONVSLICE,
|
||||
ODCL, ODCLFUNC, ODCLFIELD, ODCLARG,
|
||||
ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
|
||||
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
|
||||
ODOTTYPE,
|
||||
OEQ, ONE, OLT, OLE, OGE, OGT,
|
||||
@ -624,8 +625,8 @@ EXTERN Mpint* maxintval[NTYPE];
|
||||
EXTERN Mpflt* minfltval[NTYPE];
|
||||
EXTERN Mpflt* maxfltval[NTYPE];
|
||||
|
||||
EXTERN NodeList* autodcl;
|
||||
EXTERN NodeList* externdcl;
|
||||
EXTERN NodeList* closures;
|
||||
EXTERN NodeList* exportlist;
|
||||
EXTERN NodeList* typelist;
|
||||
EXTERN int dclcontext; // PEXTERN/PAUTO
|
||||
@ -639,7 +640,6 @@ EXTERN NodeList* lastconst;
|
||||
EXTERN Node* lasttype;
|
||||
EXTERN int32 maxarg;
|
||||
EXTERN int32 stksize; // stack size for current frame
|
||||
EXTERN int32 initstksize; // stack size for init function
|
||||
EXTERN int32 blockgen; // max block number
|
||||
EXTERN int32 block; // current block number
|
||||
EXTERN int hasdefer; // flag that curfn has defer statetment
|
||||
@ -662,8 +662,8 @@ EXTERN int exporting;
|
||||
EXTERN int noargnames;
|
||||
|
||||
EXTERN int funcdepth;
|
||||
EXTERN int typecheckok;
|
||||
|
||||
EXTERN Node* funclit;
|
||||
|
||||
/*
|
||||
* y.tab.c
|
||||
@ -859,21 +859,20 @@ int simsimtype(Type*);
|
||||
* dcl.c
|
||||
*/
|
||||
void declare(Node*, int);
|
||||
void dodclvar(Node*, Type*, NodeList**);
|
||||
Type* dodcltype(Type*);
|
||||
void updatetype(Type*, Type*);
|
||||
void defaultlit(Node**, Type*);
|
||||
void defaultlit2(Node**, Node**, int);
|
||||
int structcount(Type*);
|
||||
void addmethod(Node*, Type*, int);
|
||||
void addmethod(Sym*, Type*, int);
|
||||
Node* methodname(Node*, Type*);
|
||||
Node* methodname1(Node*, Node*);
|
||||
Sym* methodsym(Sym*, Type*);
|
||||
Type* functype(Node*, NodeList*, NodeList*);
|
||||
char* thistypenam(Node*);
|
||||
void funcnam(Type*, char*);
|
||||
Node* renameinit(Node*);
|
||||
void funchdr(Node*);
|
||||
void funcargs(Type*);
|
||||
void funcbody(Node*);
|
||||
Node* typenod(Type*);
|
||||
Type* dostruct(NodeList*, int);
|
||||
@ -906,10 +905,23 @@ Node* embedded(Sym*);
|
||||
NodeList* variter(NodeList*, Node*, NodeList*);
|
||||
NodeList* constiter(NodeList*, Node*, NodeList*);
|
||||
|
||||
Node* funclit0(Node*);
|
||||
Node* funclit1(Node*, NodeList*);
|
||||
Node* unsafenmagic(Node*, NodeList*);
|
||||
void dclchecks(void);
|
||||
void funccompile(Node*);
|
||||
|
||||
Node* typedcl0(Sym*);
|
||||
Node* typedcl1(Node*, Node*, int);
|
||||
Node* fwdtype(Node*, int);
|
||||
void typedcl2(Type*, Type*);
|
||||
|
||||
/*
|
||||
* closure.c
|
||||
*/
|
||||
void closurehdr(Node*);
|
||||
Node* closurebody(NodeList*);
|
||||
void typecheckclosure(Node*);
|
||||
Node* walkclosure(Node*, NodeList**);
|
||||
|
||||
|
||||
/*
|
||||
* sinit.c
|
||||
@ -932,10 +944,11 @@ void dumpexportvar(Sym*);
|
||||
void dumpexportconst(Sym*);
|
||||
void importconst(Sym *s, Type *t, Node *v);
|
||||
void importmethod(Sym *s, Type *t);
|
||||
void importtype(Sym *s, Type *t);
|
||||
void importtype(Type *s, Type *t);
|
||||
void importvar(Sym *s, Type *t, int ctxt);
|
||||
void checkimports(void);
|
||||
Type* pkgtype(Sym*);
|
||||
Sym* importsym(Sym*, int);
|
||||
|
||||
/*
|
||||
* walk.c
|
||||
|
168
src/cmd/gc/go.y
168
src/cmd/gc/go.y
@ -56,7 +56,7 @@
|
||||
%type <node> for_body for_header for_stmt if_header if_stmt
|
||||
%type <node> keyval labelname name
|
||||
%type <node> name_or_type non_expr_type
|
||||
%type <node> new_name dcl_name oexpr
|
||||
%type <node> new_name dcl_name oexpr typedclname
|
||||
%type <node> onew_name
|
||||
%type <node> osimple_stmt pexpr
|
||||
%type <node> pseudocall range_stmt select_stmt
|
||||
@ -72,8 +72,7 @@
|
||||
|
||||
%type <node> convtype dotdotdot
|
||||
%type <node> indcl interfacetype structtype ptrtype
|
||||
%type <type> new_type typedclname
|
||||
%type <node> chantype non_chan_type othertype non_fn_type fntype fnlitdcl
|
||||
%type <node> chantype non_chan_type othertype non_fn_type fntype
|
||||
|
||||
%type <sym> hidden_importsym hidden_pkg_importsym
|
||||
|
||||
@ -85,7 +84,7 @@
|
||||
%type <list> hidden_interfacedcl_list ohidden_interfacedcl_list
|
||||
%type <list> hidden_structdcl_list ohidden_structdcl_list
|
||||
|
||||
%type <type> hidden_type hidden_type1 hidden_type2
|
||||
%type <type> hidden_type hidden_type1 hidden_type2 hidden_pkgtype
|
||||
|
||||
%left LOROR
|
||||
%left LANDAND
|
||||
@ -121,13 +120,28 @@ file:
|
||||
imports
|
||||
xdcl_list
|
||||
{
|
||||
if(debug['f'])
|
||||
frame(1);
|
||||
typechecklist($4, Etop);
|
||||
if(nerrors == 0)
|
||||
fninit($4);
|
||||
NodeList *l;
|
||||
|
||||
if(nsyntaxerrors == 0)
|
||||
testdclstack();
|
||||
|
||||
typecheckok = 1;
|
||||
if(debug['f'])
|
||||
frame(1);
|
||||
defercheckwidth();
|
||||
typechecklist($4, Etop);
|
||||
resumecheckwidth();
|
||||
for(l=$4; l; l=l->next)
|
||||
if(l->n->op == ODCLFUNC)
|
||||
funccompile(l->n);
|
||||
if(nerrors == 0)
|
||||
fninit($4);
|
||||
while(closures) {
|
||||
l = closures;
|
||||
closures = nil;
|
||||
for(; l; l=l->next)
|
||||
funccompile(l->n);
|
||||
}
|
||||
dclchecks();
|
||||
}
|
||||
|
||||
@ -266,16 +280,10 @@ import_done:
|
||||
* declarations
|
||||
*/
|
||||
xdcl:
|
||||
{ stksize = initstksize; } common_dcl
|
||||
{
|
||||
$$ = $2;
|
||||
initstksize = stksize;
|
||||
}
|
||||
common_dcl
|
||||
| xfndcl
|
||||
{
|
||||
if($1 != N && $1->nname != N && $1->type->thistuple == 0)
|
||||
autoexport($1->nname, dclcontext);
|
||||
$$ = nil;
|
||||
$$ = list1($1);
|
||||
}
|
||||
| ';'
|
||||
{
|
||||
@ -305,26 +313,23 @@ common_dcl:
|
||||
}
|
||||
| LCONST constdcl
|
||||
{
|
||||
$$ = nil;
|
||||
$$ = $2;
|
||||
iota = 0;
|
||||
lastconst = nil;
|
||||
walkdeflist($2);
|
||||
}
|
||||
| LCONST '(' constdcl osemi ')'
|
||||
{
|
||||
$$ = nil;
|
||||
$$ = $3;
|
||||
iota = 0;
|
||||
lastconst = nil;
|
||||
yyoptsemi(0);
|
||||
walkdeflist($3);
|
||||
}
|
||||
| LCONST '(' constdcl ';' constdcl_list osemi ')'
|
||||
{
|
||||
$$ = nil;
|
||||
$$ = concat($3, $5);
|
||||
iota = 0;
|
||||
lastconst = nil;
|
||||
yyoptsemi(0);
|
||||
walkdeflist(concat($3, $5));
|
||||
}
|
||||
| LCONST '(' ')'
|
||||
{
|
||||
@ -333,15 +338,13 @@ common_dcl:
|
||||
}
|
||||
| LTYPE typedcl
|
||||
{
|
||||
$$ = nil;
|
||||
// $$ = list1($2);
|
||||
$$ = list1($2);
|
||||
if(yylast == LSEMIBRACE)
|
||||
yyoptsemi(0);
|
||||
}
|
||||
| LTYPE '(' typedcl_list osemi ')'
|
||||
{
|
||||
$$ = nil;
|
||||
// $$ = $3;
|
||||
$$ = $3;
|
||||
yyoptsemi(0);
|
||||
}
|
||||
| LTYPE '(' ')'
|
||||
@ -392,28 +395,29 @@ constdcl1:
|
||||
}
|
||||
|
||||
typedclname:
|
||||
new_type
|
||||
sym
|
||||
{
|
||||
$$ = dodcltype($1);
|
||||
defercheckwidth();
|
||||
// different from dclname because the name
|
||||
// becomes visible right here, not at the end
|
||||
// of the declaration.
|
||||
$$ = typedcl0($1);
|
||||
}
|
||||
|
||||
typedcl:
|
||||
typedclname ntype
|
||||
{
|
||||
typecheck(&$2, Etype);
|
||||
updatetype($1, $2->type);
|
||||
resumecheckwidth();
|
||||
$$ = typedcl1($1, $2, 1);
|
||||
}
|
||||
|
||||
// TODO(rsc): delete
|
||||
| typedclname LSTRUCT
|
||||
{
|
||||
updatetype($1, typ(TFORWSTRUCT));
|
||||
resumecheckwidth();
|
||||
$$ = fwdtype($1, TFORWSTRUCT);
|
||||
}
|
||||
// TODO(rsc): delete
|
||||
| typedclname LINTERFACE
|
||||
{
|
||||
updatetype($1, typ(TFORWINTER));
|
||||
resumecheckwidth();
|
||||
$$ = fwdtype($1, TFORWINTER);
|
||||
}
|
||||
|
||||
simple_stmt:
|
||||
@ -814,9 +818,6 @@ uexpr:
|
||||
pseudocall:
|
||||
pexpr '(' oexpr_or_type_list ')'
|
||||
{
|
||||
$$ = unsafenmagic($1, $3);
|
||||
if($$)
|
||||
break;
|
||||
$$ = nod(OCALL, $1, N);
|
||||
$$->list = $3;
|
||||
}
|
||||
@ -918,12 +919,6 @@ dcl_name:
|
||||
$$ = dclname($1);
|
||||
}
|
||||
|
||||
new_type:
|
||||
sym
|
||||
{
|
||||
$$ = newtype($1);
|
||||
}
|
||||
|
||||
onew_name:
|
||||
{
|
||||
$$ = N;
|
||||
@ -940,7 +935,7 @@ name:
|
||||
}
|
||||
|
||||
labelname:
|
||||
name
|
||||
new_name
|
||||
|
||||
convtype:
|
||||
'[' oexpr ']' ntype
|
||||
@ -1104,14 +1099,10 @@ keyval:
|
||||
* all in one place to show how crappy it all is
|
||||
*/
|
||||
xfndcl:
|
||||
LFUNC
|
||||
LFUNC fndcl fnbody
|
||||
{
|
||||
maxarg = 0;
|
||||
stksize = 0;
|
||||
} fndcl fnbody
|
||||
{
|
||||
$$ = $3;
|
||||
$$->nbody = $4;
|
||||
$$ = $2;
|
||||
$$->nbody = $3;
|
||||
funcbody($$);
|
||||
}
|
||||
|
||||
@ -1127,13 +1118,13 @@ fndcl:
|
||||
n = nod(OTFUNC, N, N);
|
||||
n->list = $3;
|
||||
n->rlist = $5;
|
||||
typecheck(&n, Etype);
|
||||
$$->type = n->type;
|
||||
// TODO: check if nname already has an ntype
|
||||
$$->nname->ntype = n;
|
||||
funchdr($$);
|
||||
}
|
||||
| '(' oarg_type_list ')' new_name '(' oarg_type_list ')' fnres
|
||||
{
|
||||
Node *rcvr;
|
||||
Node *rcvr, *t;
|
||||
|
||||
rcvr = $2->n;
|
||||
if($2->next != nil || $2->n->op != ODCLFIELD) {
|
||||
@ -1142,12 +1133,13 @@ fndcl:
|
||||
}
|
||||
|
||||
$$ = nod(ODCLFUNC, N, N);
|
||||
$$->nname = $4;
|
||||
$$->nname = methodname($4, rcvr->type);
|
||||
$$->type = functype(rcvr, $6, $8);
|
||||
$$->nname = methodname1($4, rcvr->right);
|
||||
t = nod(OTFUNC, rcvr, N);
|
||||
t->list = $6;
|
||||
t->rlist = $8;
|
||||
$$->nname->ntype = t;
|
||||
$$->shortname = $4;
|
||||
funchdr($$);
|
||||
if(rcvr != N)
|
||||
addmethod($4, $$->type, 1);
|
||||
}
|
||||
|
||||
fntype:
|
||||
@ -1158,19 +1150,6 @@ fntype:
|
||||
$$->rlist = $5;
|
||||
}
|
||||
|
||||
fnlitdcl:
|
||||
fntype
|
||||
{
|
||||
markdcl();
|
||||
$$ = funclit0($$);
|
||||
}
|
||||
|
||||
fnliteral:
|
||||
fnlitdcl '{' stmt_list '}'
|
||||
{
|
||||
$$ = funclit1($1, $3);
|
||||
}
|
||||
|
||||
fnbody:
|
||||
{
|
||||
$$ = nil;
|
||||
@ -1197,6 +1176,19 @@ fnres:
|
||||
$$ = $2;
|
||||
}
|
||||
|
||||
fnlitdcl:
|
||||
fntype
|
||||
{
|
||||
closurehdr($1);
|
||||
}
|
||||
|
||||
fnliteral:
|
||||
fnlitdcl '{' stmt_list '}'
|
||||
{
|
||||
$$ = closurebody($3);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* lists of things
|
||||
* note that they are left recursive
|
||||
@ -1590,15 +1582,16 @@ hidden_import:
|
||||
{
|
||||
importconst($2, $3, $5);
|
||||
}
|
||||
| LTYPE hidden_pkg_importsym hidden_type
|
||||
| LTYPE hidden_pkgtype hidden_type
|
||||
{
|
||||
importtype($2, $3);
|
||||
}
|
||||
| LTYPE hidden_pkg_importsym LSTRUCT
|
||||
// TODO(rsc): delete
|
||||
| LTYPE hidden_pkgtype LSTRUCT
|
||||
{
|
||||
importtype($2, typ(TFORWSTRUCT));
|
||||
}
|
||||
| LTYPE hidden_pkg_importsym LINTERFACE
|
||||
| LTYPE hidden_pkgtype LINTERFACE
|
||||
{
|
||||
importtype($2, typ(TFORWINTER));
|
||||
}
|
||||
@ -1615,6 +1608,13 @@ hidden_import:
|
||||
importmethod($5, functype($3->n, $7, $9));
|
||||
}
|
||||
|
||||
hidden_pkgtype:
|
||||
hidden_pkg_importsym
|
||||
{
|
||||
$$ = pkgtype($1);
|
||||
importsym($1, OTYPE);
|
||||
}
|
||||
|
||||
hidden_type:
|
||||
hidden_type1
|
||||
| hidden_type2
|
||||
@ -1690,13 +1690,11 @@ hidden_type2:
|
||||
hidden_dcl:
|
||||
sym hidden_type
|
||||
{
|
||||
$$ = nod(ODCLFIELD, newname($1), N);
|
||||
$$->type = $2;
|
||||
$$ = nod(ODCLFIELD, newname($1), typenod($2));
|
||||
}
|
||||
| '?' hidden_type
|
||||
{
|
||||
$$ = nod(ODCLFIELD, N, N);
|
||||
$$->type = $2;
|
||||
$$ = nod(ODCLFIELD, N, typenod($2));
|
||||
}
|
||||
|
||||
hidden_structdcl:
|
||||
@ -1734,11 +1732,7 @@ hidden_funres:
|
||||
}
|
||||
| hidden_type1
|
||||
{
|
||||
Node *n;
|
||||
|
||||
n = nod(ODCLFIELD, N, N);
|
||||
n->type = $1;
|
||||
$$ = list1(n);
|
||||
$$ = list1(nod(ODCLFIELD, N, typenod($1)));
|
||||
}
|
||||
|
||||
hidden_constant:
|
||||
|
@ -50,10 +50,20 @@ anyinit(NodeList *n)
|
||||
{
|
||||
uint32 h;
|
||||
Sym *s;
|
||||
NodeList *l;
|
||||
|
||||
// are there any init statements
|
||||
if(n != nil)
|
||||
return 1;
|
||||
// are there any interesting init statements
|
||||
for(l=n; l; l=l->next) {
|
||||
switch(l->n->op) {
|
||||
case ODCLFUNC:
|
||||
case ODCLCONST:
|
||||
case ODCLTYPE:
|
||||
case OEMPTY:
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// is this main
|
||||
if(strcmp(package, "main") == 0)
|
||||
@ -93,6 +103,7 @@ fninit(NodeList *n)
|
||||
return;
|
||||
}
|
||||
|
||||
n = initfix(n);
|
||||
if(!anyinit(n))
|
||||
return;
|
||||
|
||||
@ -106,7 +117,6 @@ fninit(NodeList *n)
|
||||
// (2)
|
||||
|
||||
maxarg = 0;
|
||||
stksize = initstksize;
|
||||
|
||||
snprint(namebuf, sizeof(namebuf), "Init·%s", filename);
|
||||
|
||||
@ -118,7 +128,7 @@ fninit(NodeList *n)
|
||||
fn = nod(ODCLFUNC, N, N);
|
||||
initsym = lookup(namebuf);
|
||||
fn->nname = newname(initsym);
|
||||
fn->type = functype(N, nil, nil);
|
||||
fn->nname->ntype = nod(OTFUNC, N, N);
|
||||
funchdr(fn);
|
||||
|
||||
// (3)
|
||||
@ -181,12 +191,14 @@ fninit(NodeList *n)
|
||||
exportsym(fn->nname);
|
||||
|
||||
fn->nbody = r;
|
||||
|
||||
//dump("b", fn);
|
||||
//dump("r", fn->nbody);
|
||||
|
||||
popdcl();
|
||||
initflag = 1; // flag for loader static initialization
|
||||
compile(fn);
|
||||
funcbody(fn);
|
||||
typecheck(&fn, Etop);
|
||||
funccompile(fn);
|
||||
initflag = 0;
|
||||
}
|
||||
|
||||
|
@ -310,6 +310,7 @@ importfile(Val *f)
|
||||
curio.peekc = 0;
|
||||
curio.peekc1 = 0;
|
||||
curio.infile = file;
|
||||
typecheckok = 1;
|
||||
for(;;) {
|
||||
c = getc();
|
||||
if(c == EOF)
|
||||
@ -343,6 +344,7 @@ unimportfile(void)
|
||||
curio = pushedio;
|
||||
pushedio.bin = nil;
|
||||
inimportsys = 0;
|
||||
typecheckok = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -362,6 +364,7 @@ cannedimports(char *file, char *cp)
|
||||
curio.cp = cp;
|
||||
|
||||
pkgmyname = S;
|
||||
typecheckok = 1;
|
||||
inimportsys = 1;
|
||||
}
|
||||
|
||||
@ -1308,7 +1311,8 @@ lexinit(void)
|
||||
t = typ(etype);
|
||||
t->sym = s;
|
||||
|
||||
dowidth(t);
|
||||
if(etype != TANY && etype != TSTRING)
|
||||
dowidth(t);
|
||||
types[etype] = t;
|
||||
}
|
||||
s->def = typenod(t);
|
||||
|
@ -389,6 +389,7 @@ dcommontype(Sym *s, int ot, Type *t)
|
||||
Type *elem;
|
||||
char *p;
|
||||
|
||||
dowidth(t);
|
||||
s1 = dextratype(t);
|
||||
|
||||
// empty interface pointing at this type.
|
||||
|
@ -69,6 +69,12 @@ initlin(NodeList *l)
|
||||
|
||||
for(; l; l=l->next) {
|
||||
n = l->n;
|
||||
switch(n->op) {
|
||||
case ODCLFUNC:
|
||||
case ODCLCONST:
|
||||
case ODCLTYPE:
|
||||
continue;
|
||||
}
|
||||
initlin(n->ninit);
|
||||
n->ninit = nil;
|
||||
xxx.list = list(xxx.list, n);
|
||||
|
@ -380,6 +380,7 @@ typ(int et)
|
||||
|
||||
t = mal(sizeof(*t));
|
||||
t->etype = et;
|
||||
t->width = BADWIDTH;
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -471,7 +472,6 @@ aindex(Node *b, Type *t)
|
||||
r = typ(TARRAY);
|
||||
r->type = t;
|
||||
r->bound = bound;
|
||||
checkwidth(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -517,7 +517,12 @@ dodump(Node *n, int dep)
|
||||
break;
|
||||
|
||||
case OTYPE:
|
||||
print("%O %T\n", n->op, n->type);
|
||||
print("%O %S type=%T\n", n->op, n->sym, n->type);
|
||||
if(n->type == T && n->ntype) {
|
||||
indent(dep);
|
||||
print("%O-ntype\n", n->op);
|
||||
dodump(n->ntype, dep+1);
|
||||
}
|
||||
break;
|
||||
|
||||
case OIF:
|
||||
@ -577,7 +582,7 @@ dodump(Node *n, int dep)
|
||||
break;
|
||||
}
|
||||
|
||||
if(n->ntype != nil) {
|
||||
if(0 && n->ntype != nil) {
|
||||
indent(dep);
|
||||
print("%O-ntype\n", n->op);
|
||||
dodump(n->ntype, dep+1);
|
||||
@ -1930,7 +1935,9 @@ frame(int context)
|
||||
int flag;
|
||||
|
||||
p = "stack";
|
||||
l = autodcl;
|
||||
l = nil;
|
||||
if(curfn)
|
||||
l = curfn->dcl;
|
||||
if(context) {
|
||||
p = "external";
|
||||
l = externdcl;
|
||||
@ -2202,42 +2209,6 @@ brrev(int a)
|
||||
return a;
|
||||
}
|
||||
|
||||
/*
|
||||
* make a new off the books
|
||||
*/
|
||||
void
|
||||
tempname(Node *n, Type *t)
|
||||
{
|
||||
Sym *s;
|
||||
uint32 w;
|
||||
|
||||
if(t == T) {
|
||||
yyerror("tempname called with nil type");
|
||||
t = types[TINT32];
|
||||
}
|
||||
|
||||
// give each tmp a different name so that there
|
||||
// a chance to registerizer them
|
||||
snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
|
||||
statuniqgen++;
|
||||
s = lookup(namebuf);
|
||||
|
||||
memset(n, 0, sizeof(*n));
|
||||
n->op = ONAME;
|
||||
n->sym = s;
|
||||
n->type = t;
|
||||
n->class = PAUTO;
|
||||
n->addable = 1;
|
||||
n->ullman = 1;
|
||||
n->noescape = 1;
|
||||
|
||||
dowidth(t);
|
||||
w = t->width;
|
||||
stksize += w;
|
||||
stksize = rnd(stksize, w);
|
||||
n->xoffset = -stksize;
|
||||
}
|
||||
|
||||
Node*
|
||||
staticname(Type *t)
|
||||
{
|
||||
@ -2297,58 +2268,14 @@ setmaxarg(Type *t)
|
||||
{
|
||||
int32 w;
|
||||
|
||||
dowidth(t);
|
||||
w = t->argwid;
|
||||
if(t->argwid >= 100000000)
|
||||
fatal("bad argwid %T", t);
|
||||
if(w > maxarg)
|
||||
maxarg = w;
|
||||
}
|
||||
|
||||
/*
|
||||
* gather series of offsets
|
||||
* >=0 is direct addressed field
|
||||
* <0 is pointer to next field (+1)
|
||||
*/
|
||||
int
|
||||
dotoffset(Node *n, int *oary, Node **nn)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch(n->op) {
|
||||
case ODOT:
|
||||
if(n->xoffset == BADWIDTH) {
|
||||
dump("bad width in dotoffset", n);
|
||||
fatal("bad width in dotoffset");
|
||||
}
|
||||
i = dotoffset(n->left, oary, nn);
|
||||
if(i > 0) {
|
||||
if(oary[i-1] >= 0)
|
||||
oary[i-1] += n->xoffset;
|
||||
else
|
||||
oary[i-1] -= n->xoffset;
|
||||
break;
|
||||
}
|
||||
if(i < 10)
|
||||
oary[i++] = n->xoffset;
|
||||
break;
|
||||
|
||||
case ODOTPTR:
|
||||
if(n->xoffset == BADWIDTH) {
|
||||
dump("bad width in dotoffset", n);
|
||||
fatal("bad width in dotoffset");
|
||||
}
|
||||
i = dotoffset(n->left, oary, nn);
|
||||
if(i < 10)
|
||||
oary[i++] = -(n->xoffset+1);
|
||||
break;
|
||||
|
||||
default:
|
||||
*nn = n;
|
||||
return 0;
|
||||
}
|
||||
if(i >= 10)
|
||||
*nn = N;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* code to resolve elided DOTs
|
||||
* in embedded types
|
||||
@ -2644,8 +2571,7 @@ structargs(Type **tl, int mustname)
|
||||
snprint(buf, sizeof buf, ".anon%d", gen++);
|
||||
n = newname(lookup(buf));
|
||||
}
|
||||
a = nod(ODCLFIELD, n, N);
|
||||
a->type = t->type;
|
||||
a = nod(ODCLFIELD, n, typenod(t->type));
|
||||
args = list(args, a);
|
||||
}
|
||||
return args;
|
||||
@ -2677,7 +2603,7 @@ structargs(Type **tl, int mustname)
|
||||
void
|
||||
genwrapper(Type *rcvr, Type *method, Sym *newnam)
|
||||
{
|
||||
Node *this, *fn, *call, *n;
|
||||
Node *this, *fn, *call, *n, *t;
|
||||
NodeList *l, *args, *in, *out;
|
||||
|
||||
if(debug['r'])
|
||||
@ -2687,14 +2613,17 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
|
||||
dclcontext = PEXTERN;
|
||||
markdcl();
|
||||
|
||||
this = nod(ODCLFIELD, newname(lookup(".this")), N);
|
||||
this->type = rcvr;
|
||||
this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr));
|
||||
this->left->ntype = this->right;
|
||||
in = structargs(getinarg(method->type), 1);
|
||||
out = structargs(getoutarg(method->type), 0);
|
||||
|
||||
fn = nod(ODCLFUNC, N, N);
|
||||
fn->nname = newname(newnam);
|
||||
fn->type = functype(this, in, out);
|
||||
t = nod(OTFUNC, this, N);
|
||||
t->list = in;
|
||||
t->rlist = out;
|
||||
fn->nname->ntype = t;
|
||||
funchdr(fn);
|
||||
|
||||
// arg list
|
||||
@ -2716,6 +2645,8 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
|
||||
dumplist("genwrapper body", fn->nbody);
|
||||
|
||||
funcbody(fn);
|
||||
typecheck(&fn, Etop);
|
||||
funccompile(fn);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3044,6 +2975,9 @@ checkwidth(Type *t)
|
||||
dowidth(t);
|
||||
return;
|
||||
}
|
||||
if(t->deferwidth)
|
||||
return;
|
||||
t->deferwidth = 1;
|
||||
|
||||
l = tlfree;
|
||||
if(l != nil)
|
||||
@ -3075,6 +3009,7 @@ resumecheckwidth(void)
|
||||
defercalc = 0;
|
||||
|
||||
for(l = tlq; l != nil; l = tlq) {
|
||||
l->t->deferwidth = 0;
|
||||
dowidth(l->t);
|
||||
tlq = l->next;
|
||||
l->next = tlfree;
|
||||
|
@ -27,9 +27,10 @@ static void typecheckcomplit(Node**);
|
||||
static void addrescapes(Node*);
|
||||
static void typecheckas2(Node*);
|
||||
static void typecheckas(Node*);
|
||||
static void typecheckfunc(Node*);
|
||||
static void checklvalue(Node*, char*);
|
||||
static void checkassign(Node*);
|
||||
static void checkassignlist(NodeList*);
|
||||
static void checkassign(Node*);
|
||||
static void checkassignlist(NodeList*);
|
||||
static int islvalue(Node*);
|
||||
|
||||
void
|
||||
@ -53,6 +54,10 @@ typecheck(Node **np, int top)
|
||||
int lno, ok;
|
||||
Type *t;
|
||||
|
||||
// cannot type check until all the source has been parsed
|
||||
if(!typecheckok)
|
||||
fatal("early typecheck");
|
||||
|
||||
n = *np;
|
||||
if(n == N)
|
||||
return N;
|
||||
@ -392,9 +397,10 @@ reswitch:
|
||||
if(t == T)
|
||||
goto error;
|
||||
n->op = ODOTPTR;
|
||||
checkwidth(t);
|
||||
}
|
||||
if(!lookdot(n, t)) {
|
||||
yyerror("%#N undefined (type %T has no field %S)", n, t, n->right->sym);
|
||||
yyerror("%#N undefined (type %p %T has no field %S)", n, t, t, n->right->sym);
|
||||
goto error;
|
||||
}
|
||||
switch(n->op) {
|
||||
@ -566,6 +572,10 @@ reswitch:
|
||||
n->right = N;
|
||||
goto reswitch;
|
||||
}
|
||||
if(l->op == ONAME && (r = unsafenmagic(l, n->list)) != N) {
|
||||
n = r;
|
||||
goto reswitch;
|
||||
}
|
||||
typecheck(&n->left, Erv | Etype | Ecall);
|
||||
defaultlit(&n->left, T);
|
||||
l = n->left;
|
||||
@ -575,7 +585,7 @@ reswitch:
|
||||
typechecklist(n->list, Erv);
|
||||
if((t = l->type) == T)
|
||||
goto error;
|
||||
dowidth(t);
|
||||
checkwidth(t);
|
||||
|
||||
switch(l->op) {
|
||||
case OTYPE:
|
||||
@ -818,6 +828,13 @@ reswitch:
|
||||
typechecklist(n->list, Erv);
|
||||
goto ret;
|
||||
|
||||
case OCLOSURE:
|
||||
ok |= Erv;
|
||||
typecheckclosure(n);
|
||||
if(n->type == T)
|
||||
goto error;
|
||||
goto ret;
|
||||
|
||||
/*
|
||||
* statements
|
||||
*/
|
||||
@ -905,9 +922,40 @@ reswitch:
|
||||
typechecklist(n->list, Erv);
|
||||
typechecklist(n->nbody, Etop);
|
||||
goto ret;
|
||||
|
||||
case ODCLFUNC:
|
||||
ok |= Etop;
|
||||
typecheckfunc(n);
|
||||
goto ret;
|
||||
|
||||
case ODCLCONST:
|
||||
ok |= Etop;
|
||||
typecheck(&n->left, Erv);
|
||||
goto ret;
|
||||
|
||||
case ODCLTYPE:
|
||||
ok |= Etop;
|
||||
typecheck(&n->left, Etype);
|
||||
goto ret;
|
||||
}
|
||||
|
||||
ret:
|
||||
t = n->type;
|
||||
if(t && !t->funarg && n->op != OTYPE) {
|
||||
switch(t->etype) {
|
||||
case TFUNC: // might have TANY; wait until its called
|
||||
case TANY:
|
||||
case TFORW:
|
||||
case TFORWINTER:
|
||||
case TFORWSTRUCT:
|
||||
case TIDEAL:
|
||||
case TNIL:
|
||||
break;
|
||||
default:
|
||||
checkwidth(t);
|
||||
}
|
||||
}
|
||||
|
||||
evconst(n);
|
||||
if(n->op == OTYPE && !(top & Etype)) {
|
||||
yyerror("type %T is not an expression", n->type);
|
||||
@ -921,11 +969,12 @@ ret:
|
||||
yyerror("must call %#N", n);
|
||||
goto error;
|
||||
}
|
||||
if((top & (Ecall|Erv|Etype)) && !(ok & (Erv|Etype|Ecall))) {
|
||||
// TODO(rsc): simplify
|
||||
if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
|
||||
yyerror("%#N used as value", n);
|
||||
goto error;
|
||||
}
|
||||
if((top & Etop) && !(ok & Etop)) {
|
||||
if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) {
|
||||
yyerror("%#N not used", n);
|
||||
goto error;
|
||||
}
|
||||
@ -1016,6 +1065,7 @@ lookdot(Node *n, Type *t)
|
||||
|
||||
s = n->right->sym;
|
||||
|
||||
dowidth(t);
|
||||
f1 = T;
|
||||
if(t->etype == TSTRUCT || t->etype == TINTER)
|
||||
f1 = lookdot1(s, t, t->type);
|
||||
@ -1042,6 +1092,7 @@ lookdot(Node *n, Type *t)
|
||||
|
||||
if(f2 != T) {
|
||||
tt = n->left->type;
|
||||
dowidth(tt);
|
||||
rcvr = getthisx(f2->type)->type->type;
|
||||
if(!eqtype(rcvr, tt)) {
|
||||
if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
|
||||
@ -1609,12 +1660,18 @@ addrescapes(Node *n)
|
||||
case PPARAM:
|
||||
// if func param, need separate temporary
|
||||
// to hold heap pointer.
|
||||
// the function type has already been checked
|
||||
// (we're in the function body)
|
||||
// so the param already has a valid xoffset.
|
||||
if(n->class == PPARAM) {
|
||||
// expression to refer to stack copy
|
||||
n->stackparam = nod(OPARAM, n, N);
|
||||
n->stackparam->type = n->type;
|
||||
n->stackparam->addable = 1;
|
||||
if(n->xoffset == BADWIDTH)
|
||||
fatal("addrescapes before param assignment");
|
||||
n->stackparam->xoffset = n->xoffset;
|
||||
n->xoffset = 0;
|
||||
}
|
||||
|
||||
n->class |= PHEAP;
|
||||
@ -1624,10 +1681,12 @@ addrescapes(Node *n)
|
||||
n->xoffset = 0;
|
||||
|
||||
// create stack variable to hold pointer to heap
|
||||
n->heapaddr = nod(0, N, N);
|
||||
tempname(n->heapaddr, ptrto(n->type));
|
||||
n->heapaddr = nod(ONAME, N, N);
|
||||
n->heapaddr->type = ptrto(n->type);
|
||||
snprint(buf, sizeof buf, "&%S", n->sym);
|
||||
n->heapaddr->sym = lookup(buf);
|
||||
n->heapaddr->class = PHEAP-1; // defer tempname to allocparams
|
||||
curfn->dcl = list(curfn->dcl, n->heapaddr);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -1846,3 +1905,21 @@ out:
|
||||
if(ll->n->typecheck == 0)
|
||||
typecheck(&ll->n, Erv);
|
||||
}
|
||||
|
||||
/*
|
||||
* type check function definition
|
||||
*/
|
||||
static void
|
||||
typecheckfunc(Node *n)
|
||||
{
|
||||
Type *t, *rcvr;
|
||||
|
||||
typecheck(&n->nname, Erv);
|
||||
if((t = n->nname->type) == T)
|
||||
return;
|
||||
n->type = t;
|
||||
|
||||
rcvr = getthisx(t)->type;
|
||||
if(rcvr != nil && n->shortname != N)
|
||||
addmethod(n->shortname->sym, t, 1);
|
||||
}
|
||||
|
@ -52,16 +52,9 @@ loop:
|
||||
|
||||
case OGOTO:
|
||||
case ORETURN:
|
||||
case OPANIC:
|
||||
case OPANICN:
|
||||
return 0;
|
||||
|
||||
case OCALL:
|
||||
if(n->left->op == ONAME) {
|
||||
switch(n->left->etype) {
|
||||
case OPANIC:
|
||||
case OPANICN:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -118,7 +111,7 @@ walkdeflist(NodeList *l)
|
||||
void
|
||||
walkdef(Node *n)
|
||||
{
|
||||
int lno;
|
||||
int lno, maplineno;
|
||||
NodeList *init;
|
||||
Node *e;
|
||||
Type *t;
|
||||
@ -147,6 +140,9 @@ walkdef(Node *n)
|
||||
|
||||
init = nil;
|
||||
switch(n->op) {
|
||||
default:
|
||||
fatal("walkdef %O", n->op);
|
||||
|
||||
case OLITERAL:
|
||||
if(n->ntype != N) {
|
||||
typecheck(&n->ntype, Etype);
|
||||
@ -189,8 +185,48 @@ walkdef(Node *n)
|
||||
break;
|
||||
if(n->defn == N)
|
||||
fatal("var without type, init: %S", n->sym);
|
||||
if(n->defn->op == ONAME) {
|
||||
typecheck(&n->defn, Erv);
|
||||
n->type = n->defn->type;
|
||||
break;
|
||||
}
|
||||
typecheck(&n->defn, Etop); // fills in n->type
|
||||
break;
|
||||
|
||||
case OTYPE:
|
||||
n->walkdef = 1;
|
||||
if(n->nincr != N) // fwd decl hack
|
||||
n->type = n->nincr->type;
|
||||
else
|
||||
n->type = typ(TFORW);
|
||||
n->type->sym = n->sym;
|
||||
n->typecheck = 1;
|
||||
typecheck(&n->ntype, Etype);
|
||||
if((t = n->ntype->type) == T) {
|
||||
n->diag = 1;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// copy new type and clear fields
|
||||
// that don't come along
|
||||
maplineno = n->type->maplineno;
|
||||
*n->type = *t;
|
||||
t = n->type;
|
||||
t->sym = n->sym;
|
||||
t->local = n->local;
|
||||
t->vargen = n->vargen;
|
||||
t->siggen = 0;
|
||||
t->printed = 0;
|
||||
t->method = nil;
|
||||
t->nod = N;
|
||||
|
||||
// double-check use of type as map key
|
||||
// TODO(rsc): also use of type as receiver?
|
||||
if(maplineno) {
|
||||
lineno = maplineno;
|
||||
maptype(n->type, types[TBOOL]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ret:
|
||||
@ -265,6 +301,8 @@ walkstmt(Node **np)
|
||||
case OFALL:
|
||||
case OGOTO:
|
||||
case OLABEL:
|
||||
case ODCLCONST:
|
||||
case ODCLTYPE:
|
||||
break;
|
||||
|
||||
case OBLOCK:
|
||||
@ -919,6 +957,10 @@ walkexpr(Node **np, NodeList **init)
|
||||
argtype(fn, n->type->type); // any-2
|
||||
n = mkcall1(fn, n->type, init, n->left, nodintconst(n->left->type->type->bound));
|
||||
goto ret;
|
||||
|
||||
case OCLOSURE:
|
||||
n = walkclosure(n, init);
|
||||
goto ret;
|
||||
}
|
||||
fatal("missing switch %O", n->op);
|
||||
|
||||
@ -1658,6 +1700,7 @@ ifacecvt(Type *tl, Node *n, int et, NodeList **init)
|
||||
break;
|
||||
}
|
||||
|
||||
dowidth(on->type);
|
||||
r = nod(OCALL, on, N);
|
||||
r->list = args;
|
||||
typecheck(&r, Erv | Efnstruct);
|
||||
|
Loading…
Reference in New Issue
Block a user