aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2011-12-02 14:13:12 -0500
committerRuss Cox <rsc@golang.org>2011-12-02 14:13:12 -0500
commit7dc9d8c72b5deb927028e9edfbc6015c5d0296be (patch)
tree3fdff8e3142745f7e26f98395cdb87c8ac62974f
parent5f49456465f53f96bee03ac8cbe0d564e31576c2 (diff)
downloadgo-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.go2
-rw-r--r--src/cmd/gc/esc.c10
-rw-r--r--src/cmd/gc/fmt.c7
-rw-r--r--src/cmd/gc/gen.c4
-rw-r--r--src/cmd/gc/go.h4
-rw-r--r--src/cmd/gc/go.y9
-rw-r--r--src/cmd/gc/lex.c2
-rw-r--r--src/cmd/gc/sinit.c30
-rw-r--r--src/cmd/gc/typecheck.c127
-rw-r--r--src/cmd/gc/walk.c43
-rw-r--r--test/complit.go16
-rw-r--r--test/complit1.go27
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"
+)