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:
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
......
......@@ -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;
......
......@@ -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:
......
......@@ -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);
......
......@@ -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*
......
......@@ -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
{
......
......@@ -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.
......
......@@ -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");
......
......@@ -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;
......
......@@ -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:
......@@ -1215,22 +1198,6 @@ ret:
*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*
ascompatee1(int op, Node *l, Node *r, NodeList **init)
{
......
......@@ -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)
......
......@@ -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"
)
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