From: Rémy Oudompheng Date: Sun, 7 Oct 2012 15:35:21 +0000 (+0200) Subject: cmd/gc: replace "typechecking loop" by nicer errors in some cases. X-Git-Tag: go1.1rc2~2225 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=892fa3ae6c2d70fa1554ac2c817adfbe3c4c0c50;p=gostls13.git cmd/gc: replace "typechecking loop" by nicer errors in some cases. For issue 3757: BEFORE: test/fixedbugs/bug463.go:12: typechecking loop involving a test/fixedbugs/bug463.go:12 a test/fixedbugs/bug463.go:12 AFTER: test/fixedbugs/bug463.go:12: constant definition loop test/fixedbugs/bug463.go:12: a uses a For issue 3937: BEFORE: test/fixedbugs/bug464.go:12: typechecking loop involving foo test/fixedbugs/bug464.go:12 test/fixedbugs/bug464.go:12 foo test/fixedbugs/bug464.go:12 AFTER: test/fixedbugs/bug464.go:12: foo is not a type Fixes #3757. Fixes #3937. R=golang-dev, rsc CC=golang-dev https://golang.org/cl/6614058 --- diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index e84b45f389..ebc43e7598 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -105,6 +105,27 @@ typekind(Type *t) return buf; } +/* + * sprint_depchain prints a dependency chain + * of nodes into fmt. + * It is used by typecheck in the case of OLITERAL nodes + * to print constant definition loops. + */ +static void +sprint_depchain(Fmt *fmt, NodeList *stack, Node *cur, Node *first) +{ + NodeList *l; + + for(l = stack; l; l=l->next) { + if(l->n->op == cur->op) { + if(l->n != first) + sprint_depchain(fmt, l->next, l->n, first); + fmtprint(fmt, "\n\t%L: %N uses %N", l->n->lineno, l->n, cur); + return; + } + } +} + /* * type check node *np. * replaces *np with a new pointer in some cases. @@ -155,6 +176,24 @@ typecheck(Node **np, int top) } if(n->typecheck == 2) { + // Typechecking loop. Trying printing a meaningful message, + // otherwise a stack trace of typechecking. + switch(n->op) { + case ONAME: + // We can already diagnose variables used as types. + if((top & (Erv|Etype)) == Etype) + yyerror("%N is not a type", n); + break; + case OLITERAL: + if((top & (Erv|Etype)) == Etype) { + yyerror("%N is not a type", n); + break; + } + fmtstrinit(&fmt); + sprint_depchain(&fmt, tcstack, n, n); + yyerrorl(n->lineno, "constant definition loop%s", fmtstrflush(&fmt)); + break; + } if(nsavederrors+nerrors == 0) { fmtstrinit(&fmt); for(l=tcstack; l; l=l->next) @@ -165,7 +204,7 @@ typecheck(Node **np, int top) return n; } n->typecheck = 2; - + if(tcfree != nil) { l = tcfree; tcfree = l->next; diff --git a/test/fixedbugs/bug463.go b/test/fixedbugs/bug463.go new file mode 100644 index 0000000000..3e7a184827 --- /dev/null +++ b/test/fixedbugs/bug463.go @@ -0,0 +1,22 @@ +// errorcheck + +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 3757: unhelpful typechecking loop message +// for constants that refer to themselves. + +package main + +const a = a // ERROR "refers to itself|definition loop" + +const ( + X = A + A = B // ERROR "refers to itself|definition loop" + B = D + C, D = 1, A +) + +func main() { +} diff --git a/test/fixedbugs/bug464.go b/test/fixedbugs/bug464.go new file mode 100644 index 0000000000..582193997a --- /dev/null +++ b/test/fixedbugs/bug464.go @@ -0,0 +1,12 @@ +// errorcheck + +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 3937: unhelpful typechecking loop message +// for identifiers wrongly used as types. + +package main + +func foo(x foo) {} // ERROR "expected type|not a type"