diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/gc/Makefile | 30 | ||||
-rw-r--r-- | src/cmd/gc/dcl.c | 2028 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 4 | ||||
-rw-r--r-- | src/cmd/gc/go.y | 2 | ||||
-rw-r--r-- | src/cmd/gc/init.c | 193 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 126 | ||||
-rw-r--r-- | src/cmd/gc/unsafe.c | 87 |
7 files changed, 1232 insertions, 1238 deletions
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile index ec9702055..55b61ce8b 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 3b8e67d15..7003045be 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -18,6 +18,288 @@ dflag(void) } /* + * declaration stack & operations + */ +static Sym* dclstack; + +void +dcopy(Sym *a, Sym *b) +{ + 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; +} + +Sym* +push(void) +{ + Sym *d; + + d = mal(sizeof(*d)); + d->link = dclstack; + dclstack = d; + return d; +} + +Sym* +pushdcl(Sym *s) +{ + Sym *d; + + d = push(); + dcopy(d, s); + return d; +} + +void +popdcl(void) +{ + Sym *d, *s; + +// 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; +} + +void +poptodcl(void) +{ + Sym *d, *s; + + 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; +} + +void +markdcl(void) +{ + Sym *d; + + d = push(); + d->name = nil; // used as a mark in fifo + d->block = block; + + blockgen++; + block = blockgen; + +// if(dflag()) +// print("markdcl\n"); +} + +void +dumpdcl(char *st) +{ + Sym *s, *d; + int i; + + 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); + } +} + +void +testdclstack(void) +{ + Sym *d; + + for(d=dclstack; d!=S; d=d->link) { + if(d->name == nil) { + yyerror("mark left on the stack"); + continue; + } + } +} + +/* + * declare individual names - var, typ, const + */ +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); + else + print("auto typ-dcl %S G%ld %T\n", s, s->vargen, n); + } +} + +// 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); +} + +/* * declare (possible list) n of type t. * append ODCL nodes to *init */ @@ -169,20 +451,553 @@ updatetype(Type *n, Type *t) } } +/* + * 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; + + 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; + + 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; + + 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; + + autoexport(s); + } + 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; + + 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); + + for(; vl; vl=vl->next) { + if(cl == nil) { + yyerror("missing expr in const dcl"); + break; + } + c = cl->n; + cl = cl->next; + + v = vl->n; + s = v->sym; + if(dclcontext != PEXTERN) + pushdcl(s); + redeclare("constant", s); + s->def = v; + + v->op = OLITERAL; + v->ntype = t; + v->defn = c; + autoexport(s); + } + if(cl != nil) + yyerror("extra expr in const dcl"); + iota += 1; + return vv; +} /* - * return nelem of list + * 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; + + n = nod(ONAME, N, N); + n->sym = s; + n->type = T; + n->addable = 1; + n->ullman = 1; + n->xoffset = 0; + return n; +} + +Node* +dclname(Sym *s) +{ + Node *n; + + // 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; + } + + n = newname(s); + n->op = ONONAME; // caller will correct it + return n; +} + +Node* +typenod(Type *t) +{ + if(t->nod == N) { + t->nod = nod(OTYPE, N, N); + t->nod->type = t; + t->nod->sym = t->sym; + } + return t->nod; +} + + +/* + * 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; + + 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"); + } + } + + if(n->type == T) { + // assume error already printed + continue; + } + + switch(n->val.ctype) { + case CTSTR: + if(et != TSTRUCT) + yyerror("interface method cannot have annotation"); + note = n->val.u.sval; + break; + default: + if(et != TSTRUCT) + yyerror("interface method cannot have annotation"); + else + yyerror("field annotation must be string"); + case CTxxx: + note = nil; + break; + } + + if(et == TINTER && n->left == N) { + // embedded interface - inline the methods + if(n->type->etype != TINTER) { + yyerror("interface contains embedded non-interface %T", t); + continue; + } + for(t1=n->type->type; t1!=T; t1=t1->down) { + // TODO(rsc): Is this really an error? + if(strcmp(t1->sym->package, package) != 0) + yyerror("embedded interface contains unexported method %S", t1->sym); + f = typ(TFIELD); + f->type = t1->type; + f->width = BADWIDTH; + f->nname = newname(t1->sym); + f->sym = t1->sym; + *t = f; + t = &f->down; + } + continue; + } + + f = typ(TFIELD); + f->type = n->type; + f->note = note; + f->width = BADWIDTH; + + if(n->left != N && n->left->op == ONAME) { + f->nname = n->left; + f->embedded = n->embedded; + f->sym = f->nname->sym; + if(pkgimportname != S && !exportname(f->sym->name)) + f->sym = pkglookup(f->sym->name, structpkg); + } + + *t = f; + t = &f->down; + } + + *t = T; + lineno = lno; + return t; +} + +Type* +dostruct(NodeList *l, int et) +{ + Type *t; + int funarg; + + /* + * convert a parsed id/type list into + * a type for struct/interface/arglist + */ + + funarg = 0; + if(et == TFUNC) { + funarg = 1; + et = TSTRUCT; + } + t = typ(et); + t->funarg = funarg; + stotype(l, et, &t->type); + if(!funarg) + checkwidth(t); + return t; +} + + +Node* +embedded(Sym *s) +{ + Node *n; + char *name; + + // 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; + } + + n = newname(lookup(name)); + n = nod(ODCLFIELD, n, N); + n->embedded = 1; + if(s == S) + return n; + n->right = oldname(s); + return n; +} + +static Node* +findtype(NodeList *l) +{ + for(; l; l=l->next) + if(l->n->op == OKEY) + return l->n->right; + 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; + NodeList *l; + + named = 0; + for(l=all; l; l=l->next) { + if(l->n->op == OKEY) { + named = 1; + 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 ..."); + } + } + return all; +} + + +Node* +fakethis(void) +{ + Node *n; + + n = nod(ODCLFIELD, N, N); + n->type = ptrto(typ(TSTRUCT)); + return n; +} + +/* + * Is this field a method on an interface? + * Those methods have an anonymous + * *struct{} as the receiver. + * (See fakethis above.) */ int -structcount(Type *t) +isifacemethod(Type *f) { - int v; - Iter s; + Type *rcvr; + Type *t; - v = 0; - for(t = structfirst(&s, &t); t != T; t = structnext(&s)) - v++; - return v; + rcvr = getthisx(f->type)->type; + if(rcvr->sym != S) + return 0; + t = rcvr->type; + if(!isptr[t->etype]) + return 0; + t = t->type; + if(t->sym != S || t->etype != TSTRUCT || t->type != T) + return 0; + return 1; } /* @@ -357,9 +1172,6 @@ addmethod(Node *n, Type *t, int local) stotype(list1(n), 0, &pa->method); else stotype(list1(n), 0, &d->down); - - if(dflag()) - print("method %S of type %T\n", sf, pa); return; bad: @@ -367,29 +1179,6 @@ bad: } /* - * 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); -} - -/* * declare the function proper. * and declare the arguments * called in extern-declaration context @@ -436,8 +1225,6 @@ funchdr(Node *n) 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 @@ -680,1172 +1467,3 @@ funclit1(Node *ntype, NodeList *body) n->list = args; return n; } - -/* - * 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"); - } - } - - if(n->type == T) { - // assume error already printed - continue; - } - - switch(n->val.ctype) { - case CTSTR: - if(et != TSTRUCT) - yyerror("interface method cannot have annotation"); - note = n->val.u.sval; - break; - default: - if(et != TSTRUCT) - yyerror("interface method cannot have annotation"); - else - yyerror("field annotation must be string"); - case CTxxx: - note = nil; - break; - } - - if(et == TINTER && n->left == N) { - // embedded interface - inline the methods - if(n->type->etype != TINTER) { - yyerror("interface contains embedded non-interface %T", t); - continue; - } - for(t1=n->type->type; t1!=T; t1=t1->down) { - // TODO(rsc): Is this really an error? - if(strcmp(t1->sym->package, package) != 0) - yyerror("embedded interface contains unexported method %S", t1->sym); - f = typ(TFIELD); - f->type = t1->type; - f->width = BADWIDTH; - f->nname = newname(t1->sym); - f->sym = t1->sym; - *t = f; - t = &f->down; - } - continue; - } - - f = typ(TFIELD); - f->type = n->type; - f->note = note; - f->width = BADWIDTH; - - if(n->left != N && n->left->op == ONAME) { - f->nname = n->left; - f->embedded = n->embedded; - f->sym = f->nname->sym; - if(pkgimportname != S && !exportname(f->sym->name)) - f->sym = pkglookup(f->sym->name, structpkg); - } - - *t = f; - t = &f->down; - } - - *t = T; - lineno = lno; - return t; -} - -Type* -dostruct(NodeList *l, int et) -{ - Type *t; - int funarg; - - /* - * convert a parsed id/type list into - * a type for struct/interface/arglist - */ - - funarg = 0; - if(et == TFUNC) { - funarg = 1; - et = TSTRUCT; - } - t = typ(et); - t->funarg = funarg; - stotype(l, et, &t->type); - if(!funarg) - checkwidth(t); - return t; -} - -Type* -sortinter(Type *t) -{ - return t; -} - -void -dcopy(Sym *a, Sym *b) -{ - 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; -} - -Sym* -push(void) -{ - Sym *d; - - d = mal(sizeof(*d)); - d->link = dclstack; - dclstack = d; - return d; -} - -Sym* -pushdcl(Sym *s) -{ - Sym *d; - - d = push(); - dcopy(d, s); - return d; -} - -void -popdcl(void) -{ - Sym *d, *s; - -// 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; -} - -void -poptodcl(void) -{ - Sym *d, *s; - - 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; -} - -void -markdcl(void) -{ - Sym *d; - - d = push(); - d->name = nil; // used as a mark in fifo - d->block = block; - - blockgen++; - block = blockgen; - -// 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; - } - } -} - -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); - else - print("auto typ-dcl %S G%ld %T\n", s, s->vargen, n); - } -} - -// 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) -{ - Node *n; - - n = nod(ODCLFIELD, N, N); - n->type = ptrto(typ(TSTRUCT)); - return n; -} - -/* - * Is this field a method on an interface? - * Those methods have an anonymous - * *struct{} as the receiver. - * (See fakethis above.) - */ -int -isifacemethod(Type *f) -{ - Type *rcvr; - Type *t; - - rcvr = getthisx(f->type)->type; - if(rcvr->sym != S) - return 0; - t = rcvr->type; - if(!isptr[t->etype]) - return 0; - t = t->type; - if(t->sym != S || t->etype != TSTRUCT || t->type != T) - return 0; - return 1; -} - -/* - * 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; - - n = nod(ONAME, N, N); - n->sym = s; - n->type = T; - n->addable = 1; - n->ullman = 1; - n->xoffset = 0; - return n; -} - -Node* -dclname(Sym *s) -{ - Node *n; - - // 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; - } - - n = newname(s); - n->op = ONONAME; // caller will correct it - return n; -} - -Node* -typenod(Type *t) -{ - if(t->nod == N) { - t->nod = nod(OTYPE, N, N); - t->nod->type = t; - t->nod->sym = t->sym; - } - return t->nod; -} - - -/* - * 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; - - 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; -} - -/* - * n is a node with a name. - * make it a declaration of the given type. - */ -Node* -nametodcl(Node *n, Type *t) -{ - n = nod(ODCLFIELD, n, N); - n->type = t; - return n; -} - -/* - * make an anonymous declaration for t - */ -Node* -anondcl(Type *t) -{ - Node *n; - - n = nod(ODCLFIELD, N, N); - n->type = t; - return n; -} - -static Node* -findtype(NodeList *l) -{ - for(; l; l=l->next) - if(l->n->op == OKEY) - return l->n->right; - 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; - NodeList *l; - - named = 0; - for(l=all; l; l=l->next) { - if(l->n->op == OKEY) { - named = 1; - 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 ..."); - } - } - return all; -} - -/* - * hand-craft the following initialization code - * var initdone·<file> uint8 (1) - * func Init·<file>() (2) - * if initdone·<file> { (3) - * if initdone·<file> == 2 (4) - * return - * throw(); (5) - * } - * initdone.<file>++; (6) - * // over all matching imported symbols - * <pkg>.init·<file>() (7) - * { <init stmts> } (8) - * init·<file>() // if any (9) - * initdone.<file>++; (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; h<NHASH; h++) - for(s = hash[h]; s != S; s = s->link) { - 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; h<NHASH; h++) - for(s = hash[h]; s != S; s = s->link) { - 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; -} - - -/* - * 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; - } -} - -Node* -embedded(Sym *s) -{ - Node *n; - char *name; - - // 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; - } - - n = newname(lookup(name)); - n = nod(ODCLFIELD, n, N); - n->embedded = 1; - if(s == S) - return n; - n->right = oldname(s); - return n; -} - -/* - * 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; - - 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; - - 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; - - 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; - - autoexport(s); - } - 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; - - 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); - - for(; vl; vl=vl->next) { - if(cl == nil) { - yyerror("missing expr in const dcl"); - break; - } - c = cl->n; - cl = cl->next; - - v = vl->n; - s = v->sym; - if(dclcontext != PEXTERN) - pushdcl(s); - redeclare("constant", s); - s->def = v; - - v->op = OLITERAL; - v->ntype = t; - v->defn = c; - autoexport(s); - } - if(cl != nil) - yyerror("extra expr in const dcl"); - iota += 1; - return vv; -} - -/* - * 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; -} - -void -dclchecks(void) -{ - Dcl *d; - - for(d=externdcl; d!=D; d=d->forw) { - if(d->op != ONAME) - continue; - typecheck(&d->dnode, Erv); - } -} diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index db757fa4e..8a79a1abd 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 f048c29d1..728645318 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 000000000..5fc7f8bbc --- /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·<file> uint8 (1) + * func Init·<file>() (2) + * if initdone·<file> { (3) + * if initdone·<file> == 2 (4) + * return + * throw(); (5) + * } + * initdone.<file>++; (6) + * // over all matching imported symbols + * <pkg>.init·<file>() (7) + * { <init stmts> } (8) + * init·<file>() // if any (9) + * initdone.<file>++; (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; h<NHASH; h++) + for(s = hash[h]; s != S; s = s->link) { + 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; h<NHASH; h++) + for(s = hash[h]; s != S; s = s->link) { + 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 be99a2afc..a0ef878f1 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 000000000..9c1f9519a --- /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; +} |