From: Russ Cox Date: Wed, 12 Aug 2009 20:18:19 +0000 (-0700) Subject: whole-package compilation X-Git-Tag: weekly.2009-11-06~909 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=66bb399fddbddd8c2a12510ea5ddff987cc3eb54;p=gostls13.git whole-package compilation R=ken OCL=33063 CL=33095 --- diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index fe64ee08d7..d19c0a4d2e 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -649,16 +649,9 @@ funchdr(Node *n) Node *nt; if(n->nname != N) { - // TODO(rsc): remove once forward declarations are gone - if(n->nname->sym->def && n->nname->sym->def->class == PFUNC) { - nt = n->nname->ntype; - n->nname = n->nname->sym->def; - n->nname->ntype = nt; - n->nname->type = T; - } else { - n->nname->op = ONAME; - declare(n->nname, PFUNC); - } + n->nname->op = ONAME; + declare(n->nname, PFUNC); + n->nname->defn = n; } // change the declaration context from extern to auto diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c index 20831d1614..b5abec3cca 100644 --- a/src/cmd/gc/export.c +++ b/src/cmd/gc/export.c @@ -299,6 +299,8 @@ pkgtype(Sym *s) t->sym = s; s->def = typenod(t); } + if(s->def->type == T) + yyerror("pkgtype %lS", s); return s->def->type; } @@ -314,6 +316,8 @@ mypackage(Sym *s) void importconst(Sym *s, Type *t, Node *n) { + Node *n1; + if(!exportname(s->name) && !mypackage(s)) return; importsym(s, OLITERAL); @@ -327,6 +331,11 @@ importconst(Sym *s, Type *t, Node *n) yyerror("expression must be a constant"); return; } + if(n->sym != S) { + n1 = nod(OXXX, N, N); + *n1 = *n; + n = n1; + } n->sym = s; declare(n, PEXTERN); @@ -360,7 +369,8 @@ importvar(Sym *s, Type *t, int ctxt) void importtype(Type *pt, Type *t) { - typedcl2(pt, t); + if(pt != T && t != T) + typedcl2(pt, t); if(debug['E']) print("import type %T %lT\n", pt, t); diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 72c6b745d4..e5cdadbb73 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -198,6 +198,7 @@ struct Node uchar walkdef; uchar typecheck; uchar local; + uchar initorder; // most nodes Node* left; @@ -649,6 +650,7 @@ EXTERN Mpint* maxintval[NTYPE]; EXTERN Mpflt* minfltval[NTYPE]; EXTERN Mpflt* maxfltval[NTYPE]; +EXTERN NodeList* xtop; EXTERN NodeList* externdcl; EXTERN NodeList* closures; EXTERN NodeList* exportlist; diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 4b59dfc3f2..439340caba 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -120,29 +120,7 @@ file: imports xdcl_list { - NodeList *l; - - if(nsyntaxerrors == 0) - testdclstack(); - - typecheckok = 1; - if(debug['f']) - frame(1); - defercheckwidth(); - typechecklist($4, Etop); - resumecheckwidth(); - for(l=$4; l; l=l->next) - if(l->n->op == ODCLFUNC) - funccompile(l->n); - if(nerrors == 0) - fninit($4); - while(closures) { - l = closures; - closures = nil; - for(; l; l=l->next) - funccompile(l->n); - } - dclchecks(); + xtop = concat(xtop, $4); } package: @@ -262,15 +240,17 @@ import_done: if(my == import && strcmp(import->name, package) == 0) break; - if(my->def != N) { - // TODO(rsc): this line is only needed because of the - // package net - // import "net" - // convention; if we get rid of it, the check can go away - // and we can just always print the error - if(my->def->op != OPACK || strcmp(my->name, import->name) != 0) - yyerror("redeclaration of %S by import", my); - } + // TODO(rsc): this line is needed for a package + // which does bytes := in a function, which creates + // an ONONAME for bytes, but then a different file + // imports "bytes". more generally we need to figure out + // what it means if one file imports "bytes" and another + // declares a top-level name. + if(my->def && my->def->op == ONONAME) + my->def = N; + + if(my->def) + yyerror("redeclaration of %S by import\n\t%N", my, my->def); my->def = nod(OPACK, N, N); my->def->sym = import; import->block = -1; // above top level diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c index ca6b1eb373..dd641de96b 100644 --- a/src/cmd/gc/init.c +++ b/src/cmd/gc/init.c @@ -15,6 +15,7 @@ Node* renameinit(Node *n) { Sym *s; + static int initgen; s = n->sym; if(s == S) @@ -22,7 +23,7 @@ renameinit(Node *n) if(strcmp(s->name, "init") != 0) return n; - snprint(namebuf, sizeof(namebuf), "init·%s", filename); + snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen); s = lookup(namebuf); return newname(s); } @@ -70,7 +71,7 @@ anyinit(NodeList *n) return 1; // is there an explicit init function - snprint(namebuf, sizeof(namebuf), "init·%s", filename); + snprint(namebuf, sizeof(namebuf), "init·1"); s = lookup(namebuf); if(s->def != N) return 1; @@ -92,6 +93,7 @@ anyinit(NodeList *n) void fninit(NodeList *n) { + int i; Node *gatevar; Node *a, *b, *fn; NodeList *r; @@ -110,7 +112,7 @@ fninit(NodeList *n) r = nil; // (1) - snprint(namebuf, sizeof(namebuf), "initdone·%s", filename); + snprint(namebuf, sizeof(namebuf), "initdone·"); gatevar = newname(lookup(namebuf)); addvar(gatevar, types[TUINT8], PEXTERN); @@ -118,7 +120,7 @@ fninit(NodeList *n) maxarg = 0; - snprint(namebuf, sizeof(namebuf), "Init·%s", filename); + snprint(namebuf, sizeof(namebuf), "Init·"); // this is a botch since we need a known name to // call the top level init function out of rt0 @@ -168,13 +170,15 @@ fninit(NodeList *n) } // (8) - r = concat(r, initfix(n)); + r = concat(r, 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) { + for(i=1;; i++) { + snprint(namebuf, sizeof(namebuf), "init·%d", i); + s = lookup(namebuf); + if(s->def == N) + break; a = nod(OCALL, s->def, N); r = list(r, a); } diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 8770ee5361..fddb17e98c 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -10,6 +10,7 @@ extern int yychar; Sym *anysym; +char nopackage[] = "____"; #define DBG if(!debug['x']);else print enum @@ -20,10 +21,11 @@ enum int main(int argc, char *argv[]) { - int c; + int i, c; + NodeList *l; outfile = nil; - package = "____"; + package = nopackage; ARGBEGIN { default: c = ARGC(); @@ -44,7 +46,7 @@ main(int argc, char *argv[]) break; } ARGEND - if(argc != 1) + if(argc < 1) goto usage; pathname = mal(100); @@ -69,31 +71,57 @@ main(int argc, char *argv[]) lexinit(); typeinit(); - lineno = 1; - block = 1; blockgen = 1; + dclcontext = PEXTERN; + nerrors = 0; + lineno = 1; - setfilename(argv[0]); - infile = argv[0]; - linehist(infile, 0, 0); + for(i=0; inext) + if(l->n->op == ODCLFUNC) + funccompile(l->n); + if(nerrors == 0) + fninit(xtop); + while(closures) { + l = closures; + closures = nil; + for(; l; l=l->next) + funccompile(l->n); + } + dclchecks(); + runifacechecks(); if(nerrors) errorexit(); @@ -264,6 +292,8 @@ importfile(Val *f) int32 c; int len; +// TODO: don't bother reloading imports more than once + if(f->ctype != CTSTR) { yyerror("import statement not a string"); return; @@ -1427,6 +1457,16 @@ lexname(int lex) return buf; } +int +specialsym(Sym *s) +{ + if(strcmp(s->name, "byte") == 0 && s->def->sym == lookup("uint8")) + return 1; + if(strcmp(s->name, "iota") == 0 && s->def->sym == S) + return 1; + return 0; +} + void mkpackage(char* pkg) { @@ -1434,23 +1474,43 @@ mkpackage(char* pkg) int32 h; char *p; - if(bout != nil) { - yyerror("mkpackage: called again %s %s", pkg, package); - return; + if(package == nopackage) { + // redefine all names to be this package. + for(h=0; hlink) + if(s->package == nopackage) + s->package = pkg; + package = pkg; + } else { + if(strcmp(pkg, package) != 0) + yyerror("package %s; expected %s", pkg, package); + for(h=0; hlink) { + if(s->def == N || s->package != package) + continue; + if(s->def->op == OPACK) { + // throw away top-level package name leftover + // from previous file. + s->def = N; + continue; + } + if(s->def->sym != s && !specialsym(s)) { + // throw away top-level name left over + // from previous import . "x" + s->def = N; + continue; + } + } + } } - // redefine all names to be this package - for(h=0; hlink) - if(s->package == package) - s->package = pkg; - package = pkg; - +/* // declare this name as a package s = lookup(package); s->def = nod(OPACK, N, N); s->def->sym = s; s->block = -1; // above top level +*/ if(outfile == nil) { p = strrchr(infile, '/'); diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index 83db9bff1f..4b46f7c7c0 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -457,13 +457,85 @@ return; } +static void +init1(Node *n, NodeList **out) +{ + NodeList *l; + + if(n == N) + return; + init1(n->left, out); + init1(n->right, out); + for(l=n->list; l; l=l->next) + init1(l->n, out); + + if(n->op != ONAME) + return; + switch(n->class) { + case PEXTERN: + case PFUNC: + break; + default: + return; + } + + if(n->initorder == 1) + return; + if(n->initorder == 2) + fatal("init loop"); + + // make sure that everything n depends on is initialized. + // n->defn is an assignment to n + n->initorder = 2; + if(n->defn != N) { + switch(n->defn->op) { + case ODCLFUNC: + for(l=n->defn->nbody; l; l=l->next) + init1(l->n, out); + break; + case OAS: + if(n->defn->left != n) { + default: + dump("defn", n->defn); + fatal("bad defn"); + } + init1(n->defn->right, out); + if(debug['j']) + print("%S\n", n->sym); + *out = list(*out, n->defn); + break; + } + } + n->initorder = 1; + return; +} + +static void +initreorder(NodeList *l, NodeList **out) +{ + Node *n; + + for(; l; l=l->next) { + n = l->n; + switch(n->op) { + case ODCLFUNC: + case ODCLCONST: + case ODCLTYPE: + continue; + } + initreorder(n->ninit, out); + n->ninit = nil; + init1(n, out); + } +} + NodeList* initfix(NodeList *l) { Node *r; xxx.list = nil; - initlin(l); + initreorder(l, &xxx.list); if(0) return xxx.list;