summaryrefslogtreecommitdiff
path: root/src/cmd/gc
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-06-30 15:34:22 +0200
committerOndřej Surý <ondrej@sury.org>2011-06-30 15:34:22 +0200
commitd39f5aa373a4422f7a5f3ee764fb0f6b0b719d61 (patch)
tree1833f8b72a4b3a8f00d0d143b079a8fcad01c6ae /src/cmd/gc
parent8652e6c371b8905498d3d314491d36c58d5f68d5 (diff)
downloadgolang-upstream/58.tar.gz
Imported Upstream version 58upstream/58
Diffstat (limited to 'src/cmd/gc')
-rw-r--r--src/cmd/gc/Makefile2
-rw-r--r--src/cmd/gc/align.c12
-rw-r--r--src/cmd/gc/builtin.c.boot4
-rw-r--r--src/cmd/gc/closure.c44
-rw-r--r--src/cmd/gc/const.c4
-rw-r--r--src/cmd/gc/dcl.c42
-rw-r--r--src/cmd/gc/gen.c22
-rw-r--r--src/cmd/gc/go.h29
-rw-r--r--src/cmd/gc/go.y20
-rw-r--r--src/cmd/gc/init.c5
-rw-r--r--src/cmd/gc/lex.c22
-rw-r--r--src/cmd/gc/obj.c1
-rw-r--r--src/cmd/gc/pgen.c224
-rw-r--r--src/cmd/gc/print.c4
-rw-r--r--src/cmd/gc/runtime.go1
-rw-r--r--src/cmd/gc/sinit.c4
-rw-r--r--src/cmd/gc/subr.c107
-rw-r--r--src/cmd/gc/swt.c5
-rw-r--r--src/cmd/gc/typecheck.c376
-rw-r--r--src/cmd/gc/unsafe.c1
-rw-r--r--src/cmd/gc/walk.c456
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;
}