diff options
Diffstat (limited to 'src/cmd/gc')
-rw-r--r-- | src/cmd/gc/align.c | 12 | ||||
-rw-r--r-- | src/cmd/gc/builtin.c.boot | 6 | ||||
-rw-r--r-- | src/cmd/gc/const.c | 2 | ||||
-rw-r--r-- | src/cmd/gc/dcl.c | 41 | ||||
-rw-r--r-- | src/cmd/gc/export.c | 15 | ||||
-rw-r--r-- | src/cmd/gc/gen.c | 157 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 32 | ||||
-rw-r--r-- | src/cmd/gc/go.y | 20 | ||||
-rw-r--r-- | src/cmd/gc/lex.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/obj.c | 54 | ||||
-rw-r--r-- | src/cmd/gc/print.c | 2 | ||||
-rw-r--r-- | src/cmd/gc/range.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/reflect.c | 65 | ||||
-rw-r--r-- | src/cmd/gc/runtime.go | 4 | ||||
-rw-r--r-- | src/cmd/gc/select.c | 70 | ||||
-rw-r--r-- | src/cmd/gc/sinit.c | 2 | ||||
-rw-r--r-- | src/cmd/gc/subr.c | 41 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 21 | ||||
-rw-r--r-- | src/cmd/gc/unsafe.go | 2 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 15 |
20 files changed, 392 insertions, 177 deletions
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index 833eba19a..a01e2ea46 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -172,6 +172,9 @@ dowidth(Type *t) w = 8; checkwidth(t->type); break; + case TUNSAFEPTR: + w = widthptr; + break; case TINTER: // implemented as 2 pointers w = 2*widthptr; t->align = widthptr; @@ -400,6 +403,13 @@ typeinit(void) types[TPTR64] = typ(TPTR64); dowidth(types[TPTR64]); + + t = typ(TUNSAFEPTR); + types[TUNSAFEPTR] = t; + t->sym = pkglookup("Pointer", unsafepkg); + t->sym->def = typenod(t); + + dowidth(types[TUNSAFEPTR]); tptr = TPTR32; if(widthptr == 8) @@ -481,6 +491,7 @@ typeinit(void) okforeq[TPTR32] = 1; okforeq[TPTR64] = 1; + okforeq[TUNSAFEPTR] = 1; okforeq[TINTER] = 1; okforeq[TMAP] = 1; okforeq[TCHAN] = 1; @@ -570,6 +581,7 @@ typeinit(void) simtype[TMAP] = tptr; simtype[TCHAN] = tptr; simtype[TFUNC] = tptr; + simtype[TUNSAFEPTR] = tptr; /* pick up the backend typedefs */ for(i=0; typedefs[i].name; i++) { diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot index 48f45293f..bdbca7f78 100644 --- a/src/cmd/gc/builtin.c.boot +++ b/src/cmd/gc/builtin.c.boot @@ -66,15 +66,17 @@ char *runtimeimport = "func \"\".mapiter2 (hiter *any) (key any, val any)\n" "func \"\".makechan (elem *uint8, hint int64) chan any\n" "func \"\".chanrecv1 (hchan <-chan any) any\n" - "func \"\".chanrecv3 (hchan <-chan any) (elem any, closed bool)\n" + "func \"\".chanrecv2 (hchan <-chan any) (elem any, received bool)\n" "func \"\".chansend1 (hchan chan<- any, elem any)\n" "func \"\".closechan (hchan any)\n" "func \"\".closedchan (hchan any) bool\n" "func \"\".selectnbsend (hchan chan<- any, elem any) bool\n" "func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n" + "func \"\".selectnbrecv2 (elem *any, received *bool, hchan <-chan any) bool\n" "func \"\".newselect (size int) *uint8\n" "func \"\".selectsend (sel *uint8, hchan chan<- any, elem any) bool\n" "func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n" + "func \"\".selectrecv2 (sel *uint8, hchan <-chan any, elem *any, received *bool) bool\n" "func \"\".selectdefault (sel *uint8) bool\n" "func \"\".selectgo (sel *uint8)\n" "func \"\".block ()\n" @@ -96,7 +98,7 @@ char *runtimeimport = "$$\n"; char *unsafeimport = "package unsafe\n" - "type \"\".Pointer *any\n" + "type \"\".Pointer uintptr\n" "func \"\".Offsetof (? any) int\n" "func \"\".Sizeof (? any) int\n" "func \"\".Alignof (? any) int\n" diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index a54c40f6c..a36ec68c0 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -136,7 +136,6 @@ convlit1(Node **np, Type *t, int explicit) case CTNIL: switch(et) { default: - yyerror("cannot use nil as %T", t); n->type = T; goto bad; @@ -155,6 +154,7 @@ convlit1(Node **np, Type *t, int explicit) case TMAP: case TCHAN: case TFUNC: + case TUNSAFEPTR: break; } break; diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index a71272aa2..3089a23b0 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -22,7 +22,6 @@ dflag(void) /* * declaration stack & operations */ -static Sym* dclstack; static void dcopy(Sym *a, Sym *b) @@ -656,10 +655,19 @@ typedcl2(Type *pt, Type *t) { Node *n; + // override declaration in unsafe.go for Pointer. + // there is no way in Go code to define unsafe.Pointer + // so we have to supply it. + if(incannedimport && + strcmp(importpkg->name, "unsafe") == 0 && + strcmp(pt->nod->sym->name, "Pointer") == 0) { + t = types[TUNSAFEPTR]; + } + if(pt->etype == TFORW) goto ok; if(!eqtype(pt->orig, t)) - yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t); + yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t); return; ok: @@ -684,13 +692,13 @@ ok: * turn a parsed struct into a type */ static Type** -stotype(NodeList *l, int et, Type **t) +stotype(NodeList *l, int et, Type **t, int funarg) { Type *f, *t1, *t2, **t0; Strlit *note; int lno; NodeList *init; - Node *n; + Node *n, *left; char *what; t0 = t; @@ -707,15 +715,18 @@ stotype(NodeList *l, int et, Type **t) if(n->op != ODCLFIELD) fatal("stotype: oops %N\n", n); + left = n->left; + if(funarg && isblank(left)) + left = N; if(n->right != N) { - if(et == TINTER && n->left != N) { + if(et == TINTER && left != N) { // queue resolution of method type for later. // right now all we need is the name list. // avoids cycles for recursive interface types. n->type = typ(TINTERMETH); n->type->nname = n->right; n->right = N; - n->left->type = n->type; + left->type = n->type; queuemethod(n); } else { typecheck(&n->right, Etype); @@ -724,8 +735,8 @@ stotype(NodeList *l, int et, Type **t) *t0 = T; return t0; } - if(n->left != N) - n->left->type = n->type; + if(left != N) + left->type = n->type; n->right = N; if(n->embedded && n->type != T) { t1 = n->type; @@ -763,7 +774,7 @@ stotype(NodeList *l, int et, Type **t) break; } - if(et == TINTER && n->left == N) { + if(et == TINTER && left == N) { // embedded interface - inline the methods if(n->type->etype != TINTER) { if(n->type->etype == TFORW) @@ -796,8 +807,8 @@ stotype(NodeList *l, int et, Type **t) f->width = BADWIDTH; f->isddd = n->isddd; - if(n->left != N && n->left->op == ONAME) { - f->nname = n->left; + if(left != N && left->op == ONAME) { + f->nname = left; f->embedded = n->embedded; f->sym = f->nname->sym; if(importpkg && !exportname(f->sym->name)) @@ -839,7 +850,7 @@ dostruct(NodeList *l, int et) } t = typ(et); t->funarg = funarg; - stotype(l, et, &t->type); + stotype(l, et, &t->type, funarg); if(t->type == T && l != nil) { t->broke = 1; return t; @@ -933,8 +944,6 @@ checkarglist(NodeList *all, int input) t = n; n = N; } - if(isblank(n)) - n = N; if(n != N && n->sym == S) { t = n; n = N; @@ -1151,9 +1160,9 @@ addmethod(Sym *sf, Type *t, int local) } if(d == T) - stotype(list1(n), 0, &pa->method); + stotype(list1(n), 0, &pa->method, 0); else - stotype(list1(n), 0, &d->down); + stotype(list1(n), 0, &d->down, 0); return; } diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c index 09b963f27..014f0c5f0 100644 --- a/src/cmd/gc/export.c +++ b/src/cmd/gc/export.c @@ -75,10 +75,15 @@ autoexport(Node *n, int ctxt) static void dumppkg(Pkg *p) { + char *suffix; + if(p == nil || p == localpkg || p->exported) return; p->exported = 1; - Bprint(bout, "\timport %s \"%Z\"\n", p->name, p->path); + suffix = ""; + if(!p->direct) + suffix = " // indirect"; + Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix); } static void @@ -265,7 +270,8 @@ void dumpexport(void) { NodeList *l; - int32 lno; + int32 i, lno; + Pkg *p; lno = lineno; @@ -277,6 +283,11 @@ dumpexport(void) Bprint(bout, " safe"); Bprint(bout, "\n"); + for(i=0; i<nelem(phash); i++) + for(p=phash[i]; p; p=p->link) + if(p->direct) + dumppkg(p); + for(l=exportlist; l; l=l->next) { lineno = l->n->lineno; dumpsym(l->n->sym); diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index 04af5a7bb..8ad6c437d 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -64,62 +64,83 @@ allocparams(void) lineno = lno; } +void +clearlabels(void) +{ + Label *l; + + for(l=labellist; l!=L; l=l->link) + l->sym->label = L; + + labellist = L; + lastlabel = L; +} + static void -newlab(int op, Sym *s, Node *stmt) +newlab(int op, Node *nlab, Node *stmt) { Label *lab; + Sym *s; + int32 lno; + + s = nlab->left->sym; + lno = nlab->left->lineno; lab = mal(sizeof(*lab)); - lab->link = labellist; - labellist = lab; + if(lastlabel == nil) + labellist = lab; + else + lastlabel->link = lab; + lastlabel = lab; + lab->lineno = lno; lab->sym = s; lab->op = op; lab->label = pc; lab->stmt = stmt; + if(op == OLABEL) { + if(s->label != L) { + lineno = lno; + yyerror("label %S already defined at %L", s, s->label->lineno); + } else + s->label = lab; + } } void checklabels(void) { - Label *l, *m; + Label *l; Sym *s; + int lno; -// // print the label list -// for(l=labellist; l!=L; l=l->link) { -// print("lab %O %S\n", l->op, l->sym); -// } - + lno = lineno; + + // resolve goto using syms for(l=labellist; l!=L; l=l->link) { - switch(l->op) { - case OLABEL: - // these are definitions - + switch(l->op) { + case OGOTO: s = l->sym; - for(m=labellist; m!=L; m=m->link) { - if(m->sym != s) - continue; - switch(m->op) { - case OLABEL: - // these are definitions - - // look for redefinitions - if(l != m) - yyerror("label %S redefined", s); - break; - case OGOTO: - // these are references - - // patch to definition - patch(m->label, l->label); - m->sym = S; // mark done - break; - } + if(s->label == L) { + lineno = l->lineno; + yyerror("label %S not defined", s); + break; } + s->label->used = 1; + patch(l->label, s->label->label); + break; } } - - // diagnostic for all undefined references - for(l=labellist; l!=L; l=l->link) - if(l->op == OGOTO && l->sym != S) - yyerror("label %S not defined", l->sym); + + // diagnose unused labels + for(l=labellist; l!=L; l=l->link) { + if(l->op == OLABEL && !l->used) { + lineno = l->lineno; + yyerror("label %S defined and not used", l->sym); + } + } + + lineno = lno; } /* @@ -171,7 +192,7 @@ gen(Node *n) // insert no-op so that // L:; for { } // does not treat L as a label for the loop. - if(labellist && labellist->label == p3) + if(lastlabel != L && lastlabel->label == p3) gused(N); break; @@ -180,26 +201,27 @@ gen(Node *n) break; case OLABEL: - newlab(OLABEL, n->left->sym, n->right); + newlab(OLABEL, n, n->right); break; case OGOTO: - newlab(OGOTO, n->left->sym, N); + newlab(OGOTO, n, N); gjmp(P); break; case OBREAK: if(n->left != N) { - for(lab=labellist; lab!=L; lab=lab->link) { - if(lab->sym == n->left->sym) { - if(lab->breakpc == P) - yyerror("invalid break label %S", n->left->sym); - gjmp(lab->breakpc); - goto donebreak; - } - } - if(lab == L) + lab = n->left->sym->label; + if(lab == L) { yyerror("break label not defined: %S", n->left->sym); + break; + } + lab->used = 1; + if(lab->breakpc == P) { + yyerror("invalid break label %S", n->left->sym); + break; + } + gjmp(lab->breakpc); break; } if(breakpc == P) { @@ -207,30 +229,28 @@ gen(Node *n) break; } gjmp(breakpc); - donebreak: break; case OCONTINUE: if(n->left != N) { - for(lab=labellist; lab!=L; lab=lab->link) { - if(lab->sym == n->left->sym) { - if(lab->continpc == P) - yyerror("invalid continue label %S", n->left->sym); - gjmp(lab->continpc); - goto donecont; - } - } - if(lab == L) + lab = n->left->sym->label; + if(lab == L) { yyerror("continue label not defined: %S", n->left->sym); + break; + } + lab->used = 1; + if(lab->continpc == P) { + yyerror("invalid continue label %S", n->left->sym); + break; + } + gjmp(lab->continpc); break; } - if(continpc == P) { yyerror("continue is not in a loop"); break; } gjmp(continpc); - donecont: break; case OFOR: @@ -241,10 +261,11 @@ gen(Node *n) continpc = pc; // define break and continue labels - if((lab = labellist) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n) { + if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n) { lab->breakpc = breakpc; lab->continpc = continpc; - } + } else + lab = L; gen(n->nincr); // contin: incr patch(p1, pc); // test: @@ -254,6 +275,10 @@ gen(Node *n) patch(breakpc, pc); // done: continpc = scontin; breakpc = sbreak; + if(lab) { + lab->breakpc = P; + lab->continpc = P; + } break; case OIF: @@ -274,13 +299,17 @@ gen(Node *n) breakpc = gjmp(P); // break: goto done // define break label - if((lab = labellist) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n) + if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n) lab->breakpc = breakpc; + else + lab = L; patch(p1, pc); // test: genlist(n->nbody); // switch(test) body patch(breakpc, pc); // done: breakpc = sbreak; + if(lab != L) + lab->breakpc = P; break; case OSELECT: @@ -289,13 +318,17 @@ gen(Node *n) breakpc = gjmp(P); // break: goto done // define break label - if((lab = labellist) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n) + if((lab = lastlabel) != L && lab->label == p3 && lab->op == OLABEL && lab->stmt == n) lab->breakpc = breakpc; + else + lab = L; patch(p1, pc); // test: genlist(n->nbody); // select() body patch(breakpc, pc); // done: breakpc = sbreak; + if(lab != L) + lab->breakpc = P; break; case OASOP: diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index bf84c12a1..bb258a193 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -138,6 +138,7 @@ typedef struct Sym Sym; typedef struct Node Node; typedef struct NodeList NodeList; typedef struct Type Type; +typedef struct Label Label; struct Type { @@ -302,11 +303,14 @@ struct Sym Pkg* pkg; char* name; // variable name Node* def; // definition: ONAME OTYPE OPACK or OLITERAL + Label* label; // corresponding label (ephemeral) int32 block; // blocknumber to catch redeclaration int32 lastlineno; // last declaration for diagnostic }; #define S ((Sym*)0) +EXTERN Sym* dclstack; + struct Pkg { char* name; @@ -356,12 +360,11 @@ enum OARRAY, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, - OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECVCLOSED, OAS2MAPR, OAS2DOTTYPE, OASOP, + OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP, OBAD, OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OCAP, OCLOSE, - OCLOSED, OCLOSURE, OCMPIFACE, OCMPSTR, OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, @@ -389,6 +392,7 @@ enum ORECV, ORUNESTR, OSELRECV, + OSELRECV2, OIOTA, OREAL, OIMAG, OCOMPLEX, @@ -441,27 +445,28 @@ enum TCOMPLEX64, // 12 TCOMPLEX128, - TFLOAT32, // 15 + TFLOAT32, // 14 TFLOAT64, - TBOOL, // 18 + TBOOL, // 16 - TPTR32, TPTR64, // 19 + TPTR32, TPTR64, // 17 - TFUNC, // 21 + TFUNC, // 19 TARRAY, T_old_DARRAY, - TSTRUCT, // 24 + TSTRUCT, // 22 TCHAN, TMAP, - TINTER, // 27 + TINTER, // 25 TFORW, TFIELD, TANY, TSTRING, + TUNSAFEPTR, // pseudo-types for literals - TIDEAL, // 32 + TIDEAL, // 31 TNIL, TBLANK, @@ -618,20 +623,22 @@ struct Magic typedef struct Prog Prog; -typedef struct Label Label; struct Label { uchar op; // OGOTO/OLABEL + uchar used; Sym* sym; Node* stmt; Prog* label; // pointer to code Prog* breakpc; // pointer to code Prog* continpc; // pointer to code Label* link; + int32 lineno; }; #define L ((Label*)0) EXTERN Label* labellist; +EXTERN Label* lastlabel; /* * note this is the runtime representation @@ -899,6 +906,7 @@ void allocparams(void); void cgen_as(Node *nl, Node *nr); void cgen_callmeth(Node *n, int proc); void checklabels(void); +void clearlabels(void); int dotoffset(Node *n, int *oary, Node **nn); void gen(Node *n); void genlist(NodeList *l); @@ -993,8 +1001,10 @@ int duint32(Sym *s, int off, uint32 v); int duint64(Sym *s, int off, uint64 v); int duint8(Sym *s, int off, uint8 v); int duintptr(Sym *s, int off, uint64 v); +int dsname(Sym *s, int off, char *dat, int ndat); void dumpobj(void); void ieeedtod(uint64 *ieee, double native); +Sym* stringsym(char*, int); /* * print.c @@ -1229,3 +1239,5 @@ void patch(Prog*, Prog*); void zfile(Biobuf *b, char *p, int n); void zhist(Biobuf *b, int line, vlong offset); void zname(Biobuf *b, Sym *s, int t); +void data(void); +void text(void); diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 4b838a491..89899ae1e 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -461,23 +461,32 @@ case: } break; } -| LCASE expr '=' expr ':' +| LCASE expr_or_type_list '=' expr ':' { + Node *n; + // will be converted to OCASE // right will point to next case // done in casebody() poptodcl(); $$ = nod(OXCASE, N, N); - $$->list = list1(nod(OAS, $2, $4)); + if($2->next == nil) + n = nod(OAS, $2->n, $4); + else { + n = nod(OAS2, N, N); + n->list = $2; + n->rlist = list1($4); + } + $$->list = list1(n); } -| LCASE name LCOLAS expr ':' +| LCASE expr_or_type_list LCOLAS expr ':' { // will be converted to OCASE // right will point to next case // done in casebody() poptodcl(); $$ = nod(OXCASE, N, N); - $$->list = list1(colas(list1($2), list1($4))); + $$->list = list1(colas($2, list1($4))); } | LDEFAULT ':' { @@ -1230,9 +1239,10 @@ fnlitdcl: } fnliteral: - fnlitdcl '{' stmt_list '}' + fnlitdcl lbrace stmt_list '}' { $$ = closurebody($3); + fixlbrace($2); } diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index e79d3b0f8..bfd96274e 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -124,9 +124,6 @@ main(int argc, char *argv[]) runtimepkg = mkpkg(strlit("runtime")); runtimepkg->name = "runtime"; - stringpkg = mkpkg(strlit("string")); - stringpkg->name = "string"; - typepkg = mkpkg(strlit("type")); typepkg->name = "type"; @@ -1555,7 +1552,6 @@ static struct "append", LNAME, Txxx, OAPPEND, "cap", LNAME, Txxx, OCAP, "close", LNAME, Txxx, OCLOSE, - "closed", LNAME, Txxx, OCLOSED, "complex", LNAME, Txxx, OCOMPLEX, "copy", LNAME, Txxx, OCOPY, "imag", LNAME, Txxx, OIMAG, diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index fbabe0d43..9f4b7b318 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -235,3 +235,57 @@ duintptr(Sym *s, int off, uint64 v) { return duintxx(s, off, v, widthptr); } + +Sym* +stringsym(char *s, int len) +{ + static int gen; + Sym *sym; + int off, n, m; + struct { + Strlit lit; + char buf[110]; + } tmp; + Pkg *pkg; + + if(len > 100) { + // huge strings are made static to avoid long names + snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen); + pkg = localpkg; + } else { + // small strings get named by their contents, + // so that multiple modules using the same string + // can share it. + tmp.lit.len = len; + memmove(tmp.lit.s, s, len); + tmp.lit.s[len] = '\0'; + snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp); + pkg = gostringpkg; + } + sym = pkglookup(namebuf, pkg); + + // SymUniq flag indicates that data is generated already + if(sym->flags & SymUniq) + return sym; + sym->flags |= SymUniq; + + data(); + off = 0; + + // string header + off = dsymptr(sym, off, sym, widthptr+4); + off = duint32(sym, off, len); + + // string data + for(n=0; n<len; n+=m) { + m = 8; + if(m > len-n) + m = len-n; + off = dsname(sym, off, s+n, m); + } + off = duint8(sym, off, 0); // terminating NUL for runtime + ggloblsym(sym, off, 1); + text(); + + return sym; +} diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c index 695a5a397..fee37f6d0 100644 --- a/src/cmd/gc/print.c +++ b/src/cmd/gc/print.c @@ -52,7 +52,6 @@ exprfmt(Fmt *f, Node *n, int prec) case OARRAYBYTESTR: case OCAP: case OCLOSE: - case OCLOSED: case OCOPY: case OLEN: case OMAKE: @@ -405,7 +404,6 @@ exprfmt(Fmt *f, Node *n, int prec) case OAPPEND: case OCAP: case OCLOSE: - case OCLOSED: case OLEN: case OCOPY: case OMAKE: diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c index 4ee8f39a7..dfb2b8efd 100644 --- a/src/cmd/gc/range.c +++ b/src/cmd/gc/range.c @@ -203,8 +203,8 @@ walkrange(Node *n) hb = nod(OXXX, N, N); tempname(hb, types[TBOOL]); - n->ntest = nod(ONOT, hb, N); - a = nod(OAS2RECVCLOSED, N, N); + n->ntest = nod(ONE, hb, nodbool(0)); + a = nod(OAS2RECV, N, N); a->typecheck = 1; a->list = list(list1(hv1), hb); a->rlist = list1(nod(ORECV, ha, N)); diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 8129bf1ce..b98e820c6 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -348,17 +348,19 @@ dimportpath(Pkg *p) * uncommonType * ../../pkg/runtime/type.go:/uncommonType */ -static Sym* -dextratype(Type *t) +static int +dextratype(Sym *sym, int off, Type *t, int ptroff) { int ot, n; - char *p; Sym *s; Sig *a, *m; m = methods(t); if(t->sym == nil && m == nil) - return nil; + return off; + + // fill in *extraType pointer in header + dsymptr(sym, ptroff, sym, off); n = 0; for(a=m; a; a=a->link) { @@ -366,9 +368,8 @@ dextratype(Type *t) n++; } - p = smprint("_.%#T", t); - s = pkglookup(p, typepkg); - ot = 0; + ot = off; + s = sym; if(t->sym) { ot = dgostringptr(s, ot, t->sym->name); if(t != types[t->etype]) @@ -402,9 +403,8 @@ dextratype(Type *t) else ot = duintptr(s, ot, 0); } - ggloblsym(s, ot, 0); - return s; + return ot; } enum { @@ -466,6 +466,7 @@ kinds[] = [TFUNC] = KindFunc, [TCOMPLEX64] = KindComplex64, [TCOMPLEX128] = KindComplex128, + [TUNSAFEPTR] = KindUnsafePointer, }; static char* @@ -488,6 +489,7 @@ structnames[] = [TFLOAT64] = "*runtime.FloatType", [TBOOL] = "*runtime.BoolType", [TSTRING] = "*runtime.StringType", + [TUNSAFEPTR] = "*runtime.UnsafePointerType", [TPTR32] = "*runtime.PtrType", [TPTR64] = "*runtime.PtrType", @@ -514,9 +516,6 @@ typestruct(Type *t) if(isslice(t)) name = "*runtime.SliceType"; - if(isptr[et] && t->type->etype == TANY) - name = "*runtime.UnsafePointerType"; - return pkglookup(name, typepkg); } @@ -553,6 +552,7 @@ haspointers(Type *t) case TSTRING: case TPTR32: case TPTR64: + case TUNSAFEPTR: case TINTER: case TCHAN: case TMAP: @@ -570,7 +570,6 @@ static int dcommontype(Sym *s, int ot, Type *t) { int i; - Sym *s1; Sym *sptr; char *p; @@ -582,8 +581,6 @@ dcommontype(Sym *s, int ot, Type *t) else sptr = weaktypesym(ptrto(t)); - s1 = dextratype(t); - // empty interface pointing at this type. // all the references that we emit are *interface{}; // they point here. @@ -612,8 +609,6 @@ dcommontype(Sym *s, int ot, Type *t) i = kinds[t->etype]; if(t->etype == TARRAY && t->bound < 0) i = KindSlice; - if(isptr[t->etype] && t->type->etype == TANY) - i = KindUnsafePointer; if(!haspointers(t)) i |= KindNoPointers; ot = duint8(s, ot, i); // kind @@ -622,11 +617,14 @@ dcommontype(Sym *s, int ot, Type *t) longsymnames = 0; ot = dgostringptr(s, ot, p); // string free(p); - if(s1) - ot = dsymptr(s, ot, s1, 0); // extraType - else - ot = duintptr(s, ot, 0); - ot = dsymptr(s, ot, sptr, 0); // ptr to type + + // skip pointer to extraType, + // which follows the rest of this type structure. + // caller will fill in if needed. + // otherwise linker will assume 0. + ot += widthptr; + + ot = dsymptr(s, ot, sptr, 0); // ptrto type return ot; } @@ -693,7 +691,7 @@ weaktypesym(Type *t) static Sym* dtypesym(Type *t) { - int ot, n, isddd, dupok; + int ot, xt, n, isddd, dupok; Sym *s, *s1, *s2; Sig *a, *m; Type *t1, *tbase; @@ -714,12 +712,8 @@ dtypesym(Type *t) tbase = t->type; dupok = tbase->sym == S; - if(compiling_runtime) { - if(tbase == types[tbase->etype]) // int, float, etc - goto ok; - if(tbase->etype == tptr && tbase->type->etype == TANY) // unsafe.Pointer - goto ok; - } + if(compiling_runtime && tbase == types[tbase->etype]) // int, float, etc + goto ok; // named types from other files are defined only by those files if(tbase->sym && !tbase->local) @@ -729,15 +723,18 @@ dtypesym(Type *t) ok: ot = 0; + xt = 0; switch(t->etype) { default: ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; break; case TARRAY: // ../../pkg/runtime/type.go:/ArrayType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; ot = dsymptr(s, ot, s1, 0); if(t->bound < 0) ot = duintptr(s, ot, -1); @@ -749,6 +746,7 @@ ok: // ../../pkg/runtime/type.go:/ChanType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; ot = dsymptr(s, ot, s1, 0); ot = duintptr(s, ot, t->chan); break; @@ -765,6 +763,7 @@ ok: dtypesym(t1->type); ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; ot = duint8(s, ot, isddd); // two slice headers: in and out. @@ -796,6 +795,7 @@ ok: // ../../pkg/runtime/type.go:/InterfaceType ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; ot = dsymptr(s, ot, s, ot+widthptr+2*4); ot = duint32(s, ot, n); ot = duint32(s, ot, n); @@ -812,6 +812,7 @@ ok: s1 = dtypesym(t->down); s2 = dtypesym(t->type); ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; ot = dsymptr(s, ot, s1, 0); ot = dsymptr(s, ot, s2, 0); break; @@ -826,6 +827,7 @@ ok: // ../../pkg/runtime/type.go:/PtrType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; ot = dsymptr(s, ot, s1, 0); break; @@ -838,6 +840,7 @@ ok: n++; } ot = dcommontype(s, ot, t); + xt = ot - 2*widthptr; ot = dsymptr(s, ot, s, ot+widthptr+2*4); ot = duint32(s, ot, n); ot = duint32(s, ot, n); @@ -859,7 +862,7 @@ ok: } break; } - + ot = dextratype(s, ot, t, xt); ggloblsym(s, ot, dupok); return s; } @@ -908,7 +911,7 @@ dumptypestructs(void) for(i=1; i<=TBOOL; i++) dtypesym(ptrto(types[i])); dtypesym(ptrto(types[TSTRING])); - dtypesym(ptrto(pkglookup("Pointer", unsafepkg)->def->type)); + dtypesym(ptrto(types[TUNSAFEPTR])); // add paths for runtime and main, which 6l imports implicitly. dimportpath(runtimepkg); diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index bf7d045c0..35d11eca9 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -92,17 +92,19 @@ func mapiter2(hiter *any) (key any, val any) // *byte is really *runtime.Type func makechan(elem *byte, hint int64) (hchan chan any) func chanrecv1(hchan <-chan any) (elem any) -func chanrecv3(hchan <-chan any) (elem any, closed bool) +func chanrecv2(hchan <-chan any) (elem any, received bool) func chansend1(hchan chan<- any, elem any) func closechan(hchan any) func closedchan(hchan any) bool func selectnbsend(hchan chan<- any, elem any) bool func selectnbrecv(elem *any, hchan <-chan any) bool +func selectnbrecv2(elem *any, received *bool, hchan <-chan any) bool func newselect(size int) (sel *byte) func selectsend(sel *byte, hchan chan<- any, elem any) (selected bool) func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool) +func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool) func selectdefault(sel *byte) (selected bool) func selectgo(sel *byte) func block() diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c index 58a147745..91d4ebfd5 100644 --- a/src/cmd/gc/select.c +++ b/src/cmd/gc/select.c @@ -58,6 +58,18 @@ typecheckselect(Node *sel) n->op = OSELRECV; break; + case OAS2RECV: + // convert x, ok = <-c into OSELRECV(x, <-c) with ntest=ok + if(n->right->op != ORECV) { + yyerror("select assignment must have receive on right hand side"); + break; + } + n->op = OSELRECV2; + n->left = n->list->n; + n->ntest = n->list->next->n; + n->right = n->rlist->n; + break; + case ORECV: // convert <-c into OSELRECV(N, <-c) n = nod(OSELRECV, N, n); @@ -122,6 +134,18 @@ walkselect(Node *sel) typecheck(&n, Etop); } break; + + case OSELRECV2: + r = n->right; + ch = cheapexpr(r->left, &l); + r->left = ch; + + a = nod(OAS2, N, N); + a->list = n->list; + a->rlist = n->rlist; + n = a; + typecheck(&n, Etop); + break; } // if ch == nil { block() }; n; @@ -146,6 +170,7 @@ walkselect(Node *sel) continue; switch(n->op) { case OSELRECV: + case OSELRECV2: ch = n->right->left; // If we can use the address of the target without @@ -154,6 +179,28 @@ walkselect(Node *sel) // Also introduce a temporary for := variables that escape, // so that we can delay the heap allocation until the case // is selected. + if(n->op == OSELRECV2) { + if(n->ntest == N || isblank(n->ntest)) + n->ntest = nodnil(); + else if(n->ntest->op == ONAME && + (!n->colas || (n->ntest->class&PHEAP) == 0) && + convertop(types[TBOOL], n->ntest->type, nil) == OCONVNOP) { + n->ntest = nod(OADDR, n->ntest, N); + n->ntest->etype = 1; // pointer does not escape + typecheck(&n->ntest, Erv); + } else { + tmp = nod(OXXX, N, N); + tempname(tmp, types[TBOOL]); + a = nod(OADDR, tmp, N); + a->etype = 1; // pointer does not escape + typecheck(&a, Erv); + r = nod(OAS, n->ntest, tmp); + typecheck(&r, Etop); + cas->nbody = concat(list1(r), cas->nbody); + n->ntest = a; + } + } + if(n->left == N || isblank(n->left)) n->left = nodnil(); else if(n->left->op == ONAME && @@ -171,10 +218,12 @@ walkselect(Node *sel) r = nod(OAS, n->left, tmp); typecheck(&r, Etop); cas->nbody = concat(list1(r), cas->nbody); - cas->nbody = concat(n->ninit, cas->nbody); - n->ninit = nil; n->left = a; } + + cas->nbody = concat(n->ninit, cas->nbody); + n->ninit = nil; + break; } } @@ -212,6 +261,16 @@ walkselect(Node *sel) mkcall1(chanfn("selectnbrecv", 2, ch->type), types[TBOOL], &r->ninit, n->left, ch)); break; + + case OSELRECV2: + // if c != nil && selectnbrecv2(&v, c) { body } else { default body } + r = nod(OIF, N, N); + r->ninit = cas->ninit; + ch = cheapexpr(n->right->left, &r->ninit); + r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()), + mkcall1(chanfn("selectnbrecv2", 2, ch->type), + types[TBOOL], &r->ninit, n->left, n->ntest, ch)); + break; } typecheck(&r->ntest, Erv); r->nbody = cas->nbody; @@ -254,11 +313,18 @@ walkselect(Node *sel) r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], &init, var, n->left, n->right); break; + case OSELRECV: // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL], &init, var, n->right->left, n->left); break; + + case OSELRECV2: + // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool); + r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL], + &init, var, n->right->left, n->left, n->ntest); + break; } } r->nbody = concat(r->nbody, cas->nbody); diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index 31781646d..be96a1477 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -94,7 +94,7 @@ init1(Node *n, NodeList **out) case OAS2FUNC: case OAS2MAPR: case OAS2DOTTYPE: - case OAS2RECVCLOSED: + case OAS2RECV: if(n->defn->initorder) break; n->defn->initorder = 1; diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 142e5ba41..2098794a7 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -135,6 +135,7 @@ yyerror(char *fmt, ...) int i; static int lastsyntax; va_list arg; + char buf[512], *p; if(strncmp(fmt, "syntax error", 12) == 0) { nsyntaxerrors++; @@ -147,6 +148,16 @@ yyerror(char *fmt, ...) return; lastsyntax = lexlineno; + if(strstr(fmt, "{ or {")) { + // The grammar has { and LBRACE but both show up as {. + // Rewrite syntax error referring to "{ or {" to say just "{". + strecpy(buf, buf+sizeof buf, fmt); + p = strstr(buf, "{ or {"); + if(p) + memmove(p+1, p+6, strlen(p+6)+1); + fmt = buf; + } + // look for parse state-specific errors in list (see go.errors). for(i=0; i<nelem(yymsg); i++) { if(yymsg[i].yystate == yystate && yymsg[i].yychar == yychar) { @@ -834,7 +845,6 @@ goopnames[] = [OCALL] = "function call", [OCAP] = "cap", [OCASE] = "case", - [OCLOSED] = "closed", [OCLOSE] = "close", [OCOMPLEX] = "complex", [OCOM] = "^", @@ -1144,7 +1154,7 @@ Tpretty(Fmt *fp, Type *t) && t->sym != S && !(fp->flags&FmtLong)) { s = t->sym; - if(t == types[t->etype]) + if(t == types[t->etype] && t->etype != TUNSAFEPTR) return fmtprint(fp, "%s", s->name); if(exporting) { if(fp->flags & FmtShort) @@ -1304,6 +1314,11 @@ Tpretty(Fmt *fp, Type *t) if(t->sym) return fmtprint(fp, "undefined %S", t->sym); return fmtprint(fp, "undefined"); + + case TUNSAFEPTR: + if(exporting) + return fmtprint(fp, "\"unsafe\".Pointer"); + return fmtprint(fp, "unsafe.Pointer"); } // Don't know how to handle - fall back to detailed prints. @@ -1346,6 +1361,9 @@ Tconv(Fmt *fp) } } + if(sharp || exporting) + fatal("missing %E case during export", t->etype); + et = t->etype; fmtprint(fp, "%E ", et); if(t->sym != S) @@ -1663,6 +1681,9 @@ isselect(Node *n) s = pkglookup("selectrecv", runtimepkg); if(s == n->sym) return 1; + s = pkglookup("selectrecv2", runtimepkg); + if(s == n->sym) + return 1; s = pkglookup("selectdefault", runtimepkg); if(s == n->sym) return 1; @@ -1864,7 +1885,7 @@ assignop(Type *src, Type *dst, char **why) if(why != nil) *why = ""; - if(safemode && (isptrto(src, TANY) || isptrto(dst, TANY))) { + if(safemode && src != T && src->etype == TUNSAFEPTR) { yyerror("cannot use unsafe.Pointer"); errorexit(); } @@ -1879,8 +1900,9 @@ assignop(Type *src, Type *dst, char **why) return OCONVNOP; // 2. src and dst have identical underlying types - // and either src or dst is not a named type. - if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S)) + // and either src or dst is not a named type or + // both are interface types. + if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || src->etype == TINTER)) return OCONVNOP; // 3. dst is an interface type and src implements dst. @@ -2028,11 +2050,11 @@ convertop(Type *src, Type *dst, char **why) } // 8. src is a pointer or uintptr and dst is unsafe.Pointer. - if((isptr[src->etype] || src->etype == TUINTPTR) && isptrto(dst, TANY)) + if((isptr[src->etype] || src->etype == TUINTPTR) && dst->etype == TUNSAFEPTR) return OCONVNOP; // 9. src is unsafe.Pointer and dst is a pointer or uintptr. - if(isptrto(src, TANY) && (isptr[dst->etype] || dst->etype == TUINTPTR)) + if(src->etype == TUNSAFEPTR && (isptr[dst->etype] || dst->etype == TUINTPTR)) return OCONVNOP; return 0; @@ -2043,13 +2065,16 @@ Node* assignconv(Node *n, Type *t, char *context) { int op; - Node *r; + Node *r, *old; char *why; if(n == N || n->type == T) return n; + old = n; + old->diag++; // silence errors about n; we'll issue one below defaultlit(&n, t); + old->diag--; if(t->etype == TBLANK) return n; diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 3e8f35877..1cc5abd5c 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -318,7 +318,7 @@ reswitch: n->left = N; goto ret; } - if(!isptr[t->etype] || (t->type != T && t->type->etype == TANY) /* unsafe.Pointer */) { + if(!isptr[t->etype]) { yyerror("invalid indirect of %+N", n->left); goto error; } @@ -921,7 +921,6 @@ reswitch: n->type = t; goto ret; - case OCLOSED: case OCLOSE: if(onearg(n, "%#O", n->op) < 0) goto error; @@ -934,11 +933,7 @@ reswitch: yyerror("invalid operation: %#N (non-chan type %T)", n, t); goto error; } - if(n->op == OCLOSED) { - n->type = types[TBOOL]; - ok |= Erv; - } else - ok |= Etop; + ok |= Etop; goto ret; case OAPPEND: @@ -1316,7 +1311,7 @@ ret: // TODO(rsc): should not need to check importpkg, // but reflect mentions unsafe.Pointer. - if(safemode && !incannedimport && !importpkg && isptrto(t, TANY)) + if(safemode && !incannedimport && !importpkg && t && t->etype == TUNSAFEPTR) yyerror("cannot use unsafe.Pointer"); evconst(n); @@ -1639,11 +1634,6 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char * for(tl=tstruct->type; tl; tl=tl->down) { t = tl->type; if(tl->isddd) { - if(nl != nil && nl->n->op == ONAME && nl->n->isddd && !isddd) { - // TODO(rsc): This is not actually illegal, but it will help catch bugs. - yyerror("to pass '%#N' as ...%T, use '%#N...'", nl->n, t->type, nl->n); - isddd = 1; - } if(isddd) { if(nl == nil) goto notenough; @@ -2377,8 +2367,9 @@ typecheckas2(Node *n) n->op = OAS2MAPR; goto common; case ORECV: - yyerror("cannot use multiple-value assignment for non-blocking receive; use select"); - goto out; + n->op = OAS2RECV; + n->right = n->rlist->n; + goto common; case ODOTTYPE: n->op = OAS2DOTTYPE; r->op = ODOTTYPE2; diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go index bd7b7771a..b2a341d39 100644 --- a/src/cmd/gc/unsafe.go +++ b/src/cmd/gc/unsafe.go @@ -8,7 +8,7 @@ package PACKAGE -type Pointer *any +type Pointer uintptr // not really; filled in by compiler func Offsetof(any) int func Sizeof(any) int diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index b32b6fff5..b8c6842e0 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -403,12 +403,11 @@ walkstmt(Node **np) case OAS: case OAS2: case OAS2DOTTYPE: - case OAS2RECVCLOSED: + case OAS2RECV: case OAS2FUNC: case OAS2MAPW: case OAS2MAPR: case OCLOSE: - case OCLOSED: case OCOPY: case OCALLMETH: case OCALLINTER: @@ -822,14 +821,13 @@ walkexpr(Node **np, NodeList **init) n = liststmt(concat(concat(list1(r), ll), lpost)); goto ret; - case OAS2RECVCLOSED: - // a = <-c; b = closed(c) but atomic + case OAS2RECV: *init = concat(*init, n->ninit); n->ninit = nil; r = n->rlist->n; walkexprlistsafe(n->list, init); walkexpr(&r->left, init); - fn = chanfn("chanrecv3", 2, r->left->type); + fn = chanfn("chanrecv2", 2, r->left->type); r = mkcall1(fn, getoutargx(fn->type), init, r->left); n->rlist->n = r; n->op = OAS2FUNC; @@ -1309,13 +1307,6 @@ walkexpr(Node **np, NodeList **init) n = mkcall1(fn, T, init, n->left); goto ret; - case OCLOSED: - // cannot use chanfn - closechan takes any, not chan any - fn = syslook("closedchan", 1); - argtype(fn, n->left->type); - n = mkcall1(fn, n->type, init, n->left); - goto ret; - case OMAKECHAN: n = mkcall1(chanfn("makechan", 1, n->type), n->type, init, typename(n->type->type), |