From aa347c4a0dfe285ed1dec12e77108106804fa3d4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Tue, 4 Aug 2009 18:43:32 -0700 Subject: [PATCH] move various bits of code around and delete some dead code. no actual changes here. R=ken OCL=32764 CL=32764 --- src/cmd/gc/Makefile | 30 +- src/cmd/gc/dcl.c | 2496 ++++++++++++++++++------------------------- src/cmd/gc/go.h | 4 - src/cmd/gc/go.y | 2 - src/cmd/gc/init.c | 193 ++++ src/cmd/gc/subr.c | 126 ++- src/cmd/gc/unsafe.c | 87 ++ 7 files changed, 1466 insertions(+), 1472 deletions(-) create mode 100644 src/cmd/gc/init.c create mode 100644 src/cmd/gc/unsafe.c diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile index ec97020554..55b61ce8b3 100644 --- a/src/cmd/gc/Makefile +++ b/src/cmd/gc/Makefile @@ -15,28 +15,30 @@ YFILES=\ go.y\ OFILES=\ - reflect.$O\ - y.tab.$O\ - lex.$O\ - subr.$O\ + align.$O\ + bits.$O\ + builtin.$O\ + compat.$O\ + const.$O\ dcl.$O\ - sinit.$O\ export.$O\ - walk.$O\ - swt.$O\ - const.$O\ + gen.$O\ + init.$O\ + lex.$O\ mparith1.$O\ mparith2.$O\ mparith3.$O\ - builtin.$O\ - compat.$O\ - bits.$O\ - align.$O\ - gen.$O\ obj.$O\ print.$O\ - typecheck.$O\ + reflect.$O\ select.$O\ + sinit.$O\ + subr.$O\ + swt.$O\ + typecheck.$O\ + unsafe.$O\ + walk.$O\ + y.tab.$O\ $(LIB): $(OFILES) ar rsc $(LIB) $(OFILES) diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index 3b8e67d15a..7003045bea 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -18,697 +18,747 @@ dflag(void) } /* - * declare (possible list) n of type t. - * append ODCL nodes to *init + * declaration stack & operations */ +static Sym* dclstack; + void -dodclvar(Node *n, Type *t, NodeList **init) +dcopy(Sym *a, Sym *b) { - if(n == N) - return; - - if(t != T && (t->etype == TIDEAL || t->etype == TNIL)) - fatal("dodclvar %T", t); - dowidth(t); + a->name = b->name; + a->def = b->def; + a->package = b->package; + a->undef = b->undef; + a->vargen = b->vargen; + a->block = b->block; + a->lastlineno = b->lastlineno; + a->offset = b->offset; +} - // in case of type checking error, - // use "undefined" type for variable type, - // to avoid fatal in addvar. - if(t == T) - t = typ(TFORW); +Sym* +push(void) +{ + Sym *d; - addvar(n, t, dclcontext); - autoexport(n->sym); - if(funcdepth > 0) - *init = list(*init, nod(ODCL, n, N)); + d = mal(sizeof(*d)); + d->link = dclstack; + dclstack = d; + return d; } -// TODO(rsc): cut -void -dodclconst(Node *n, Node *e) +Sym* +pushdcl(Sym *s) { - if(n == N) - return; - addconst(n, e, dclcontext); - autoexport(n->sym); + Sym *d; + + d = push(); + dcopy(d, s); + return d; } -/* - * introduce a type named n - * but it is an unknown type for now - */ -Type* -dodcltype(Type *n) +void +popdcl(void) { - Sym *s; + Sym *d, *s; - // if n has been forward declared, - // use the Type* created then - s = n->sym; - if((funcdepth == 0 || s->block == block) && s->def != N && s->def->op == OTYPE) { - switch(s->def->type->etype) { - case TFORWSTRUCT: - case TFORWINTER: - n = s->def->type; - if(s->block != block) { - // completing forward struct from other file - Dcl *d, *r; - d = dcl(); - d->dsym = s; - d->dtype = n; - d->op = OTYPE; - r = externdcl; - d->back = r->back; - r->back->forw = d; - r->back = d; - } - goto found; - } +// if(dflag()) +// print("revert\n"); + + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) + break; + s = pkglookup(d->name, d->package); + dcopy(s, d); + if(dflag()) + print("\t%L pop %S\n", lineno, s); } + if(d == S) + fatal("popdcl: no mark"); + dclstack = d->link; + block = d->block; +} - // otherwise declare a new type - addtyp(n, dclcontext); +void +poptodcl(void) +{ + Sym *d, *s; -found: - n->local = 1; - autoexport(n->sym); - return n; + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) + break; + s = pkglookup(d->name, d->package); + dcopy(s, d); + if(dflag()) + print("\t%L pop %S\n", lineno, s); + } + if(d == S) + fatal("poptodcl: no mark"); + dclstack = d; } -/* - * now we know what n is: it's t - */ void -updatetype(Type *n, Type *t) +markdcl(void) { - Sym *s; - int local, vargen; - int maplineno, lno, etype; + Sym *d; - if(t == T) - return; - s = n->sym; - if(s == S || s->def == N || s->def->op != OTYPE || s->def->type != n) - fatal("updatetype %T = %T", n, t); + d = push(); + d->name = nil; // used as a mark in fifo + d->block = block; - etype = n->etype; - switch(n->etype) { - case TFORW: - break; + blockgen++; + block = blockgen; - case TFORWSTRUCT: - if(t->etype != TSTRUCT) { - yyerror("%T forward declared as struct", n); - return; - } - n->local = 1; - break; +// if(dflag()) +// print("markdcl\n"); +} - case TFORWINTER: - if(t->etype != TINTER) { - yyerror("%T forward declared as interface", n); - return; - } - break; +void +dumpdcl(char *st) +{ + Sym *s, *d; + int i; - default: - fatal("updatetype %T / %T", n, t); + i = 0; + for(d=dclstack; d!=S; d=d->link) { + i++; + print(" %.2d %p", i, d); + if(d->name == nil) { + print("\n"); + continue; + } + print(" '%s'", d->name); + s = pkglookup(d->name, d->package); + print(" %lS\n", s); } +} - // decl was - // type n t; - // copy t, but then zero out state associated with t - // that is no longer associated with n. - maplineno = n->maplineno; - local = n->local; - vargen = n->vargen; - *n = *t; - n->sym = s; - n->local = local; - n->siggen = 0; - n->printed = 0; - n->method = nil; - n->vargen = vargen; - n->nod = N; - - // catch declaration of incomplete type - switch(n->etype) { - case TFORWSTRUCT: - case TFORWINTER: - break; - default: - checkwidth(n); - } +void +testdclstack(void) +{ + Sym *d; - // double-check use of type as map key - if(maplineno) { - lno = lineno; - lineno = maplineno; - maptype(n, types[TBOOL]); - lineno = lno; + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) { + yyerror("mark left on the stack"); + continue; + } } } - /* - * return nelem of list + * declare individual names - var, typ, const */ -int -structcount(Type *t) +static void +redeclare(char *str, Sym *s) { - int v; - Iter s; - - v = 0; - for(t = structfirst(&s, &t); t != T; t = structnext(&s)) - v++; - return v; + if(s->block == block) { + yyerror("%s %S redeclared in this block", str, s); + print(" previous declaration at %L\n", s->lastlineno); + } + s->block = block; + s->lastlineno = lineno; } -/* - * turn a parsed function declaration - * into a type - */ -Type* -functype(Node *this, NodeList *in, NodeList *out) +void +addvar(Node *n, Type *t, int ctxt) { - Type *t; - NodeList *rcvr; - - t = typ(TFUNC); + Dcl *r, *d; + Sym *s; + int gen; - rcvr = nil; - if(this) - rcvr = list1(this); - t->type = dostruct(rcvr, TFUNC); - t->type->down = dostruct(out, TFUNC); - t->type->down->down = dostruct(in, TFUNC); + if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T) + fatal("addvar: n=%N t=%T nil", n, t); - if(this) - t->thistuple = 1; - t->outtuple = count(out); - t->intuple = count(in); + s = n->sym; - checkwidth(t); - return t; -} + if(ctxt == PEXTERN || ctxt == PFUNC) { + r = externdcl; + gen = 0; + } else { + r = autodcl; + vargen++; + gen = vargen; + pushdcl(s); + } -int -methcmp(Type *t1, Type *t2) -{ - if(t1->etype != TFUNC) - return 0; - if(t2->etype != TFUNC) - return 0; + redeclare("variable", s); + n->op = ONAME; + s->vargen = gen; + s->def = n; + s->offset = 0; - t1 = t1->type->down; // skip this arg - t2 = t2->type->down; // skip this arg - for(;;) { - if(t1 == t2) - break; - if(t1 == T || t2 == T) - return 0; - if(t1->etype != TSTRUCT || t2->etype != TSTRUCT) - return 0; + n->funcdepth = funcdepth; + n->type = t; + n->vargen = gen; + n->class = ctxt; - if(!eqtype(t1->type, t2->type)) - return 0; + d = dcl(); + d->dsym = s; + d->dnode = n; + d->op = ONAME; - t1 = t1->down; - t2 = t2->down; + r->back->forw = d; + r->back = d; + + if(dflag()) { + if(ctxt == PEXTERN) + print("extern var-dcl %S G%ld %T\n", s, s->vargen, t); + else if(ctxt == PFUNC) + print("extern func-dcl %S G%ld %T\n", s, s->vargen, t); + else + print("auto var-dcl %S G%ld %T\n", s, s->vargen, t); } - return 1; } -Sym* -methodsym(Sym *nsym, Type *t0) +void +addtyp(Type *n, int ctxt) { + Dcl *r, *d; Sym *s; - char buf[NSYMB]; - Type *t; + static int typgen; - t = t0; - if(t == T) - goto bad; - s = t->sym; - if(s == S) { - if(!isptr[t->etype]) - goto bad; - t = t->type; - if(t == T) - goto bad; - s = t->sym; - if(s == S) - goto bad; + if(n==T || n->sym == S) + fatal("addtyp: n=%T t=%T nil", n); + + s = n->sym; + + if(ctxt == PEXTERN) + r = externdcl; + else { + r = autodcl; + pushdcl(s); + n->vargen = ++typgen; } - // if t0 == *t and t0 has a sym, - // we want to see *t, not t0, in the method name. - if(t != t0 && t0->sym) - t0 = ptrto(t); + redeclare("type", s); + s->def = typenod(n); - snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name); -//print("methodname %s\n", buf); - return pkglookup(buf, s->package); + d = dcl(); + d->dsym = s; + d->dtype = n; + d->op = OTYPE; -bad: - yyerror("illegal type: %T", t); - return S; -} + d->back = r->back; + r->back->forw = d; + r->back = d; -Node* -methodname(Node *n, Type *t) -{ - Sym *s; + d = dcl(); + d->dtype = n; + d->op = OTYPE; - s = methodsym(n->sym, t); - if(s == S) - return n; - return newname(s); + r = typelist; + d->back = r->back; + r->back->forw = d; + r->back = d; + + if(dflag()) { + if(ctxt == PEXTERN) + print("extern typ-dcl %S G%ld %T\n", s, s->vargen, n); + else + print("auto typ-dcl %S G%ld %T\n", s, s->vargen, n); + } } -/* - * add a method, declared as a function, - * n is fieldname, pa is base type, t is function type - */ +// TODO(rsc): cut void -addmethod(Node *n, Type *t, int local) +addconst(Node *n, Node *e, int ctxt) { - Type *f, *d, *pa; - Sym *sf; - - 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; - - // 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; - - f = methtype(pa); - if(f == T) - goto bad; - - pa = f; - if(pkgimportname != S && !exportname(sf->name)) - sf = pkglookup(sf->name, pkgimportname->name); + Sym *s; + Dcl *r, *d; - n = nod(ODCLFIELD, newname(sf), N); - n->type = t; + if(n->op != ONAME && n->op != ONONAME) + fatal("addconst: not a name"); - d = T; // last found - for(f=pa->method; f!=T; f=f->down) { - d = f; - if(f->etype != TFIELD) - fatal("addmethod: not TFIELD: %N", f); - if(strcmp(sf->name, f->sym->name) != 0) - continue; - if(!eqtype(t, f->type)) { - yyerror("method redeclared: %T.%S", pa, sf); - print("\t%T\n\t%T\n", f->type, t); - } + if(e->op != OLITERAL) { + yyerror("expression must be a constant"); return; } - if(local && !pa->local) { - // defining method on non-local type. - // method must have been forward declared - // elsewhere, i.e. where the type was. - yyerror("cannot define new methods on non-local type %T", pa); - return; + s = n->sym; + + if(ctxt == PEXTERN) + r = externdcl; + else { + r = autodcl; + pushdcl(s); } - if(d == T) - stotype(list1(n), 0, &pa->method); - else - stotype(list1(n), 0, &d->down); + redeclare("constant", s); + s->def = e; + e->sym = s; - if(dflag()) - print("method %S of type %T\n", sf, pa); - return; + d = dcl(); + d->dsym = s; + d->dnode = e; + d->op = OLITERAL; + d->back = r->back; + r->back->forw = d; + r->back = d; -bad: - yyerror("invalid receiver type %T", pa); + if(dflag()) + print("const-dcl %S %N\n", n->sym, n->sym->def); } /* - * a function named init is a special case. - * it is called by the initialization before - * main is run. to make it unique within a - * package and also uncallable, the name, - * normally "pkg.init", is altered to "pkg.init·filename". + * declare (possible list) n of type t. + * append ODCL nodes to *init */ -Node* -renameinit(Node *n) +void +dodclvar(Node *n, Type *t, NodeList **init) { - Sym *s; + if(n == N) + return; - s = n->sym; - if(s == S) - return n; - if(strcmp(s->name, "init") != 0) - return n; + if(t != T && (t->etype == TIDEAL || t->etype == TNIL)) + fatal("dodclvar %T", t); + dowidth(t); - snprint(namebuf, sizeof(namebuf), "init·%s", filename); - s = lookup(namebuf); - return newname(s); + // 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); + autoexport(n->sym); + if(funcdepth > 0) + *init = list(*init, nod(ODCL, n, N)); } -/* - * declare the function proper. - * and declare the arguments - * called in extern-declaration context - * returns in auto-declaration context. - */ +// TODO(rsc): cut void -funchdr(Node *n) +dodclconst(Node *n, Node *e) { - Node *on; - Sym *s; + if(n == N) + return; + addconst(n, e, dclcontext); + autoexport(n->sym); +} - s = n->nname->sym; - on = s->def; - if(on != N && (on->op != ONAME || on->builtin)) - on = N; +/* + * introduce a type named n + * but it is an unknown type for now + */ +Type* +dodcltype(Type *n) +{ + Sym *s; - // 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); + // if n has been forward declared, + // use the Type* created then + s = n->sym; + if((funcdepth == 0 || s->block == block) && s->def != N && s->def->op == OTYPE) { + switch(s->def->type->etype) { + case TFORWSTRUCT: + case TFORWINTER: + n = s->def->type; + if(s->block != block) { + // completing forward struct from other file + Dcl *d, *r; + d = dcl(); + d->dsym = s; + d->dtype = n; + d->op = OTYPE; + r = externdcl; + d->back = r->back; + r->back->forw = d; + r->back = d; } - } else { - yyerror("function redeclared: %S", s); - print("\t%T\n\t%T\n", on->type, n->type); - on = N; + goto found; } } - // 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; - if(dflag()) - print("forew var-dcl %S %T\n", n->sym, n->type); - } - - // change the declaration context from extern to auto - autodcl = dcl(); - autodcl->back = autodcl; - - if(funcdepth == 0 && dclcontext != PEXTERN) - fatal("funchdr: dclcontext"); + // otherwise declare a new type + addtyp(n, dclcontext); - dclcontext = PAUTO; - markdcl(); - funcargs(n->type); +found: + n->local = 1; + autoexport(n->sym); + return n; } +/* + * now we know what n is: it's t + */ void -funcargs(Type *ft) +updatetype(Type *n, Type *t) { - Type *t; - Iter save; - int all; + Sym *s; + int local, vargen; + int maplineno, lno, etype; - funcdepth++; + if(t == T) + return; + s = n->sym; + if(s == S || s->def == N || s->def->op != OTYPE || s->def->type != n) + fatal("updatetype %T = %T", n, t); - // 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); + etype = n->etype; + switch(n->etype) { + case TFORW: + break; + + case TFORWSTRUCT: + if(t->etype != TSTRUCT) { + yyerror("%T forward declared as struct", n); + return; } - t = funcnext(&save); - } + n->local = 1; + break; - // 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); + case TFORWINTER: + if(t->etype != TINTER) { + yyerror("%T forward declared as interface", n); + return; + } + break; + + default: + fatal("updatetype %T / %T", n, t); } - // this test is remarkedly similar to checkarglist - if(all == 3) - yyerror("cannot mix anonymous and named output arguments"); + // decl was + // type n t; + // copy t, but then zero out state associated with t + // that is no longer associated with n. + maplineno = n->maplineno; + local = n->local; + vargen = n->vargen; + *n = *t; + n->sym = s; + n->local = local; + n->siggen = 0; + n->printed = 0; + n->method = nil; + n->vargen = vargen; + n->nod = N; - ft->outnamed = 0; - if(all == 1) - ft->outnamed = 1; + // catch declaration of incomplete type + switch(n->etype) { + case TFORWSTRUCT: + case TFORWINTER: + break; + default: + checkwidth(n); + } + + // double-check use of type as map key + if(maplineno) { + lno = lineno; + lineno = maplineno; + maptype(n, types[TBOOL]); + lineno = lno; + } } /* - * compile the function. - * called in auto-declaration context. - * returns in extern-declaration context. + * declare variables from grammar + * new_name_list (type | [type] = expr_list) */ -void -funcbody(Node *n) +NodeList* +variter(NodeList *vl, Node *t, NodeList *el) { + int doexpr, gen; + Node *v, *e; + NodeList *init; + Sym *s; + Dcl *r, *d; - compile(n); - - // change the declaration context from auto to extern - if(dclcontext != PAUTO) - fatal("funcbody: dclcontext"); - popdcl(); - funcdepth--; - if(funcdepth == 0) - dclcontext = PEXTERN; -} + init = nil; + doexpr = el != nil; + for(; vl; vl=vl->next) { + if(doexpr) { + if(el == nil) { + yyerror("missing expr in var dcl"); + break; + } + e = el->n; + el = el->next; + } else + e = N; -Node* -funclit0(Node *t) -{ - Node *n; + v = vl->n; + s = v->sym; + if(dclcontext == PEXTERN || dclcontext == PFUNC) { + r = externdcl; + gen = 0; + } else { + r = autodcl; + gen = ++vargen; + pushdcl(s); + } + + redeclare("variable", s); + s->def = v; + // TODO: vargen + s->offset = 0; + s->block = block; - n = nod(OXXX, N, N); - n->outer = funclit; - n->dcl = autodcl; - funclit = n; + v->op = ONAME; + v->class = dclcontext; + v->ntype = t; + v->funcdepth = funcdepth; + v->vargen = gen; + if(e != N || funcdepth > 0) { + if(funcdepth > 0) + init = list(init, nod(ODCL, v, N)); + e = nod(OAS, v, e); + init = list(init, e); + if(e->right != N) + v->defn = e; + } + + d = dcl(); + d->dsym = s; + d->dnode = v; + d->op = ONAME; + r->back->forw = d; + r->back = d; - // new declaration context - autodcl = dcl(); - autodcl->back = autodcl; - - typecheck(&t, Etype); - funcargs(t->type); - return t; + autoexport(s); + } + if(el != nil) + yyerror("extra expr in var dcl"); + return init; } -Node* -funclit1(Node *ntype, NodeList *body) +/* + * declare constants from grammar + * new_name_list [[type] = expr_list] + */ +NodeList* +constiter(NodeList *vl, Node *t, NodeList *cl) { - Node *func; - Type *type; - Node *a, *d, *f, *n, *clos; - Type *ft, *t; - Iter save; - int narg, shift; - NodeList *args, *l, *in, *out; - - 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; + Node *v, *c; + NodeList *vv; + Sym *s; - // unlink from actual ONAME in symbol table - a->closure->closure = a->outer; + vv = vl; + if(cl == nil) { + if(t != N) + yyerror("constdcl cannot have type without expr"); + cl = lastconst; + t = lasttype; + } else { + lastconst = cl; + lasttype = t; } + cl = listtreecopy(cl); - // 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; + for(; vl; vl=vl->next) { + if(cl == nil) { + yyerror("missing expr in const dcl"); + break; } - } + c = cl->n; + cl = cl->next; - // 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); + v = vl->n; + s = v->sym; + if(dclcontext != PEXTERN) + pushdcl(s); + redeclare("constant", s); + s->def = v; - a = t->nname; - if(a != N) { - if(a->stackparam != N) - a = a->stackparam; - a->xoffset += shift; - } + v->op = OLITERAL; + v->ntype = t; + v->defn = c; + autoexport(s); } + if(cl != nil) + yyerror("extra expr in const dcl"); + iota += 1; + return vv; +} - ft = functype(N, in, out); - ft->outnamed = type->outnamed; +/* + * this generates a new name that is + * pushed down on the declaration list. + * no diagnostics are produced as this + * name will soon be declared. + */ +Node* +newname(Sym *s) +{ + Node *n; - // declare function. - vargen++; - snprint(namebuf, sizeof(namebuf), "_f%.3ld·%s", vargen, filename); - f = newname(lookup(namebuf)); - addvar(f, ft, PFUNC); - f->funcdepth = 0; + n = nod(ONAME, N, N); + n->sym = s; + n->type = T; + n->addable = 1; + n->ullman = 1; + n->xoffset = 0; + return n; +} - // 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; +Node* +dclname(Sym *s) +{ + Node *n; - // 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); + // 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) { + // 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; } - d = nod(ODCLFIELD, N, N); - d->type = type; - out = list1(d); - - clos = syslook("closure", 1); - clos->type = functype(N, in, out); + n = newname(s); + n->op = ONONAME; // caller will correct it + return n; +} - // 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)); +Node* +typenod(Type *t) +{ + if(t->nod == N) { + t->nod = nod(OTYPE, N, N); + t->nod->type = t; + t->nod->sym = t->sym; } - typechecklist(args, Erv); - - n = nod(OCALL, clos, N); - n->list = args; - return n; + return t->nod; } + /* - * turn a parsed struct into a type + * this will return an old name + * that has already been pushed on the + * declaration list. a diagnostic is + * generated if no name has been defined. */ -Type** -stotype(NodeList *l, int et, Type **t) +Node* +oldname(Sym *s) { - Type *f, *t1; - Strlit *note; - int lno; - NodeList *init; Node *n; + Node *c; - init = nil; - lno = lineno; - for(; l; l=l->next) { - n = l->n; - lineno = n->lineno; - note = nil; - - if(n->op != ODCLFIELD) - fatal("stotype: oops %N\n", n); - if(n->right != N) { - typecheck(&n->right, Etype); - n->type = n->right->type; - n->right = N; - if(n->embedded && n->type != T) { - t1 = n->type; - if(t1->sym == S && isptr[t1->etype]) + n = s->def; + if(n == N) { + // maybe a top-level name will come along + // to give this a definition later. + n = newname(s); + n->op = ONONAME; + s->def = n; + } + if(n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) { + // 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->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); + } + // return ref to closure var, not original + return n->closure; + } + return n; +} + +/* + * same for types + */ +Type* +newtype(Sym *s) +{ + Type *t; + + t = typ(TFORW); + t->sym = s; + t->type = T; + return t; +} + +Type* +oldtype(Sym *s) +{ + Type *t; + + if(s == S) + return T; + if(s->def == N || s->def->op != OTYPE) { + if(!s->undef) + yyerror("%S is not a type", s); + return T; + } + t = s->def->type; + + /* + * If t is lowercase and not in our package + * and this isn't a reference during the parsing + * of import data, complain. + */ + if(pkgimportname == S && !exportname(s->name) && strcmp(s->package, package) != 0) + yyerror("cannot use type %T", t); + return t; +} + +/* + * type check top level declarations + */ +void +dclchecks(void) +{ + Dcl *d; + + for(d=externdcl; d!=D; d=d->forw) { + if(d->op != ONAME) + continue; + typecheck(&d->dnode, Erv); + } +} + + +/* + * structs, functions, and methods. + * they don't belong here, but where do they belong? + */ + + +/* + * turn a parsed struct into a type + */ +Type** +stotype(NodeList *l, int et, Type **t) +{ + Type *f, *t1; + Strlit *note; + int lno; + NodeList *init; + Node *n; + + init = nil; + lno = lineno; + for(; l; l=l->next) { + n = l->n; + lineno = n->lineno; + note = nil; + + if(n->op != ODCLFIELD) + fatal("stotype: oops %N\n", n); + if(n->right != N) { + typecheck(&n->right, Etype); + n->type = n->right->type; + n->right = N; + if(n->embedded && n->type != T) { + t1 = n->type; + if(t1->sym == S && isptr[t1->etype]) t1 = t1->type; if(t1 != T && isptr[t1->etype]) yyerror("embedded type cannot be a pointer"); @@ -803,289 +853,118 @@ dostruct(NodeList *l, int et) return t; } -Type* -sortinter(Type *t) -{ - return t; -} -void -dcopy(Sym *a, Sym *b) +Node* +embedded(Sym *s) { - a->name = b->name; - a->def = b->def; - a->package = b->package; - a->undef = b->undef; - a->vargen = b->vargen; - a->block = b->block; - a->lastlineno = b->lastlineno; - a->offset = b->offset; -} + Node *n; + char *name; -Sym* -push(void) -{ - Sym *d; + // Names sometimes have disambiguation junk + // appended after a center dot. Discard it when + // making the name for the embedded struct field. + enum { CenterDot = 0xB7 }; + name = s->name; + if(utfrune(s->name, CenterDot)) { + name = strdup(s->name); + *utfrune(name, CenterDot) = 0; + } - d = mal(sizeof(*d)); - d->link = dclstack; - dclstack = d; - return d; + n = newname(lookup(name)); + n = nod(ODCLFIELD, n, N); + n->embedded = 1; + if(s == S) + return n; + n->right = oldname(s); + return n; } -Sym* -pushdcl(Sym *s) +static Node* +findtype(NodeList *l) { - Sym *d; - - d = push(); - dcopy(d, s); - return d; + for(; l; l=l->next) + if(l->n->op == OKEY) + return l->n->right; + return N; } -void -popdcl(void) +static Node* +xanondcl(Node *nt) { - Sym *d, *s; - -// if(dflag()) -// print("revert\n"); + Node *n; + Type *t; - for(d=dclstack; d!=S; d=d->link) { - if(d->name == nil) - break; - s = pkglookup(d->name, d->package); - dcopy(s, d); - if(dflag()) - print("\t%L pop %S\n", lineno, s); + typecheck(&nt, Etype); + t = nt->type; + if(nt->op != OTYPE) { + yyerror("%S is not a type", nt->sym); + t = types[TINT32]; } - if(d == S) - fatal("popdcl: no mark"); - dclstack = d->link; - block = d->block; + n = nod(ODCLFIELD, N, N); + n->type = t; + return n; } -void -poptodcl(void) +static Node* +namedcl(Node *nn, Node *nt) { - Sym *d, *s; + Node *n; + Type *t; - for(d=dclstack; d!=S; d=d->link) { - if(d->name == nil) - break; - s = pkglookup(d->name, d->package); - dcopy(s, d); - if(dflag()) - print("\t%L pop %S\n", lineno, s); + 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); } - if(d == S) - fatal("poptodcl: no mark"); - dclstack = d; + 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; } -void -markdcl(void) +/* + * check that the list of declarations is either all anonymous or all named + */ +NodeList* +checkarglist(NodeList *all) { - Sym *d; - - d = push(); - d->name = nil; // used as a mark in fifo - d->block = block; - - blockgen++; - block = blockgen; + int named; + Node *r; + NodeList *l; -// if(dflag()) -// print("markdcl\n"); -} - -void -dumpdcl(char *st) -{ - Sym *s, *d; - int i; - - print("\ndumpdcl: %s %p\n", st, b0stack); - - i = 0; - for(d=dclstack; d!=S; d=d->link) { - i++; - print(" %.2d %p", i, d); - if(d == b0stack) - print(" (b0)"); - if(d->name == nil) { - print("\n"); - continue; - } - print(" '%s'", d->name); - s = pkglookup(d->name, d->package); - print(" %lS\n", s); - } -} - -void -testdclstack(void) -{ - Sym *d; - - for(d=dclstack; d!=S; d=d->link) { - if(d->name == nil) { - yyerror("mark left on the stack"); - continue; + named = 0; + for(l=all; l; l=l->next) { + if(l->n->op == OKEY) { + named = 1; + break; } } -} - -static void -redeclare(char *str, Sym *s) -{ - if(s->block == block) { - yyerror("%s %S redeclared in this block", str, s); - print(" previous declaration at %L\n", s->lastlineno); - } - s->block = block; - s->lastlineno = lineno; -} - -void -addvar(Node *n, Type *t, int ctxt) -{ - Dcl *r, *d; - Sym *s; - int gen; - - if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T) - fatal("addvar: n=%N t=%T nil", n, t); - - s = n->sym; - - if(ctxt == PEXTERN || ctxt == PFUNC) { - r = externdcl; - gen = 0; - } else { - r = autodcl; - vargen++; - gen = vargen; - pushdcl(s); - } - - redeclare("variable", s); - n->op = ONAME; - s->vargen = gen; - s->def = n; - s->offset = 0; - - n->funcdepth = funcdepth; - n->type = t; - n->vargen = gen; - n->class = ctxt; - - d = dcl(); - d->dsym = s; - d->dnode = n; - d->op = ONAME; - - r->back->forw = d; - r->back = d; - - if(dflag()) { - if(ctxt == PEXTERN) - print("extern var-dcl %S G%ld %T\n", s, s->vargen, t); - else if(ctxt == PFUNC) - print("extern func-dcl %S G%ld %T\n", s, s->vargen, t); - else - print("auto var-dcl %S G%ld %T\n", s, s->vargen, t); - } -} - -void -addtyp(Type *n, int ctxt) -{ - Dcl *r, *d; - Sym *s; - static int typgen; - - if(n==T || n->sym == S) - fatal("addtyp: n=%T t=%T nil", n); - - s = n->sym; - - if(ctxt == PEXTERN) - r = externdcl; - else { - r = autodcl; - pushdcl(s); - n->vargen = ++typgen; - } - - redeclare("type", s); - s->def = typenod(n); - - d = dcl(); - d->dsym = s; - d->dtype = n; - d->op = OTYPE; - - d->back = r->back; - r->back->forw = d; - r->back = d; - - d = dcl(); - d->dtype = n; - d->op = OTYPE; - - r = typelist; - d->back = r->back; - r->back->forw = d; - r->back = d; - if(dflag()) { - if(ctxt == PEXTERN) - print("extern typ-dcl %S G%ld %T\n", s, s->vargen, n); + for(l=all; l; l=l->next) { + if(named) + l->n = namedcl(l->n, findtype(l)); else - print("auto typ-dcl %S G%ld %T\n", s, s->vargen, n); + 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 ..."); + } } + return all; } -// TODO(rsc): cut -void -addconst(Node *n, Node *e, int ctxt) -{ - Sym *s; - Dcl *r, *d; - - if(n->op != ONAME && n->op != ONONAME) - fatal("addconst: not a name"); - - if(e->op != OLITERAL) { - yyerror("expression must be a constant"); - return; - } - - s = n->sym; - - if(ctxt == PEXTERN) - r = externdcl; - else { - r = autodcl; - pushdcl(s); - } - - redeclare("constant", s); - s->def = e; - e->sym = s; - - d = dcl(); - d->dsym = s; - d->dnode = e; - d->op = OLITERAL; - d->back = r->back; - r->back->forw = d; - r->back = d; - - if(dflag()) - print("const-dcl %S %N\n", n->sym, n->sym->def); -} Node* fakethis(void) @@ -1122,730 +1001,469 @@ isifacemethod(Type *f) } /* - * this generates a new name that is - * pushed down on the declaration list. - * no diagnostics are produced as this - * name will soon be declared. + * turn a parsed function declaration + * into a type */ -Node* -newname(Sym *s) +Type* +functype(Node *this, NodeList *in, NodeList *out) { - Node *n; + Type *t; + NodeList *rcvr; - n = nod(ONAME, N, N); - n->sym = s; - n->type = T; - n->addable = 1; - n->ullman = 1; - n->xoffset = 0; - return n; -} + t = typ(TFUNC); -Node* -dclname(Sym *s) -{ - Node *n; + rcvr = nil; + if(this) + rcvr = list1(this); + t->type = dostruct(rcvr, TFUNC); + t->type->down = dostruct(out, TFUNC); + t->type->down->down = dostruct(in, TFUNC); - // 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) { - // 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(this) + t->thistuple = 1; + t->outtuple = count(out); + t->intuple = count(in); - n = newname(s); - n->op = ONONAME; // caller will correct it - return n; + checkwidth(t); + return t; } -Node* -typenod(Type *t) +int +methcmp(Type *t1, Type *t2) { - if(t->nod == N) { - t->nod = nod(OTYPE, N, N); - t->nod->type = t; - t->nod->sym = t->sym; - } - return t->nod; -} + if(t1->etype != TFUNC) + return 0; + if(t2->etype != TFUNC) + return 0; + t1 = t1->type->down; // skip this arg + t2 = t2->type->down; // skip this arg + for(;;) { + if(t1 == t2) + break; + if(t1 == T || t2 == T) + return 0; + if(t1->etype != TSTRUCT || t2->etype != TSTRUCT) + return 0; -/* - * this will return an old name - * that has already been pushed on the - * declaration list. a diagnostic is - * generated if no name has been defined. - */ -Node* -oldname(Sym *s) -{ - Node *n; - Node *c; + if(!eqtype(t1->type, t2->type)) + return 0; - n = s->def; - if(n == N) { - // maybe a top-level name will come along - // to give this a definition later. - n = newname(s); - n->op = ONONAME; - s->def = n; - } - if(n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) { - // 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->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); - } - // return ref to closure var, not original - return n->closure; + t1 = t1->down; + t2 = t2->down; } - return n; + return 1; } -/* - * same for types - */ -Type* -newtype(Sym *s) +Sym* +methodsym(Sym *nsym, Type *t0) { + Sym *s; + char buf[NSYMB]; Type *t; - t = typ(TFORW); - t->sym = s; - t->type = T; - return t; -} + t = t0; + if(t == T) + goto bad; + s = t->sym; + if(s == S) { + if(!isptr[t->etype]) + goto bad; + t = t->type; + if(t == T) + goto bad; + s = t->sym; + if(s == S) + goto bad; + } -Type* -oldtype(Sym *s) -{ - Type *t; + // if t0 == *t and t0 has a sym, + // we want to see *t, not t0, in the method name. + if(t != t0 && t0->sym) + t0 = ptrto(t); - if(s == S) - return T; - if(s->def == N || s->def->op != OTYPE) { - if(!s->undef) - yyerror("%S is not a type", s); - return T; - } - t = s->def->type; + snprint(buf, sizeof(buf), "%#hT·%s", t0, nsym->name); +//print("methodname %s\n", buf); + return pkglookup(buf, s->package); - /* - * If t is lowercase and not in our package - * and this isn't a reference during the parsing - * of import data, complain. - */ - if(pkgimportname == S && !exportname(s->name) && strcmp(s->package, package) != 0) - yyerror("cannot use type %T", t); - return t; +bad: + yyerror("illegal type: %T", t); + return S; } -/* - * n is a node with a name. - * make it a declaration of the given type. - */ Node* -nametodcl(Node *n, Type *t) +methodname(Node *n, Type *t) { - n = nod(ODCLFIELD, n, N); - n->type = t; - return n; + Sym *s; + + s = methodsym(n->sym, t); + if(s == S) + return n; + return newname(s); } /* - * make an anonymous declaration for t + * add a method, declared as a function, + * n is fieldname, pa is base type, t is function type */ -Node* -anondcl(Type *t) +void +addmethod(Node *n, Type *t, int local) { - Node *n; + Type *f, *d, *pa; + Sym *sf; - n = nod(ODCLFIELD, N, N); - n->type = t; - return n; -} + pa = nil; + sf = nil; -static Node* -findtype(NodeList *l) -{ - for(; l; l=l->next) - if(l->n->op == OKEY) - return l->n->right; - return N; -} + // get field sym + if(n == N) + goto bad; + if(n->op != ONAME) + goto bad; + sf = n->sym; + if(sf == S) + goto bad; -static Node* -xanondcl(Node *nt) -{ - Node *n; - Type *t; + // 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; - 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; -} + f = methtype(pa); + if(f == T) + goto bad; -static Node* -namedcl(Node *nn, Node *nt) -{ - Node *n; - Type *t; + pa = f; + if(pkgimportname != S && !exportname(sf->name)) + sf = pkglookup(sf->name, pkgimportname->name); - 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); + n = nod(ODCLFIELD, newname(sf), N); + n->type = t; + + d = T; // last found + for(f=pa->method; f!=T; f=f->down) { + d = f; + if(f->etype != TFIELD) + fatal("addmethod: not TFIELD: %N", f); + if(strcmp(sf->name, f->sym->name) != 0) + continue; + if(!eqtype(t, f->type)) { + yyerror("method redeclared: %T.%S", pa, sf); + print("\t%T\n\t%T\n", f->type, t); + } + return; } - 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; + + if(local && !pa->local) { + // defining method on non-local type. + // method must have been forward declared + // elsewhere, i.e. where the type was. + yyerror("cannot define new methods on non-local type %T", pa); + return; } - n = nod(ODCLFIELD, newname(nn->sym), N); - n->type = t; - return n; + + if(d == T) + stotype(list1(n), 0, &pa->method); + else + stotype(list1(n), 0, &d->down); + return; + +bad: + yyerror("invalid receiver type %T", pa); } /* - * check that the list of declarations is either all anonymous or all named + * declare the function proper. + * and declare the arguments + * called in extern-declaration context + * returns in auto-declaration context. */ -NodeList* -checkarglist(NodeList *all) -{ - int named; - Node *r; - NodeList *l; +void +funchdr(Node *n) +{ + Node *on; + Sym *s; - named = 0; - for(l=all; l; l=l->next) { - if(l->n->op == OKEY) { - named = 1; - break; + 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; } } - for(l=all; l; l=l->next) { - if(named) - l->n = namedcl(l->n, findtype(l)); + // 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 - 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 ..."); - } + n->nname->class = PFUNC; + } else { + // identical redeclaration + // steal previous names + n->nname = on; + n->type = on->type; + n->class = on->class; + n->sym = s; } - return all; -} -/* - * hand-craft the following initialization code - * var initdone· uint8 (1) - * func Init·() (2) - * if initdone· { (3) - * if initdone· == 2 (4) - * return - * throw(); (5) - * } - * initdone.++; (6) - * // over all matching imported symbols - * .init·() (7) - * { } (8) - * init·() // if any (9) - * initdone.++; (10) - * return (11) - * } - */ -int -anyinit(NodeList *n) -{ - uint32 h; - Sym *s; - - // are there any init statements - if(n != nil) - return 1; - - // is this main - if(strcmp(package, "main") == 0) - return 1; - - // is there an explicit init function - snprint(namebuf, sizeof(namebuf), "init·%s", filename); - s = lookup(namebuf); - if(s->def != N) - return 1; + // change the declaration context from extern to auto + autodcl = dcl(); + autodcl->back = autodcl; - // are there any imported init functions - for(h=0; hlink) { - if(s->name[0] != 'I' || strncmp(s->name, "Init·", 6) != 0) - continue; - if(s->def == N) - continue; - return 1; - } + if(funcdepth == 0 && dclcontext != PEXTERN) + fatal("funchdr: dclcontext"); - // then none - return 0; + dclcontext = PAUTO; + markdcl(); + funcargs(n->type); } void -fninit(NodeList *n) +funcargs(Type *ft) { - Node *gatevar; - Node *a, *b, *fn; - NodeList *r; - uint32 h; - Sym *s, *initsym; - - if(strcmp(package, "PACKAGE") == 0) { - // sys.go or unsafe.go during compiler build - return; - } - - if(!anyinit(n)) - return; - - r = nil; - - // (1) - snprint(namebuf, sizeof(namebuf), "initdone·%s", filename); - gatevar = newname(lookup(namebuf)); - addvar(gatevar, types[TUINT8], PEXTERN); - - // (2) - - maxarg = 0; - stksize = initstksize; - - snprint(namebuf, sizeof(namebuf), "Init·%s", filename); - - // this is a botch since we need a known name to - // call the top level init function out of rt0 - if(strcmp(package, "main") == 0) - snprint(namebuf, sizeof(namebuf), "init"); - - fn = nod(ODCLFUNC, N, N); - initsym = lookup(namebuf); - fn->nname = newname(initsym); - fn->type = functype(N, nil, nil); - funchdr(fn); - - // (3) - a = nod(OIF, N, N); - a->ntest = nod(ONE, gatevar, nodintconst(0)); - r = list(r, a); - - // (4) - b = nod(OIF, N, N); - b->ntest = nod(OEQ, gatevar, nodintconst(2)); - b->nbody = list1(nod(ORETURN, N, N)); - a->nbody = list1(b); - - // (5) - b = syslook("throwinit", 0); - b = nod(OCALL, b, N); - a->nbody = list(a->nbody, b); - - // (6) - a = nod(OASOP, gatevar, nodintconst(1)); - a->etype = OADD; - r = list(r, a); + Type *t; + Iter save; + int all; - // (7) - for(h=0; hlink) { - if(s->name[0] != 'I' || strncmp(s->name, "Init·", 6) != 0) - continue; - if(s->def == N) - continue; - if(s == initsym) - continue; + funcdepth++; - // could check that it is fn of no args/returns - a = nod(OCALL, s->def, N); - r = list(r, a); + // 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); } - // (8) - r = concat(r, initfix(n)); - - // (9) - // could check that it is fn of no args/returns - snprint(namebuf, sizeof(namebuf), "init·%s", filename); - s = lookup(namebuf); - if(s->def != N) { - a = nod(OCALL, s->def, N); - r = list(r, a); + // 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); } - // (10) - a = nod(OASOP, gatevar, nodintconst(1)); - a->etype = OADD; - r = list(r, a); - - // (11) - a = nod(ORETURN, N, N); - r = list(r, a); - - exportsym(fn->nname->sym); - - fn->nbody = r; -//dump("b", fn); -//dump("r", fn->nbody); + // this test is remarkedly similar to checkarglist + if(all == 3) + yyerror("cannot mix anonymous and named output arguments"); - popdcl(); - initflag = 1; // flag for loader static initialization - compile(fn); - initflag = 0; + ft->outnamed = 0; + if(all == 1) + ft->outnamed = 1; } - /* - * when a type's width should be known, we call checkwidth - * to compute it. during a declaration like - * - * type T *struct { next T } - * - * it is necessary to defer the calculation of the struct width - * until after T has been initialized to be a pointer to that struct. - * similarly, during import processing structs may be used - * before their definition. in those situations, calling - * defercheckwidth() stops width calculations until - * resumecheckwidth() is called, at which point all the - * checkwidths that were deferred are executed. - * sometimes it is okay to + * compile the function. + * called in auto-declaration context. + * returns in extern-declaration context. */ -typedef struct TypeList TypeList; -struct TypeList { - Type *t; - TypeList *next; -}; - -static TypeList *tlfree; -static TypeList *tlq; -static int defercalc; - void -checkwidth(Type *t) +funcbody(Node *n) { - TypeList *l; - - // function arg structs should not be checked - // outside of the enclosing function. - if(t->funarg) - fatal("checkwidth %T", t); - - if(!defercalc) { - dowidth(t); - return; - } - l = tlfree; - if(l != nil) - tlfree = l->next; - else - l = mal(sizeof *l); + compile(n); - l->t = t; - l->next = tlq; - tlq = l; + // change the declaration context from auto to extern + if(dclcontext != PAUTO) + fatal("funcbody: dclcontext"); + popdcl(); + funcdepth--; + if(funcdepth == 0) + dclcontext = PEXTERN; } -void -defercheckwidth(void) +Node* +funclit0(Node *t) { - // we get out of sync on syntax errors, so don't be pedantic. - // if(defercalc) - // fatal("defercheckwidth"); - defercalc = 1; -} + Node *n; -void -resumecheckwidth(void) -{ - TypeList *l; + n = nod(OXXX, N, N); + n->outer = funclit; + n->dcl = autodcl; + funclit = n; - if(!defercalc) - fatal("restartcheckwidth"); - defercalc = 0; + // new declaration context + autodcl = dcl(); + autodcl->back = autodcl; - for(l = tlq; l != nil; l = tlq) { - dowidth(l->t); - tlq = l->next; - l->next = tlfree; - tlfree = l; - } + typecheck(&t, Etype); + funcargs(t->type); + return t; } Node* -embedded(Sym *s) +funclit1(Node *ntype, NodeList *body) { - Node *n; - char *name; + Node *func; + Type *type; + Node *a, *d, *f, *n, *clos; + Type *ft, *t; + Iter save; + int narg, shift; + NodeList *args, *l, *in, *out; - // Names sometimes have disambiguation junk - // appended after a center dot. Discard it when - // making the name for the embedded struct field. - enum { CenterDot = 0xB7 }; - name = s->name; - if(utfrune(s->name, CenterDot)) { - name = strdup(s->name); - *utfrune(name, CenterDot) = 0; - } + type = ntype->type; + popdcl(); + func = funclit; + funclit = func->outer; - n = newname(lookup(name)); - n = nod(ODCLFIELD, n, N); - n->embedded = 1; - if(s == S) - return n; - n->right = oldname(s); - return n; -} + // 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); -/* - * declare variables from grammar - * new_name_list (type | [type] = expr_list) - */ -NodeList* -variter(NodeList *vl, Node *t, NodeList *el) -{ - int doexpr, gen; - Node *v, *e; - NodeList *init; - Sym *s; - Dcl *r, *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; - init = nil; - doexpr = el != nil; - for(; vl; vl=vl->next) { - if(doexpr) { - if(el == nil) { - yyerror("missing expr in var dcl"); - break; - } - e = el->n; - el = el->next; - } else - e = N; + a->xoffset = 0; - v = vl->n; - s = v->sym; - if(dclcontext == PEXTERN || dclcontext == PFUNC) { - r = externdcl; - gen = 0; - } else { - r = autodcl; - gen = ++vargen; - pushdcl(s); - } + // unlink from actual ONAME in symbol table + a->closure->closure = a->outer; + } - redeclare("variable", s); - s->def = v; - // TODO: vargen - s->offset = 0; - s->block = block; + // add a dummy arg for the closure's caller pc + d = nod(ODCLFIELD, N, N); + d->type = types[TUINTPTR]; + in = list(in, d); - v->op = ONAME; - v->class = dclcontext; - v->ntype = t; - v->funcdepth = funcdepth; - v->vargen = gen; - if(e != N || funcdepth > 0) { - if(funcdepth > 0) - init = list(init, nod(ODCL, v, N)); - e = nod(OAS, v, e); - init = list(init, e); - if(e->right != N) - v->defn = e; - } + // slide param offset to make room for ptrs above. + // narg+1 to skip over caller pc. + shift = (narg+1)*types[tptr]->width; - d = dcl(); - d->dsym = s; - d->dnode = v; - d->op = ONAME; - r->back->forw = d; - r->back = d; + // 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); - autoexport(s); + a = t->nname; + if(a != N) { + if(a->stackparam != N) + a = a->stackparam; + a->xoffset += shift; + } } - if(el != nil) - yyerror("extra expr in var dcl"); - return init; -} -/* - * declare constants from grammar - * new_name_list [[type] = expr_list] - */ -NodeList* -constiter(NodeList *vl, Node *t, NodeList *cl) -{ - Node *v, *c; - NodeList *vv; - Sym *s; + // 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); - vv = vl; - if(cl == nil) { - if(t != N) - yyerror("constdcl cannot have type without expr"); - cl = lastconst; - t = lasttype; - } else { - lastconst = cl; - lasttype = t; + a = t->nname; + if(a != N) { + if(a->stackparam != N) + a = a->stackparam; + a->xoffset += shift; + } } - cl = listtreecopy(cl); - for(; vl; vl=vl->next) { - if(cl == nil) { - yyerror("missing expr in const dcl"); - break; - } - c = cl->n; - cl = cl->next; + ft = functype(N, in, out); + ft->outnamed = type->outnamed; - v = vl->n; - s = v->sym; - if(dclcontext != PEXTERN) - pushdcl(s); - redeclare("constant", s); - s->def = v; + // declare function. + vargen++; + snprint(namebuf, sizeof(namebuf), "_f%.3ld·%s", vargen, filename); + f = newname(lookup(namebuf)); + addvar(f, ft, PFUNC); + f->funcdepth = 0; - v->op = OLITERAL; - v->ntype = t; - v->defn = c; - autoexport(s); - } - if(cl != nil) - yyerror("extra expr in const dcl"); - iota += 1; - return vv; -} + // 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; -/* - * look for - * unsafe.Sizeof - * unsafe.Offsetof - * rewrite with a constant - */ -Node* -unsafenmagic(Node *fn, NodeList *args) -{ - Node *r, *n; - Sym *s; - Type *t, *tr; - long v; - Val val; - - if(fn == N || fn->op != ONAME || (s = fn->sym) == S) - goto no; - if(strcmp(s->package, "unsafe") != 0) - goto no; - - if(args == nil) { - yyerror("missing argument for %S", s); - goto no; - } - r = args->n; - - n = nod(OLITERAL, N, N); - if(strcmp(s->name, "Sizeof") == 0) { - typecheck(&r, Erv); - tr = r->type; - if(r->op == OLITERAL && r->val.ctype == CTSTR) - tr = types[TSTRING]; - if(tr == T) - goto no; - v = tr->width; - goto yes; - } - if(strcmp(s->name, "Offsetof") == 0) { - if(r->op != ODOT && r->op != ODOTPTR) - goto no; - typecheck(&r, Erv); - v = r->xoffset; - goto yes; - } - if(strcmp(s->name, "Alignof") == 0) { - typecheck(&r, Erv); - tr = r->type; - if(r->op == OLITERAL && r->val.ctype == CTSTR) - tr = types[TSTRING]; - if(tr == T) - goto no; - - // make struct { byte; T; } - t = typ(TSTRUCT); - t->type = typ(TFIELD); - t->type->type = types[TUINT8]; - t->type->down = typ(TFIELD); - t->type->down->type = tr; - // compute struct widths - dowidth(t); - - // the offset of T is its required alignment - v = t->type->down->width; - goto yes; + // 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); } -no: - return N; - -yes: - if(args->next != nil) - yyerror("extra arguments for %S", s); - // any side effects disappear; ignore init - val.ctype = CTINT; - val.u.xval = mal(sizeof(*n->val.u.xval)); - mpmovecfix(val.u.xval, v); - n = nod(OLITERAL, N, N); - n->val = val; - n->type = types[TINT]; - return n; -} + d = nod(ODCLFIELD, N, N); + d->type = type; + out = list1(d); -void -dclchecks(void) -{ - Dcl *d; + clos = syslook("closure", 1); + clos->type = functype(N, in, out); - for(d=externdcl; d!=D; d=d->forw) { - if(d->op != ONAME) - continue; - typecheck(&d->dnode, Erv); + // 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; } diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index db757fa4e7..8a79a1abd4 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -601,8 +601,6 @@ EXTERN char namebuf[NSYMB]; EXTERN char lexbuf[NSYMB]; EXTERN char debug[256]; EXTERN Sym* hash[NHASH]; -EXTERN Sym* dclstack; -EXTERN Sym* b0stack; EXTERN Sym* pkgmyname; // my name for package EXTERN Sym* pkgimportname; // package name from imported package EXTERN int tptr; // either TPTR32 or TPTR64 @@ -814,7 +812,6 @@ void argtype(Node*, Type*); int eqargs(Type*, Type*); uint32 typehash(Type*, int, int); void frame(int); -Node* dobad(void); Node* nodintconst(int64); void nodconst(Node*, Type*, int64); Node* nodnil(void); @@ -921,7 +918,6 @@ Type* newtype(Sym*); Type* oldtype(Sym*); void fninit(NodeList*); Node* nametodcl(Node*, Type*); -Node* anondcl(Type*); NodeList* checkarglist(NodeList*); void checkwidth(Type*); void defercheckwidth(void); diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index f048c29d14..7286453189 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -1137,7 +1137,6 @@ fndcl: { Node *n; - b0stack = dclstack; // mark base for fn literals $$ = nod(ODCLFUNC, N, N); $$->nname = $1; if($3 == nil && $5 == nil) @@ -1159,7 +1158,6 @@ fndcl: rcvr = N; } - b0stack = dclstack; // mark base for fn literals $$ = nod(ODCLFUNC, N, N); $$->nname = $4; $$->nname = methodname($4, rcvr->type); diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c new file mode 100644 index 0000000000..5fc7f8bbc7 --- /dev/null +++ b/src/cmd/gc/init.c @@ -0,0 +1,193 @@ +// 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. + +#include "go.h" + +/* + * a function named init is a special case. + * it is called by the initialization before + * main is run. to make it unique within a + * package and also uncallable, the name, + * normally "pkg.init", is altered to "pkg.init·filename". + */ +Node* +renameinit(Node *n) +{ + Sym *s; + + s = n->sym; + if(s == S) + return n; + if(strcmp(s->name, "init") != 0) + return n; + + snprint(namebuf, sizeof(namebuf), "init·%s", filename); + s = lookup(namebuf); + return newname(s); +} + +/* + * hand-craft the following initialization code + * var initdone· uint8 (1) + * func Init·() (2) + * if initdone· { (3) + * if initdone· == 2 (4) + * return + * throw(); (5) + * } + * initdone.++; (6) + * // over all matching imported symbols + * .init·() (7) + * { } (8) + * init·() // if any (9) + * initdone.++; (10) + * return (11) + * } + */ +int +anyinit(NodeList *n) +{ + uint32 h; + Sym *s; + + // are there any init statements + if(n != nil) + return 1; + + // is this main + if(strcmp(package, "main") == 0) + return 1; + + // is there an explicit init function + snprint(namebuf, sizeof(namebuf), "init·%s", filename); + s = lookup(namebuf); + if(s->def != N) + return 1; + + // are there any imported init functions + for(h=0; hlink) { + if(s->name[0] != 'I' || strncmp(s->name, "Init·", 6) != 0) + continue; + if(s->def == N) + continue; + return 1; + } + + // then none + return 0; +} + +void +fninit(NodeList *n) +{ + Node *gatevar; + Node *a, *b, *fn; + NodeList *r; + uint32 h; + Sym *s, *initsym; + + if(strcmp(package, "PACKAGE") == 0) { + // sys.go or unsafe.go during compiler build + return; + } + + if(!anyinit(n)) + return; + + r = nil; + + // (1) + snprint(namebuf, sizeof(namebuf), "initdone·%s", filename); + gatevar = newname(lookup(namebuf)); + addvar(gatevar, types[TUINT8], PEXTERN); + + // (2) + + maxarg = 0; + stksize = initstksize; + + snprint(namebuf, sizeof(namebuf), "Init·%s", filename); + + // this is a botch since we need a known name to + // call the top level init function out of rt0 + if(strcmp(package, "main") == 0) + snprint(namebuf, sizeof(namebuf), "init"); + + fn = nod(ODCLFUNC, N, N); + initsym = lookup(namebuf); + fn->nname = newname(initsym); + fn->type = functype(N, nil, nil); + funchdr(fn); + + // (3) + a = nod(OIF, N, N); + a->ntest = nod(ONE, gatevar, nodintconst(0)); + r = list(r, a); + + // (4) + b = nod(OIF, N, N); + b->ntest = nod(OEQ, gatevar, nodintconst(2)); + b->nbody = list1(nod(ORETURN, N, N)); + a->nbody = list1(b); + + // (5) + b = syslook("throwinit", 0); + b = nod(OCALL, b, N); + a->nbody = list(a->nbody, b); + + // (6) + a = nod(OASOP, gatevar, nodintconst(1)); + a->etype = OADD; + r = list(r, a); + + // (7) + for(h=0; hlink) { + if(s->name[0] != 'I' || strncmp(s->name, "Init·", 6) != 0) + continue; + if(s->def == N) + continue; + if(s == initsym) + continue; + + // could check that it is fn of no args/returns + a = nod(OCALL, s->def, N); + r = list(r, a); + } + + // (8) + r = concat(r, initfix(n)); + + // (9) + // could check that it is fn of no args/returns + snprint(namebuf, sizeof(namebuf), "init·%s", filename); + s = lookup(namebuf); + if(s->def != N) { + a = nod(OCALL, s->def, N); + r = list(r, a); + } + + // (10) + a = nod(OASOP, gatevar, nodintconst(1)); + a->etype = OADD; + r = list(r, a); + + // (11) + a = nod(ORETURN, N, N); + r = list(r, a); + + exportsym(fn->nname->sym); + + fn->nbody = r; +//dump("b", fn); +//dump("r", fn->nbody); + + popdcl(); + initflag = 1; // flag for loader static initialization + compile(fn); + initflag = 0; +} + + diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index be99a2afc5..a0ef878f1f 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -393,10 +393,11 @@ typ(int et) return t; } -Node* -dobad(void) + +Type* +sortinter(Type *t) { - return nod(OBAD, N, N); + return t; } Node* @@ -2636,23 +2637,25 @@ NodeList* structargs(Type **tl, int mustname) { Iter savet; - Node *a; + Node *a, *n; NodeList *args; Type *t; - char nam[100]; - int n; + char buf[100]; + int gen; args = nil; - n = 0; + gen = 0; for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) { + n = N; if(t->sym) - a = nametodcl(newname(t->sym), t->type); + n = newname(t->sym); else if(mustname) { // have to give it a name so we can refer to it in trampoline - snprint(nam, sizeof nam, ".anon%d", n++); - a = nametodcl(newname(lookup(nam)), t->type); - } else - a = anondcl(t->type); + snprint(buf, sizeof buf, ".anon%d", gen++); + n = newname(lookup(buf)); + } + a = nod(ODCLFIELD, n, N); + a->type = t->type; args = list(args, a); } return args; @@ -2694,7 +2697,8 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam) dclcontext = PEXTERN; markdcl(); - this = nametodcl(newname(lookup(".this")), rcvr); + this = nod(ODCLFIELD, newname(lookup(".this")), N); + this->type = rcvr; in = structargs(getinarg(method->type), 1); out = structargs(getoutarg(method->type), 0); @@ -2982,6 +2986,9 @@ liststmt(NodeList *l) return n; } +/* + * return nelem of list + */ int count(NodeList *l) { @@ -2992,3 +2999,96 @@ count(NodeList *l) n++; return n; } + +/* + * return nelem of list + */ +int +structcount(Type *t) +{ + int v; + Iter s; + + v = 0; + for(t = structfirst(&s, &t); t != T; t = structnext(&s)) + v++; + return v; +} + +/* + * when a type's width should be known, we call checkwidth + * to compute it. during a declaration like + * + * type T *struct { next T } + * + * it is necessary to defer the calculation of the struct width + * until after T has been initialized to be a pointer to that struct. + * similarly, during import processing structs may be used + * before their definition. in those situations, calling + * defercheckwidth() stops width calculations until + * resumecheckwidth() is called, at which point all the + * checkwidths that were deferred are executed. + * sometimes it is okay to + */ +typedef struct TypeList TypeList; +struct TypeList { + Type *t; + TypeList *next; +}; + +static TypeList *tlfree; +static TypeList *tlq; +static int defercalc; + +void +checkwidth(Type *t) +{ + TypeList *l; + + // function arg structs should not be checked + // outside of the enclosing function. + if(t->funarg) + fatal("checkwidth %T", t); + + if(!defercalc) { + dowidth(t); + return; + } + + l = tlfree; + if(l != nil) + tlfree = l->next; + else + l = mal(sizeof *l); + + l->t = t; + l->next = tlq; + tlq = l; +} + +void +defercheckwidth(void) +{ + // we get out of sync on syntax errors, so don't be pedantic. + // if(defercalc) + // fatal("defercheckwidth"); + defercalc = 1; +} + +void +resumecheckwidth(void) +{ + TypeList *l; + + if(!defercalc) + fatal("restartcheckwidth"); + defercalc = 0; + + for(l = tlq; l != nil; l = tlq) { + dowidth(l->t); + tlq = l->next; + l->next = tlfree; + tlfree = l; + } +} + diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c new file mode 100644 index 0000000000..9c1f9519af --- /dev/null +++ b/src/cmd/gc/unsafe.c @@ -0,0 +1,87 @@ +// 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. + +#include "go.h" + +/* + * look for + * unsafe.Sizeof + * unsafe.Offsetof + * rewrite with a constant + */ +Node* +unsafenmagic(Node *fn, NodeList *args) +{ + Node *r, *n; + Sym *s; + Type *t, *tr; + long v; + Val val; + + if(fn == N || fn->op != ONAME || (s = fn->sym) == S) + goto no; + if(strcmp(s->package, "unsafe") != 0) + goto no; + + if(args == nil) { + yyerror("missing argument for %S", s); + goto no; + } + r = args->n; + + n = nod(OLITERAL, N, N); + if(strcmp(s->name, "Sizeof") == 0) { + typecheck(&r, Erv); + tr = r->type; + if(r->op == OLITERAL && r->val.ctype == CTSTR) + tr = types[TSTRING]; + if(tr == T) + goto no; + v = tr->width; + goto yes; + } + if(strcmp(s->name, "Offsetof") == 0) { + if(r->op != ODOT && r->op != ODOTPTR) + goto no; + typecheck(&r, Erv); + v = r->xoffset; + goto yes; + } + if(strcmp(s->name, "Alignof") == 0) { + typecheck(&r, Erv); + tr = r->type; + if(r->op == OLITERAL && r->val.ctype == CTSTR) + tr = types[TSTRING]; + if(tr == T) + goto no; + + // make struct { byte; T; } + t = typ(TSTRUCT); + t->type = typ(TFIELD); + t->type->type = types[TUINT8]; + t->type->down = typ(TFIELD); + t->type->down->type = tr; + // compute struct widths + dowidth(t); + + // the offset of T is its required alignment + v = t->type->down->width; + goto yes; + } + +no: + return N; + +yes: + if(args->next != nil) + yyerror("extra arguments for %S", s); + // any side effects disappear; ignore init + val.ctype = CTINT; + val.u.xval = mal(sizeof(*n->val.u.xval)); + mpmovecfix(val.u.xval, v); + n = nod(OLITERAL, N, N); + n->val = val; + n->type = types[TINT]; + return n; +} -- 2.48.1