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
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
case ONAME:
case OPARAM:
case ODDDARG:
+ case OPTRLIT:
case OARRAYLIT:
case OMAPLIT:
case OSTRUCTLIT:
}
break;
+ case OPTRLIT:
case OADDR:
if(leaks) {
src->esc = EscHeap;
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]",
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:
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) {
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);
OCLOSE,
OCLOSURE,
OCMPIFACE, OCMPSTR,
- OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
+ OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, OPTRLIT,
OCONV, OCONVIFACE, OCONVNOP,
OCOPY,
ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
#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*
}
| '&' 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
{
errorexit();
// Phase 3b: escape analysis.
- if(!debug['s'])
+ if(!debug['N'])
escapes();
// Phase 4: Compile function bodies.
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:
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:
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");
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;
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;
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;
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;
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;
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) {
}
}
- 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;
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;
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;
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;
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;
}
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;
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**);
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;
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:
*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)
{
}
}
+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
}
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")
}
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)
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"
+)