diff options
author | Russ Cox <rsc@golang.org> | 2011-12-02 14:13:12 -0500 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2011-12-02 14:13:12 -0500 |
commit | 7dc9d8c72b5deb927028e9edfbc6015c5d0296be (patch) | |
tree | 3fdff8e3142745f7e26f98395cdb87c8ac62974f | |
parent | 5f49456465f53f96bee03ac8cbe0d564e31576c2 (diff) | |
download | go-7dc9d8c72b5deb927028e9edfbc6015c5d0296be.tar.gz go-7dc9d8c72b5deb927028e9edfbc6015c5d0296be.zip |
gc: composite literals as per Go 1
R=ken2
CC=golang-dev
https://golang.org/cl/5450067
-rw-r--r-- | src/cmd/gc/doc.go | 2 | ||||
-rw-r--r-- | src/cmd/gc/esc.c | 10 | ||||
-rw-r--r-- | src/cmd/gc/fmt.c | 7 | ||||
-rw-r--r-- | src/cmd/gc/gen.c | 4 | ||||
-rw-r--r-- | src/cmd/gc/go.h | 4 | ||||
-rw-r--r-- | src/cmd/gc/go.y | 9 | ||||
-rw-r--r-- | src/cmd/gc/lex.c | 2 | ||||
-rw-r--r-- | src/cmd/gc/sinit.c | 30 | ||||
-rw-r--r-- | src/cmd/gc/typecheck.c | 127 | ||||
-rw-r--r-- | src/cmd/gc/walk.c | 43 | ||||
-rw-r--r-- | test/complit.go | 16 | ||||
-rw-r--r-- | test/complit1.go | 27 |
12 files changed, 186 insertions, 95 deletions
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go index 5bb5e0e146..c704011ef7 100644 --- a/src/cmd/gc/doc.go +++ b/src/cmd/gc/doc.go @@ -42,6 +42,8 @@ Flags: show entire file path when printing line numbers in errors -I dir1 -I dir2 add dir1 and dir2 to the list of paths to check for imported packages + -N + disable optimizations -S write assembly language text to standard output -u diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c index 0213f0e4b4..3794efc7dd 100644 --- a/src/cmd/gc/esc.c +++ b/src/cmd/gc/esc.c @@ -291,6 +291,14 @@ esc(Node *n) for(ll=n->list; ll; ll=ll->next) escassign(n, ll->n->right); break; + + case OPTRLIT: + n->esc = EscNone; // until proven otherwise + noesc = list(noesc, n); + n->escloopdepth = loopdepth; + // Contents make it to memory, lose track. + escassign(&theSink, n->left); + break; case OMAPLIT: n->esc = EscNone; // until proven otherwise @@ -387,6 +395,7 @@ escassign(Node *dst, Node *src) case ONAME: case OPARAM: case ODDDARG: + case OPTRLIT: case OARRAYLIT: case OMAPLIT: case OSTRUCTLIT: @@ -647,6 +656,7 @@ escwalk(int level, Node *dst, Node *src) } break; + case OPTRLIT: case OADDR: if(leaks) { src->esc = EscHeap; diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c index ae73539362..453cbc6856 100644 --- a/src/cmd/gc/fmt.c +++ b/src/cmd/gc/fmt.c @@ -156,7 +156,7 @@ Lconv(Fmt *fp) break; fmtprint(fp, " "); } - if(debug['L']) + if(debug['L'] || (fp->flags&FmtLong)) fmtprint(fp, "%s/", pathname); if(a[i].line) fmtprint(fp, "%s:%d[%s:%d]", @@ -1116,6 +1116,11 @@ exprfmt(Fmt *f, Node *n, int prec) case OCOMPLIT: return fmtstrcpy(f, "composite literal"); + case OPTRLIT: + if(fmtmode == FErr) + return fmtprint(f, "&%T literal", n->type->type); + return fmtprint(f, "&%T{ %,H }", n->type->type, n->list); + case OARRAYLIT: case OMAPLIT: case OSTRUCTLIT: diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index e3a3b71919..ebdd0f02dc 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -54,7 +54,7 @@ addrescapes(Node *n) if(n->class == PAUTO && n->esc == EscNever) break; - if(debug['s'] && n->esc != EscUnknown) + if(debug['N'] && n->esc != EscUnknown) fatal("without escape analysis, only PAUTO's should have esc: %N", n); switch(n->class) { @@ -91,7 +91,7 @@ addrescapes(Node *n) snprint(buf, sizeof buf, "&%S", n->sym); n->heapaddr->sym = lookup(buf); n->heapaddr->orig->sym = n->heapaddr->sym; - if(!debug['s']) + if(!debug['N']) n->esc = EscHeap; if(debug['m']) print("%L: moved to heap: %N\n", n->lineno, n); diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 7b121e6005..5ac044c820 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -438,7 +438,7 @@ enum OCLOSE, OCLOSURE, OCMPIFACE, OCMPSTR, - OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, + OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, OPTRLIT, OCONV, OCONVIFACE, OCONVNOP, OCOPY, ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE, @@ -1340,6 +1340,8 @@ void zname(Biobuf *b, Sym *s, int t); #pragma varargck type "F" Mpflt* #pragma varargck type "H" NodeList* #pragma varargck type "J" Node* +#pragma varargck type "lL" int +#pragma varargck type "lL" uint #pragma varargck type "L" int #pragma varargck type "L" uint #pragma varargck type "N" Node* diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 0ec1905b55..81a02c01e4 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -804,7 +804,14 @@ uexpr: } | '&' uexpr { - $$ = nod(OADDR, $2, N); + if($2->op == OCOMPLIT) { + // Special case for &T{...}: turn into (*T){...}. + $$ = $2; + $$->right = nod(OIND, $$->right, N); + $$->right->implicit = 1; + } else { + $$ = nod(OADDR, $2, N); + } } | '+' uexpr { diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index b1eab441c3..bf5a26d006 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -335,7 +335,7 @@ main(int argc, char *argv[]) errorexit(); // Phase 3b: escape analysis. - if(!debug['s']) + if(!debug['N']) escapes(); // Phase 4: Compile function bodies. diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index 4550577a4f..8d199e0240 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -262,6 +262,14 @@ staticcopy(Node *l, Node *r, NodeList **out) case ONAME: gdata(l, r, l->type->width); return 1; + } + break; + + case OPTRLIT: + switch(r->left->op) { + default: + //dump("not static addr", r); + break; case OARRAYLIT: case OSTRUCTLIT: case OMAPLIT: @@ -347,7 +355,14 @@ staticassign(Node *l, Node *r, NodeList **out) case ONAME: gdata(l, r, l->type->width); return 1; - + } + + case OPTRLIT: + switch(r->left->op) { + default: + //dump("not static ptrlit", r); + break; + case OARRAYLIT: case OMAPLIT: case OSTRUCTLIT: @@ -918,6 +933,19 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) default: fatal("anylit: not lit"); + case OPTRLIT: + if(!isptr[t->etype]) + fatal("anylit: not ptr"); + + a = nod(OAS, var, callnew(t->type)); + typecheck(&a, Etop); + *init = list(*init, a); + + var = nod(OIND, var, N); + typecheck(&var, Erv | Easgn); + anylit(ctxt, n->left, var, init); + break; + case OSTRUCTLIT: if(t->etype != TSTRUCT) fatal("anylit: not struct"); diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 25072a7fa2..8cd0dce334 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -344,6 +344,7 @@ reswitch: ntop = Erv | Etype; if(!(top & Eaddr)) // The *x in &*x is not an indirect. ntop |= Eindir; + ntop |= top & Ecomplit; l = typecheck(&n->left, ntop); if((t = l->type) == T) goto error; @@ -537,15 +538,7 @@ reswitch: typecheck(&n->left, Erv | Eaddr); if(n->left->type == T) goto error; - switch(n->left->op) { - case OMAPLIT: - case OSTRUCTLIT: - case OARRAYLIT: - if(!n->implicit) - break; - default: - checklvalue(n->left, "take the address of"); - } + checklvalue(n->left, "take the address of"); for(l=n->left; l->op == ODOT; l=l->left) l->addrtaken = 1; l->addrtaken = 1; @@ -555,7 +548,7 @@ reswitch: goto error; // top&Eindir means this is &x in *&x. (or the arg to built-in print) // n->etype means code generator flagged it as non-escaping. - if(debug['s'] && !(top & Eindir) && !n->etype) + if(debug['N'] && !(top & Eindir) && !n->etype) addrescapes(n->left); n->type = ptrto(t); goto ret; @@ -1670,7 +1663,7 @@ lookdot(Node *n, Type *t, int dostrcmp) if(!eqtype(rcvr, tt)) { if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) { checklvalue(n->left, "call pointer method on"); - if(debug['s']) + if(debug['N']) addrescapes(n->left); n->left = nod(OADDR, n->left, N); n->left->implicit = 1; @@ -1967,13 +1960,51 @@ inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash) return h; } +static int +iscomptype(Type *t) +{ + switch(t->etype) { + case TARRAY: + case TSTRUCT: + case TMAP: + return 1; + case TPTR32: + case TPTR64: + switch(t->type->etype) { + case TARRAY: + case TSTRUCT: + case TMAP: + return 1; + } + break; + } + return 0; +} + +static void +pushtype(Node *n, Type *t) +{ + if(n == N || n->op != OCOMPLIT || !iscomptype(t)) + return; + + if(n->right == N) { + n->right = typenod(t); + n->right->implicit = 1; + } + else if(debug['s']) { + typecheck(&n->right, Etype); + if(n->right->type != T && eqtype(n->right->type, t)) + print("%lL: redundant type: %T\n", n->right->lineno, t); + } +} + static void typecheckcomplit(Node **np) { int bad, i, len, nerr; - Node *l, *n, **hash; + Node *l, *n, *r, **hash; NodeList *ll; - Type *t, *f, *pushtype; + Type *t, *f; Sym *s; int32 lno; ulong nhash; @@ -1988,30 +2019,29 @@ typecheckcomplit(Node **np) yyerror("missing type in composite literal"); goto error; } - + setlineno(n->right); l = typecheck(&n->right /* sic */, Etype|Ecomplit); if((t = l->type) == T) goto error; nerr = nerrors; - - // can omit type on composite literal values if the outer - // composite literal is array, slice, or map, and the - // element type is itself a struct, array, slice, or map. - pushtype = T; - if(t->etype == TARRAY || t->etype == TMAP) { - pushtype = t->type; - if(pushtype != T) { - switch(pushtype->etype) { - case TSTRUCT: - case TARRAY: - case TMAP: - break; - default: - pushtype = T; - break; - } + n->type = t; + + if(isptr[t->etype]) { + // For better or worse, we don't allow pointers as + // the composite literal type, except when using + // the &T syntax, which sets implicit. + if(!n->right->implicit) { + yyerror("invalid pointer type %T for composite literal (use &%T instead)", t, t->type); + goto error; } + + // Also, the underlying type must be a struct, map, slice, or array. + if(!iscomptype(t)) { + yyerror("invalid pointer type %T for composite literal", t); + goto error; + } + t = t->type; } switch(t->etype) { @@ -2054,11 +2084,11 @@ typecheckcomplit(Node **np) } } - if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T) - l->right->right = typenod(pushtype); - typecheck(&l->right, Erv); - defaultlit(&l->right, t->type); - l->right = assignconv(l->right, t->type, "array element"); + r = l->right; + pushtype(r, t->type); + typecheck(&r, Erv); + defaultlit(&r, t->type); + l->right = assignconv(r, t->type, "array element"); } if(t->bound == -100) t->bound = len; @@ -2084,11 +2114,11 @@ typecheckcomplit(Node **np) l->left = assignconv(l->left, t->down, "map key"); keydup(l->left, hash, nhash); - if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T) - l->right->right = typenod(pushtype); - typecheck(&l->right, Erv); - defaultlit(&l->right, t->type); - l->right = assignconv(l->right, t->type, "map value"); + r = l->right; + pushtype(r, t->type); + typecheck(&r, Erv); + defaultlit(&r, t->type); + l->right = assignconv(r, t->type, "map value"); } n->op = OMAPLIT; break; @@ -2109,6 +2139,7 @@ typecheckcomplit(Node **np) s = f->sym; if(s != nil && !exportname(s->name) && s->pkg != localpkg) yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t); + // No pushtype allowed here. Must name fields for that. ll->n = assignconv(ll->n, f->type, "field value"); ll->n = nod(OKEY, newname(f->sym), ll->n); ll->n->left->type = f; @@ -2142,7 +2173,6 @@ typecheckcomplit(Node **np) if(s->pkg != localpkg) s = lookup(s->name); f = lookdot1(s, t, t->type, 0); - typecheck(&l->right, Erv); if(f == nil) { yyerror("unknown %T field '%s' in struct literal", t, s->name); continue; @@ -2152,7 +2182,10 @@ typecheckcomplit(Node **np) l->left->type = f; s = f->sym; fielddup(newname(s), hash, nhash); - l->right = assignconv(l->right, f->type, "field value"); + r = l->right; + pushtype(r, f->type); + typecheck(&r, Erv); + l->right = assignconv(r, f->type, "field value"); } } n->op = OSTRUCTLIT; @@ -2160,7 +2193,13 @@ typecheckcomplit(Node **np) } if(nerr != nerrors) goto error; - n->type = t; + + if(isptr[n->type->etype]) { + n = nod(OPTRLIT, n, N); + n->typecheck = 1; + n->type = n->left->type; + n->left->type = t; + } *np = n; lineno = lno; diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index e1ea935828..2d8ae64913 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -10,7 +10,6 @@ static Node* walkprint(Node*, NodeList**, int); static Node* conv(Node*, Type*); static Node* mapfn(char*, Type*); static Node* mapfndel(char*, Type*); -static Node* makenewvar(Type*, NodeList**, Node**); static Node* ascompatee1(int, Node*, Node*, NodeList**); static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**); static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**); @@ -976,24 +975,7 @@ walkexpr(Node **np, NodeList **init) nodintconst(t->type->width)); goto ret; - case OADDR:; - Node *nvar, *nstar; - - // turn &Point(1, 2) or &[]int(1, 2) or &[...]int(1, 2) into allocation. - // initialize with - // nvar := new(*Point); - // *nvar = Point(1, 2); - // and replace expression with nvar - switch(n->left->op) { - case OARRAYLIT: - case OMAPLIT: - case OSTRUCTLIT: - nvar = makenewvar(n->type, init, &nstar); - anylit(0, n->left, nstar, init); - n = nvar; - goto ret; - } - + case OADDR: walkexpr(&n->left, init); goto ret; @@ -1191,9 +1173,10 @@ walkexpr(Node **np, NodeList **init) case OARRAYLIT: case OMAPLIT: case OSTRUCTLIT: - nvar = temp(n->type); - anylit(0, n, nvar, init); - n = nvar; + case OPTRLIT: + var = temp(n->type); + anylit(0, n, var, init); + n = var; goto ret; case OSEND: @@ -1216,22 +1199,6 @@ ret: } static Node* -makenewvar(Type *t, NodeList **init, Node **nstar) -{ - Node *nvar, *nas; - - nvar = temp(t); - nas = nod(OAS, nvar, callnew(t->type)); - typecheck(&nas, Etop); - walkexpr(&nas, init); - *init = list(*init, nas); - - *nstar = nod(OIND, nvar, N); - typecheck(nstar, Erv); - return nvar; -} - -static Node* ascompatee1(int op, Node *l, Node *r, NodeList **init) { USED(op); diff --git a/test/complit.go b/test/complit.go index f5f7aca9d9..c9de616f55 100644 --- a/test/complit.go +++ b/test/complit.go @@ -31,6 +31,18 @@ func eq(a []*R) { } } +func teq(t *T, n int) { + for i := 0; i < n; i++ { + if t == nil || t.i != i { + panic("bad") + } + t = t.next + } + if t != nil { + panic("bad") + } +} + type P struct { a, b int } @@ -46,6 +58,9 @@ func main() { var tp *T tp = &T{0, 7.2, "hi", &t} + tl := &T{i: 0, next: {i: 1, next: {i: 2, next: {i: 3, next: {i: 4}}}}} + teq(tl, 5) + a1 := []int{1, 2, 3} if len(a1) != 3 { panic("a1") @@ -93,6 +108,7 @@ func main() { } eq([]*R{itor(0), itor(1), itor(2), itor(3), itor(4), itor(5)}) + eq([]*R{{0}, {1}, {2}, {3}, {4}, {5}}) p1 := NewP(1, 2) p2 := NewP(1, 2) diff --git a/test/complit1.go b/test/complit1.go index 23b3bbd192..f4f7311af3 100644 --- a/test/complit1.go +++ b/test/complit1.go @@ -7,18 +7,33 @@ package main var m map[int][3]int + func f() [3]int func fp() *[3]int + var mp map[int]*[3]int var ( - _ = [3]int{1,2,3}[:] // ERROR "slice of unaddressable value" - _ = m[0][:] // ERROR "slice of unaddressable value" - _ = f()[:] // ERROR "slice of unaddressable value" - + _ = [3]int{1, 2, 3}[:] // ERROR "slice of unaddressable value" + _ = m[0][:] // ERROR "slice of unaddressable value" + _ = f()[:] // ERROR "slice of unaddressable value" + // these are okay because they are slicing a pointer to an array - _ = (&[3]int{1,2,3})[:] + _ = (&[3]int{1, 2, 3})[:] _ = mp[0][:] _ = fp()[:] -)
\ No newline at end of file +) + +type T struct { + i int + f float64 + s string + next *T +} + +var ( + _ = &T{0, 0, "", nil} // ok + _ = &T{i: 0, f: 0, s: "", next: {}} // ok + _ = &T{0, 0, "", {}} // ERROR "missing type in composite literal" +) |