diff options
| author | Russ Cox <rsc@golang.org> | 2010-06-12 11:17:24 -0700 | 
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2010-06-12 11:17:24 -0700 | 
| commit | 171e56e8ce55c0937e4f4fe0487c0e69ddac2f74 (patch) | |
| tree | 791790d4d7d3f5aabc0cf1235a9ff2a4e40c0e66 /src | |
| parent | 5cc45168f9d5aa01db50aa19ce69e39fc4967541 (diff) | |
| download | golang-171e56e8ce55c0937e4f4fe0487c0e69ddac2f74.tar.gz | |
gc: less aggressive name binding, for better line numbers in errors
Cleans up a few other corner cases too.
R=ken2
CC=golang-dev
http://codereview.appspot.com/1592045
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/gc/dcl.c | 24 | ||||
| -rw-r--r-- | src/cmd/gc/export.c | 2 | ||||
| -rw-r--r-- | src/cmd/gc/go.h | 8 | ||||
| -rw-r--r-- | src/cmd/gc/go.y | 28 | ||||
| -rw-r--r-- | src/cmd/gc/lex.c | 36 | ||||
| -rw-r--r-- | src/cmd/gc/subr.c | 12 | ||||
| -rw-r--r-- | src/cmd/gc/typecheck.c | 49 | ||||
| -rw-r--r-- | src/cmd/gc/walk.c | 34 | 
8 files changed, 111 insertions, 82 deletions
| diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index 48391d510..fadd4a039 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -430,24 +430,13 @@ newname(Sym *s)  /*   * this generates a new name node for a name - * being declared.  if at the top level, it might return - * an ONONAME node created by an earlier reference. + * being declared.   */  Node*  dclname(Sym *s)  {  	Node *n; -	// top-level name: might already have been -	// referred to, in which case s->def is already -	// set to an ONONAME. -	if(dclcontext == PEXTERN && s->block <= 1) { -		if(s->def == N) -			oldname(s); -		if(s->def->op == ONONAME) -			return s->def; -	} -  	n = newname(s);  	n->op = ONONAME;	// caller will correct it  	return n; @@ -484,12 +473,12 @@ oldname(Sym *s)  	if(n == N) {  		// maybe a top-level name will come along  		// to give this a definition later. +		// walkdef will check s->def again once +		// all the input source has been processed.  		n = newname(s);  		n->op = ONONAME; -		s->def = n; +		n->iota = iota;	// save current iota value in const declarations  	} -	if(n->oldref < 100) -		n->oldref++;  	if(curfn != nil && n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {  		// inner func is referring to var in outer func.  		// @@ -587,11 +576,6 @@ colasdefn(NodeList *left, Node *defn)  		if(n->sym->block == block)  			continue; -		// If we created an ONONAME just for this :=, -		// delete it, to avoid confusion with top-level imports. -		if(n->op == ONONAME && n->oldref < 100 && --n->oldref == 0) -			n->sym->def = N; -  		nnew++;  		n = newname(n->sym);  		declare(n, dclcontext); diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c index c73c476b6..aa9d2f149 100644 --- a/src/cmd/gc/export.c +++ b/src/cmd/gc/export.c @@ -120,7 +120,7 @@ dumpexportconst(Sym *s)  	switch(n->val.ctype) {  	default: -		fatal("dumpexportconst: unknown ctype: %S", s); +		fatal("dumpexportconst: unknown ctype: %S %d", s, n->val.ctype);  	case CTINT:  		Bprint(bout, "%B\n", n->val.u.xval);  		break; diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 2f63ba40f..3f6550247 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -201,7 +201,6 @@ struct	Node  	uchar	etype;		// op for OASOP, etype for OTYPE, exclam for export  	uchar	class;		// PPARAM, PAUTO, PEXTERN, etc  	uchar	method;		// OCALLMETH name -	uchar	iota;		// OLITERAL made from iota  	uchar	embedded;	// ODCLFIELD embedded type  	uchar	colas;		// OAS resulting from :=  	uchar	diag;		// already printed error about this @@ -214,7 +213,6 @@ struct	Node  	uchar	initorder;  	uchar	dodata;		// compile literal assignment as data statement  	uchar	used; -	uchar	oldref;  	uchar	isddd;  	uchar	pun;		// dont registerize variable ONAME @@ -270,6 +268,7 @@ struct	Node  	int32	lineno;  	vlong	xoffset;  	int32	ostk; +	int32	iota;  };  #define	N	((Node*)0) @@ -721,7 +720,7 @@ EXTERN	int	incannedimport;  EXTERN	int	statuniqgen;		// name generator for static temps  EXTERN	int	loophack; -EXTERN	uint32	iota; +EXTERN	int32	iota;  EXTERN	NodeList*	lastconst;  EXTERN	Node*	lasttype;  EXTERN	int32	maxarg; @@ -1079,7 +1078,7 @@ void	anylit(Node*, Node*, NodeList**);  int	oaslit(Node*, NodeList**);  void	heapmoves(void);  void	walkdeflist(NodeList*); -void	walkdef(Node*); +Node*	walkdef(Node*);  void	typechecklist(NodeList*, int);  void	typecheckswitch(Node*);  void	typecheckselect(Node*); @@ -1089,6 +1088,7 @@ Node*	typecheck(Node**, int);  int	islvalue(Node*);  void	queuemethod(Node*);  int	exportassignok(Type*, char*); +Node*	resolve(Node*);  /*   *	const.c diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 2c4623f15..5e6d14b54 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -194,12 +194,7 @@ import_stmt:  		}  		if(my->name[0] == '_' && my->name[1] == '\0')  			break; - -		// Can end up with my->def->op set to ONONAME -		// if one package refers to p without importing it. -		// Don't want to give an error on a good import -		// in another file. -		if(my->def && my->def->op != ONONAME) { +		if(my->def) {  			lineno = $1;  			redeclare(my, "as imported package name");  		} @@ -307,27 +302,28 @@ common_dcl:  	{  		$$ = nil;  	} -|	LCONST constdcl +|	lconst constdcl  	{  		$$ = $2; -		iota = 0; +		iota = -100000;  		lastconst = nil;  	} -|	LCONST '(' constdcl osemi ')' +|	lconst '(' constdcl osemi ')'  	{  		$$ = $3; -		iota = 0; +		iota = -100000;  		lastconst = nil;  	} -|	LCONST '(' constdcl ';' constdcl_list osemi ')' +|	lconst '(' constdcl ';' constdcl_list osemi ')'  	{  		$$ = concat($3, $5); -		iota = 0; +		iota = -100000;  		lastconst = nil;  	} -|	LCONST '(' ')' +|	lconst '(' ')'  	{  		$$ = nil; +		iota = -100000;  	}  |	LTYPE typedcl  	{ @@ -342,6 +338,12 @@ common_dcl:  		$$ = nil;  	} +lconst: +	LCONST +	{ +		iota = 0; +	} +  vardcl:  	dcl_name_list ntype  	{ diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index b08100993..791686caf 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -1444,11 +1444,6 @@ lexinit(void)  		}  	} -	s = lookup("iota"); -	s->def = nod(ONONAME, N, N); -	s->def->iota = 1; -	s->def->sym = s; -  	// logically, the type of a string literal.  	// types[TSTRING] is the named type string  	// (the type of x in var x string or var x = "hello"). @@ -1491,13 +1486,12 @@ lexfini(void)  		s->lexical = lex;  		etype = syms[i].etype; -		if(etype != Txxx && (etype != TANY || debug['A'])) -		if(s->def != N && s->def->op == ONONAME) -			*s->def = *typenod(types[etype]); +		if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N) +			s->def = typenod(types[etype]);  		etype = syms[i].op; -		if(etype != OXXX && s->def != N && s->def->op == ONONAME) { -			s->def->op = ONAME; +		if(etype != OXXX && s->def == N) { +			s->def = nod(ONAME, N, N);  			s->def->sym = s;  			s->def->etype = etype;  			s->def->builtin = 1; @@ -1506,29 +1500,35 @@ lexfini(void)  	for(i=0; typedefs[i].name; i++) {  		s = lookup(typedefs[i].name); -		if(s->def != N && s->def->op == ONONAME) -			*s->def = *typenod(types[typedefs[i].etype]); +		if(s->def == N) +			s->def = typenod(types[typedefs[i].etype]);  	}  	// there's only so much table-driven we can handle.  	// these are special cases.  	types[TNIL] = typ(TNIL);  	s = lookup("nil"); -	if(s->def != N && s->def->op == ONONAME) { +	if(s->def == N) {  		v.ctype = CTNIL; -		*s->def = *nodlit(v); +		s->def = nodlit(v); +		s->def->sym = s; +	} +	 +	s = lookup("iota"); +	if(s->def == N) { +		s->def = nod(OIOTA, N, N);  		s->def->sym = s;  	}  	s = lookup("true"); -	if(s->def != N && s->def->op == ONONAME) { -		*s->def = *nodbool(1); +	if(s->def == N) { +		s->def = nodbool(1);  		s->def->sym = s;  	}  	s = lookup("false"); -	if(s->def != N && s->def->op == ONONAME) { -		*s->def = *nodbool(0); +	if(s->def == N) { +		s->def = nodbool(0);  		s->def->sym = s;  	} diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 649b8f542..c836b60f2 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -1529,13 +1529,19 @@ treecopy(Node *n)  		break;  	case ONONAME: -		if(n->iota) { -			m = nod(OIOTA, n, nodintconst(iota)); +		if(n->sym == lookup("iota")) { +			// Not sure yet whether this is the real iota, +			// but make a copy of the Node* just in case, +			// so that all the copies of this const definition +			// don't have the same iota value. +			m = nod(OXXX, N, N); +			*m = *n; +			m->iota = iota;  			break;  		}  		// fall through -	case OLITERAL:  	case ONAME: +	case OLITERAL:  	case OTYPE:  		m = n;  		break; diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 70aa3cb9d..8a2fcd735 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -33,6 +33,23 @@ static void	checkassign(Node*);  static void	checkassignlist(NodeList*);  static void stringtoarraylit(Node**); +/* + * resolve ONONAME to definition, if any. + */ +Node* +resolve(Node *n) +{ +	Node *r; + +	if(n != N && n->op == ONONAME && (r = n->sym->def) != N) { +		if(r->op != OIOTA) +			n = r; +		else if(n->iota >= 0) +			n = nodintconst(n->iota); +	} +	return n; +} +  void  typechecklist(NodeList *l, int top)  { @@ -64,6 +81,10 @@ typecheck(Node **np, int top)  	n = *np;  	if(n == N)  		return N; +	 +	// Resolve definition of name and value of iota lazily. +	n = resolve(n); +	*np = n;  	// Skip typecheck if already done.  	// But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed. @@ -85,10 +106,9 @@ typecheck(Node **np, int top)  	}  	n->typecheck = 2; -redo:  	lno = setlineno(n);  	if(n->sym) { -		if(n->op == ONAME && n->etype != 0) { +		if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) {  			yyerror("use of builtin %S not in function call", n->sym);  			goto error;  		} @@ -96,6 +116,7 @@ redo:  		if(n->op == ONONAME)  			goto error;  	} +	*np = n;  reswitch:  	ok = 0; @@ -138,15 +159,6 @@ reswitch:  		yyerror("use of package %S not in selector", n->sym);  		goto error; -	case OIOTA: -		// looked like iota during parsing but might -		// have been redefined.  decide. -		if(n->left->op != ONONAME) -			n = n->left; -		else -			n = n->right; -		goto redo; -  	case ODDD:  		break; @@ -680,6 +692,12 @@ reswitch:  	 */  	case OCALL:  		l = n->left; +		if(l->op == ONAME && (r = unsafenmagic(l, n->list)) != N) { +			n = r; +			goto reswitch; +		} +		typecheck(&n->left, Erv | Etype | Ecall); +		l = n->left;  		if(l->op == ONAME && l->etype != 0) {  			// builtin: OLEN, OCAP, etc.  			n->op = l->etype; @@ -687,11 +705,6 @@ reswitch:  			n->right = N;  			goto reswitch;  		} -		if(l->op == ONAME && (r = unsafenmagic(l, n->list)) != N) { -			n = r; -			goto reswitch; -		} -		typecheck(&n->left, Erv | Etype | Ecall);  		defaultlit(&n->left, T);  		l = n->left;  		if(l->op == OTYPE) { @@ -895,7 +908,7 @@ reswitch:  	case OCONV:  	doconv:  		ok |= Erv; -		typecheck(&n->left, Erv | (top & Eindir)); +		typecheck(&n->left, Erv | (top & (Eindir | Eiota)));  		convlit1(&n->left, n->type, 1);  		if((t = n->left->type) == T || n->type == T)  			goto error; @@ -1929,6 +1942,7 @@ typecheckas(Node *n)  	// if the variable has a type (ntype) then typechecking  	// will not look at defn, so it is okay (and desirable,  	// so that the conversion below happens). +	n->left = resolve(n->left);  	if(n->left->defn != n || n->left->ntype)  		typecheck(&n->left, Erv | Easgn); @@ -1976,6 +1990,7 @@ typecheckas2(Node *n)  	for(ll=n->list; ll; ll=ll->next) {  		// delicate little dance. +		ll->n = resolve(ll->n);  		if(ll->n->defn != n || ll->n->ntype)  			typecheck(&ll->n, Erv | Easgn);  	} diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index a4e509650..3974e1e29 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -9,6 +9,8 @@ static	Node*	conv(Node*, Type*);  static	Node*	mapfn(char*, Type*);  static	Node*	makenewvar(Type*, NodeList**, Node**); +static	NodeList*	walkdefstack; +  // can this code branch reach the end  // without an undcontitional RETURN  // this is hard, so it is conservative @@ -186,13 +188,14 @@ queuemethod(Node *n)  	methodqueue = list(methodqueue, n);  } -void +Node*  walkdef(Node *n)  {  	int lno;  	NodeList *init;  	Node *e;  	Type *t; +	NodeList *l;  	lno = lineno;  	setlineno(n); @@ -204,14 +207,24 @@ walkdef(Node *n)  				lineno = n->lineno;  			yyerror("undefined: %S", n->sym);  		} -		return; +		return n;  	}  	if(n->walkdef == 1) -		return; +		return n; + +	l = mal(sizeof *l); +	l->n = n; +	l->next = walkdefstack; +	walkdefstack = l; +  	if(n->walkdef == 2) { -		// TODO(rsc): better loop message -		fatal("loop"); +		flusherrors(); +		print("walkdef loop:"); +		for(l=walkdefstack; l; l=l->next) +			print(" %S", l->n->sym); +		print("\n"); +		fatal("walkdef loop");  	}  	n->walkdef = 2; @@ -266,8 +279,11 @@ walkdef(Node *n)  		}  		if(n->type != T)  			break; -		if(n->defn == N) +		if(n->defn == N) { +			if(n->etype != 0)	// like OPRINTN +				break;  			fatal("var without type, init: %S", n->sym); +		}  		if(n->defn->op == ONAME) {  			typecheck(&n->defn, Erv);  			n->type = n->defn->type; @@ -289,8 +305,14 @@ walkdef(Node *n)  	}  ret: +	if(walkdefstack->n != n) +		fatal("walkdefstack mismatch"); +	l = walkdefstack; +	walkdefstack = l->next; +  	lineno = lno;  	n->walkdef = 1; +	return n;  }  void | 
