summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd/gc/Makefile30
-rw-r--r--src/cmd/gc/dcl.c2028
-rw-r--r--src/cmd/gc/go.h4
-rw-r--r--src/cmd/gc/go.y2
-rw-r--r--src/cmd/gc/init.c193
-rw-r--r--src/cmd/gc/subr.c126
-rw-r--r--src/cmd/gc/unsafe.c87
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;
+}