update compiler to new func rules

R=ken
OCL=23958
CL=23961
diff --git a/src/cmd/6g/align.c b/src/cmd/6g/align.c
index 3aa7212..5d55e2c 100644
--- a/src/cmd/6g/align.c
+++ b/src/cmd/6g/align.c
@@ -75,6 +75,7 @@
 void
 dowidth(Type *t)
 {
+	int32 et;
 	uint32 w;
 
 	if(t == T)
@@ -88,8 +89,22 @@
 
 	t->width = -2;
 
+
+	et = t->etype;
+	switch(et) {
+	case TFUNC:
+	case TCHAN:
+	case TMAP:
+	case TSTRING:
+		break;
+
+	default:
+		et = simtype[t->etype];
+		break;
+	}
+
 	w = 0;
-	switch(simtype[t->etype]) {
+	switch(et) {
 	default:
 		fatal("dowidth: unknown type: %E", t->etype);
 		break;
@@ -162,16 +177,18 @@
 		w = widstruct(t, 0, 1);
 		if(w == 0)
 			w = maxround;
-		offmod(t);
 		break;
 
 	case TFUNC:
-		// function is 3 cated structures
+		// function is 3 cated structures;
+		// compute their widths as side-effect.
 		w = widstruct(*getthis(t), 0, 1);
 		w = widstruct(*getinarg(t), w, 0);
 		w = widstruct(*getoutarg(t), w, 1);
 		t->argwid = w;
-		w = 0;
+
+		// but width of func type is pointer
+		w = wptr;
 		break;
 	}
 	t->width = w;
@@ -222,6 +239,7 @@
 	simtype[TMAP] = tptr;
 	simtype[TCHAN] = tptr;
 	simtype[TSTRING] = tptr;
+	simtype[TFUNC] = tptr;
 
 	zprog.link = P;
 	zprog.as = AGOK;
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index 2774456..ba1427d 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -19,8 +19,8 @@
 	Addr addr;
 
 	if(debug['g']) {
-		dump("\ncgen-res", res);
-		dump("cgen-r", n);
+		dump("\ncgen-n", n);
+		dump("cgen-res", res);
 	}
 	if(n == N || n->type == T)
 		return;
@@ -82,6 +82,8 @@
 			} else
 				p1 = gins(a, n, N);
 			p1->to = addr;
+			if(debug['g'])
+				print("%P [ignore previous line]\n", p1);
 			sudoclean();
 			goto ret;
 		}
@@ -448,7 +450,7 @@
 					nodconst(&n2, types[TUINT64], v);
 					gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
 					p1 = gbranch(optoas(OGT, types[TUINT32]), T);
-					gins(ACALL, N, throwindex);
+					ginscall(throwindex, 0);
 					patch(p1, pc);
 				}
 
@@ -494,7 +496,7 @@
 				nodconst(&n1, types[TUINT64], nl->type->bound);
 			gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
 			p1 = gbranch(optoas(OLT, types[TUINT32]), T);
-			gins(ACALL, N, throwindex);
+			ginscall(throwindex, 0);
 			patch(p1, pc);
 		}
 
diff --git a/src/cmd/6g/gen.c b/src/cmd/6g/gen.c
index e6a6850..e2c06d1 100644
--- a/src/cmd/6g/gen.c
+++ b/src/cmd/6g/gen.c
@@ -8,6 +8,17 @@
 #include "gg.h"
 #include "opt.h"
 
+static Node*
+sysfunc(char *name)
+{
+	Node *n;
+
+	n = newname(pkglookup(name, "sys"));
+	n->class = PFUNC;
+	return n;
+}
+
+
 void
 compile(Node *fn)
 {
@@ -18,45 +29,16 @@
 	Type *t;
 	Iter save;
 
-if(newproc == N) {
-	newproc = nod(ONAME, N, N);
-	newproc->sym = pkglookup("newproc", "sys");
-	newproc->class = PEXTERN;
-	newproc->addable = 1;
-	newproc->ullman = 1;
-}
-
-if(deferproc == N) {
-	deferproc = nod(ONAME, N, N);
-	deferproc->sym = pkglookup("deferproc", "sys");
-	deferproc->class = PEXTERN;
-	deferproc->addable = 1;
-	deferproc->ullman = 1;
-}
-
-if(deferreturn == N) {
-	deferreturn = nod(ONAME, N, N);
-	deferreturn->sym = pkglookup("deferreturn", "sys");
-	deferreturn->class = PEXTERN;
-	deferreturn->addable = 1;
-	deferreturn->ullman = 1;
-}
-
-if(throwindex == N) {
-	throwindex = nod(ONAME, N, N);
-	throwindex->sym = pkglookup("throwindex", "sys");
-	throwindex->class = PEXTERN;
-	throwindex->addable = 1;
-	throwindex->ullman = 1;
-}
-
-if(throwreturn == N) {
-	throwreturn = nod(ONAME, N, N);
-	throwreturn->sym = pkglookup("throwreturn", "sys");
-	throwreturn->class = PEXTERN;
-	throwreturn->addable = 1;
-	throwreturn->ullman = 1;
-}
+	if(newproc == N)
+		newproc = sysfunc("newproc");
+	if(deferproc == N)
+		deferproc = sysfunc("deferproc");
+	if(deferreturn == N)
+		deferreturn = sysfunc("deferreturn");
+	if(throwindex == N)
+		throwindex = sysfunc("throwindex");
+	if(throwreturn == N)
+		throwreturn = sysfunc("throwreturn");
 
 	if(fn->nbody == N)
 		return;
@@ -95,6 +77,7 @@
 
 	nodconst(&nod1, types[TINT32], 0);
 	ptxt = gins(ATEXT, curfn->nname, &nod1);
+	afunclit(&ptxt->from);
 
 //	inarggen();
 
@@ -104,12 +87,11 @@
 	gclean();
 	checklabels();
 
-	if(curfn->type->outtuple != 0) {
-		gins(ACALL, N, throwreturn);
-	}
+	if(curfn->type->outtuple != 0)
+		ginscall(throwreturn, 0);
 
 	if(hasdefer)
-		gins(ACALL, N, deferreturn);
+		ginscall(deferreturn, 0);
 	pc->as = ARET;	// overwrite AEND
 	pc->lineno = lineno;
 
@@ -720,6 +702,7 @@
 void
 ginscall(Node *f, int proc)
 {
+	Prog *p;
 	Node reg, con;
 
 	switch(proc) {
@@ -728,23 +711,20 @@
 		break;
 
 	case 0:	// normal call
-		gins(ACALL, N, f);
+		p = gins(ACALL, N, f);
+		afunclit(&p->to);
 		break;
 
 	case 1:	// call in new proc (go)
 	case 2:	// defered call (defer)
 		nodreg(&reg, types[TINT64], D_AX);
-		if(f->op != OREGISTER) {
-			gins(ALEAQ, f, &reg);
-			gins(APUSHQ, &reg, N);
-		} else
-			gins(APUSHQ, f, N);
+		gins(APUSHQ, f, N);
 		nodconst(&con, types[TINT32], argsize(f->type));
 		gins(APUSHQ, &con, N);
 		if(proc == 1)
-			gins(ACALL, N, newproc);
+			ginscall(newproc, 0);
 		else
-			gins(ACALL, N, deferproc);
+			ginscall(deferproc, 0);
 		gins(APOPQ, N, &reg);
 		gins(APOPQ, N, &reg);
 		break;
@@ -827,7 +807,7 @@
 	n->left->type = l->type;
 
 	if(n->left->op == ONAME)
-		n->left->class = PEXTERN;
+		n->left->class = PFUNC;
 	cgen_call(n, proc);
 }
 
@@ -850,16 +830,11 @@
 		// if name involves a fn call
 		// precompute the address of the fn
 		tempname(&afun, types[tptr]);
-		if(isptr[n->left->type->etype])
-			cgen(n->left, &afun);
-		else
-			agen(n->left, &afun);
+		cgen(n->left, &afun);
 	}
 
 	gen(n->right, L);	// assign the args
 	t = n->left->type;
-	if(isptr[t->etype])
-		t = t->type;
 
 	setmaxarg(t);
 
@@ -874,7 +849,7 @@
 	}
 
 	// call pointer
-	if(isptr[n->left->type->etype]) {
+	if(n->left->op != ONAME || n->left->class != PFUNC) {
 		regalloc(&nod, types[tptr], N);
 		cgen_as(&nod, n->left);
 		nod.type = t;
@@ -887,6 +862,7 @@
 	n->left->method = 1;
 	ginscall(n->left, proc);
 
+
 ret:
 	;
 }
@@ -992,7 +968,7 @@
 {
 	gen(n->left, L);	// copy out args
 	if(hasdefer)
-		gins(ACALL, N, deferreturn);
+		ginscall(deferreturn, 0);
 	gins(ARET, N, N);
 }
 
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index 602de32..a44f104 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -164,6 +164,7 @@
 void	genconv(Type*, Type*);
 void	allocparams(void);
 void	checklabels();
+void	ginscall(Node*, int);
 
 /*
  * cgen
@@ -219,6 +220,7 @@
 void	setmaxarg(Type*);
 void	sudoclean(void);
 int	sudoaddable(Node*, Addr*);
+void	afunclit(Addr*);
 
 /*
  * list.c
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index cd4f6e2..0f71c10 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -1084,6 +1084,10 @@
 		case PPARAMOUT:
 			a->type = D_PARAM;
 			break;
+		case PFUNC:
+			a->index = D_EXTERN;
+			a->type = D_ADDR;
+			break;
 		}
 		break;
 
@@ -1156,6 +1160,20 @@
 }
 
 /*
+ * naddr of func generates code for address of func.
+ * if using opcode that can take address implicitly,
+ * call afunclit to fix up the argument.
+ */
+void
+afunclit(Addr *a)
+{
+	if(a->type == D_ADDR && a->index == D_EXTERN) {
+		a->type = D_EXTERN;
+		a->index = D_NONE;
+	}
+}
+
+/*
  * return Axxx for Oxxx on type t.
  */
 int
@@ -1889,6 +1907,10 @@
 
 	switch(n->op) {
 	case ODOT:
+		if(n->xoffset == BADWIDTH) {
+			dump("bad width in dotoffset", n);
+			fatal("bad width in dotoffset");
+		}
 		i = dotoffset(n->left, oary, nn);
 		if(i > 0) {
 			if(oary[i-1] >= 0)
@@ -1902,6 +1924,10 @@
 		break;
 
 	case ODOTPTR:
+		if(n->xoffset == BADWIDTH) {
+			dump("bad width in dotoffset", n);
+			fatal("bad width in dotoffset");
+		}
 		i = dotoffset(n->left, oary, nn);
 		if(i < 10)
 			oary[i++] = -(n->xoffset+1);
@@ -2084,7 +2110,7 @@
 		}
 		gins(optoas(OCMP, types[TUINT32]), reg1, &n2);
 		p1 = gbranch(optoas(OLT, types[TUINT32]), T);
-		gins(ACALL, N, throwindex);
+		ginscall(throwindex, 0);
 		patch(p1, pc);
 	}
 
@@ -2126,7 +2152,7 @@
 			nodconst(&n2, types[TUINT64], v);
 			gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
 			p1 = gbranch(optoas(OGT, types[TUINT32]), T);
-			gins(ACALL, N, throwindex);
+			ginscall(throwindex, 0);
 			patch(p1, pc);
 		}
 
diff --git a/src/cmd/6g/obj.c b/src/cmd/6g/obj.c
index cd44bd6..02f987d 100644
--- a/src/cmd/6g/obj.c
+++ b/src/cmd/6g/obj.c
@@ -70,7 +70,7 @@
 		if(n == N || n->type == T)
 			fatal("external %S nil\n", s);
 
-		if(n->type->etype == TFUNC)
+		if(n->class == PFUNC)
 			continue;
 
 		dowidth(n->type);
@@ -664,7 +664,7 @@
 			a->hash += PRIME10*stringhash(package);
 		a->perm = o;
 		a->sym = methodsym(method, rcvrt);
-		
+
 		sighash = sighash*100003 + a->hash;
 
 		if(!a->sym->siggen) {
@@ -803,7 +803,7 @@
 		a->perm = o;
 		a->sym = methodsym(f->sym, t);
 		a->offset = 0;
-		
+
 		sighash = sighash*100003 + a->hash;
 
 		o++;
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index 8552812..85d8a1d 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -71,6 +71,7 @@
 		case TARRAY:
 		case TMAP:
 		case TCHAN:
+		case TFUNC:
 			break;
 		}
 		break;
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 2ae8fd3..1ca2d50 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -384,9 +384,9 @@
 		// declare fun name, argument types and argument names
 		n->nname->type = n->type;
 		if(n->type->thistuple == 0)
-			addvar(n->nname, n->type, PEXTERN);
+			addvar(n->nname, n->type, PFUNC);
 		else
-			n->nname->class = PEXTERN;
+			n->nname->class = PFUNC;
 	} else {
 		// identical redeclaration
 		// steal previous names
@@ -501,9 +501,6 @@
 	if(n->op != ODCLFIELD || n->type == T)
 		fatal("stotype: oops %N\n", n);
 
-	if(et == TSTRUCT && n->type->etype == TFUNC)
-		yyerror("bad structure field type: %T", n->type);
-
 	switch(n->val.ctype) {
 	case CTSTR:
 		note = n->val.u.sval;
@@ -742,7 +739,7 @@
 
 	s = n->sym;
 
-	if(ctxt == PEXTERN) {
+	if(ctxt == PEXTERN || ctxt == PFUNC) {
 		r = externdcl;
 		gen = 0;
 	} else {
@@ -773,6 +770,8 @@
 	if(dflag()) {
 		if(ctxt == PEXTERN)
 			print("extern var-dcl %S G%ld %T\n", s, s->vargen, t);
+		else if(ctxt == PFUNC)
+			print("extern func-dcl %S G%ld %T\n", s, s->vargen, t);
 		else
 			print("auto   var-dcl %S G%ld %T\n", s, s->vargen, t);
 	}
@@ -896,6 +895,7 @@
 	n->type = T;
 	n->addable = 1;
 	n->ullman = 1;
+	n->xoffset = 0;
 	return n;
 }
 
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
index 8730292..ee1ce40 100644
--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -153,11 +153,11 @@
 	dumpprereq(t);
 
 	Bprint(bout, "\t");
-	if(t->etype == TFUNC)
-		Bprint(bout, "func ");
+	if(t->etype == TFUNC && n->class == PFUNC)
+		Bprint(bout, "func %lS %#hhT", s, t);
 	else
-		Bprint(bout, "var ");
-	Bprint(bout, "%lS %#T\n", s, t);
+		Bprint(bout, "var %lS %#T", s, t);
+	Bprint(bout, "\n");
 }
 
 void
@@ -199,7 +199,7 @@
 
 		dumpexporttype(s);
 		for(f=s->otype->method; f!=T; f=f->down)
-			Bprint(bout, "\tfunc (%#T) %hS %#hT\n",
+			Bprint(bout, "\tfunc (%#T) %hS %#hhT\n",
 				f->type->type->type, f->sym, f->type);
 		break;
 	case LNAME:
@@ -368,7 +368,7 @@
 }
 
 void
-importvar(Node *ss, Type *t)
+importvar(Node *ss, Type *t, int ctxt)
 {
 	Sym *s;
 
@@ -383,7 +383,7 @@
 			s, s->oname->type, t);
 	}
 	checkwidth(t);
-	addvar(newname(s), t, PEXTERN);
+	addvar(newname(s), t, ctxt);
 
 	if(debug['e'])
 		print("import var %S %lT\n", s, t);
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 1e1f4b2..1dd041b 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -414,6 +414,7 @@
 	PAUTO,
 	PPARAM,
 	PPARAMOUT,
+	PFUNC,
 
 	PHEAP = 1<<7,
 };
@@ -778,7 +779,7 @@
 void	importconst(Node *ss, Type *t, Val *v);
 void	importmethod(Sym *s, Type *t);
 void	importtype(Node *ss, Type *t);
-void	importvar(Node *ss, Type *t);
+void	importvar(Node *ss, Type *t, int ctxt);
 void	checkimports(void);
 Type*	pkgtype(char*, char*);
 
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 29c9b29..e323276 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -1231,15 +1231,15 @@
 |	Bfntype
 
 Afntype:
-	'(' oarg_type_list ')' Afnres
+	LFUNC '(' oarg_type_list ')' Afnres
 	{
-		$$ = functype(N, $2, $4);
+		$$ = functype(N, $3, $5);
 	}
 
 Bfntype:
-	'(' oarg_type_list ')' Bfnres
+	LFUNC '(' oarg_type_list ')' Bfnres
 	{
-		$$ = functype(N, $2, $4);
+		$$ = functype(N, $3, $5);
 	}
 
 fnlitdcl:
@@ -1251,7 +1251,7 @@
 	}
 
 fnliteral:
-	LFUNC fnlitdcl '{' ostmt_list '}'
+	fnlitdcl '{' ostmt_list '}'
 	{
 		popdcl();
 
@@ -1259,21 +1259,19 @@
 		snprint(namebuf, sizeof(namebuf), "_f%.3ld", vargen);
 
 		$$ = newname(lookup(namebuf));
-		addvar($$, $2, PEXTERN);
+		addvar($$, $1, PFUNC);
 
 		{
 			Node *n;
 
 			n = nod(ODCLFUNC, N, N);
 			n->nname = $$;
-			n->type = $2;
-			n->nbody = $4;
+			n->type = $1;
+			n->nbody = $3;
 			if(n->nbody == N)
 				n->nbody = nod(ORETURN, N, N);
 			compile(n);
 		}
-
-		$$ = nod(OADDR, $$, N);
 	}
 
 fnbody:
@@ -1417,12 +1415,6 @@
 		// without func keyword
 		$$ = functype(fakethis(), $2, $4);
 	}
-|	latype
-	{
-		$$ = oldtype($1);
-		if($$ == T || $$->etype != TFUNC)
-			yyerror("illegal type for function literal");
-	}
 
 /*
  * function arguments.
@@ -1733,7 +1725,7 @@
 	/* variables */
 |	LVAR hidden_pkg_importsym hidden_type
 	{
-		importvar($2, $3);
+		importvar($2, $3, PEXTERN);
 	}
 |	LCONST hidden_pkg_importsym '=' hidden_constant
 	{
@@ -1749,7 +1741,7 @@
 	}
 |	LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres
 	{
-		importvar($2, functype(N, $4, $6));
+		importvar($2, functype(N, $4, $6), PFUNC);
 	}
 |	LFUNC '(' hidden_funarg_list ')' sym1 '(' ohidden_funarg_list ')' ohidden_funres
 	{
@@ -1829,9 +1821,9 @@
 		$$->type = $2;
 		$$->chan = Cboth;
 	}
-|	'(' ohidden_funarg_list ')' ohidden_funres
+|	LFUNC '(' ohidden_funarg_list ')' ohidden_funres
 	{
-		$$ = functype(N, $2, $4);
+		$$ = functype(N, $3, $5);
 	}
 
 hidden_dcl:
@@ -1980,11 +1972,6 @@
 		yyerror("no type %s", $1->name);
 		YYERROR;
 	}
-|	lpack '.' LNAME
-	{
-		yyerror("no type %s.%s", context, $3->name);
-		YYERROR;
-	}
 
 nametype:
 	LNAME
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index b851454..7e16fa9 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -1154,6 +1154,7 @@
 		case TINTER:
 		case TMAP:
 		case TCHAN:
+		case TFUNC:
 			okforeq[i] = 1;
 			break;
 		}
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index d6fb2514..4fdfb78 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -283,6 +283,7 @@
 		n->lineno = lineno;
 	else
 		n->lineno = prevlineno;
+	n->xoffset = BADWIDTH;
 	return n;
 }
 
@@ -291,7 +292,7 @@
 {
 	int a;
 
-	if(issimple[t->etype] || isptr[t->etype] || t->etype == TCHAN)
+	if(issimple[t->etype] || isptr[t->etype] || t->etype == TCHAN || t->etype == TFUNC)
 		a = AMEM;	// just bytes (int, ptr, etc)
 	else
 	if(t->etype == TSTRING)
@@ -1040,6 +1041,8 @@
 			fmtprint(fp, ")");
 		}
 
+		if(!(fp->flags&FmtByte))
+			fmtprint(fp, "func");
 		fmtprint(fp, "(");
 		for(t1=getinargx(t)->type; t1; t1=t1->down) {
 			fmtprint(fp, "%T", t1);
@@ -1052,7 +1055,7 @@
 			break;
 		case 1:
 			t1 = getoutargx(t)->type;
-			if(t1->etype != TFIELD) {
+			if(t1->etype != TFIELD && t1->etype != TFUNC) {
 				fmtprint(fp, " %T", t1);
 				break;
 			}
@@ -1077,7 +1080,7 @@
 	case TINTER:
 		fmtprint(fp, "interface {");
 		for(t1=t->type; t1!=T; t1=t1->down) {
-			fmtprint(fp, " %hS %hT", t1->sym, t1->type);
+			fmtprint(fp, " %hS %hhT", t1->sym, t1->type);
 			if(t1->down)
 				fmtprint(fp, ";");
 		}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 1b5ca47..24a3a39 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -1020,6 +1020,12 @@
 			indir(n, nvar);
 			goto ret;
 		}
+		if(istype(n->left->type, TFUNC) && n->left->class == PFUNC) {
+			if(!n->diag) {
+				n->diag = 1;
+				yyerror("cannot take address of function");
+			}
+		}
 		walktype(n->left, Elv);
 		addrescapes(n->left);
 		if(n->left == N)
@@ -1060,10 +1066,8 @@
 			goto ret;
 		}
 		t = n->type;
-		if(t == T || t->etype == TFUNC) {
-			yyerror("cannot new(%T)", t);
+		if(t == T)
 			goto ret;
-		}
 		indir(n, callnew(t));
 		goto ret;
 	}
@@ -1721,6 +1725,8 @@
 		badtype(op, l->type, r->type);
 		return N;
 	}
+	if(l->op == ONAME && l->class == PFUNC)
+		yyerror("cannot assign to function");
 
 	a = nod(OAS, l, r);
 	a = convas(a);