diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-06-30 15:34:22 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-06-30 15:34:22 +0200 |
commit | d39f5aa373a4422f7a5f3ee764fb0f6b0b719d61 (patch) | |
tree | 1833f8b72a4b3a8f00d0d143b079a8fcad01c6ae /src/cmd/gc | |
parent | 8652e6c371b8905498d3d314491d36c58d5f68d5 (diff) | |
download | golang-upstream/58.tar.gz |
Imported Upstream version 58upstream/58
Diffstat (limited to 'src/cmd/gc')
-rw-r--r-- | src/cmd/gc/Makefile | 2 | ||||
-rw-r--r-- | src/cmd/gc/align.c | 12 | ||||
-rw-r--r-- | src/cmd/gc/builtin.c.boot | 4 | ||||
-rw-r--r-- | src/cmd/gc/closure.c | 44 | ||||
-rw-r--r-- | src/cmd/gc/const.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/dcl.c | 42 | ||||
-rw-r--r-- | src/cmd/gc/gen.c | 22 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 29 | ||||
-rw-r--r-- | src/cmd/gc/go.y | 20 | ||||
-rw-r--r-- | src/cmd/gc/init.c | 5 | ||||
-rw-r--r-- | src/cmd/gc/lex.c | 22 | ||||
-rw-r--r-- | src/cmd/gc/obj.c | 1 | ||||
-rw-r--r-- | src/cmd/gc/pgen.c | 224 | ||||
-rw-r--r-- | src/cmd/gc/print.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/runtime.go | 1 | ||||
-rw-r--r-- | src/cmd/gc/sinit.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 107 | ||||
-rw-r--r-- | src/cmd/gc/swt.c | 5 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 376 | ||||
-rw-r--r-- | src/cmd/gc/unsafe.c | 1 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 456 |
21 files changed, 937 insertions, 448 deletions
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile index dbfd86474..286618ec1 100644 --- a/src/cmd/gc/Makefile +++ b/src/cmd/gc/Makefile @@ -49,7 +49,7 @@ include ../../Make.clib install: $(LIB) y1.tab.c: y.tab.c # make yystate global, yytname mutable - cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/' >y1.tab.c + cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c yerr.h: bisonerrors go.errors y.tab.h # y.tab.h rule generates y.output too awk -f bisonerrors y.output go.errors >yerr.h diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index a8454bf13..7fcac4833 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -234,9 +234,11 @@ dowidth(Type *t) if(t->bound > cap) yyerror("type %lT larger than address space", t); w = t->bound * t->type->width; - if(w == 0) - w = 1; t->align = t->type->align; + if(w == 0) { + w = 1; + t->align = 1; + } } else if(t->bound == -1) { w = sizeof_Array; @@ -253,10 +255,10 @@ dowidth(Type *t) if(t->funarg) fatal("dowidth fn struct %T", t); w = widstruct(t, 0, 1); - if(w == 0) + if(w == 0) { w = 1; - //if(t->align < widthptr) - // warn("align %d: %T\n", t->align, t); + t->align = 1; + } break; case TFUNC: diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot index bdbca7f78..c9bf501d1 100644 --- a/src/cmd/gc/builtin.c.boot +++ b/src/cmd/gc/builtin.c.boot @@ -1,5 +1,6 @@ char *runtimeimport = "package runtime\n" + "import runtime \"runtime\"\n" "func \"\".new (? int32) *any\n" "func \"\".panicindex ()\n" "func \"\".panicslice ()\n" @@ -21,7 +22,6 @@ char *runtimeimport = "func \"\".printsp ()\n" "func \"\".goprintf ()\n" "func \"\".concatstring ()\n" - "func \"\".append ()\n" "func \"\".appendslice (typ *uint8, x any, y []any) any\n" "func \"\".cmpstring (? string, ? string) int\n" "func \"\".slicestring (? string, ? int, ? int) string\n" @@ -81,6 +81,7 @@ char *runtimeimport = "func \"\".selectgo (sel *uint8)\n" "func \"\".block ()\n" "func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n" + "func \"\".growslice (typ *uint8, old []any, cap int64) []any\n" "func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n" "func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n" "func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n" @@ -98,6 +99,7 @@ char *runtimeimport = "$$\n"; char *unsafeimport = "package unsafe\n" + "import runtime \"runtime\"\n" "type \"\".Pointer uintptr\n" "func \"\".Offsetof (? any) int\n" "func \"\".Sizeof (? any) int\n" diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index eb7014366..906dadbc9 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -75,7 +75,7 @@ closurebody(NodeList *body) } void -typecheckclosure(Node *func) +typecheckclosure(Node *func, int top) { Node *oldfn; NodeList *l; @@ -106,6 +106,10 @@ typecheckclosure(Node *func) v->op = 0; continue; } + // For a closure that is called in place, but not + // inside a go statement, avoid moving variables to the heap. + if ((top & (Ecall|Eproc)) == Ecall) + v->heapaddr->etype = 1; typecheck(&v->heapaddr, Erv); func->enter = list(func->enter, v->heapaddr); v->heapaddr = N; @@ -199,3 +203,41 @@ walkclosure(Node *func, NodeList **init) walkexpr(&call, init); return call; } + +// Special case for closures that get called in place. +// Optimize runtime.closure(X, __func__xxxx_, .... ) away +// to __func__xxxx_(Y ....). +// On entry, expect n->op == OCALL, n->left->op == OCLOSURE. +void +walkcallclosure(Node *n, NodeList **init) +{ + Node *z; + NodeList *ll, *cargs; + + walkexpr(&n->left, init); + cargs = n->left // FUNC runtime.closure + ->list // arguments + ->next // skip first + ->next; // skip second + + n->left = n->left // FUNC runtime.closure + ->list // arguments + ->next // skip first + ->n // AS (to indreg) + ->right; // argument == the generated function + + // New arg list for n. First the closure-args, stolen from + // runtime.closure's 3rd and following, + ll = nil; + for (; cargs; cargs = cargs->next) + ll = list(ll, cargs->n->right); // cargs->n is the OAS(INDREG, arg) + + // then an extra zero, to fill the dummy return pointer slot, + z = nod(OXXX, N, N); + nodconst(z, types[TUINTPTR], 0); + z->typecheck = 1; + ll = list(ll, z); + + // and finally the original parameter list. + n->list = concat(ll, n->list); +} diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index a36ec68c0..8fe9072b2 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -103,6 +103,8 @@ convlit1(Node **np, Type *t, int explicit) case ORSH: convlit1(&n->left, t, explicit && isideal(n->left->type)); t = n->left->type; + if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT) + n->val = toint(n->val); if(t != T && !isint[t->etype]) { yyerror("invalid operation: %#N (shift of type %T)", n, t); t = T; @@ -514,6 +516,8 @@ evconst(Node *n) n->right = nr; if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype])) goto illegal; + nl->val = toint(nl->val); + nr->val = toint(nr->val); break; } diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index 8e790ef08..335d056a0 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -188,6 +188,7 @@ declare(Node *n, int ctxt) else if(n->op == ONAME) gen = ++vargen; pushdcl(s); + n->curfn = curfn; } if(ctxt == PAUTO) n->xoffset = BADWIDTH; @@ -437,20 +438,6 @@ newtype(Sym *s) return t; } -/* - * type check top level declarations - */ -void -dclchecks(void) -{ - NodeList *l; - - for(l=externdcl; l; l=l->next) { - if(l->n->op != ONAME) - continue; - typecheck(&l->n, Erv); - } -} /* * := declarations @@ -524,6 +511,30 @@ colas(NodeList *left, NodeList *right) } /* + * declare the arguments in an + * interface field declaration. + */ +void +ifacedcl(Node *n) +{ + if(n->op != ODCLFIELD || n->right == N) + fatal("ifacedcl"); + + dclcontext = PAUTO; + markdcl(); + funcdepth++; + n->outer = curfn; + curfn = n; + funcargs(n->right); + + // funcbody is normally called after the parser has + // seen the body of a function but since an interface + // field declaration does not have a body, we must + // call it now to pop the current declaration context. + funcbody(n); +} + +/* * declare the function proper * and declare the arguments. * called in extern-declaration context @@ -1226,9 +1237,6 @@ funccompile(Node *n, int isclosure) if(curfn) fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym); - curfn = n; - typechecklist(n->nbody, Etop); - curfn = nil; stksize = 0; dclcontext = PAUTO; diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index 857fcbef9..ad7b65b30 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -51,6 +51,8 @@ allocparams(void) } if(n->op != ONAME || n->class != PAUTO) continue; + if (n->xoffset != BADWIDTH) + continue; if(n->type == T) continue; dowidth(n->type); @@ -59,6 +61,8 @@ allocparams(void) fatal("bad width"); stksize += w; stksize = rnd(stksize, n->type->align); + if(thechar == '5') + stksize = rnd(stksize, widthptr); n->xoffset = -stksize; } lineno = lno; @@ -668,14 +672,18 @@ dotoffset(Node *n, int *oary, Node **nn) * make a new off the books */ void -tempname(Node *n, Type *t) +tempname(Node *nn, Type *t) { + Node *n; Sym *s; uint32 w; if(stksize < 0) fatal("tempname not during code generation"); + if (curfn == N) + fatal("no curfn for tempname"); + if(t == T) { yyerror("tempname called with nil type"); t = types[TINT32]; @@ -686,19 +694,25 @@ tempname(Node *n, Type *t) snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen); statuniqgen++; s = lookup(namebuf); - memset(n, 0, sizeof(*n)); - n->op = ONAME; + n = nod(ONAME, N, N); n->sym = s; n->type = t; n->class = PAUTO; n->addable = 1; n->ullman = 1; n->noescape = 1; + n->curfn = curfn; + curfn->dcl = list(curfn->dcl, n); dowidth(t); w = t->width; stksize += w; stksize = rnd(stksize, t->align); + if(thechar == '5') + stksize = rnd(stksize, widthptr); n->xoffset = -stksize; - n->pun = anyregalloc(); + + // print("\ttmpname (%d): %N\n", stksize, n); + + *nn = *n; } diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 4b4e8fcd1..c16903e77 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -225,6 +225,7 @@ struct Node Type* realtype; // as determined by typecheck NodeList* list; NodeList* rlist; + Node* orig; // original form, for printing, and tracking copies of ONAMEs // for-body NodeList* ninit; @@ -253,6 +254,7 @@ struct Node Node* ntype; Node* defn; Node* pack; // real package for import . names + Node* curfn; // function for local variables // ONAME func param with PHEAP Node* heapaddr; // temp holding heap address of param @@ -271,6 +273,7 @@ struct Node int32 lineno; int32 endlineno; vlong xoffset; + int32 stkdelta; // offset added by stack frame compaction phase. int32 ostk; int32 iota; }; @@ -516,15 +519,16 @@ enum enum { - Etop = 1<<1, // evaluated at statement level - Erv = 1<<2, // evaluated in value context + Etop = 1<<1, // evaluated at statement level + Erv = 1<<2, // evaluated in value context Etype = 1<<3, - Ecall = 1<<4, // call-only expressions are ok + Ecall = 1<<4, // call-only expressions are ok Efnstruct = 1<<5, // multivalue function returns are ok Eiota = 1<<6, // iota is ok Easgn = 1<<7, // assigning to expression Eindir = 1<<8, // indirecting through expression Eaddr = 1<<9, // taking address of expression + Eproc = 1<<10, // inside a go statement }; #define BITS 5 @@ -544,6 +548,7 @@ struct Var vlong offset; Sym* sym; Sym* gotype; + Node* node; int width; char name; char etype; @@ -814,8 +819,9 @@ int bset(Bits a, uint n); */ Node* closurebody(NodeList *body); void closurehdr(Node *ntype); -void typecheckclosure(Node *func); +void typecheckclosure(Node *func, int top); Node* walkclosure(Node *func, NodeList **init); +void walkcallclosure(Node *n, NodeList **init); /* * const.c @@ -858,7 +864,6 @@ NodeList* checkarglist(NodeList *all, int input); Node* colas(NodeList *left, NodeList *right); void colasdefn(NodeList *left, Node *defn); NodeList* constiter(NodeList *vl, Node *t, NodeList *cl); -void dclchecks(void); Node* dclname(Sym *s); void declare(Node *n, int ctxt); Type* dostruct(NodeList *l, int et); @@ -869,6 +874,7 @@ void funcbody(Node *n); void funccompile(Node *n, int isclosure); void funchdr(Node *n); Type* functype(Node *this, NodeList *in, NodeList *out); +void ifacedcl(Node *n); int isifacemethod(Type *f); void markdcl(void); Node* methodname(Node *n, Type *t); @@ -1103,6 +1109,7 @@ int istype(Type *t, int et); void linehist(char *file, int32 off, int relative); NodeList* list(NodeList *l, Node *n); NodeList* list1(Node *n); +void listsort(NodeList**, int(*f)(Node*, Node*)); Node* liststmt(NodeList *l); NodeList* listtreecopy(NodeList *l); Sym* lookup(char *name); @@ -1161,6 +1168,11 @@ int exportassignok(Type *t, char *desc); int islvalue(Node *n); Node* typecheck(Node **np, int top); void typechecklist(NodeList *l, int top); +Node* typecheckdef(Node *n); +void resumetypecopy(void); +void copytype(Node *n, Type *t); +void defertypecopy(Node *n, Type *t); +void queuemethod(Node *n); /* * unsafe.c @@ -1172,15 +1184,10 @@ Node* unsafenmagic(Node *n); */ Node* callnew(Type *t); Node* chanfn(char *name, int n, Type *t); -void copytype(Node *n, Type *t); -void defertypecopy(Node *n, Type *t); Node* mkcall(char *name, Type *t, NodeList **init, ...); Node* mkcall1(Node *fn, Type *t, NodeList **init, ...); -void queuemethod(Node *n); -void resumetypecopy(void); int vmatch1(Node *l, Node *r); void walk(Node *fn); -Node* walkdef(Node *n); void walkexpr(Node **np, NodeList **init); void walkexprlist(NodeList *l, NodeList **init); void walkexprlistsafe(NodeList *l, NodeList **init); @@ -1208,6 +1215,7 @@ EXTERN Prog* continpc; EXTERN Prog* breakpc; EXTERN Prog* pc; EXTERN Prog* firstpc; +EXTERN Prog* retpc; EXTERN Node* nodfp; @@ -1221,6 +1229,7 @@ void cgen_callinter(Node *n, Node *res, int proc); void cgen_ret(Node *n); void clearfat(Node *n); void compile(Node*); +void defframe(Prog*); int dgostringptr(Sym*, int off, char *str); int dgostrlitptr(Sym*, int off, Strlit*); int dstringptr(Sym *s, int off, char *str); diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 7adfd002a..1278c2586 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -1380,6 +1380,7 @@ interfacedcl: new_name indcl { $$ = nod(ODCLFIELD, $1, $2); + ifacedcl($$); } | packname { @@ -1791,24 +1792,12 @@ hidden_opt_sym: } hidden_dcl: - hidden_opt_sym hidden_type + hidden_opt_sym hidden_type hidden_tag { $$ = nod(ODCLFIELD, $1, typenod($2)); + $$->val = $3; } -| hidden_opt_sym LDDD - { - Type *t; - - yyerror("invalid variadic function type in import - recompile import"); - - t = typ(TARRAY); - t->bound = -1; - t->type = typ(TINTER); - $$ = nod(ODCLFIELD, $1, typenod(t)); - $$->isddd = 1; - } - -| hidden_opt_sym LDDD hidden_type +| hidden_opt_sym LDDD hidden_type hidden_tag { Type *t; @@ -1817,6 +1806,7 @@ hidden_dcl: t->type = $3; $$ = nod(ODCLFIELD, $1, typenod(t)); $$->isddd = 1; + $$->val = $4; } hidden_structdcl: diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c index af4eb0336..8818db08c 100644 --- a/src/cmd/gc/init.c +++ b/src/cmd/gc/init.c @@ -182,11 +182,14 @@ fninit(NodeList *n) // (11) a = nod(ORETURN, N, N); r = list(r, a); - exportsym(fn->nname); fn->nbody = r; funcbody(fn); + + curfn = fn; typecheck(&fn, Etop); + typechecklist(r, Etop); + curfn = nil; funccompile(fn, 0); } diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 04dd0d5b9..88acb60af 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -5,7 +5,7 @@ #define EXTERN #include "go.h" #include "y.tab.h" -#include <ar.h> +#include <ar.h> #undef getc #undef ungetc @@ -235,13 +235,14 @@ main(int argc, char *argv[]) if(debug['f']) frame(1); - // Process top-level declarations in three phases. + // Process top-level declarations in four phases. // Phase 1: const, type, and names and types of funcs. // This will gather all the information about types // and methods but doesn't depend on any of it. // Phase 2: Variable assignments. // To check interface assignments, depends on phase 1. - // Phase 3: Function bodies. + // Phase 3: Type check function bodies. + // Phase 4: Compile function bodies. defercheckwidth(); for(l=xtop; l; l=l->next) if(l->n->op != ODCL && l->n->op != OAS) @@ -251,18 +252,31 @@ main(int argc, char *argv[]) typecheck(&l->n, Etop); resumetypecopy(); resumecheckwidth(); + + for(l=xtop; l; l=l->next) + if(l->n->op == ODCLFUNC) { + curfn = l->n; + typechecklist(l->n->nbody, Etop); + } + curfn = nil; + for(l=xtop; l; l=l->next) if(l->n->op == ODCLFUNC) funccompile(l->n, 0); + if(nerrors == 0) fninit(xtop); + while(closures) { l = closures; closures = nil; for(; l; l=l->next) funccompile(l->n, 1); } - dclchecks(); + + for(l=externdcl; l; l=l->next) + if(l->n->op == ONAME) + typecheck(&l->n, Erv); if(nerrors) errorexit(); diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index 9f4b7b318..f34fc76c8 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -284,6 +284,7 @@ stringsym(char *s, int len) off = dsname(sym, off, s+n, m); } off = duint8(sym, off, 0); // terminating NUL for runtime + off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment ggloblsym(sym, off, 1); text(); diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c new file mode 100644 index 000000000..ab6186697 --- /dev/null +++ b/src/cmd/gc/pgen.c @@ -0,0 +1,224 @@ +// Copyright 2011 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 "gg.h" +#include "opt.h" + +static void compactframe(Prog* p); + +void +compile(Node *fn) +{ + Plist *pl; + Node nod1, *n; + Prog *ptxt; + int32 lno; + Type *t; + Iter save; + vlong oldstksize; + + if(newproc == N) { + newproc = sysfunc("newproc"); + deferproc = sysfunc("deferproc"); + deferreturn = sysfunc("deferreturn"); + panicindex = sysfunc("panicindex"); + panicslice = sysfunc("panicslice"); + throwreturn = sysfunc("throwreturn"); + } + + if(fn->nbody == nil) + return; + + // set up domain for labels + clearlabels(); + + lno = setlineno(fn); + + curfn = fn; + dowidth(curfn->type); + + if(curfn->type->outnamed) { + // add clearing of the output parameters + t = structfirst(&save, getoutarg(curfn->type)); + while(t != T) { + if(t->nname != N) { + n = nod(OAS, t->nname, N); + typecheck(&n, Etop); + curfn->nbody = concat(list1(n), curfn->nbody); + } + t = structnext(&save); + } + } + + hasdefer = 0; + walk(curfn); + if(nerrors != 0 || isblank(curfn->nname)) + goto ret; + + allocparams(); + + continpc = P; + breakpc = P; + + pl = newplist(); + pl->name = curfn->nname; + + setlineno(curfn); + + nodconst(&nod1, types[TINT32], 0); + ptxt = gins(ATEXT, curfn->nname, &nod1); + afunclit(&ptxt->from); + + ginit(); + genlist(curfn->enter); + + retpc = nil; + if(hasdefer || curfn->exit) { + Prog *p1; + + p1 = gjmp(nil); + retpc = gjmp(nil); + patch(p1, pc); + } + + genlist(curfn->nbody); + gclean(); + checklabels(); + if(nerrors != 0) + goto ret; + if(curfn->endlineno) + lineno = curfn->endlineno; + + if(curfn->type->outtuple != 0) + ginscall(throwreturn, 0); + + if(retpc) + patch(retpc, pc); + ginit(); + if(hasdefer) + ginscall(deferreturn, 0); + if(curfn->exit) + genlist(curfn->exit); + gclean(); + if(nerrors != 0) + goto ret; + pc->as = ARET; // overwrite AEND + pc->lineno = lineno; + + if(!debug['N'] || debug['R'] || debug['P']) { + regopt(ptxt); + } + + oldstksize = stksize; + if(thechar != '5') + compactframe(ptxt); + if(0) + print("compactframe: %ld to %ld\n", oldstksize, stksize); + + defframe(ptxt); + + if(0) + frame(0); + +ret: + lineno = lno; +} + + +// Sort the list of stack variables. autos after anything else, +// within autos, unused after used, and within used on reverse alignment. +// non-autos sort on offset. +static int +cmpstackvar(Node *a, Node *b) +{ + if (a->class != b->class) + return (a->class == PAUTO) ? 1 : -1; + if (a->class != PAUTO) + return a->xoffset - b->xoffset; + if ((a->used == 0) != (b->used == 0)) + return b->used - a->used; + return b->type->align - a->type->align; + +} + +static void +compactframe(Prog* ptxt) +{ + NodeList *ll; + Node* n; + Prog *p; + uint32 w; + + if (stksize == 0) + return; + + // Mark the PAUTO's unused. + for(ll=curfn->dcl; ll != nil; ll=ll->next) + if (ll->n->class == PAUTO && ll->n->op == ONAME) + ll->n->used = 0; + + // Sweep the prog list to mark any used nodes. + for (p = ptxt; p; p = p->link) { + if (p->from.type == D_AUTO && p->from.node) + p->from.node->used++; + + if (p->to.type == D_AUTO && p->to.node) + p->to.node->used++; + } + + listsort(&curfn->dcl, cmpstackvar); + + // Unused autos are at the end, chop 'em off. + ll = curfn->dcl; + n = ll->n; + if (n->class == PAUTO && n->op == ONAME && !n->used) { + curfn->dcl = nil; + stksize = 0; + return; + } + + for(ll = curfn->dcl; ll->next != nil; ll=ll->next) { + n = ll->next->n; + if (n->class == PAUTO && n->op == ONAME && !n->used) { + ll->next = nil; + curfn->dcl->end = ll; + break; + } + } + + // Reassign stack offsets of the locals that are still there. + stksize = 0; + for(ll = curfn->dcl; ll != nil; ll=ll->next) { + n = ll->n; + // TODO find out where the literal autos come from + if (n->class != PAUTO || n->op != ONAME) + continue; + + w = n->type->width; + if((w >= MAXWIDTH) || (w < 1)) + fatal("bad width"); + stksize += w; + stksize = rnd(stksize, n->type->align); + if(thechar == '5') + stksize = rnd(stksize, widthptr); + n->stkdelta = -stksize - n->xoffset; + } + + // Fixup instructions. + for (p = ptxt; p; p = p->link) { + if (p->from.type == D_AUTO && p->from.node) + p->from.offset += p->from.node->stkdelta; + + if (p->to.type == D_AUTO && p->to.node) + p->to.offset += p->to.node->stkdelta; + } + + // The debug information needs accurate offsets on the symbols. + for(ll = curfn->dcl ;ll != nil; ll=ll->next) { + if (ll->n->class != PAUTO || ll->n->op != ONAME) + continue; + ll->n->xoffset += ll->n->stkdelta; + ll->n->stkdelta = 0; + } +} diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c index e03a14080..e88e0f844 100644 --- a/src/cmd/gc/print.c +++ b/src/cmd/gc/print.c @@ -134,6 +134,10 @@ exprfmt(Fmt *f, Node *n, int prec) fmtprint(f, "(node %O)", n->op); break; + case OREGISTER: + fmtprint(f, "%R", n->val.u.reg); + break; + case OLITERAL: if(n->sym != S) { fmtprint(f, "%S", n->sym); diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 35d11eca9..00fc720b8 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -110,6 +110,7 @@ func selectgo(sel *byte) func block() func makeslice(typ *byte, nel int64, cap int64) (ary []any) +func growslice(typ *byte, old []any, n int64) (ary []any) func sliceslice1(old []any, lb uint64, width uint64) (ary []any) func sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any) func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any) diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index be96a1477..eb7ef31ec 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -173,10 +173,10 @@ initfix(NodeList *l) /* * from here down is the walk analysis - * of composit literals. + * of composite literals. * most of the work is to generate * data statements for the constant - * part of the composit literal. + * part of the composite literal. */ static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init); diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index bb2505694..49797f9df 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -105,7 +105,7 @@ hcrash(void) flusherrors(); if(outfile) unlink(outfile); - *(int*)0 = 0; + *(volatile int*)0 = 0; } } @@ -480,6 +480,7 @@ nod(int op, Node *nleft, Node *nright) n->right = nright; n->lineno = parserline(); n->xoffset = BADWIDTH; + n->orig = n; return n; } @@ -1031,10 +1032,21 @@ Econv(Fmt *fp) return fmtstrcpy(fp, etnames[et]); } +static const char* classnames[] = { + "Pxxx", + "PEXTERN", + "PAUTO", + "PPARAM", + "PPARAMOUT", + "PPARAMREF", + "PFUNC", +}; + int Jconv(Fmt *fp) { Node *n; + char *s; n = va_arg(fp->args, Node*); if(n->ullman != 0) @@ -1049,12 +1061,18 @@ Jconv(Fmt *fp) if(n->lineno != 0) fmtprint(fp, " l(%d)", n->lineno); - if(n->xoffset != 0) - fmtprint(fp, " x(%lld)", n->xoffset); - - if(n->class != 0) - fmtprint(fp, " class(%d)", n->class); + if(n->xoffset != BADWIDTH) + fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta); + if(n->class != 0) { + s = ""; + if (n->class & PHEAP) s = ",heap"; + if ((n->class & ~PHEAP) < nelem(classnames)) + fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s); + else + fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s); + } + if(n->colas != 0) fmtprint(fp, " colas(%d)", n->colas); @@ -1073,6 +1091,11 @@ Jconv(Fmt *fp) if(n->implicit != 0) fmtprint(fp, " implicit(%d)", n->implicit); + if(n->pun != 0) + fmtprint(fp, " pun(%d)", n->pun); + + if(n->used != 0) + fmtprint(fp, " used(%d)", n->used); return 0; } @@ -1141,7 +1164,7 @@ Tpretty(Fmt *fp, Type *t) Type *t1; Sym *s; - if(debug['r']) { + if(0 && debug['r']) { debug['r'] = 0; fmtprint(fp, "%T (orig=%T)", t, t->orig); debug['r'] = 1; @@ -1454,6 +1477,8 @@ Nconv(Fmt *fp) } if(fp->flags & FmtSharp) { + if(n->orig != N) + n = n->orig; exprfmt(fp, n, 0); goto out; } @@ -3107,7 +3132,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) Type *tpad; int isddd; - if(debug['r']) + if(0 && debug['r']) print("genwrapper rcvrtype=%T method=%T newnam=%S\n", rcvr, method, newnam); @@ -3161,11 +3186,14 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) fn->nbody = list1(n); } - if(debug['r']) + if(0 && debug['r']) dumplist("genwrapper body", fn->nbody); funcbody(fn); + curfn = fn; typecheck(&fn, Etop); + typechecklist(fn->nbody, Etop); + curfn = nil; funccompile(fn, 0); } @@ -3256,8 +3284,9 @@ implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr) // the method does not exist for value types. rcvr = getthisx(tm->type)->type->type; if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) { - if(debug['r']) + if(0 && debug['r']) yyerror("interface pointer mismatch"); + *m = im; *samename = nil; *ptr = 1; @@ -3330,6 +3359,64 @@ list(NodeList *l, Node *n) return concat(l, list1(n)); } +void +listsort(NodeList** l, int(*f)(Node*, Node*)) +{ + NodeList *l1, *l2, *le; + + if(*l == nil || (*l)->next == nil) + return; + + l1 = *l; + l2 = *l; + for(;;) { + l2 = l2->next; + if(l2 == nil) + break; + l2 = l2->next; + if(l2 == nil) + break; + l1 = l1->next; + } + + l2 = l1->next; + l1->next = nil; + l2->end = (*l)->end; + (*l)->end = l1; + + l1 = *l; + listsort(&l1, f); + listsort(&l2, f); + + if ((*f)(l1->n, l2->n) < 0) { + *l = l1; + } else { + *l = l2; + l2 = l1; + l1 = *l; + } + + // now l1 == *l; and l1 < l2 + + while ((l1 != nil) && (l2 != nil)) { + while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0) + l1 = l1->next; + + // l1 is last one from l1 that is < l2 + le = l1->next; // le is the rest of l1, first one that is >= l2 + if (le != nil) + le->end = (*l)->end; + + (*l)->end = l1; // cut *l at l1 + *l = concat(*l, l2); // glue l2 to *l's tail + + l1 = l2; // l1 is the first element of *l that is < the new l2 + l2 = le; // ... because l2 now is the old tail of l1 + } + + *l = concat(*l, l2); // any remainder +} + NodeList* listtreecopy(NodeList *l) { diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c index 6e8436c3c..c2968c44b 100644 --- a/src/cmd/gc/swt.c +++ b/src/cmd/gc/swt.c @@ -867,8 +867,11 @@ typecheckswitch(Node *n) case Etype: // type switch if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) ; - else if(ll->n->op != OTYPE && ll->n->type != T) + else if(ll->n->op != OTYPE && ll->n->type != T) { yyerror("%#N is not a type", ll->n); + // reset to original type + ll->n = n->ntest->right; + } break; } } diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index c48bf7a29..04dc1a507 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -8,7 +8,6 @@ * evaluates compile time constants. * marks variables that escape the local frame. * rewrites n->op to be more specific in some cases. - * sets n->walk to walking function. */ #include "go.h" @@ -29,10 +28,12 @@ static void typecheckfunc(Node*); static void checklvalue(Node*, char*); static void checkassign(Node*); static void checkassignlist(NodeList*); -static void stringtoarraylit(Node**); -static Node* resolve(Node*); +static void stringtoarraylit(Node**); +static Node* resolve(Node*); static Type* getforwtype(Node*); +static NodeList* typecheckdefstack; + /* * resolve ONONAME to definition, if any. */ @@ -159,7 +160,7 @@ typecheck(Node **np, int top) if(n->op == OTYPE && (ft = getforwtype(n->ntype)) != T) defertypecopy(n, ft); - walkdef(n); + typecheckdef(n); n->realtype = n->type; if(n->op == ONONAME) goto error; @@ -780,7 +781,7 @@ reswitch: n = r; goto reswitch; } - typecheck(&n->left, Erv | Etype | Ecall); + typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc)); l = n->left; if(l->op == ONAME && l->etype != 0) { if(n->isddd && l->etype != OAPPEND) @@ -794,7 +795,7 @@ reswitch: defaultlit(&n->left, T); l = n->left; if(l->op == OTYPE) { - if(n->isddd) + if(n->isddd || l->type->bound == -100) yyerror("invalid use of ... in type conversion", l); // pick off before type-checking arguments ok |= Erv; @@ -822,7 +823,13 @@ reswitch: case ODOTMETH: n->op = OCALLMETH; - typecheckaste(OCALL, n->left, 0, getthisx(t), list1(l->left), "method receiver"); + // typecheckaste was used here but there wasn't enough + // information further down the call chain to know if we + // were testing a method receiver for unexported fields. + // It isn't necessary, so just do a sanity check. + tp = getthisx(t)->type->type; + if(l->left == N || !eqtype(l->left->type, tp)) + fatal("method receiver"); break; default: @@ -894,12 +901,20 @@ reswitch: // might be constant switch(t->etype) { case TSTRING: - if(isconst(l, CTSTR)) - nodconst(n, types[TINT], l->val.u.sval->len); + if(isconst(l, CTSTR)) { + r = nod(OXXX, N, N); + nodconst(r, types[TINT], l->val.u.sval->len); + r->orig = n; + n = r; + } break; case TARRAY: - if(t->bound >= 0 && l->op == ONAME) - nodconst(n, types[TINT], t->bound); + if(t->bound >= 0 && l->op == ONAME) { + r = nod(OXXX, N, N); + nodconst(r, types[TINT], t->bound); + r->orig = n; + n = r; + } break; } n->type = types[TINT]; @@ -1013,9 +1028,9 @@ reswitch: // copy([]byte, string) if(isslice(n->left->type) && n->right->type->etype == TSTRING) { - if (n->left->type->type ==types[TUINT8]) - goto ret; - yyerror("arguments to copy have different element types: %lT and string", n->left->type); + if (n->left->type->type == types[TUINT8]) + goto ret; + yyerror("arguments to copy have different element types: %lT and string", n->left->type); goto error; } @@ -1203,7 +1218,7 @@ reswitch: case OCLOSURE: ok |= Erv; - typecheckclosure(n); + typecheckclosure(n, top); if(n->type == T) goto error; goto ret; @@ -1232,11 +1247,15 @@ reswitch: goto ret; case ODEFER: - case OPROC: ok |= Etop; typecheck(&n->left, Etop); goto ret; + case OPROC: + ok |= Etop; + typecheck(&n->left, Etop|Eproc); + goto ret; + case OFOR: ok |= Etop; typechecklist(n->ninit, Etop); @@ -1357,7 +1376,10 @@ ret: goto error; } if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) { - yyerror("%#N not used", n); + if(n->diag == 0) { + yyerror("%#N not used", n); + n->diag = 1; + } goto error; } @@ -2148,7 +2170,9 @@ addrescapes(Node *n) if(n->noescape) break; switch(n->class) { - case PAUTO: + case PPARAMREF: + addrescapes(n->defn); + break; case PPARAM: case PPARAMOUT: // if func param, need separate temporary @@ -2156,16 +2180,17 @@ addrescapes(Node *n) // the function type has already been checked // (we're in the function body) // so the param already has a valid xoffset. - if(n->class == PPARAM || n->class == PPARAMOUT) { - // expression to refer to stack copy - n->stackparam = nod(OPARAM, n, N); - n->stackparam->type = n->type; - n->stackparam->addable = 1; - if(n->xoffset == BADWIDTH) - fatal("addrescapes before param assignment"); - n->stackparam->xoffset = n->xoffset; - n->xoffset = 0; - } + + // expression to refer to stack copy + n->stackparam = nod(OPARAM, n, N); + n->stackparam->type = n->type; + n->stackparam->addable = 1; + if(n->xoffset == BADWIDTH) + fatal("addrescapes before param assignment"); + n->stackparam->xoffset = n->xoffset; + n->xoffset = 0; + // fallthrough + case PAUTO: n->class |= PHEAP; n->addable = 0; @@ -2178,7 +2203,9 @@ addrescapes(Node *n) snprint(buf, sizeof buf, "&%S", n->sym); n->heapaddr->sym = lookup(buf); n->heapaddr->class = PHEAP-1; // defer tempname to allocparams - curfn->dcl = list(curfn->dcl, n->heapaddr); + n->heapaddr->ullman = 1; + n->curfn->dcl = list(n->curfn->dcl, n->heapaddr); + break; } break; @@ -2497,3 +2524,294 @@ getforwtype(Node *n) } } } + +static int ntypecheckdeftype; +static NodeList *methodqueue; + +static void +domethod(Node *n) +{ + Node *nt; + + nt = n->type->nname; + typecheck(&nt, Etype); + if(nt->type == T) { + // type check failed; leave empty func + n->type->etype = TFUNC; + n->type->nod = N; + return; + } + *n->type = *nt->type; + n->type->nod = N; + checkwidth(n->type); +} + +typedef struct NodeTypeList NodeTypeList; +struct NodeTypeList { + Node *n; + Type *t; + NodeTypeList *next; +}; + +static NodeTypeList *dntq; +static NodeTypeList *dntend; + +void +defertypecopy(Node *n, Type *t) +{ + NodeTypeList *ntl; + + if(n == N || t == T) + return; + + ntl = mal(sizeof *ntl); + ntl->n = n; + ntl->t = t; + ntl->next = nil; + + if(dntq == nil) + dntq = ntl; + else + dntend->next = ntl; + + dntend = ntl; +} + +void +resumetypecopy(void) +{ + NodeTypeList *l; + + for(l=dntq; l; l=l->next) + copytype(l->n, l->t); +} + +void +copytype(Node *n, Type *t) +{ + *n->type = *t; + + t = n->type; + t->sym = n->sym; + t->local = n->local; + t->vargen = n->vargen; + t->siggen = 0; + t->method = nil; + t->nod = N; + t->printed = 0; + t->deferwidth = 0; +} + +static void +typecheckdeftype(Node *n) +{ + int maplineno, embedlineno, lno; + Type *t; + NodeList *l; + + ntypecheckdeftype++; + lno = lineno; + setlineno(n); + n->type->sym = n->sym; + n->typecheck = 1; + typecheck(&n->ntype, Etype); + if((t = n->ntype->type) == T) { + n->diag = 1; + goto ret; + } + if(n->type == T) { + n->diag = 1; + goto ret; + } + + maplineno = n->type->maplineno; + embedlineno = n->type->embedlineno; + + // copy new type and clear fields + // that don't come along. + // anything zeroed here must be zeroed in + // typedcl2 too. + copytype(n, t); + + // double-check use of type as map key. + if(maplineno) { + lineno = maplineno; + maptype(n->type, types[TBOOL]); + } + if(embedlineno) { + lineno = embedlineno; + if(isptr[t->etype]) + yyerror("embedded type cannot be a pointer"); + } + +ret: + lineno = lno; + + // if there are no type definitions going on, it's safe to + // try to resolve the method types for the interfaces + // we just read. + if(ntypecheckdeftype == 1) { + while((l = methodqueue) != nil) { + methodqueue = nil; + for(; l; l=l->next) + domethod(l->n); + } + } + ntypecheckdeftype--; +} + +void +queuemethod(Node *n) +{ + if(ntypecheckdeftype == 0) { + domethod(n); + return; + } + methodqueue = list(methodqueue, n); +} + +Node* +typecheckdef(Node *n) +{ + int lno; + Node *e; + Type *t; + NodeList *l; + + lno = lineno; + setlineno(n); + + if(n->op == ONONAME) { + if(!n->diag) { + n->diag = 1; + if(n->lineno != 0) + lineno = n->lineno; + yyerror("undefined: %S", n->sym); + } + return n; + } + + if(n->walkdef == 1) + return n; + + l = mal(sizeof *l); + l->n = n; + l->next = typecheckdefstack; + typecheckdefstack = l; + + if(n->walkdef == 2) { + flusherrors(); + print("typecheckdef loop:"); + for(l=typecheckdefstack; l; l=l->next) + print(" %S", l->n->sym); + print("\n"); + fatal("typecheckdef loop"); + } + n->walkdef = 2; + + if(n->type != T || n->sym == S) // builtin or no name + goto ret; + + switch(n->op) { + default: + fatal("typecheckdef %O", n->op); + + case OLITERAL: + if(n->ntype != N) { + typecheck(&n->ntype, Etype); + n->type = n->ntype->type; + n->ntype = N; + if(n->type == T) { + n->diag = 1; + goto ret; + } + } + e = n->defn; + n->defn = N; + if(e == N) { + lineno = n->lineno; + dump("typecheckdef nil defn", n); + yyerror("xxx"); + } + typecheck(&e, Erv | Eiota); + if(e->type != T && e->op != OLITERAL) { + yyerror("const initializer must be constant"); + goto ret; + } + if(isconst(e, CTNIL)) { + yyerror("const initializer cannot be nil"); + goto ret; + } + t = n->type; + if(t != T) { + if(!okforconst[t->etype]) { + yyerror("invalid constant type %T", t); + goto ret; + } + if(!isideal(e->type) && !eqtype(t, e->type)) { + yyerror("cannot use %+N as type %T in const initializer", e, t); + goto ret; + } + convlit(&e, t); + } + n->val = e->val; + n->type = e->type; + break; + + case ONAME: + if(n->ntype != N) { + typecheck(&n->ntype, Etype); + n->type = n->ntype->type; + if(n->type == T) { + n->diag = 1; + goto ret; + } + } + if(n->type != T) + break; + if(n->defn == N) { + if(n->etype != 0) // like OPRINTN + break; + if(nerrors > 0) { + // Can have undefined variables in x := foo + // that make x have an n->ndefn == nil. + // If there are other errors anyway, don't + // bother adding to the noise. + break; + } + fatal("var without type, init: %S", n->sym); + } + if(n->defn->op == ONAME) { + typecheck(&n->defn, Erv); + n->type = n->defn->type; + break; + } + typecheck(&n->defn, Etop); // fills in n->type + break; + + case OTYPE: + if(curfn) + defercheckwidth(); + n->walkdef = 1; + n->type = typ(TFORW); + n->type->sym = n->sym; + typecheckdeftype(n); + if(curfn) + resumecheckwidth(); + break; + + case OPACK: + // nothing to see here + break; + } + +ret: + if(typecheckdefstack->n != n) + fatal("typecheckdefstack mismatch"); + l = typecheckdefstack; + typecheckdefstack = l->next; + + lineno = lno; + n->walkdef = 1; + return n; +} diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c index 33f375631..540994ddd 100644 --- a/src/cmd/gc/unsafe.c +++ b/src/cmd/gc/unsafe.c @@ -41,6 +41,7 @@ unsafenmagic(Node *nn) tr = r->type; if(tr == T) goto bad; + dowidth(tr); v = tr->width; goto yes; } diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 278eef414..65a504bff 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -18,12 +18,11 @@ static NodeList* paramstoheap(Type **argin, int out); static NodeList* reorder1(NodeList*); static NodeList* reorder3(NodeList*); static Node* addstr(Node*, NodeList**); +static Node* appendslice(Node*, NodeList**); static Node* append(Node*, NodeList**); -static NodeList* walkdefstack; - // can this code branch reach the end -// without an undcontitional RETURN +// without an unconditional RETURN // this is hard, so it is conservative static int walkret(NodeList *l) @@ -65,6 +64,7 @@ walk(Node *fn) int lno; curfn = fn; + if(debug['W']) { snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym); dumplist(s, curfn->nbody); @@ -72,7 +72,7 @@ walk(Node *fn) if(curfn->type->outtuple) if(walkret(curfn->nbody)) yyerror("function ends without a return statement"); - typechecklist(curfn->nbody, Etop); + lno = lineno; for(l=fn->dcl; l; l=l->next) { n = l->n; @@ -98,296 +98,6 @@ walk(Node *fn) } } -static int nwalkdeftype; -static NodeList *methodqueue; - -static void -domethod(Node *n) -{ - Node *nt; - - nt = n->type->nname; - typecheck(&nt, Etype); - if(nt->type == T) { - // type check failed; leave empty func - n->type->etype = TFUNC; - n->type->nod = N; - return; - } - *n->type = *nt->type; - n->type->nod = N; - checkwidth(n->type); -} - -typedef struct NodeTypeList NodeTypeList; -struct NodeTypeList { - Node *n; - Type *t; - NodeTypeList *next; -}; - -static NodeTypeList *dntq; -static NodeTypeList *dntend; - -void -defertypecopy(Node *n, Type *t) -{ - NodeTypeList *ntl; - - if(n == N || t == T) - return; - - ntl = mal(sizeof *ntl); - ntl->n = n; - ntl->t = t; - ntl->next = nil; - - if(dntq == nil) - dntq = ntl; - else - dntend->next = ntl; - - dntend = ntl; -} - -void -resumetypecopy(void) -{ - NodeTypeList *l; - - for(l=dntq; l; l=l->next) - copytype(l->n, l->t); -} - -void -copytype(Node *n, Type *t) -{ - *n->type = *t; - - t = n->type; - t->sym = n->sym; - t->local = n->local; - t->vargen = n->vargen; - t->siggen = 0; - t->method = nil; - t->nod = N; - t->printed = 0; - t->deferwidth = 0; -} - -static void -walkdeftype(Node *n) -{ - int maplineno, embedlineno, lno; - Type *t; - NodeList *l; - - nwalkdeftype++; - lno = lineno; - setlineno(n); - n->type->sym = n->sym; - n->typecheck = 1; - typecheck(&n->ntype, Etype); - if((t = n->ntype->type) == T) { - n->diag = 1; - goto ret; - } - if(n->type == T) { - n->diag = 1; - goto ret; - } - - maplineno = n->type->maplineno; - embedlineno = n->type->embedlineno; - - // copy new type and clear fields - // that don't come along. - // anything zeroed here must be zeroed in - // typedcl2 too. - copytype(n, t); - - // double-check use of type as map key. - if(maplineno) { - lineno = maplineno; - maptype(n->type, types[TBOOL]); - } - if(embedlineno) { - lineno = embedlineno; - if(isptr[t->etype]) - yyerror("embedded type cannot be a pointer"); - } - -ret: - lineno = lno; - - // if there are no type definitions going on, it's safe to - // try to resolve the method types for the interfaces - // we just read. - if(nwalkdeftype == 1) { - while((l = methodqueue) != nil) { - methodqueue = nil; - for(; l; l=l->next) - domethod(l->n); - } - } - nwalkdeftype--; -} - -void -queuemethod(Node *n) -{ - if(nwalkdeftype == 0) { - domethod(n); - return; - } - methodqueue = list(methodqueue, n); -} - -Node* -walkdef(Node *n) -{ - int lno; - Node *e; - Type *t; - NodeList *l; - - lno = lineno; - setlineno(n); - - if(n->op == ONONAME) { - if(!n->diag) { - n->diag = 1; - if(n->lineno != 0) - lineno = n->lineno; - yyerror("undefined: %S", n->sym); - } - return n; - } - - if(n->walkdef == 1) - return n; - - l = mal(sizeof *l); - l->n = n; - l->next = walkdefstack; - walkdefstack = l; - - if(n->walkdef == 2) { - flusherrors(); - print("walkdef loop:"); - for(l=walkdefstack; l; l=l->next) - print(" %S", l->n->sym); - print("\n"); - fatal("walkdef loop"); - } - n->walkdef = 2; - - if(n->type != T || n->sym == S) // builtin or no name - goto ret; - - switch(n->op) { - default: - fatal("walkdef %O", n->op); - - case OLITERAL: - if(n->ntype != N) { - typecheck(&n->ntype, Etype); - n->type = n->ntype->type; - n->ntype = N; - if(n->type == T) { - n->diag = 1; - goto ret; - } - } - e = n->defn; - n->defn = N; - if(e == N) { - lineno = n->lineno; - dump("walkdef nil defn", n); - yyerror("xxx"); - } - typecheck(&e, Erv | Eiota); - if(e->type != T && e->op != OLITERAL) { - yyerror("const initializer must be constant"); - goto ret; - } - if(isconst(e, CTNIL)) { - yyerror("const initializer cannot be nil"); - goto ret; - } - t = n->type; - if(t != T) { - if(!okforconst[t->etype]) { - yyerror("invalid constant type %T", t); - goto ret; - } - if(!isideal(e->type) && !eqtype(t, e->type)) { - yyerror("cannot use %+N as type %T in const initializer", e, t); - goto ret; - } - convlit(&e, t); - } - n->val = e->val; - n->type = e->type; - break; - - case ONAME: - if(n->ntype != N) { - typecheck(&n->ntype, Etype); - n->type = n->ntype->type; - if(n->type == T) { - n->diag = 1; - goto ret; - } - } - if(n->type != T) - break; - if(n->defn == N) { - if(n->etype != 0) // like OPRINTN - break; - if(nerrors > 0) { - // Can have undefined variables in x := foo - // that make x have an n->ndefn == nil. - // If there are other errors anyway, don't - // bother adding to the noise. - break; - } - fatal("var without type, init: %S", n->sym); - } - if(n->defn->op == ONAME) { - typecheck(&n->defn, Erv); - n->type = n->defn->type; - break; - } - typecheck(&n->defn, Etop); // fills in n->type - break; - - case OTYPE: - if(curfn) - defercheckwidth(); - n->walkdef = 1; - n->type = typ(TFORW); - n->type->sym = n->sym; - walkdeftype(n); - if(curfn) - resumecheckwidth(); - break; - - case OPACK: - // nothing to see here - break; - } - -ret: - if(walkdefstack->n != n) - fatal("walkdefstack mismatch"); - l = walkdefstack; - walkdefstack = l->next; - - lineno = lno; - n->walkdef = 1; - return n; -} void walkstmtlist(NodeList *l) @@ -467,8 +177,10 @@ walkstmt(Node **np) case OPANIC: case OEMPTY: case ORECOVER: - if(n->typecheck == 0) + if(n->typecheck == 0) { + dump("missing typecheck:", n); fatal("missing typecheck"); + } init = n->ninit; n->ninit = nil; walkexpr(&n, &init); @@ -769,8 +481,15 @@ walkexpr(Node **np, NodeList **init) t = n->left->type; if(n->list && n->list->n->op == OAS) goto ret; - walkexpr(&n->left, init); + + if(n->left->op == OCLOSURE) { + walkcallclosure(n, init); + t = n->left->type; + } else + walkexpr(&n->left, init); + walkexprlist(n->list, init); + ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); n->list = reorder1(ll); if(isselect(n)) { @@ -805,18 +524,17 @@ walkexpr(Node **np, NodeList **init) n->ninit = nil; walkexpr(&n->left, init); n->left = safeexpr(n->left, init); + if(oaslit(n, init)) goto ret; + walkexpr(&n->right, init); - l = n->left; - r = n->right; - if(l == N || r == N) - goto ret; - r = ascompatee1(n->op, l, r, init); - if(r != N) { + if(n->left != N && n->right != N) { + r = convas(nod(OAS, n->left, n->right), init); r->dodata = n->dodata; n = r; } + goto ret; case OAS2: @@ -1134,6 +852,7 @@ walkexpr(Node **np, NodeList **init) case OINDEXMAP: if(n->etype == 1) goto ret; + t = n->left->type; n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right); goto ret; @@ -1188,6 +907,7 @@ walkexpr(Node **np, NodeList **init) // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any) // sliceslice1(old []any, lb uint64, width uint64) (ary []any) t = n->type; + et = n->etype; if(n->right->left == N) l = nodintconst(0); else @@ -1210,6 +930,7 @@ walkexpr(Node **np, NodeList **init) l, nodintconst(t->type->width)); } + n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call. goto ret; slicearray: @@ -1332,7 +1053,10 @@ walkexpr(Node **np, NodeList **init) goto ret; case OAPPEND: - n = append(n, init); + if(n->isddd) + n = appendslice(n, init); + else + n = append(n, init); goto ret; case OCOPY: @@ -1519,7 +1243,7 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init) static int fncall(Node *l, Type *rt) { - if(l->ullman >= UINF) + if(l->ullman >= UINF || l->op == OINDEXMAP) return 1; if(eqtype(l->type, rt)) return 0; @@ -1953,23 +1677,18 @@ callnew(Type *t) static Node* convas(Node *n, NodeList **init) { - Node *l, *r; Type *lt, *rt; if(n->op != OAS) fatal("convas: not OAS %O", n->op); - n->typecheck = 1; - lt = T; - rt = T; + n->typecheck = 1; - l = n->left; - r = n->right; - if(l == N || r == N) + if(n->left == N || n->right == N) goto out; - lt = l->type; - rt = r->type; + lt = n->left->type; + rt = n->right->type; if(lt == T || rt == T) goto out; @@ -1987,7 +1706,7 @@ convas(Node *n, NodeList **init) if(eqtype(lt, rt)) goto out; - n->right = assignconv(r, lt, "assignment"); + n->right = assignconv(n->right, lt, "assignment"); walkexpr(&n->right, init); out: @@ -2365,42 +2084,85 @@ addstr(Node *n, NodeList **init) } static Node* -append(Node *n, NodeList **init) +appendslice(Node *n, NodeList **init) { - int i, j; - Node *f, *r; - NodeList *in, *args; + Node *f; - if(n->isddd) { - f = syslook("appendslice", 1); - argtype(f, n->type); - argtype(f, n->type->type); - argtype(f, n->type); - r = mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n); - return r; + f = syslook("appendslice", 1); + argtype(f, n->type); + argtype(f, n->type->type); + argtype(f, n->type); + return mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n); +} + +// expand append(src, a [, b]* ) to +// +// init { +// s := src +// const argc = len(args) - 1 +// if cap(s) - len(s) < argc { +// s = growslice(s, argc) +// } +// n := len(s) +// s = s[:n+argc] +// s[n] = a +// s[n+1] = b +// ... +// } +// s +static Node* +append(Node *n, NodeList **init) +{ + NodeList *l, *a; + Node *nsrc, *ns, *nn, *na, *nx, *fn; + int argc; + + walkexprlistsafe(n->list, init); + + nsrc = n->list->n; + argc = count(n->list) - 1; + if (argc < 1) { + return nsrc; } - j = count(n->list) - 1; - f = syslook("append", 1); - f->type = T; - f->ntype = nod(OTFUNC, N, N); - in = list1(nod(ODCLFIELD, N, typenod(ptrto(types[TUINT8])))); // type - in = list(in, nod(ODCLFIELD, N, typenod(types[TINT]))); // count - in = list(in, nod(ODCLFIELD, N, typenod(n->type))); // slice - for(i=0; i<j; i++) - in = list(in, nod(ODCLFIELD, N, typenod(n->type->type))); - f->ntype->list = in; - f->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(n->type))); - - args = list1(typename(n->type)); - args = list(args, nodintconst(j)); - args = concat(args, n->list); - - r = nod(OCALL, f, N); - r->list = args; - typecheck(&r, Erv); - walkexpr(&r, init); - r->type = n->type; + l = nil; - return r; + ns = nod(OXXX, N, N); // var s + tempname(ns, nsrc->type); + l = list(l, nod(OAS, ns, nsrc)); // s = src + + na = nodintconst(argc); // const argc + nx = nod(OIF, N, N); // if cap(s) - len(s) < argc + nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na); + + fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T) + argtype(fn, ns->type->type); // 1 old []any + argtype(fn, ns->type->type); // 2 ret []any + + nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit, + typename(ns->type), + ns, + conv(na, types[TINT64])))); + l = list(l, nx); + + nn = nod(OXXX, N, N); // var n + tempname(nn, types[TINT]); + l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s) + + nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc] + nx->etype = 1; // disable bounds check + l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc] + + for (a = n->list->next; a != nil; a = a->next) { + nx = nod(OINDEX, ns, nn); // s[n] ... + nx->etype = 1; // disable bounds check + l = list(l, nod(OAS, nx, a->n)); // s[n] = arg + if (a->next != nil) + l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1 + } + + typechecklist(l, Etop); + walkstmtlist(l); + *init = concat(*init, l); + return ns; } |