mirror of
https://github.com/golang/go
synced 2024-11-24 11:10:03 -07:00
gc: composite literals as per Go 1
R=ken2 CC=golang-dev https://golang.org/cl/5450067
This commit is contained in:
parent
5f49456465
commit
7dc9d8c72b
@ -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()[:]
|
||||
)
|
||||
)
|
||||
|
||||
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"
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user