Commit 7dc9d8c7 authored by Russ Cox's avatar Russ Cox

gc: composite literals as per Go 1

R=ken2
CC=golang-dev
https://golang.org/cl/5450067
parent 5f494564
...@@ -42,6 +42,8 @@ Flags: ...@@ -42,6 +42,8 @@ Flags:
show entire file path when printing line numbers in errors show entire file path when printing line numbers in errors
-I dir1 -I dir2 -I dir1 -I dir2
add dir1 and dir2 to the list of paths to check for imported packages add dir1 and dir2 to the list of paths to check for imported packages
-N
disable optimizations
-S -S
write assembly language text to standard output write assembly language text to standard output
-u -u
......
...@@ -291,6 +291,14 @@ esc(Node *n) ...@@ -291,6 +291,14 @@ esc(Node *n)
for(ll=n->list; ll; ll=ll->next) for(ll=n->list; ll; ll=ll->next)
escassign(n, ll->n->right); escassign(n, ll->n->right);
break; 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: case OMAPLIT:
n->esc = EscNone; // until proven otherwise n->esc = EscNone; // until proven otherwise
...@@ -387,6 +395,7 @@ escassign(Node *dst, Node *src) ...@@ -387,6 +395,7 @@ escassign(Node *dst, Node *src)
case ONAME: case ONAME:
case OPARAM: case OPARAM:
case ODDDARG: case ODDDARG:
case OPTRLIT:
case OARRAYLIT: case OARRAYLIT:
case OMAPLIT: case OMAPLIT:
case OSTRUCTLIT: case OSTRUCTLIT:
...@@ -647,6 +656,7 @@ escwalk(int level, Node *dst, Node *src) ...@@ -647,6 +656,7 @@ escwalk(int level, Node *dst, Node *src)
} }
break; break;
case OPTRLIT:
case OADDR: case OADDR:
if(leaks) { if(leaks) {
src->esc = EscHeap; src->esc = EscHeap;
......
...@@ -156,7 +156,7 @@ Lconv(Fmt *fp) ...@@ -156,7 +156,7 @@ Lconv(Fmt *fp)
break; break;
fmtprint(fp, " "); fmtprint(fp, " ");
} }
if(debug['L']) if(debug['L'] || (fp->flags&FmtLong))
fmtprint(fp, "%s/", pathname); fmtprint(fp, "%s/", pathname);
if(a[i].line) if(a[i].line)
fmtprint(fp, "%s:%d[%s:%d]", fmtprint(fp, "%s:%d[%s:%d]",
...@@ -1116,6 +1116,11 @@ exprfmt(Fmt *f, Node *n, int prec) ...@@ -1116,6 +1116,11 @@ exprfmt(Fmt *f, Node *n, int prec)
case OCOMPLIT: case OCOMPLIT:
return fmtstrcpy(f, "composite literal"); 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 OARRAYLIT:
case OMAPLIT: case OMAPLIT:
case OSTRUCTLIT: case OSTRUCTLIT:
......
...@@ -54,7 +54,7 @@ addrescapes(Node *n) ...@@ -54,7 +54,7 @@ addrescapes(Node *n)
if(n->class == PAUTO && n->esc == EscNever) if(n->class == PAUTO && n->esc == EscNever)
break; 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); fatal("without escape analysis, only PAUTO's should have esc: %N", n);
switch(n->class) { switch(n->class) {
...@@ -91,7 +91,7 @@ addrescapes(Node *n) ...@@ -91,7 +91,7 @@ addrescapes(Node *n)
snprint(buf, sizeof buf, "&%S", n->sym); snprint(buf, sizeof buf, "&%S", n->sym);
n->heapaddr->sym = lookup(buf); n->heapaddr->sym = lookup(buf);
n->heapaddr->orig->sym = n->heapaddr->sym; n->heapaddr->orig->sym = n->heapaddr->sym;
if(!debug['s']) if(!debug['N'])
n->esc = EscHeap; n->esc = EscHeap;
if(debug['m']) if(debug['m'])
print("%L: moved to heap: %N\n", n->lineno, n); print("%L: moved to heap: %N\n", n->lineno, n);
......
...@@ -438,7 +438,7 @@ enum ...@@ -438,7 +438,7 @@ enum
OCLOSE, OCLOSE,
OCLOSURE, OCLOSURE,
OCMPIFACE, OCMPSTR, OCMPIFACE, OCMPSTR,
OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, OPTRLIT,
OCONV, OCONVIFACE, OCONVNOP, OCONV, OCONVIFACE, OCONVNOP,
OCOPY, OCOPY,
ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE, ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
...@@ -1340,6 +1340,8 @@ void zname(Biobuf *b, Sym *s, int t); ...@@ -1340,6 +1340,8 @@ void zname(Biobuf *b, Sym *s, int t);
#pragma varargck type "F" Mpflt* #pragma varargck type "F" Mpflt*
#pragma varargck type "H" NodeList* #pragma varargck type "H" NodeList*
#pragma varargck type "J" Node* #pragma varargck type "J" Node*
#pragma varargck type "lL" int
#pragma varargck type "lL" uint
#pragma varargck type "L" int #pragma varargck type "L" int
#pragma varargck type "L" uint #pragma varargck type "L" uint
#pragma varargck type "N" Node* #pragma varargck type "N" Node*
......
...@@ -804,7 +804,14 @@ uexpr: ...@@ -804,7 +804,14 @@ uexpr:
} }
| '&' 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 | '+' uexpr
{ {
......
...@@ -335,7 +335,7 @@ main(int argc, char *argv[]) ...@@ -335,7 +335,7 @@ main(int argc, char *argv[])
errorexit(); errorexit();
// Phase 3b: escape analysis. // Phase 3b: escape analysis.
if(!debug['s']) if(!debug['N'])
escapes(); escapes();
// Phase 4: Compile function bodies. // Phase 4: Compile function bodies.
......
...@@ -262,6 +262,14 @@ staticcopy(Node *l, Node *r, NodeList **out) ...@@ -262,6 +262,14 @@ staticcopy(Node *l, Node *r, NodeList **out)
case ONAME: case ONAME:
gdata(l, r, l->type->width); gdata(l, r, l->type->width);
return 1; return 1;
}
break;
case OPTRLIT:
switch(r->left->op) {
default:
//dump("not static addr", r);
break;
case OARRAYLIT: case OARRAYLIT:
case OSTRUCTLIT: case OSTRUCTLIT:
case OMAPLIT: case OMAPLIT:
...@@ -347,7 +355,14 @@ staticassign(Node *l, Node *r, NodeList **out) ...@@ -347,7 +355,14 @@ staticassign(Node *l, Node *r, NodeList **out)
case ONAME: case ONAME:
gdata(l, r, l->type->width); gdata(l, r, l->type->width);
return 1; return 1;
}
case OPTRLIT:
switch(r->left->op) {
default:
//dump("not static ptrlit", r);
break;
case OARRAYLIT: case OARRAYLIT:
case OMAPLIT: case OMAPLIT:
case OSTRUCTLIT: case OSTRUCTLIT:
...@@ -918,6 +933,19 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init) ...@@ -918,6 +933,19 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
default: default:
fatal("anylit: not lit"); 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: case OSTRUCTLIT:
if(t->etype != TSTRUCT) if(t->etype != TSTRUCT)
fatal("anylit: not struct"); fatal("anylit: not struct");
......
...@@ -344,6 +344,7 @@ reswitch: ...@@ -344,6 +344,7 @@ reswitch:
ntop = Erv | Etype; ntop = Erv | Etype;
if(!(top & Eaddr)) // The *x in &*x is not an indirect. if(!(top & Eaddr)) // The *x in &*x is not an indirect.
ntop |= Eindir; ntop |= Eindir;
ntop |= top & Ecomplit;
l = typecheck(&n->left, ntop); l = typecheck(&n->left, ntop);
if((t = l->type) == T) if((t = l->type) == T)
goto error; goto error;
...@@ -537,15 +538,7 @@ reswitch: ...@@ -537,15 +538,7 @@ reswitch:
typecheck(&n->left, Erv | Eaddr); typecheck(&n->left, Erv | Eaddr);
if(n->left->type == T) if(n->left->type == T)
goto error; goto error;
switch(n->left->op) { checklvalue(n->left, "take the address of");
case OMAPLIT:
case OSTRUCTLIT:
case OARRAYLIT:
if(!n->implicit)
break;
default:
checklvalue(n->left, "take the address of");
}
for(l=n->left; l->op == ODOT; l=l->left) for(l=n->left; l->op == ODOT; l=l->left)
l->addrtaken = 1; l->addrtaken = 1;
l->addrtaken = 1; l->addrtaken = 1;
...@@ -555,7 +548,7 @@ reswitch: ...@@ -555,7 +548,7 @@ reswitch:
goto error; goto error;
// top&Eindir means this is &x in *&x. (or the arg to built-in print) // 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. // 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); addrescapes(n->left);
n->type = ptrto(t); n->type = ptrto(t);
goto ret; goto ret;
...@@ -1670,7 +1663,7 @@ lookdot(Node *n, Type *t, int dostrcmp) ...@@ -1670,7 +1663,7 @@ lookdot(Node *n, Type *t, int dostrcmp)
if(!eqtype(rcvr, tt)) { if(!eqtype(rcvr, tt)) {
if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) { if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
checklvalue(n->left, "call pointer method on"); checklvalue(n->left, "call pointer method on");
if(debug['s']) if(debug['N'])
addrescapes(n->left); addrescapes(n->left);
n->left = nod(OADDR, n->left, N); n->left = nod(OADDR, n->left, N);
n->left->implicit = 1; n->left->implicit = 1;
...@@ -1967,13 +1960,51 @@ inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash) ...@@ -1967,13 +1960,51 @@ inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash)
return h; 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 static void
typecheckcomplit(Node **np) typecheckcomplit(Node **np)
{ {
int bad, i, len, nerr; int bad, i, len, nerr;
Node *l, *n, **hash; Node *l, *n, *r, **hash;
NodeList *ll; NodeList *ll;
Type *t, *f, *pushtype; Type *t, *f;
Sym *s; Sym *s;
int32 lno; int32 lno;
ulong nhash; ulong nhash;
...@@ -1988,30 +2019,29 @@ typecheckcomplit(Node **np) ...@@ -1988,30 +2019,29 @@ typecheckcomplit(Node **np)
yyerror("missing type in composite literal"); yyerror("missing type in composite literal");
goto error; goto error;
} }
setlineno(n->right); setlineno(n->right);
l = typecheck(&n->right /* sic */, Etype|Ecomplit); l = typecheck(&n->right /* sic */, Etype|Ecomplit);
if((t = l->type) == T) if((t = l->type) == T)
goto error; goto error;
nerr = nerrors; nerr = nerrors;
n->type = t;
// can omit type on composite literal values if the outer
// composite literal is array, slice, or map, and the if(isptr[t->etype]) {
// element type is itself a struct, array, slice, or map. // For better or worse, we don't allow pointers as
pushtype = T; // the composite literal type, except when using
if(t->etype == TARRAY || t->etype == TMAP) { // the &T syntax, which sets implicit.
pushtype = t->type; if(!n->right->implicit) {
if(pushtype != T) { yyerror("invalid pointer type %T for composite literal (use &%T instead)", t, t->type);
switch(pushtype->etype) { goto error;
case TSTRUCT:
case TARRAY:
case TMAP:
break;
default:
pushtype = T;
break;
}
} }
// 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) { switch(t->etype) {
...@@ -2054,11 +2084,11 @@ typecheckcomplit(Node **np) ...@@ -2054,11 +2084,11 @@ typecheckcomplit(Node **np)
} }
} }
if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T) r = l->right;
l->right->right = typenod(pushtype); pushtype(r, t->type);
typecheck(&l->right, Erv); typecheck(&r, Erv);
defaultlit(&l->right, t->type); defaultlit(&r, t->type);
l->right = assignconv(l->right, t->type, "array element"); l->right = assignconv(r, t->type, "array element");
} }
if(t->bound == -100) if(t->bound == -100)
t->bound = len; t->bound = len;
...@@ -2084,11 +2114,11 @@ typecheckcomplit(Node **np) ...@@ -2084,11 +2114,11 @@ typecheckcomplit(Node **np)
l->left = assignconv(l->left, t->down, "map key"); l->left = assignconv(l->left, t->down, "map key");
keydup(l->left, hash, nhash); keydup(l->left, hash, nhash);
if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T) r = l->right;
l->right->right = typenod(pushtype); pushtype(r, t->type);
typecheck(&l->right, Erv); typecheck(&r, Erv);
defaultlit(&l->right, t->type); defaultlit(&r, t->type);
l->right = assignconv(l->right, t->type, "map value"); l->right = assignconv(r, t->type, "map value");
} }
n->op = OMAPLIT; n->op = OMAPLIT;
break; break;
...@@ -2109,6 +2139,7 @@ typecheckcomplit(Node **np) ...@@ -2109,6 +2139,7 @@ typecheckcomplit(Node **np)
s = f->sym; s = f->sym;
if(s != nil && !exportname(s->name) && s->pkg != localpkg) if(s != nil && !exportname(s->name) && s->pkg != localpkg)
yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t); 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 = assignconv(ll->n, f->type, "field value");
ll->n = nod(OKEY, newname(f->sym), ll->n); ll->n = nod(OKEY, newname(f->sym), ll->n);
ll->n->left->type = f; ll->n->left->type = f;
...@@ -2142,7 +2173,6 @@ typecheckcomplit(Node **np) ...@@ -2142,7 +2173,6 @@ typecheckcomplit(Node **np)
if(s->pkg != localpkg) if(s->pkg != localpkg)
s = lookup(s->name); s = lookup(s->name);
f = lookdot1(s, t, t->type, 0); f = lookdot1(s, t, t->type, 0);
typecheck(&l->right, Erv);
if(f == nil) { if(f == nil) {
yyerror("unknown %T field '%s' in struct literal", t, s->name); yyerror("unknown %T field '%s' in struct literal", t, s->name);
continue; continue;
...@@ -2152,7 +2182,10 @@ typecheckcomplit(Node **np) ...@@ -2152,7 +2182,10 @@ typecheckcomplit(Node **np)
l->left->type = f; l->left->type = f;
s = f->sym; s = f->sym;
fielddup(newname(s), hash, nhash); 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; n->op = OSTRUCTLIT;
...@@ -2160,7 +2193,13 @@ typecheckcomplit(Node **np) ...@@ -2160,7 +2193,13 @@ typecheckcomplit(Node **np)
} }
if(nerr != nerrors) if(nerr != nerrors)
goto error; 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; *np = n;
lineno = lno; lineno = lno;
......
...@@ -10,7 +10,6 @@ static Node* walkprint(Node*, NodeList**, int); ...@@ -10,7 +10,6 @@ static Node* walkprint(Node*, NodeList**, int);
static Node* conv(Node*, Type*); static Node* conv(Node*, Type*);
static Node* mapfn(char*, Type*); static Node* mapfn(char*, Type*);
static Node* mapfndel(char*, Type*); static Node* mapfndel(char*, Type*);
static Node* makenewvar(Type*, NodeList**, Node**);
static Node* ascompatee1(int, Node*, Node*, NodeList**); static Node* ascompatee1(int, Node*, Node*, NodeList**);
static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**); static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**); static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
...@@ -976,24 +975,7 @@ walkexpr(Node **np, NodeList **init) ...@@ -976,24 +975,7 @@ walkexpr(Node **np, NodeList **init)
nodintconst(t->type->width)); nodintconst(t->type->width));
goto ret; goto ret;
case OADDR:; 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;
}
walkexpr(&n->left, init); walkexpr(&n->left, init);
goto ret; goto ret;
...@@ -1191,9 +1173,10 @@ walkexpr(Node **np, NodeList **init) ...@@ -1191,9 +1173,10 @@ walkexpr(Node **np, NodeList **init)
case OARRAYLIT: case OARRAYLIT:
case OMAPLIT: case OMAPLIT:
case OSTRUCTLIT: case OSTRUCTLIT:
nvar = temp(n->type); case OPTRLIT:
anylit(0, n, nvar, init); var = temp(n->type);
n = nvar; anylit(0, n, var, init);
n = var;
goto ret; goto ret;
case OSEND: case OSEND:
...@@ -1215,22 +1198,6 @@ ret: ...@@ -1215,22 +1198,6 @@ ret:
*np = n; *np = n;
} }
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* static Node*
ascompatee1(int op, Node *l, Node *r, NodeList **init) ascompatee1(int op, Node *l, Node *r, NodeList **init)
{ {
......
...@@ -31,6 +31,18 @@ func eq(a []*R) { ...@@ -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 { type P struct {
a, b int a, b int
} }
...@@ -46,6 +58,9 @@ func main() { ...@@ -46,6 +58,9 @@ func main() {
var tp *T var tp *T
tp = &T{0, 7.2, "hi", &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} a1 := []int{1, 2, 3}
if len(a1) != 3 { if len(a1) != 3 {
panic("a1") panic("a1")
...@@ -93,6 +108,7 @@ func main() { ...@@ -93,6 +108,7 @@ func main() {
} }
eq([]*R{itor(0), itor(1), itor(2), itor(3), itor(4), itor(5)}) 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) p1 := NewP(1, 2)
p2 := NewP(1, 2) p2 := NewP(1, 2)
......
...@@ -7,18 +7,33 @@ ...@@ -7,18 +7,33 @@
package main package main
var m map[int][3]int var m map[int][3]int
func f() [3]int func f() [3]int
func fp() *[3]int func fp() *[3]int
var mp map[int]*[3]int var mp map[int]*[3]int
var ( var (
_ = [3]int{1,2,3}[:] // ERROR "slice of unaddressable value" _ = [3]int{1, 2, 3}[:] // ERROR "slice of unaddressable value"
_ = m[0][:] // ERROR "slice of unaddressable value" _ = m[0][:] // ERROR "slice of unaddressable value"
_ = f()[:] // ERROR "slice of unaddressable value" _ = f()[:] // ERROR "slice of unaddressable value"
// these are okay because they are slicing a pointer to an array // these are okay because they are slicing a pointer to an array
_ = (&[3]int{1,2,3})[:] _ = (&[3]int{1, 2, 3})[:]
_ = mp[0][:] _ = mp[0][:]
_ = fp()[:] _ = 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"
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment