diff options
Diffstat (limited to 'src/cmd/gc')
46 files changed, 13950 insertions, 3332 deletions
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile index 0af7659e4..58e25faaf 100644 --- a/src/cmd/gc/Makefile +++ b/src/cmd/gc/Makefile @@ -1,71 +1,17 @@ -# Copyright 2009 The Go Authors. All rights reserved. +# 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. -include ../../Make.inc -O:=$(HOST_O) +include ../../Make.dist -LIB=gc.a +install: y.tab.h builtin.c -HFILES=\ - go.h\ - y.tab.h\ - md5.h\ - -YFILES=\ - go.y\ - -OFILES=\ - align.$O\ - bits.$O\ - builtin.$O\ - closure.$O\ - const.$O\ - dcl.$O\ - export.$O\ - gen.$O\ - init.$O\ - lex.$O\ - md5.$O\ - mparith1.$O\ - mparith2.$O\ - mparith3.$O\ - obj.$O\ - print.$O\ - range.$O\ - reflect.$O\ - select.$O\ - sinit.$O\ - subr.$O\ - swt.$O\ - typecheck.$O\ - unsafe.$O\ - walk.$O\ - y1.tab.$O\ - -NOINSTALL=1 -include ../../Make.clib - -install: $(LIB) - -y1.tab.c: y.tab.c # make yystate global, yytname mutable +y.tab.h: go.y go.errors bisonerrors + bison -v -y -d go.y + # make yystate global, yytname mutable cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c - -yerr.h: bisonerrors go.errors y.tab.h # y.tab.h rule generates y.output too + mv y1.tab.c y.tab.c awk -f bisonerrors y.output go.errors >yerr.h -subr.$O: yerr.h - -builtin.c: builtin.c.boot - cp builtin.c.boot builtin.c - -subr.$O: opnames.h - -opnames.h: mkopnames go.h - ./mkopnames go.h >opnames.h - -CLEANFILES+=*.[568] [568].out y1.tab.c yerr.h mkbuiltin1 builtin.c _builtin.c opnames.h - -mkbuiltin1: mkbuiltin1.$O - $(HOST_LD) -o $@ mkbuiltin1.$O -L"$(GOROOT)"/lib -lbio -l9 -lm $(HOST_LDFLAGS) - +builtin.c: runtime.go unsafe.go + ./mkbuiltin diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index 14c1c4a8d..6982bbe56 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" /* @@ -283,6 +285,9 @@ dowidth(Type *t) break; } + if(widthptr == 4 && w != (int32)w) + yyerror("type %T too large", t); + t->width = w; if(t->align == 0) { if(w > 8 || (w&(w-1)) != 0) @@ -489,12 +494,13 @@ typeinit(void) okforeq[TPTR64] = 1; okforeq[TUNSAFEPTR] = 1; okforeq[TINTER] = 1; - okforeq[TMAP] = 1; okforeq[TCHAN] = 1; - okforeq[TFUNC] = 1; okforeq[TSTRING] = 1; okforeq[TBOOL] = 1; - okforeq[TARRAY] = 1; // refined in typecheck + okforeq[TMAP] = 1; // nil only; refined in typecheck + okforeq[TFUNC] = 1; // nil only; refined in typecheck + okforeq[TARRAY] = 1; // nil slice only; refined in typecheck + okforeq[TSTRUCT] = 1; // it's complicated; refined in typecheck okforcmp[TSTRING] = 1; diff --git a/src/cmd/gc/bisonerrors b/src/cmd/gc/bisonerrors index 5110f5350..0f865d086 100755 --- a/src/cmd/gc/bisonerrors +++ b/src/cmd/gc/bisonerrors @@ -46,24 +46,36 @@ bison && /^state 0/ { grammar = 0; states = 1 } states && /^state / { state = $2 } states { statetext[state] = statetext[state] $0 "\n" } -states && / shift, and go to state/ { +states && / shift/ { n = nshift[state]++ - shift[state,n] = $7 + if($0 ~ /and go to/) + shift[state,n] = $7 # GNU Bison + else + shift[state,n] = $3 # Plan 9 Yacc shifttoken[state,n] = $1 next } -states && / go to state/ { +states && / (go to|goto)/ { n = nshift[state]++ - shift[state,n] = $5 + if($0 ~ /go to/) + shift[state,n] = $5 # GNU Bison + else + shift[state,n] = $3 # Plan 9 Yacc shifttoken[state,n] = $1 next } -states && / reduce using rule/ { +states && / reduce/ { n = nreduce[state]++ - reduce[state,n] = $5 + if($0 ~ /reduce using rule/) + reduce[state,n] = $5 # GNU Bison + else + reduce[state,n] = $3 # Plan 9 yacc reducetoken[state,n] = $1 next -} +} + +# Skip over the summary information printed by Plan 9 yacc. +/nonterminals$/,/^maximum spread/ { next } # First // comment marks the beginning of the pattern file. /^\/\// { bison = 0; grammar = 0; state = 0 } @@ -96,7 +108,8 @@ $1 == "%" { if(found) continue for(j=0; j<nreduce[state]; j++) { - if(reducetoken[state,j] == tok || reducetoken[state,j] == "$default") { + t = reducetoken[state,j] + if(t == tok || t == "$default" || t == ".") { stack[nstack++] = state rule = reduce[state,j] nstack -= rulesize[rule] diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c index 7188ac411..c0fd4d85e 100644 --- a/src/cmd/gc/bits.c +++ b/src/cmd/gc/bits.c @@ -28,6 +28,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include <u.h> +#include <libc.h> #include "go.h" /* @@ -148,12 +150,12 @@ Qconv(Fmt *fp) first = 0; else fmtprint(fp, " "); - if(var[i].sym == S) - fmtprint(fp, "$%lld", var[i].offset); + if(var[i].node == N || var[i].node->sym == S) + fmtprint(fp, "$%d", i); else { - fmtprint(fp, var[i].sym->name); + fmtprint(fp, "%s", var[i].node->sym->name); if(var[i].offset != 0) - fmtprint(fp, "%+d", var[i].offset); + fmtprint(fp, "%+lld", (vlong)var[i].offset); } bits.b[i/32] &= ~(1L << (i%32)); } diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c new file mode 100644 index 000000000..ca3d6670d --- /dev/null +++ b/src/cmd/gc/builtin.c @@ -0,0 +1,118 @@ +char *runtimeimport = + "package runtime\n" + "import runtime \"runtime\"\n" + "func @\"\".new(@\"\".typ *byte) (? *any)\n" + "func @\"\".panicindex()\n" + "func @\"\".panicslice()\n" + "func @\"\".throwreturn()\n" + "func @\"\".throwinit()\n" + "func @\"\".panicwrap(? string, ? string, ? string)\n" + "func @\"\".panic(? interface {})\n" + "func @\"\".recover(? *int32) (? interface {})\n" + "func @\"\".printbool(? bool)\n" + "func @\"\".printfloat(? float64)\n" + "func @\"\".printint(? int64)\n" + "func @\"\".printuint(? uint64)\n" + "func @\"\".printcomplex(? complex128)\n" + "func @\"\".printstring(? string)\n" + "func @\"\".printpointer(? any)\n" + "func @\"\".printiface(? any)\n" + "func @\"\".printeface(? any)\n" + "func @\"\".printslice(? any)\n" + "func @\"\".printnl()\n" + "func @\"\".printsp()\n" + "func @\"\".goprintf()\n" + "func @\"\".concatstring()\n" + "func @\"\".append()\n" + "func @\"\".appendslice(@\"\".typ *byte, @\"\".x any, @\"\".y []any) (? any)\n" + "func @\"\".appendstr(@\"\".typ *byte, @\"\".x []byte, @\"\".y string) (? []byte)\n" + "func @\"\".cmpstring(? string, ? string) (? int)\n" + "func @\"\".slicestring(? string, ? int, ? int) (? string)\n" + "func @\"\".slicestring1(? string, ? int) (? string)\n" + "func @\"\".intstring(? int64) (? string)\n" + "func @\"\".slicebytetostring(? []byte) (? string)\n" + "func @\"\".slicerunetostring(? []rune) (? string)\n" + "func @\"\".stringtoslicebyte(? string) (? []byte)\n" + "func @\"\".stringtoslicerune(? string) (? []rune)\n" + "func @\"\".stringiter(? string, ? int) (? int)\n" + "func @\"\".stringiter2(? string, ? int) (@\"\".retk int, @\"\".retv rune)\n" + "func @\"\".copy(@\"\".to any, @\"\".fr any, @\"\".wid uint32) (? int)\n" + "func @\"\".slicestringcopy(@\"\".to any, @\"\".fr any) (? int)\n" + "func @\"\".convI2E(@\"\".elem any) (@\"\".ret any)\n" + "func @\"\".convI2I(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n" + "func @\"\".convT2E(@\"\".typ *byte, @\"\".elem any) (@\"\".ret any)\n" + "func @\"\".convT2I(@\"\".typ *byte, @\"\".typ2 *byte, @\"\".elem any) (@\"\".ret any)\n" + "func @\"\".assertE2E(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n" + "func @\"\".assertE2E2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n" + "func @\"\".assertE2I(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n" + "func @\"\".assertE2I2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n" + "func @\"\".assertE2T(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n" + "func @\"\".assertE2T2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n" + "func @\"\".assertI2E(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n" + "func @\"\".assertI2E2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n" + "func @\"\".assertI2I(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n" + "func @\"\".assertI2I2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n" + "func @\"\".assertI2T(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any)\n" + "func @\"\".assertI2T2(@\"\".typ *byte, @\"\".iface any) (@\"\".ret any, @\"\".ok bool)\n" + "func @\"\".ifaceeq(@\"\".i1 any, @\"\".i2 any) (@\"\".ret bool)\n" + "func @\"\".efaceeq(@\"\".i1 any, @\"\".i2 any) (@\"\".ret bool)\n" + "func @\"\".ifacethash(@\"\".i1 any) (@\"\".ret uint32)\n" + "func @\"\".efacethash(@\"\".i1 any) (@\"\".ret uint32)\n" + "func @\"\".equal(@\"\".typ *byte, @\"\".x1 any, @\"\".x2 any) (@\"\".ret bool)\n" + "func @\"\".makemap(@\"\".mapType *byte, @\"\".hint int64) (@\"\".hmap map[any]any)\n" + "func @\"\".mapaccess1(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".key any) (@\"\".val any)\n" + "func @\"\".mapaccess2(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".key any) (@\"\".val any, @\"\".pres bool)\n" + "func @\"\".mapassign1(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".key any, @\"\".val any)\n" + "func @\"\".mapassign2(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".key any, @\"\".val any, @\"\".pres bool)\n" + "func @\"\".mapiterinit(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".hiter *any)\n" + "func @\"\".mapdelete(@\"\".mapType *byte, @\"\".hmap map[any]any, @\"\".key any)\n" + "func @\"\".mapiternext(@\"\".hiter *any)\n" + "func @\"\".mapiter1(@\"\".hiter *any) (@\"\".key any)\n" + "func @\"\".mapiter2(@\"\".hiter *any) (@\"\".key any, @\"\".val any)\n" + "func @\"\".makechan(@\"\".chanType *byte, @\"\".hint int64) (@\"\".hchan chan any)\n" + "func @\"\".chanrecv1(@\"\".chanType *byte, @\"\".hchan <-chan any) (@\"\".elem any)\n" + "func @\"\".chanrecv2(@\"\".chanType *byte, @\"\".hchan <-chan any) (@\"\".elem any, @\"\".received bool)\n" + "func @\"\".chansend1(@\"\".chanType *byte, @\"\".hchan chan<- any, @\"\".elem any)\n" + "func @\"\".closechan(@\"\".hchan any)\n" + "func @\"\".selectnbsend(@\"\".chanType *byte, @\"\".hchan chan<- any, @\"\".elem any) (? bool)\n" + "func @\"\".selectnbrecv(@\"\".chanType *byte, @\"\".elem *any, @\"\".hchan <-chan any) (? bool)\n" + "func @\"\".selectnbrecv2(@\"\".chanType *byte, @\"\".elem *any, @\"\".received *bool, @\"\".hchan <-chan any) (? bool)\n" + "func @\"\".newselect(@\"\".size int) (@\"\".sel *byte)\n" + "func @\"\".selectsend(@\"\".sel *byte, @\"\".hchan chan<- any, @\"\".elem *any) (@\"\".selected bool)\n" + "func @\"\".selectrecv(@\"\".sel *byte, @\"\".hchan <-chan any, @\"\".elem *any) (@\"\".selected bool)\n" + "func @\"\".selectrecv2(@\"\".sel *byte, @\"\".hchan <-chan any, @\"\".elem *any, @\"\".received *bool) (@\"\".selected bool)\n" + "func @\"\".selectdefault(@\"\".sel *byte) (@\"\".selected bool)\n" + "func @\"\".selectgo(@\"\".sel *byte)\n" + "func @\"\".block()\n" + "func @\"\".makeslice(@\"\".typ *byte, @\"\".nel int64, @\"\".cap int64) (@\"\".ary []any)\n" + "func @\"\".growslice(@\"\".typ *byte, @\"\".old []any, @\"\".n int64) (@\"\".ary []any)\n" + "func @\"\".sliceslice1(@\"\".old []any, @\"\".lb uint64, @\"\".width uint64) (@\"\".ary []any)\n" + "func @\"\".sliceslice(@\"\".old []any, @\"\".lb uint64, @\"\".hb uint64, @\"\".width uint64) (@\"\".ary []any)\n" + "func @\"\".slicearray(@\"\".old *any, @\"\".nel uint64, @\"\".lb uint64, @\"\".hb uint64, @\"\".width uint64) (@\"\".ary []any)\n" + "func @\"\".closure()\n" + "func @\"\".memequal(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n" + "func @\"\".memequal8(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n" + "func @\"\".memequal16(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n" + "func @\"\".memequal32(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n" + "func @\"\".memequal64(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n" + "func @\"\".memequal128(@\"\".eq *bool, @\"\".size uintptr, @\"\".x *any, @\"\".y *any)\n" + "func @\"\".int64div(? int64, ? int64) (? int64)\n" + "func @\"\".uint64div(? uint64, ? uint64) (? uint64)\n" + "func @\"\".int64mod(? int64, ? int64) (? int64)\n" + "func @\"\".uint64mod(? uint64, ? uint64) (? uint64)\n" + "func @\"\".float64toint64(? float64) (? int64)\n" + "func @\"\".float64touint64(? float64) (? uint64)\n" + "func @\"\".int64tofloat64(? int64) (? float64)\n" + "func @\"\".uint64tofloat64(? uint64) (? float64)\n" + "func @\"\".complex128div(@\"\".num complex128, @\"\".den complex128) (@\"\".quo complex128)\n" + "\n" + "$$\n"; +char *unsafeimport = + "package unsafe\n" + "import runtime \"runtime\"\n" + "type @\"\".Pointer uintptr\n" + "func @\"\".Offsetof(? any) (? uintptr)\n" + "func @\"\".Sizeof(? any) (? uintptr)\n" + "func @\"\".Alignof(? any) (? uintptr)\n" + "\n" + "$$\n"; diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot deleted file mode 100644 index 190c56008..000000000 --- a/src/cmd/gc/builtin.c.boot +++ /dev/null @@ -1,114 +0,0 @@ -char *runtimeimport = - "package runtime\n" - "import runtime \"runtime\"\n" - "func \"\".new (? int32) *any\n" - "func \"\".panicindex ()\n" - "func \"\".panicslice ()\n" - "func \"\".throwreturn ()\n" - "func \"\".throwinit ()\n" - "func \"\".panicwrap (? string, ? string, ? string)\n" - "func \"\".panic (? interface { })\n" - "func \"\".recover (? *int32) interface { }\n" - "func \"\".printbool (? bool)\n" - "func \"\".printfloat (? float64)\n" - "func \"\".printint (? int64)\n" - "func \"\".printuint (? uint64)\n" - "func \"\".printcomplex (? complex128)\n" - "func \"\".printstring (? string)\n" - "func \"\".printpointer (? any)\n" - "func \"\".printiface (? any)\n" - "func \"\".printeface (? any)\n" - "func \"\".printslice (? any)\n" - "func \"\".printnl ()\n" - "func \"\".printsp ()\n" - "func \"\".goprintf ()\n" - "func \"\".concatstring ()\n" - "func \"\".append ()\n" - "func \"\".appendslice (typ *uint8, x any, y []any) any\n" - "func \"\".cmpstring (? string, ? string) int\n" - "func \"\".slicestring (? string, ? int, ? int) string\n" - "func \"\".slicestring1 (? string, ? int) string\n" - "func \"\".intstring (? int64) string\n" - "func \"\".slicebytetostring (? []uint8) string\n" - "func \"\".sliceinttostring (? []int) string\n" - "func \"\".stringtoslicebyte (? string) []uint8\n" - "func \"\".stringtosliceint (? string) []int\n" - "func \"\".stringiter (? string, ? int) int\n" - "func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n" - "func \"\".slicecopy (to any, fr any, wid uint32) int\n" - "func \"\".slicestringcopy (to any, fr any) int\n" - "func \"\".convI2E (elem any) any\n" - "func \"\".convI2I (typ *uint8, elem any) any\n" - "func \"\".convT2E (typ *uint8, elem any) any\n" - "func \"\".convT2I (typ *uint8, typ2 *uint8, elem any) any\n" - "func \"\".assertE2E (typ *uint8, iface any) any\n" - "func \"\".assertE2E2 (typ *uint8, iface any) (ret any, ok bool)\n" - "func \"\".assertE2I (typ *uint8, iface any) any\n" - "func \"\".assertE2I2 (typ *uint8, iface any) (ret any, ok bool)\n" - "func \"\".assertE2T (typ *uint8, iface any) any\n" - "func \"\".assertE2T2 (typ *uint8, iface any) (ret any, ok bool)\n" - "func \"\".assertI2E (typ *uint8, iface any) any\n" - "func \"\".assertI2E2 (typ *uint8, iface any) (ret any, ok bool)\n" - "func \"\".assertI2I (typ *uint8, iface any) any\n" - "func \"\".assertI2I2 (typ *uint8, iface any) (ret any, ok bool)\n" - "func \"\".assertI2T (typ *uint8, iface any) any\n" - "func \"\".assertI2T2 (typ *uint8, iface any) (ret any, ok bool)\n" - "func \"\".ifaceeq (i1 any, i2 any) bool\n" - "func \"\".efaceeq (i1 any, i2 any) bool\n" - "func \"\".ifacethash (i1 any) uint32\n" - "func \"\".efacethash (i1 any) uint32\n" - "func \"\".makemap (mapType *uint8, hint int64) map[any] any\n" - "func \"\".mapaccess1 (mapType *uint8, hmap map[any] any, key any) any\n" - "func \"\".mapaccess2 (mapType *uint8, hmap map[any] any, key any) (val any, pres bool)\n" - "func \"\".mapassign1 (mapType *uint8, hmap map[any] any, key any, val any)\n" - "func \"\".mapassign2 (mapType *uint8, hmap map[any] any, key any, val any, pres bool)\n" - "func \"\".mapiterinit (mapType *uint8, hmap map[any] any, hiter *any)\n" - "func \"\".mapiternext (hiter *any)\n" - "func \"\".mapiter1 (hiter *any) any\n" - "func \"\".mapiter2 (hiter *any) (key any, val any)\n" - "func \"\".makechan (chanType *uint8, hint int64) chan any\n" - "func \"\".chanrecv1 (chanType *uint8, hchan <-chan any) any\n" - "func \"\".chanrecv2 (chanType *uint8, hchan <-chan any) (elem any, received bool)\n" - "func \"\".chansend1 (chanType *uint8, hchan chan<- any, elem any)\n" - "func \"\".closechan (hchan any)\n" - "func \"\".selectnbsend (chanType *uint8, hchan chan<- any, elem any) bool\n" - "func \"\".selectnbrecv (chanType *uint8, elem *any, hchan <-chan any) bool\n" - "func \"\".selectnbrecv2 (chanType *uint8, elem *any, received *bool, hchan <-chan any) bool\n" - "func \"\".newselect (size int) *uint8\n" - "func \"\".selectsend (sel *uint8, hchan chan<- any, elem *any) bool\n" - "func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n" - "func \"\".selectrecv2 (sel *uint8, hchan <-chan any, elem *any, received *bool) bool\n" - "func \"\".selectdefault (sel *uint8) bool\n" - "func \"\".selectgo (sel *uint8)\n" - "func \"\".block ()\n" - "func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n" - "func \"\".growslice (typ *uint8, old []any, n int64) []any\n" - "func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n" - "func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n" - "func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n" - "func \"\".closure ()\n" - "func \"\".int64div (? int64, ? int64) int64\n" - "func \"\".uint64div (? uint64, ? uint64) uint64\n" - "func \"\".int64mod (? int64, ? int64) int64\n" - "func \"\".uint64mod (? uint64, ? uint64) uint64\n" - "func \"\".float64toint64 (? float64) int64\n" - "func \"\".float64touint64 (? float64) uint64\n" - "func \"\".int64tofloat64 (? int64) float64\n" - "func \"\".uint64tofloat64 (? uint64) float64\n" - "func \"\".complex128div (num complex128, den complex128) complex128\n" - "\n" - "$$\n"; -char *unsafeimport = - "package unsafe\n" - "import runtime \"runtime\"\n" - "type \"\".Pointer uintptr\n" - "func \"\".Offsetof (? any) uintptr\n" - "func \"\".Sizeof (? any) uintptr\n" - "func \"\".Alignof (? any) uintptr\n" - "func \"\".Typeof (i interface { }) interface { }\n" - "func \"\".Reflect (i interface { }) (typ interface { }, addr \"\".Pointer)\n" - "func \"\".Unreflect (typ interface { }, addr \"\".Pointer) interface { }\n" - "func \"\".New (typ interface { }) \"\".Pointer\n" - "func \"\".NewArray (typ interface { }, n int) \"\".Pointer\n" - "\n" - "$$\n"; diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index 1261eefb7..fa44e40fa 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -6,6 +6,8 @@ * function literals aka closures */ +#include <u.h> +#include <libc.h> #include "go.h" void @@ -57,7 +59,6 @@ closurebody(NodeList *body) body = list1(nod(OEMPTY, N, N)); func = curfn; - l = func->dcl; func->nbody = body; funcbody(func); @@ -129,6 +130,8 @@ makeclosure(Node *func, NodeList **init, int nowrap) static int closgen; char *p; + USED(init); + /* * wrap body in external function * with extra closure parameters. @@ -189,6 +192,10 @@ walkclosure(Node *func, NodeList **init) Node *xtype, *xfunc, *call, *clos; NodeList *l, *in; + // no closure vars, don't bother wrapping + if(func->cvars == nil) + return makeclosure(func, init, 1)->nname; + /* * wrap body in external function * with extra closure parameters. diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index 36a64cb97..e27c88338 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" #define TUP(x,y) (((x)<<16)|(y)) @@ -85,6 +87,8 @@ convlit1(Node **np, Type *t, int explicit) switch(n->op) { default: + if(n->type == idealbool) + n->type = types[TBOOL]; if(n->type->etype == TIDEAL) { convlit(&n->left, t); convlit(&n->right, t); @@ -106,7 +110,7 @@ convlit1(Node **np, Type *t, int explicit) if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT) n->val = toint(n->val); if(t != T && !isint[t->etype]) { - yyerror("invalid operation: %#N (shift of type %T)", n, t); + yyerror("invalid operation: %N (shift of type %T)", n, t); t = T; } n->type = t; @@ -168,6 +172,7 @@ convlit1(Node **np, Type *t, int explicit) break; case CTINT: + case CTRUNE: case CTFLT: case CTCPLX: ct = n->val.ctype; @@ -177,6 +182,7 @@ convlit1(Node **np, Type *t, int explicit) goto bad; case CTCPLX: case CTFLT: + case CTRUNE: n->val = toint(n->val); // flowthrough case CTINT: @@ -190,6 +196,7 @@ convlit1(Node **np, Type *t, int explicit) goto bad; case CTCPLX: case CTINT: + case CTRUNE: n->val = toflt(n->val); // flowthrough case CTFLT: @@ -204,6 +211,7 @@ convlit1(Node **np, Type *t, int explicit) goto bad; case CTFLT: case CTINT: + case CTRUNE: n->val = tocplx(n->val); break; case CTCPLX: @@ -211,7 +219,7 @@ convlit1(Node **np, Type *t, int explicit) break; } } else - if(et == TSTRING && ct == CTINT && explicit) + if(et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit) n->val = tostr(n->val); else goto bad; @@ -222,7 +230,7 @@ convlit1(Node **np, Type *t, int explicit) bad: if(!n->diag) { - yyerror("cannot convert %#N to type %T", n, t); + yyerror("cannot convert %N to type %T", n, t); n->diag = 1; } if(isideal(n->type)) { @@ -241,6 +249,7 @@ copyval(Val v) switch(v.ctype) { case CTINT: + case CTRUNE: i = mal(sizeof(*i)); mpmovefixfix(i, v.u.xval); v.u.xval = i; @@ -267,6 +276,7 @@ tocplx(Val v) switch(v.ctype) { case CTINT: + case CTRUNE: c = mal(sizeof(*c)); mpmovefixflt(&c->real, v.u.xval); mpmovecflt(&c->imag, 0.0); @@ -291,6 +301,7 @@ toflt(Val v) switch(v.ctype) { case CTINT: + case CTRUNE: f = mal(sizeof(*f)); mpmovefixflt(f, v.u.xval); v.ctype = CTFLT; @@ -314,6 +325,9 @@ toint(Val v) Mpint *i; switch(v.ctype) { + case CTRUNE: + v.ctype = CTINT; + break; case CTFLT: i = mal(sizeof(*i)); if(mpmovefltfix(i, v.u.fval) < 0) @@ -343,6 +357,7 @@ overflow(Val v, Type *t) return; switch(v.ctype) { case CTINT: + case CTRUNE: if(!isint[t->etype]) fatal("overflow: %T integer constant", t); if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 || @@ -377,6 +392,7 @@ tostr(Val v) switch(v.ctype) { case CTINT: + case CTRUNE: if(mpcmpfixfix(v.u.xval, minintval[TINT]) < 0 || mpcmpfixfix(v.u.xval, maxintval[TINT]) > 0) yyerror("overflow in int -> string"); @@ -413,7 +429,12 @@ consttype(Node *n) int isconst(Node *n, int ct) { - return consttype(n) == ct; + int t; + + t = consttype(n); + // If the caller is asking for CTINT, allow CTRUNE too. + // Makes life easier for back ends. + return t == ct || (ct == CTINT && t == CTRUNE); } /* @@ -422,7 +443,7 @@ isconst(Node *n, int ct) void evconst(Node *n) { - Node *nl, *nr; + Node *nl, *nr, *norig; int32 len; Strlit *str; int wl, wr, lno, et; @@ -516,7 +537,8 @@ evconst(Node *n) n->right = nr; if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype])) goto illegal; - nl->val = toint(nl->val); + if(nl->val.ctype != CTRUNE) + nl->val = toint(nl->val); nr->val = toint(nr->val); break; } @@ -538,6 +560,17 @@ evconst(Node *n) v = toflt(v); rv = toflt(rv); } + + // Rune and int turns into rune. + if(v.ctype == CTRUNE && rv.ctype == CTINT) + rv.ctype = CTRUNE; + if(v.ctype == CTINT && rv.ctype == CTRUNE) { + if(n->op == OLSH || n->op == ORSH) + rv.ctype = CTINT; + else + v.ctype = CTRUNE; + } + if(v.ctype != rv.ctype) { // Use of undefined name as constant? if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0) @@ -557,15 +590,19 @@ evconst(Node *n) return; case TUP(OADD, CTINT): - mpaddfixfix(v.u.xval, rv.u.xval); + case TUP(OADD, CTRUNE): + mpaddfixfix(v.u.xval, rv.u.xval, 0); break; case TUP(OSUB, CTINT): + case TUP(OSUB, CTRUNE): mpsubfixfix(v.u.xval, rv.u.xval); break; case TUP(OMUL, CTINT): + case TUP(OMUL, CTRUNE): mpmulfixfix(v.u.xval, rv.u.xval); break; case TUP(ODIV, CTINT): + case TUP(ODIV, CTRUNE): if(mpcmpfixc(rv.u.xval, 0) == 0) { yyerror("division by zero"); mpmovecfix(v.u.xval, 1); @@ -574,6 +611,7 @@ evconst(Node *n) mpdivfixfix(v.u.xval, rv.u.xval); break; case TUP(OMOD, CTINT): + case TUP(OMOD, CTRUNE): if(mpcmpfixc(rv.u.xval, 0) == 0) { yyerror("division by zero"); mpmovecfix(v.u.xval, 1); @@ -583,21 +621,27 @@ evconst(Node *n) break; case TUP(OLSH, CTINT): + case TUP(OLSH, CTRUNE): mplshfixfix(v.u.xval, rv.u.xval); break; case TUP(ORSH, CTINT): + case TUP(ORSH, CTRUNE): mprshfixfix(v.u.xval, rv.u.xval); break; case TUP(OOR, CTINT): + case TUP(OOR, CTRUNE): mporfixfix(v.u.xval, rv.u.xval); break; case TUP(OAND, CTINT): + case TUP(OAND, CTRUNE): mpandfixfix(v.u.xval, rv.u.xval); break; case TUP(OANDNOT, CTINT): + case TUP(OANDNOT, CTRUNE): mpandnotfixfix(v.u.xval, rv.u.xval); break; case TUP(OXOR, CTINT): + case TUP(OXOR, CTRUNE): mpxorfixfix(v.u.xval, rv.u.xval); break; @@ -618,6 +662,14 @@ evconst(Node *n) } mpdivfltflt(v.u.fval, rv.u.fval); break; + case TUP(OMOD, CTFLT): + // The default case above would print 'ideal % ideal', + // which is not quite an ideal error. + if(!n->diag) { + yyerror("illegal constant expression: floating-point %% operation"); + n->diag = 1; + } + return; case TUP(OADD, CTCPLX): mpaddfltflt(&v.u.cval->real, &rv.u.cval->real); @@ -647,26 +699,32 @@ evconst(Node *n) goto setfalse; case TUP(OEQ, CTINT): + case TUP(OEQ, CTRUNE): if(mpcmpfixfix(v.u.xval, rv.u.xval) == 0) goto settrue; goto setfalse; case TUP(ONE, CTINT): + case TUP(ONE, CTRUNE): if(mpcmpfixfix(v.u.xval, rv.u.xval) != 0) goto settrue; goto setfalse; case TUP(OLT, CTINT): + case TUP(OLT, CTRUNE): if(mpcmpfixfix(v.u.xval, rv.u.xval) < 0) goto settrue; goto setfalse; case TUP(OLE, CTINT): + case TUP(OLE, CTRUNE): if(mpcmpfixfix(v.u.xval, rv.u.xval) <= 0) goto settrue; goto setfalse; case TUP(OGE, CTINT): + case TUP(OGE, CTRUNE): if(mpcmpfixfix(v.u.xval, rv.u.xval) >= 0) goto settrue; goto setfalse; case TUP(OGT, CTINT): + case TUP(OGT, CTRUNE): if(mpcmpfixfix(v.u.xval, rv.u.xval) > 0) goto settrue; goto setfalse; @@ -784,17 +842,21 @@ unary: } // fall through case TUP(OCONV, CTINT): + case TUP(OCONV, CTRUNE): case TUP(OCONV, CTFLT): case TUP(OCONV, CTSTR): convlit1(&nl, n->type, 1); break; case TUP(OPLUS, CTINT): + case TUP(OPLUS, CTRUNE): break; case TUP(OMINUS, CTINT): + case TUP(OMINUS, CTRUNE): mpnegfix(v.u.xval); break; case TUP(OCOM, CTINT): + case TUP(OCOM, CTRUNE): et = Txxx; if(nl->type != T) et = nl->type->etype; @@ -840,8 +902,15 @@ unary: } ret: - // rewrite n in place. + if(n == n->orig) { + // duplicate node for n->orig. + norig = nod(OLITERAL, N, N); + *norig = *n; + } else + norig = n->orig; *n = *nl; + // restore value of n->orig. + n->orig = norig; n->val = v; // check range. @@ -880,6 +949,7 @@ nodlit(Val v) n->type = idealbool; break; case CTINT: + case CTRUNE: case CTFLT: case CTCPLX: n->type = types[TIDEAL]; @@ -937,11 +1007,15 @@ defaultlit(Node **np, Type *t) defaultlit(&n->left, t); t = n->left->type; if(t != T && !isint[t->etype]) { - yyerror("invalid operation: %#N (shift of type %T)", n, t); + yyerror("invalid operation: %N (shift of type %T)", n, t); t = T; } n->type = t; return; + case ONOT: + defaultlit(&n->left, t); + n->type = n->left->type; + return; default: if(n->left == N) { dump("defaultlit", n); @@ -961,13 +1035,18 @@ defaultlit(Node **np, Type *t) } else if(t == T && (n->left->op == OLSH || n->left->op == ORSH)) { defaultlit(&n->right, T); defaultlit(&n->left, n->right->type); + } else if(iscmp[n->op]) { + defaultlit2(&n->left, &n->right, 1); } else { defaultlit(&n->left, t); defaultlit(&n->right, t); } - if(n->type == idealbool || n->type == idealstring) - n->type = types[n->type->etype]; - else + if(n->type == idealbool || n->type == idealstring) { + if(t != T && t->etype == n->type->etype) + n->type = t; + else + n->type = types[n->type->etype]; + } else n->type = n->left->type; return; } @@ -989,7 +1068,7 @@ defaultlit(Node **np, Type *t) n->type = types[TSTRING]; break; } - yyerror("defaultlit: unknown literal: %#N", n); + yyerror("defaultlit: unknown literal: %N", n); break; case CTBOOL: n->type = types[TBOOL]; @@ -999,6 +1078,9 @@ defaultlit(Node **np, Type *t) case CTINT: n->type = types[TINT]; goto num; + case CTRUNE: + n->type = runetype; + goto num; case CTFLT: n->type = types[TFLOAT64]; goto num; @@ -1053,6 +1135,10 @@ defaultlit2(Node **lp, Node **rp, int force) } if(!force) return; + if(l->type->etype == TBOOL) { + convlit(lp, types[TBOOL]); + convlit(rp, types[TBOOL]); + } if(isconst(l, CTCPLX) || isconst(r, CTCPLX)) { convlit(lp, types[TCOMPLEX128]); convlit(rp, types[TCOMPLEX128]); @@ -1063,6 +1149,13 @@ defaultlit2(Node **lp, Node **rp, int force) convlit(rp, types[TFLOAT64]); return; } + + if(isconst(l, CTRUNE) || isconst(r, CTRUNE)) { + convlit(lp, runetype); + convlit(rp, runetype); + return; + } + convlit(lp, types[TINT]); convlit(rp, types[TINT]); } @@ -1099,7 +1192,7 @@ cmpslit(Node *l, Node *r) int smallintconst(Node *n) { - if(n->op == OLITERAL && n->type != T) + if(n->op == OLITERAL && isconst(n, CTINT) && n->type != T) switch(simtype[n->type->etype]) { case TINT8: case TUINT8: @@ -1110,6 +1203,7 @@ smallintconst(Node *n) case TBOOL: case TPTR32: return 1; + case TIDEAL: case TINT64: case TUINT64: if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0 @@ -1200,6 +1294,7 @@ convconst(Node *con, Type *t, Val *val) default: fatal("convconst ctype=%d %lT", val->ctype, t); case CTINT: + case CTRUNE: i = mpgetfix(val->u.xval); break; case CTBOOL: diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c index 890cf7f10..dea7bc3bb 100644 --- a/src/cmd/gc/cplx.c +++ b/src/cmd/gc/cplx.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "gg.h" static void subnode(Node *nr, Node *ni, Node *nc); @@ -131,6 +133,9 @@ complexgen(Node *n, Node *res) dump("\ncomplexgen-n", n); dump("complexgen-res", res); } + + while(n->op == OCONVNOP) + n = n->left; // pick off float/complex opcodes switch(n->op) { @@ -199,6 +204,8 @@ complexgen(Node *n, Node *res) case OIND: case ONAME: // PHEAP or PPARAMREF var case OCALLFUNC: + case OCALLMETH: + case OCALLINTER: igen(n, &n1, res); complexmove(&n1, res); regfree(&n1); diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index 5bfeeb97a..4121a45ab 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -2,10 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" #include "y.tab.h" static void funcargs(Node*); +static void funcargs2(Type*); static int dflag(void) @@ -115,6 +118,8 @@ dumpdcl(char *st) Sym *s, *d; int i; + USED(st); + i = 0; for(d=dclstack; d!=S; d=d->link) { i++; @@ -170,6 +175,11 @@ declare(Node *n, int ctxt) n->lineno = parserline(); s = n->sym; + + // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later. + if(importpkg == nil && !typecheckok && s->pkg != localpkg) + yyerror("cannot declare name %S", s); + gen = 0; if(ctxt == PEXTERN) { externdcl = list(externdcl, n); @@ -188,7 +198,7 @@ declare(Node *n, int ctxt) n->curfn = curfn; } if(ctxt == PAUTO) - n->xoffset = BADWIDTH; + n->xoffset = 0; if(s->block == block) redeclare(s, "in this block"); @@ -411,6 +421,7 @@ oldname(Sym *s) c->funcdepth = funcdepth; c->outer = n->closure; n->closure = c; + n->addrtaken = 1; c->closure = n; c->xoffset = 0; curfn->cvars = list(curfn->cvars, c); @@ -468,7 +479,7 @@ colasdefn(NodeList *left, Node *defn) if(isblank(n)) continue; if(!colasname(n)) { - yyerror("non-name %#N on left side of :=", n); + yyerror("non-name %N on left side of :=", n); nerr++; continue; } @@ -542,13 +553,6 @@ ifacedcl(Node *n) void funchdr(Node *n) { - - if(n->nname != N) { - n->nname->op = ONAME; - declare(n->nname, PFUNC); - n->nname->defn = n; - } - // change the declaration context from extern to auto if(funcdepth == 0 && dclcontext != PEXTERN) fatal("funchdr: dclcontext"); @@ -559,16 +563,19 @@ funchdr(Node *n) n->outer = curfn; curfn = n; + if(n->nname) funcargs(n->nname->ntype); - else + else if (n->ntype) funcargs(n->ntype); + else + funcargs2(n->type); } static void funcargs(Node *nt) { - Node *n; + Node *n, *nn; NodeList *l; int gen; @@ -577,11 +584,11 @@ funcargs(Node *nt) // declare the receiver and in arguments. // no n->defn because type checking of func header - // will fill in the types before we can demand them. + // will not fill in the types until later if(nt->left != N) { n = nt->left; if(n->op != ODCLFIELD) - fatal("funcargs1 %O", n->op); + fatal("funcargs receiver %O", n->op); if(n->left != N) { n->left->op = ONAME; n->left->ntype = n->right; @@ -591,7 +598,7 @@ funcargs(Node *nt) for(l=nt->list; l; l=l->next) { n = l->n; if(n->op != ODCLFIELD) - fatal("funcargs2 %O", n->op); + fatal("funcargs in %O", n->op); if(n->left != N) { n->left->op = ONAME; n->left->ntype = n->right; @@ -604,12 +611,16 @@ funcargs(Node *nt) for(l=nt->rlist; l; l=l->next) { n = l->n; if(n->op != ODCLFIELD) - fatal("funcargs3 %O", n->op); + fatal("funcargs out %O", n->op); if(n->left != N) { n->left->op = ONAME; n->left->ntype = n->right; if(isblank(n->left)) { // Give it a name so we can assign to it during return. + // preserve the original in ->orig + nn = nod(OXXX, N, N); + *nn = *n->left; + n->left = nn; snprint(namebuf, sizeof(namebuf), ".anon%d", gen++); n->left->sym = lookup(namebuf); } @@ -619,6 +630,48 @@ funcargs(Node *nt) } /* + * Same as funcargs, except run over an already constructed TFUNC. + * This happens during import, where the hidden_fndcl rule has + * used functype directly to parse the function's type. + */ +static void +funcargs2(Type *t) +{ + Type *ft; + Node *n; + + if(t->etype != TFUNC) + fatal("funcargs2 %T", t); + + if(t->thistuple) + for(ft=getthisx(t)->type; ft; ft=ft->down) { + if(!ft->nname || !ft->nname->sym) + continue; + n = ft->nname; // no need for newname(ft->nname->sym) + n->type = ft->type; + declare(n, PPARAM); + } + + if(t->intuple) + for(ft=getinargx(t)->type; ft; ft=ft->down) { + if(!ft->nname || !ft->nname->sym) + continue; + n = ft->nname; + n->type = ft->type; + declare(n, PPARAM); + } + + if(t->outtuple) + for(ft=getoutargx(t)->type; ft; ft=ft->down) { + if(!ft->nname || !ft->nname->sym) + continue; + n = ft->nname; + n->type = ft->type; + declare(n, PPARAMOUT); + } +} + +/* * finish the body. * called in auto-declaration context. * returns in extern-declaration context. @@ -645,7 +698,7 @@ typedcl0(Sym *s) { Node *n; - n = dclname(s); + n = newname(s); n->op = OTYPE; declare(n, dclcontext); return n; @@ -665,217 +718,265 @@ typedcl1(Node *n, Node *t, int local) } /* - * typedcl1 but during imports + * structs, functions, and methods. + * they don't belong here, but where do they belong? */ -void -typedcl2(Type *pt, Type *t) + +static void +checkembeddedtype(Type *t) { - Node *n; + if (t == T) + return; - // override declaration in unsafe.go for Pointer. - // there is no way in Go code to define unsafe.Pointer - // so we have to supply it. - if(incannedimport && - strcmp(importpkg->name, "unsafe") == 0 && - strcmp(pt->nod->sym->name, "Pointer") == 0) { - t = types[TUNSAFEPTR]; + if(t->sym == S && isptr[t->etype]) { + t = t->type; + if(t->etype == TINTER) + yyerror("embedded type cannot be a pointer to interface"); } + if(isptr[t->etype]) + yyerror("embedded type cannot be a pointer"); + else if(t->etype == TFORW && t->embedlineno == 0) + t->embedlineno = lineno; +} - if(pt->etype == TFORW) - goto ok; - if(!eqtype(pt->orig, t)) - yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt->orig, t); - return; +static Type* +structfield(Node *n) +{ + Type *f; + int lno; -ok: - n = pt->nod; - copytype(pt->nod, t); - // unzero nod - pt->nod = n; + lno = lineno; + lineno = n->lineno; + + if(n->op != ODCLFIELD) + fatal("structfield: oops %N\n", n); + + f = typ(TFIELD); + f->isddd = n->isddd; + + if(n->right != N) { + typecheck(&n->right, Etype); + n->type = n->right->type; + if(n->left != N) + n->left->type = n->type; + if(n->embedded) + checkembeddedtype(n->type); + } + n->right = N; + + f->type = n->type; + if(f->type == T) + f->broke = 1; + + switch(n->val.ctype) { + case CTSTR: + f->note = n->val.u.sval; + break; + default: + yyerror("field annotation must be string"); + // fallthrough + case CTxxx: + f->note = nil; + break; + } - pt->sym->lastlineno = parserline(); - declare(n, PEXTERN); + if(n->left && n->left->op == ONAME) { + f->nname = n->left; + f->embedded = n->embedded; + f->sym = f->nname->sym; + } - checkwidth(pt); + lineno = lno; + return f; } -/* - * structs, functions, and methods. - * they don't belong here, but where do they belong? - */ +static void +checkdupfields(Type *t, char* what) +{ + Type* t1; + int lno; + lno = lineno; + + for( ; t; t=t->down) + if(t->sym && t->nname && !isblank(t->nname)) + for(t1=t->down; t1; t1=t1->down) + if(t1->sym == t->sym) { + lineno = t->nname->lineno; + yyerror("duplicate %s %s", what, t->sym->name); + break; + } + + lineno = lno; +} /* - * turn a parsed struct into a type + * convert a parsed id/type list into + * a type for struct/interface/arglist */ -static Type** -stotype(NodeList *l, int et, Type **t, int funarg) +Type* +tostruct(NodeList *l) { - Type *f, *t1, *t2, **t0; - Strlit *note; + Type *t, *f, **tp; + t = typ(TSTRUCT); + + for(tp = &t->type; l; l=l->next) { + f = structfield(l->n); + + *tp = f; + tp = &f->down; + } + + for(f=t->type; f && !t->broke; f=f->down) + if(f->broke) + t->broke = 1; + + checkdupfields(t->type, "field"); + + if (!t->broke) + checkwidth(t); + + return t; +} + +static Type* +tofunargs(NodeList *l) +{ + Type *t, *f, **tp; + + t = typ(TSTRUCT); + t->funarg = 1; + + for(tp = &t->type; l; l=l->next) { + f = structfield(l->n); + f->funarg = 1; + + // esc.c needs to find f given a PPARAM to add the tag. + if(l->n->left && l->n->left->class == PPARAM) + l->n->left->paramfld = f; + + *tp = f; + tp = &f->down; + } + + for(f=t->type; f && !t->broke; f=f->down) + if(f->broke) + t->broke = 1; + + checkdupfields(t->type, "argument"); + return t; +} + +static Type* +interfacefield(Node *n) +{ + Type *f; int lno; - Node *n, *left; - char *what; - t0 = t; lno = lineno; - what = "field"; - if(et == TINTER) - what = "method"; + lineno = n->lineno; - for(; l; l=l->next) { - n = l->n; - lineno = n->lineno; - note = nil; + if(n->op != ODCLFIELD) + fatal("interfacefield: oops %N\n", n); - if(n->op != ODCLFIELD) - fatal("stotype: oops %N\n", n); - left = n->left; - if(funarg && isblank(left)) - left = N; - if(n->right != N) { - if(et == TINTER && left != N) { - // queue resolution of method type for later. - // right now all we need is the name list. - // avoids cycles for recursive interface types. - n->type = typ(TINTERMETH); - n->type->nname = n->right; - n->right = N; - left->type = n->type; - queuemethod(n); - } else { - typecheck(&n->right, Etype); - n->type = n->right->type; - if(n->type == T) - continue; - if(left != N) - left->type = n->type; - n->right = N; - if(n->embedded && n->type != T) { - t1 = n->type; - if(t1->sym == S && isptr[t1->etype]) { - t1 = t1->type; - if(t1->etype == TINTER) - yyerror("embedded type cannot be a pointer to interface"); - } - if(isptr[t1->etype]) - yyerror("embedded type cannot be a pointer"); - else if(t1->etype == TFORW && t1->embedlineno == 0) - t1->embedlineno = lineno; - } + if (n->val.ctype != CTxxx) + yyerror("interface method cannot have annotation"); + + f = typ(TFIELD); + f->isddd = n->isddd; + + if(n->right != N) { + if(n->left != N) { + // queue resolution of method type for later. + // right now all we need is the name list. + // avoids cycles for recursive interface types. + n->type = typ(TINTERMETH); + n->type->nname = n->right; + n->left->type = n->type; + queuemethod(n); + + if(n->left->op == ONAME) { + f->nname = n->left; + f->embedded = n->embedded; + f->sym = f->nname->sym; + if(importpkg && !exportname(f->sym->name)) + f->sym = pkglookup(f->sym->name, structpkg); } - } - if(n->type == T) { - // assume error already printed - continue; - } + } else { - switch(n->val.ctype) { - case CTSTR: - if(et != TSTRUCT) - yyerror("interface method cannot have annotation"); - note = n->val.u.sval; - break; - default: - if(et != TSTRUCT) - yyerror("interface method cannot have annotation"); - else - yyerror("field annotation must be string"); - case CTxxx: - note = nil; - break; - } + typecheck(&n->right, Etype); + n->type = n->right->type; + + if(n->embedded) + checkembeddedtype(n->type); - if(et == TINTER && left == N) { - // embedded interface - inline the methods - if(n->type->etype != TINTER) { - if(n->type->etype == TFORW) + if(n->type) + switch(n->type->etype) { + case TINTER: + break; + case TFORW: yyerror("interface type loop involving %T", n->type); - else + f->broke = 1; + break; + default: yyerror("interface contains embedded non-interface %T", n->type); - continue; - } - for(t1=n->type->type; t1!=T; t1=t1->down) { - f = typ(TFIELD); - f->type = t1->type; - f->width = BADWIDTH; - f->nname = newname(t1->sym); - f->sym = t1->sym; - for(t2=*t0; t2!=T; t2=t2->down) { - if(t2->sym == f->sym) { - yyerror("duplicate method %s", t2->sym->name); - break; - } + f->broke = 1; + break; } - *t = f; - t = &f->down; - } - continue; } - - f = typ(TFIELD); - f->type = n->type; - f->note = note; - f->width = BADWIDTH; - f->isddd = n->isddd; - - if(left != N && left->op == ONAME) { - f->nname = left; - f->embedded = n->embedded; - f->sym = f->nname->sym; - if(importpkg && !exportname(f->sym->name)) - f->sym = pkglookup(f->sym->name, structpkg); - if(f->sym && !isblank(f->nname)) { - for(t1=*t0; t1!=T; t1=t1->down) { - if(t1->sym == f->sym) { - yyerror("duplicate %s %s", what, t1->sym->name); - break; - } - } - } - } - - *t = f; - t = &f->down; } - *t = T; + n->right = N; + + f->type = n->type; + if(f->type == T) + f->broke = 1; + lineno = lno; - return t; + return f; } Type* -dostruct(NodeList *l, int et) +tointerface(NodeList *l) { - Type *t; - int funarg; + Type *t, *f, **tp, *t1; - /* - * convert a parsed id/type list into - * a type for struct/interface/arglist - */ + t = typ(TINTER); - funarg = 0; - if(et == TFUNC) { - funarg = 1; - et = TSTRUCT; - } - t = typ(et); - t->funarg = funarg; - stotype(l, et, &t->type, funarg); - if(t->type == T && l != nil) { - t->broke = 1; - return t; + tp = &t->type; + for(; l; l=l->next) { + f = interfacefield(l->n); + + if (l->n->left == N && f->type->etype == TINTER) { + // embedded interface, inline methods + for(t1=f->type->type; t1; t1=t1->down) { + f = typ(TFIELD); + f->type = t1->type; + f->broke = t1->broke; + f->sym = t1->sym; + if(f->sym) + f->nname = newname(f->sym); + *tp = f; + tp = &f->down; + } + } else { + *tp = f; + tp = &f->down; + } } - if(et == TINTER) - t = sortinter(t); - if(!funarg) - checkwidth(t); + + for(f=t->type; f && !t->broke; f=f->down) + if(f->broke) + t->broke = 1; + + checkdupfields(t->type, "method"); + t = sortinter(t); + checkwidth(t); + return t; } - Node* embedded(Sym *s) { @@ -892,7 +993,10 @@ embedded(Sym *s) *utfrune(name, CenterDot) = 0; } - n = newname(lookup(name)); + if(exportname(name) || s->pkg == builtinpkg) // old behaviour, tests pass, but is it correct? + n = newname(lookup(name)); + else + n = newname(pkglookup(name, s->pkg)); n = nod(ODCLFIELD, n, oldname(s)); n->embedded = 1; return n; @@ -957,6 +1061,17 @@ checkarglist(NodeList *all, int input) t = n; n = N; } + + // during import l->n->op is OKEY, but l->n->left->sym == S + // means it was a '?', not that it was + // a lone type This doesn't matter for the exported + // declarations, which are parsed by rules that don't + // use checkargs, but can happen for func literals in + // the inline bodies. + // TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.c prints _ instead of ? + if(importpkg && n->sym == S) + n = N; + if(n != N && n->sym == S) { t = n; n = N; @@ -1030,9 +1145,12 @@ functype(Node *this, NodeList *in, NodeList *out) rcvr = nil; if(this) rcvr = list1(this); - t->type = dostruct(rcvr, TFUNC); - t->type->down = dostruct(out, TFUNC); - t->type->down->down = dostruct(in, TFUNC); + t->type = tofunargs(rcvr); + t->type->down = tofunargs(out); + t->type->down->down = tofunargs(in); + + if (t->type->broke || t->type->down->broke || t->type->down->down->broke) + t->broke = 1; if(this) t->thistuple = 1; @@ -1050,21 +1168,22 @@ methodsym(Sym *nsym, Type *t0, int iface) char *p; Type *t; char *suffix; + Pkg *spkg; + static Pkg *toppkg; t = t0; if(t == T) goto bad; s = t->sym; - if(s == S) { - if(!isptr[t->etype]) - goto bad; + if(s == S && isptr[t->etype]) { t = t->type; if(t == T) goto bad; s = t->sym; - if(s == S) - goto bad; } + spkg = nil; + if(s != S) + spkg = s->pkg; // if t0 == *t and t0 has a sym, // we want to see *t, not t0, in the method name. @@ -1077,11 +1196,23 @@ methodsym(Sym *nsym, Type *t0, int iface) if(t0->width < types[tptr]->width) suffix = "·i"; } - if(t0->sym == S && isptr[t0->etype]) - p = smprint("(%#hT).%s%s", t0, nsym->name, suffix); - else - p = smprint("%#hT.%s%s", t0, nsym->name, suffix); - s = pkglookup(p, s->pkg); + if((spkg == nil || nsym->pkg != spkg) && !exportname(nsym->name)) { + if(t0->sym == S && isptr[t0->etype]) + p = smprint("(%-hT).%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix); + else + p = smprint("%-hT.%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix); + } else { + if(t0->sym == S && isptr[t0->etype]) + p = smprint("(%-hT).%s%s", t0, nsym->name, suffix); + else + p = smprint("%-hT.%s%s", t0, nsym->name, suffix); + } + if(spkg == nil) { + if(toppkg == nil) + toppkg = mkpkg(strlit("go")); + spkg = toppkg; + } + s = pkglookup(p, spkg); free(p); return s; @@ -1114,11 +1245,16 @@ methodname1(Node *n, Node *t) } if(t->sym == S || isblank(n)) return newname(n->sym); + if(star) p = smprint("(%s%S).%S", star, t->sym, n->sym); else p = smprint("%S.%S", t->sym, n->sym); - n = newname(pkglookup(p, t->sym->pkg)); + + if(exportname(t->sym->name)) + n = newname(lookup(p)); + else + n = newname(pkglookup(p, t->sym->pkg)); free(p); return n; } @@ -1133,8 +1269,6 @@ addmethod(Sym *sf, Type *t, int local) Type *f, *d, *pa; Node *n; - pa = nil; - // get field sym if(sf == S) fatal("no method symbol"); @@ -1147,7 +1281,7 @@ addmethod(Sym *sf, Type *t, int local) } pa = pa->type; - f = methtype(pa); + f = methtype(pa, 1); if(f == T) { t = pa; if(t != T) { @@ -1159,6 +1293,8 @@ addmethod(Sym *sf, Type *t, int local) t = t->type; } } + if(t->broke) // rely on typecheck having complained before + return; if(t != T) { if(t->sym == S) { yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t); @@ -1180,8 +1316,14 @@ addmethod(Sym *sf, Type *t, int local) } pa = f; - if(importpkg && !exportname(sf->name)) - sf = pkglookup(sf->name, importpkg); + if(pa->etype == TSTRUCT) { + for(f=pa->type; f; f=f->down) { + if(f->sym == sf) { + yyerror("type %T has both field and method named %S", pa, sf); + return; + } + } + } n = nod(ODCLFIELD, newname(sf), N); n->type = t; @@ -1204,10 +1346,16 @@ addmethod(Sym *sf, Type *t, int local) return; } + f = structfield(n); + + // during import unexported method names should be in the type's package + if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg) + fatal("imported method name %+S in wrong package %s\n", f->sym, structpkg->name); + if(d == T) - stotype(list1(n), 0, &pa->method, 0); + pa->method = f; else - stotype(list1(n), 0, &d->down, 0); + d->down = f; return; } @@ -1249,6 +1397,3 @@ funccompile(Node *n, int isclosure) funcdepth = 0; dclcontext = PEXTERN; } - - - diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go index 3fe7fafdd..163d3862c 100644 --- a/src/cmd/gc/doc.go +++ b/src/cmd/gc/doc.go @@ -26,7 +26,7 @@ package P to read the files of P's dependencies, only the compiled output of P. Usage: - 6g [flags] file... + go tool 6g [flags] file... The specified files must be Go source files and all part of the same package. Substitute 6g with 8g or 5g where appropriate. @@ -35,12 +35,17 @@ Flags: output file, default file.6 for 6g, etc. -e normally the compiler quits after 10 errors; -e prints all errors + -p path + assume that path is the eventual import path for this code, + and diagnose any attempt to import a package that depends on it. + -D path + treat a relative import as relative to path -L 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 optimization + disable optimizations -S write assembly language text to standard output -u diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c new file mode 100644 index 000000000..2614b5f35 --- /dev/null +++ b/src/cmd/gc/esc.c @@ -0,0 +1,805 @@ +// Copyright 2011 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. +// +// Escape analysis. +// +// First escfunc, esc and escassign recurse over the ast of each +// function to dig out flow(dst,src) edges between any +// pointer-containing nodes and store them in dst->escflowsrc. For +// variables assigned to a variable in an outer scope or used as a +// return value, they store a flow(theSink, src) edge to a fake node +// 'the Sink'. For variables referenced in closures, an edge +// flow(closure, &var) is recorded and the flow of a closure itself to +// an outer scope is tracked the same way as other variables. +// +// Then escflood walks the graph starting at theSink and tags all +// variables of it can reach an & node as escaping and all function +// parameters it can reach as leaking. +// +// If a value's address is taken but the address does not escape, +// then the value can stay on the stack. If the value new(T) does +// not escape, then new(T) can be rewritten into a stack allocation. +// The same is true of slice literals. +// +// If escape analysis is disabled (-s), this code is not used. +// Instead, the compiler assumes that any value whose address +// is taken without being immediately dereferenced +// needs to be moved to the heap, and new(T) and slice +// literals are always real allocations. + +#include <u.h> +#include <libc.h> +#include "go.h" + +static void escfunc(Node *func); +static void esclist(NodeList *l); +static void esc(Node *n); +static void escloopdepthlist(NodeList *l); +static void escloopdepth(Node *n); +static void escassign(Node *dst, Node *src); +static void esccall(Node*); +static void escflows(Node *dst, Node *src); +static void escflood(Node *dst); +static void escwalk(int level, Node *dst, Node *src); +static void esctag(Node *func); + +// Fake node that all +// - return values and output variables +// - parameters on imported functions not marked 'safe' +// - assignments to global variables +// flow to. +static Node theSink; + +static NodeList* dsts; // all dst nodes +static int loopdepth; // for detecting nested loop scopes +static int pdepth; // for debug printing in recursions. +static Strlit* safetag; // gets slapped on safe parameters' field types for export +static int dstcount, edgecount; // diagnostic +static NodeList* noesc; // list of possible non-escaping nodes, for printing + +void +escapes(NodeList *all) +{ + NodeList *l; + + theSink.op = ONAME; + theSink.orig = &theSink; + theSink.class = PEXTERN; + theSink.sym = lookup(".sink"); + theSink.escloopdepth = -1; + + safetag = strlit("noescape"); + noesc = nil; + + // flow-analyze functions + for(l=all; l; l=l->next) + if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) + escfunc(l->n); + + // print("escapes: %d dsts, %d edges\n", dstcount, edgecount); + + // visit the updstream of each dst, mark address nodes with + // addrescapes, mark parameters unsafe + for(l = dsts; l; l=l->next) + escflood(l->n); + + // for all top level functions, tag the typenodes corresponding to the param nodes + for(l=all; l; l=l->next) + if(l->n->op == ODCLFUNC) + esctag(l->n); + + if(debug['m']) { + for(l=noesc; l; l=l->next) + if(l->n->esc == EscNone) + warnl(l->n->lineno, "%S %hN does not escape", + (l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S, + l->n); + } +} + + +static void +escfunc(Node *func) +{ + Node *savefn, *n; + NodeList *ll; + int saveld; + + saveld = loopdepth; + loopdepth = 1; + savefn = curfn; + curfn = func; + + for(ll=curfn->dcl; ll; ll=ll->next) { + if(ll->n->op != ONAME) + continue; + switch (ll->n->class) { + case PPARAMOUT: + // output parameters flow to the sink + escflows(&theSink, ll->n); + ll->n->escloopdepth = loopdepth; + break; + case PPARAM: + if(ll->n->type && !haspointers(ll->n->type)) + break; + ll->n->esc = EscNone; // prime for escflood later + noesc = list(noesc, ll->n); + ll->n->escloopdepth = loopdepth; + break; + } + } + + // walk will take the address of cvar->closure later and assign it to cvar. + // handle that here by linking a fake oaddr node directly to the closure. + for(ll=curfn->cvars; ll; ll=ll->next) { + if(ll->n->op == OXXX) // see dcl.c:398 + continue; + + n = nod(OADDR, ll->n->closure, N); + n->lineno = ll->n->lineno; + typecheck(&n, Erv); + escassign(curfn, n); + } + + escloopdepthlist(curfn->nbody); + esclist(curfn->nbody); + curfn = savefn; + loopdepth = saveld; +} + +// Mark labels that have no backjumps to them as not increasing loopdepth. +// Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat +// and set it to one of the following two. Then in esc we'll clear it again. +static Label looping; +static Label nonlooping; + +static void +escloopdepthlist(NodeList *l) +{ + for(; l; l=l->next) + escloopdepth(l->n); +} + +static void +escloopdepth(Node *n) +{ + if(n == N) + return; + + escloopdepthlist(n->ninit); + + switch(n->op) { + case OLABEL: + if(!n->left || !n->left->sym) + fatal("esc:label without label: %+N", n); + // Walk will complain about this label being already defined, but that's not until + // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc + // if(n->left->sym->label != nil) + // fatal("escape analysis messed up analyzing label: %+N", n); + n->left->sym->label = &nonlooping; + break; + case OGOTO: + if(!n->left || !n->left->sym) + fatal("esc:goto without label: %+N", n); + // If we come past one that's uninitialized, this must be a (harmless) forward jump + // but if it's set to nonlooping the label must have preceded this goto. + if(n->left->sym->label == &nonlooping) + n->left->sym->label = &looping; + break; + } + + escloopdepth(n->left); + escloopdepth(n->right); + escloopdepthlist(n->list); + escloopdepth(n->ntest); + escloopdepth(n->nincr); + escloopdepthlist(n->nbody); + escloopdepthlist(n->nelse); + escloopdepthlist(n->rlist); + +} + +static void +esclist(NodeList *l) +{ + for(; l; l=l->next) + esc(l->n); +} + +static void +esc(Node *n) +{ + int lno; + NodeList *ll, *lr; + + if(n == N) + return; + + lno = setlineno(n); + + if(n->op == OFOR || n->op == ORANGE) + loopdepth++; + + esc(n->left); + esc(n->right); + esc(n->ntest); + esc(n->nincr); + esclist(n->ninit); + esclist(n->nbody); + esclist(n->nelse); + esclist(n->list); + esclist(n->rlist); + + if(n->op == OFOR || n->op == ORANGE) + loopdepth--; + + if(debug['m'] > 1) + print("%L:[%d] %S esc: %N\n", lineno, loopdepth, + (curfn && curfn->nname) ? curfn->nname->sym : S, n); + + switch(n->op) { + case ODCL: + // Record loop depth at declaration. + if(n->left) + n->left->escloopdepth = loopdepth; + break; + + case OLABEL: + if(n->left->sym->label == &nonlooping) { + if(debug['m'] > 1) + print("%L:%N non-looping label\n", lineno, n); + } else if(n->left->sym->label == &looping) { + if(debug['m'] > 1) + print("%L: %N looping label\n", lineno, n); + loopdepth++; + } + // See case OLABEL in escloopdepth above + // else if(n->left->sym->label == nil) + // fatal("escape anaylysis missed or messed up a label: %+N", n); + + n->left->sym->label = nil; + + case ORANGE: + // Everything but fixed array is a dereference. + if(isfixedarray(n->type) && n->list->next) + escassign(n->list->next->n, n->right); + break; + + case OSWITCH: + if(n->ntest && n->ntest->op == OTYPESW) { + for(ll=n->list; ll; ll=ll->next) { // cases + // ntest->right is the argument of the .(type), + // ll->n->nname is the variable per case + escassign(ll->n->nname, n->ntest->right); + } + } + break; + + case OAS: + case OASOP: + escassign(n->left, n->right); + break; + + case OAS2: // x,y = a,b + if(count(n->list) == count(n->rlist)) + for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) + escassign(ll->n, lr->n); + break; + + case OAS2RECV: // v, ok = <-ch + case OAS2MAPR: // v, ok = m[k] + case OAS2DOTTYPE: // v, ok = x.(type) + escassign(n->list->n, n->rlist->n); + break; + + case OSEND: // ch <- x + escassign(&theSink, n->right); + break; + + case ODEFER: + if(loopdepth == 1) // top level + break; + // arguments leak out of scope + // TODO: leak to a dummy node instead + // fallthrough + case OPROC: + // go f(x) - f and x escape + escassign(&theSink, n->left->left); + escassign(&theSink, n->left->right); // ODDDARG for call + for(ll=n->left->list; ll; ll=ll->next) + escassign(&theSink, ll->n); + break; + + case ORETURN: + for(ll=n->list; ll; ll=ll->next) + escassign(&theSink, ll->n); + break; + + case OPANIC: + // Argument could leak through recover. + escassign(&theSink, n->left); + break; + + case OAPPEND: + if(!n->isddd) + for(ll=n->list->next; ll; ll=ll->next) + escassign(&theSink, ll->n); // lose track of assign to dereference + break; + + case OCALLMETH: + case OCALLFUNC: + case OCALLINTER: + esccall(n); + break; + + case OCONV: + case OCONVNOP: + case OCONVIFACE: + escassign(n, n->left); + break; + + case OARRAYLIT: + if(isslice(n->type)) { + n->esc = EscNone; // until proven otherwise + noesc = list(noesc, n); + n->escloopdepth = loopdepth; + // Values make it to memory, lose track. + for(ll=n->list; ll; ll=ll->next) + escassign(&theSink, ll->n->right); + } else { + // Link values to array. + for(ll=n->list; ll; ll=ll->next) + escassign(n, ll->n->right); + } + break; + + case OSTRUCTLIT: + // Link values to struct. + 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 + noesc = list(noesc, n); + n->escloopdepth = loopdepth; + // Keys and values make it to memory, lose track. + for(ll=n->list; ll; ll=ll->next) { + escassign(&theSink, ll->n->left); + escassign(&theSink, ll->n->right); + } + break; + + case OADDR: + case OCLOSURE: + case OMAKECHAN: + case OMAKEMAP: + case OMAKESLICE: + case ONEW: + n->escloopdepth = loopdepth; + n->esc = EscNone; // until proven otherwise + noesc = list(noesc, n); + break; + } + + lineno = lno; +} + +// Assert that expr somehow gets assigned to dst, if non nil. for +// dst==nil, any name node expr still must be marked as being +// evaluated in curfn. For expr==nil, dst must still be examined for +// evaluations inside it (e.g *f(x) = y) +static void +escassign(Node *dst, Node *src) +{ + int lno; + + if(isblank(dst) || dst == N || src == N || src->op == ONONAME || src->op == OXXX) + return; + + if(debug['m'] > 1) + print("%L:[%d] %S escassign: %hN = %hN\n", lineno, loopdepth, + (curfn && curfn->nname) ? curfn->nname->sym : S, dst, src); + + setlineno(dst); + + // Analyze lhs of assignment. + // Replace dst with theSink if we can't track it. + switch(dst->op) { + default: + dump("dst", dst); + fatal("escassign: unexpected dst"); + + case OARRAYLIT: + case OCLOSURE: + case OCONV: + case OCONVIFACE: + case OCONVNOP: + case OMAPLIT: + case OSTRUCTLIT: + break; + + case ONAME: + if(dst->class == PEXTERN) + dst = &theSink; + break; + case ODOT: // treat "dst.x = src" as "dst = src" + escassign(dst->left, src); + return; + case OINDEX: + if(isfixedarray(dst->left->type)) { + escassign(dst->left, src); + return; + } + dst = &theSink; // lose track of dereference + break; + case OIND: + case ODOTPTR: + dst = &theSink; // lose track of dereference + break; + case OINDEXMAP: + // lose track of key and value + escassign(&theSink, dst->right); + dst = &theSink; + break; + } + + lno = setlineno(src); + pdepth++; + + switch(src->op) { + case OADDR: // dst = &x + case OIND: // dst = *x + case ODOTPTR: // dst = (*x).f + case ONAME: + case OPARAM: + case ODDDARG: + case OPTRLIT: + case OARRAYLIT: + case OMAPLIT: + case OSTRUCTLIT: + // loopdepth was set in the defining statement or function header + escflows(dst, src); + break; + + case ODOT: + // A non-pointer escaping from a struct does not concern us. + if(src->type && !haspointers(src->type)) + break; + // fallthrough + case OCONV: + case OCONVIFACE: + case OCONVNOP: + case ODOTMETH: // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC + // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here + case ODOTTYPE: + case ODOTTYPE2: + case OSLICE: + case OSLICEARR: + // Conversions, field access, slice all preserve the input value. + escassign(dst, src->left); + break; + + case OAPPEND: + // Append returns first argument. + escassign(dst, src->list->n); + break; + + case OINDEX: + // Index of array preserves input value. + if(isfixedarray(src->left->type)) + escassign(dst, src->left); + break; + + case OMAKECHAN: + case OMAKEMAP: + case OMAKESLICE: + case ONEW: + escflows(dst, src); + break; + + case OCLOSURE: + escflows(dst, src); + escfunc(src); + break; + + case OADD: + case OSUB: + case OOR: + case OXOR: + case OMUL: + case ODIV: + case OMOD: + case OLSH: + case ORSH: + case OAND: + case OANDNOT: + case OPLUS: + case OMINUS: + case OCOM: + // Might be pointer arithmetic, in which case + // the operands flow into the result. + // TODO(rsc): Decide what the story is here. This is unsettling. + escassign(dst, src->left); + escassign(dst, src->right); + break; + + } + + pdepth--; + lineno = lno; +} + + +// This is a bit messier than fortunate, pulled out of escassign's big +// switch for clarity. We either have the paramnodes, which may be +// connected to other things throug flows or we have the parameter type +// nodes, which may be marked 'n(ofloworescape)'. Navigating the ast is slightly +// different for methods vs plain functions and for imported vs +// this-package +static void +esccall(Node *n) +{ + NodeList *ll, *lr; + Node *a, *fn, *src; + Type *t, *fntype; + + fn = N; + switch(n->op) { + default: + fatal("esccall"); + + case OCALLFUNC: + fn = n->left; + fntype = fn->type; + break; + + case OCALLMETH: + fn = n->left->right->sym->def; + if(fn) + fntype = fn->type; + else + fntype = n->left->type; + break; + + case OCALLINTER: + fntype = n->left->type; + break; + } + + ll = n->list; + if(n->list != nil && n->list->next == nil) { + a = n->list->n; + if(a->type->etype == TSTRUCT && a->type->funarg) { + // f(g()). + // Since f's arguments are g's results and + // all function results escape, we're done. + ll = nil; + } + } + + if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype) { + // Local function. Incorporate into flow graph. + + // Receiver. + if(n->op != OCALLFUNC) + escassign(fn->ntype->left->left, n->left->left); + + for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) { + src = ll->n; + if(lr->n->isddd && !n->isddd) { + // Introduce ODDDARG node to represent ... allocation. + src = nod(ODDDARG, N, N); + src->escloopdepth = loopdepth; + src->lineno = n->lineno; + src->esc = EscNone; // until we find otherwise + noesc = list(noesc, src); + n->right = src; + } + if(lr->n->left != N) + escassign(lr->n->left, src); + if(src != ll->n) + break; + } + // "..." arguments are untracked + for(; ll; ll=ll->next) + escassign(&theSink, ll->n); + return; + } + + // Imported function. Use the escape tags. + if(n->op != OCALLFUNC) { + t = getthisx(fntype)->type; + if(!t->note || strcmp(t->note->s, safetag->s) != 0) + escassign(&theSink, n->left->left); + } + for(t=getinargx(fntype)->type; ll; ll=ll->next) { + src = ll->n; + if(t->isddd && !n->isddd) { + // Introduce ODDDARG node to represent ... allocation. + src = nod(ODDDARG, N, N); + src->escloopdepth = loopdepth; + src->lineno = n->lineno; + src->esc = EscNone; // until we find otherwise + noesc = list(noesc, src); + n->right = src; + } + if(!t->note || strcmp(t->note->s, safetag->s) != 0) + escassign(&theSink, src); + if(src != ll->n) + break; + t = t->down; + } + // "..." arguments are untracked + for(; ll; ll=ll->next) + escassign(&theSink, ll->n); +} + +// Store the link src->dst in dst, throwing out some quick wins. +static void +escflows(Node *dst, Node *src) +{ + if(dst == nil || src == nil || dst == src) + return; + + // Don't bother building a graph for scalars. + if(src->type && !haspointers(src->type)) + return; + + if(debug['m']>2) + print("%L::flows:: %hN <- %hN\n", lineno, dst, src); + + if(dst->escflowsrc == nil) { + dsts = list(dsts, dst); + dstcount++; + } + edgecount++; + + dst->escflowsrc = list(dst->escflowsrc, src); +} + +// Whenever we hit a reference node, the level goes up by one, and whenever +// we hit an OADDR, the level goes down by one. as long as we're on a level > 0 +// finding an OADDR just means we're following the upstream of a dereference, +// so this address doesn't leak (yet). +// If level == 0, it means the /value/ of this node can reach the root of this flood. +// so if this node is an OADDR, it's argument should be marked as escaping iff +// it's currfn/loopdepth are different from the flood's root. +// Once an object has been moved to the heap, all of it's upstream should be considered +// escaping to the global scope. +static void +escflood(Node *dst) +{ + NodeList *l; + + switch(dst->op) { + case ONAME: + case OCLOSURE: + break; + default: + return; + } + + if(debug['m']>1) + print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst, + (dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S, + dst->escloopdepth); + + for(l = dst->escflowsrc; l; l=l->next) { + walkgen++; + escwalk(0, dst, l->n); + } +} + +static void +escwalk(int level, Node *dst, Node *src) +{ + NodeList *ll; + int leaks; + + if(src->walkgen == walkgen) + return; + src->walkgen = walkgen; + + if(debug['m']>1) + print("escwalk: level:%d depth:%d %.*s %hN scope:%S[%d]\n", + level, pdepth, pdepth, "\t\t\t\t\t\t\t\t\t\t", src, + (src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth); + + pdepth++; + + leaks = (level <= 0) && (dst->escloopdepth < src->escloopdepth); + + switch(src->op) { + case ONAME: + if(src->class == PPARAM && leaks && src->esc == EscNone) { + src->esc = EscScope; + if(debug['m']) + warnl(src->lineno, "leaking param: %hN", src); + } + break; + + case OPTRLIT: + case OADDR: + if(leaks) { + src->esc = EscHeap; + addrescapes(src->left); + if(debug['m']) + warnl(src->lineno, "%hN escapes to heap", src); + } + escwalk(level-1, dst, src->left); + break; + + case OARRAYLIT: + if(isfixedarray(src->type)) + break; + // fall through + case ODDDARG: + case OMAKECHAN: + case OMAKEMAP: + case OMAKESLICE: + case OMAPLIT: + case ONEW: + case OCLOSURE: + if(leaks) { + src->esc = EscHeap; + if(debug['m']) + warnl(src->lineno, "%hN escapes to heap", src); + } + break; + + case OINDEX: + if(isfixedarray(src->type)) + break; + // fall through + case OSLICE: + case ODOTPTR: + case OINDEXMAP: + case OIND: + escwalk(level+1, dst, src->left); + } + + for(ll=src->escflowsrc; ll; ll=ll->next) + escwalk(level, dst, ll->n); + + pdepth--; +} + +static void +esctag(Node *func) +{ + Node *savefn; + NodeList *ll; + + // External functions must be assumed unsafe. + if(func->nbody == nil) + return; + + savefn = curfn; + curfn = func; + + for(ll=curfn->dcl; ll; ll=ll->next) { + if(ll->n->op != ONAME || ll->n->class != PPARAM) + continue; + + switch (ll->n->esc) { + case EscNone: // not touched by escflood + if(haspointers(ll->n->type)) // don't bother tagging for scalars + ll->n->paramfld->note = safetag; + case EscHeap: // touched by escflood, moved to heap + case EscScope: // touched by escflood, value leaves scope + break; + } + } + + curfn = savefn; +} diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c index 014f0c5f0..bbed8ae36 100644 --- a/src/cmd/gc/export.c +++ b/src/cmd/gc/export.c @@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" #include "y.tab.h" -static void dumpsym(Sym*); -static void dumpexporttype(Sym*); -static void dumpexportvar(Sym*); -static void dumpexportconst(Sym*); +static void dumpexporttype(Type *t); +// Mark n's symbol as exported void exportsym(Node *n) { @@ -25,6 +25,7 @@ exportsym(Node *n) exportlist = list(exportlist, n); } +// Mark n's symbol as package-local static void packagesym(Node *n) { @@ -77,7 +78,7 @@ dumppkg(Pkg *p) { char *suffix; - if(p == nil || p == localpkg || p->exported) + if(p == nil || p == localpkg || p->exported || p == builtinpkg) return; p->exported = 1; suffix = ""; @@ -86,25 +87,84 @@ dumppkg(Pkg *p) Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix); } +// Look for anything we need for the inline body +static void reexportdep(Node *n); static void -dumpprereq(Type *t) +reexportdeplist(NodeList *ll) { - if(t == T) - return; + for(; ll ;ll=ll->next) + reexportdep(ll->n); +} + +static void +reexportdep(Node *n) +{ + Type *t; - if(t->printed || t == types[t->etype]) + if(!n) return; - t->printed = 1; - if(t->sym != S) { - dumppkg(t->sym->pkg); - if(t->etype != TFIELD) - dumpsym(t->sym); +// print("reexportdep %+hN\n", n); + switch(n->op) { + case ONAME: + switch(n->class&~PHEAP) { + case PFUNC: + // methods will be printed along with their type + if(!n->type || n->type->thistuple > 0) + break; + // fallthrough + case PEXTERN: + if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg) + exportlist = list(exportlist, n); + } + break; + + + case OLITERAL: + t = n->type; + if(t != types[n->type->etype] && t != idealbool && t != idealstring) { + if(isptr[t->etype]) + t = t->type; + if (t && t->sym && t->sym->def && t->sym->pkg != localpkg && t->sym->pkg != builtinpkg) { +// print("reexport literal type %+hN\n", t->sym->def); + exportlist = list(exportlist, t->sym->def); + } + } + // fallthrough + case OTYPE: + if (n->sym && n->sym->pkg != localpkg && n->sym->pkg != builtinpkg) + exportlist = list(exportlist, n); + break; + + // for operations that need a type when rendered, put the type on the export list. + case OCONV: + case OCONVIFACE: + case OCONVNOP: + case ODOTTYPE: + case OSTRUCTLIT: + case OPTRLIT: + t = n->type; + if(!t->sym && t->type) + t = t->type; + if (t && t->sym && t->sym->def && t->sym->pkg != localpkg && t->sym->pkg != builtinpkg) { +// print("reexport convnop %+hN\n", t->sym->def); + exportlist = list(exportlist, t->sym->def); + } + break; } - dumpprereq(t->type); - dumpprereq(t->down); + + reexportdep(n->left); + reexportdep(n->right); + reexportdeplist(n->list); + reexportdeplist(n->rlist); + reexportdeplist(n->ninit); + reexportdep(n->ntest); + reexportdep(n->nincr); + reexportdeplist(n->nbody); + reexportdeplist(n->nelse); } + static void dumpexportconst(Sym *s) { @@ -117,37 +177,12 @@ dumpexportconst(Sym *s) fatal("dumpexportconst: oconst nil: %S", s); t = n->type; // may or may not be specified - if(t != T) - dumpprereq(t); + dumpexporttype(t); - Bprint(bout, "\t"); - Bprint(bout, "const %#S", s); if(t != T && !isideal(t)) - Bprint(bout, " %#T", t); - Bprint(bout, " = "); - - switch(n->val.ctype) { - default: - fatal("dumpexportconst: unknown ctype: %S %d", s, n->val.ctype); - case CTINT: - Bprint(bout, "%B\n", n->val.u.xval); - break; - case CTBOOL: - if(n->val.u.bval) - Bprint(bout, "true\n"); - else - Bprint(bout, "false\n"); - break; - case CTFLT: - Bprint(bout, "%F\n", n->val.u.fval); - break; - case CTCPLX: - Bprint(bout, "(%F+%F)\n", &n->val.u.cval->real, &n->val.u.cval->imag); - break; - case CTSTR: - Bprint(bout, "\"%Z\"\n", n->val.u.sval); - break; - } + Bprint(bout, "\tconst %#S %#T = %#V\n", s, t, &n->val); + else + Bprint(bout, "\tconst %#S = %#V\n", s, &n->val); } static void @@ -157,38 +192,27 @@ dumpexportvar(Sym *s) Type *t; n = s->def; - typecheck(&n, Erv); + typecheck(&n, Erv|Ecall); if(n == N || n->type == T) { yyerror("variable exported but not defined: %S", s); return; } t = n->type; - dumpprereq(t); - - Bprint(bout, "\t"); - if(t->etype == TFUNC && n->class == PFUNC) - Bprint(bout, "func %#S %#hhT", s, t); - else - Bprint(bout, "var %#S %#T", s, t); - Bprint(bout, "\n"); -} - -static void -dumpexporttype(Sym *s) -{ - Type *t; - - t = s->def->type; - dumpprereq(t); - Bprint(bout, "\t"); - switch (t->etype) { - case TFORW: - yyerror("export of incomplete type %T", t); - return; - } - if(Bprint(bout, "type %#T %l#T\n", t, t) < 0) - fatal("Bprint failed for %T", t); + dumpexporttype(t); + + if(t->etype == TFUNC && n->class == PFUNC) { + if (n->inl) { + // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. + // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package + if(debug['l'] < 2) + typecheckinl(n); + Bprint(bout, "\tfunc %#S%#hT { %#H }\n", s, t, n->inl); + reexportdeplist(n->inl); + } else + Bprint(bout, "\tfunc %#S%#hT\n", s, t); + } else + Bprint(bout, "\tvar %#S %#T\n", s, t); } static int @@ -202,12 +226,57 @@ methcmp(const void *va, const void *vb) } static void -dumpsym(Sym *s) +dumpexporttype(Type *t) { - Type *f, *t; + Type *f; Type **m; int i, n; + if(t == T) + return; + if(t->printed || t == types[t->etype] || t == bytetype || t == runetype || t == errortype) + return; + t->printed = 1; + + if(t->sym != S && t->etype != TFIELD) + dumppkg(t->sym->pkg); + + dumpexporttype(t->type); + dumpexporttype(t->down); + + if (t->sym == S || t->etype == TFIELD) + return; + + n = 0; + for(f=t->method; f!=T; f=f->down) { + dumpexporttype(f); + n++; + } + + m = mal(n*sizeof m[0]); + i = 0; + for(f=t->method; f!=T; f=f->down) + m[i++] = f; + qsort(m, n, sizeof m[0], methcmp); + + Bprint(bout, "\ttype %#S %#lT\n", t->sym, t); + for(i=0; i<n; i++) { + f = m[i]; + if (f->type->nname && f->type->nname->inl) { // nname was set by caninl + // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. + // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package + if(debug['l'] < 2) + typecheckinl(f->type->nname); + Bprint(bout, "\tfunc (%#T) %#hhS%#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl); + reexportdeplist(f->type->nname->inl); + } else + Bprint(bout, "\tfunc (%#T) %#hhS%#hT\n", getthisx(f->type)->type, f->sym, f->type); + } +} + +static void +dumpsym(Sym *s) +{ if(s->flags & SymExported) return; s->flags |= SymExported; @@ -216,56 +285,31 @@ dumpsym(Sym *s) yyerror("unknown export symbol: %S", s); return; } - +// print("dumpsym %O %+S\n", s->def->op, s); dumppkg(s->pkg); switch(s->def->op) { default: yyerror("unexpected export symbol: %O %S", s->def->op, s); break; + case OLITERAL: dumpexportconst(s); break; + case OTYPE: - t = s->def->type; - n = 0; - for(f=t->method; f!=T; f=f->down) { - dumpprereq(f); - n++; - } - m = mal(n*sizeof m[0]); - i = 0; - for(f=t->method; f!=T; f=f->down) - m[i++] = f; - qsort(m, n, sizeof m[0], methcmp); - - dumpexporttype(s); - for(i=0; i<n; i++) { - f = m[i]; - Bprint(bout, "\tfunc (%#T) %hS %#hhT\n", - f->type->type->type, f->sym, f->type); - } + if(s->def->type->etype == TFORW) + yyerror("export of incomplete type %S", s); + else + dumpexporttype(s->def->type); break; + case ONAME: dumpexportvar(s); break; } } -static void -dumptype(Type *t) -{ - // no need to re-dump type if already exported - if(t->printed) - return; - - // no need to dump type if it's not ours (was imported) - if(t->sym != S && t->sym->def == typenod(t) && !t->local) - return; - - Bprint(bout, "type %#T %l#T\n", t, t); -} - void dumpexport(void) { @@ -275,10 +319,7 @@ dumpexport(void) lno = lineno; - packagequotes = 1; - Bprint(bout, "\n$$ // exports\n"); - - Bprint(bout, " package %s", localpkg->name); + Bprint(bout, "\n$$ // exports\n package %s", localpkg->name); if(safemode) Bprint(bout, " safe"); Bprint(bout, "\n"); @@ -293,15 +334,7 @@ dumpexport(void) dumpsym(l->n->sym); } - Bprint(bout, "\n$$ // local types\n"); - - for(l=typelist; l; l=l->next) { - lineno = l->n->lineno; - dumptype(l->n->type); - } - - Bprint(bout, "\n$$\n"); - packagequotes = 0; + Bprint(bout, "\n$$ // local types\n\n$$\n"); // 6l expects this. (see ld/go.c) lineno = lno; } @@ -344,16 +377,29 @@ pkgtype(Sym *s) s->def = typenod(t); } if(s->def->type == T) - yyerror("pkgtype %lS", s); + yyerror("pkgtype %S", s); return s->def->type; } -static int -mypackage(Sym *s) +void +importimport(Sym *s, Strlit *z) { - // we import all definitions for runtime. - // lowercase ones can only be used by the compiler. - return s->pkg == localpkg || s->pkg == runtimepkg; + // Informational: record package name + // associated with import path, for use in + // human-readable messages. + Pkg *p; + + p = mkpkg(z); + if(p->name == nil) { + p->name = s->name; + pkglookup(s->name, nil)->npkg++; + } else if(strcmp(p->name, s->name) != 0) + yyerror("conflicting names %s and %s for package \"%Z\"", p->name, s->name, p->path); + + if(!incannedimport && myimportpath != nil && strcmp(z->s, myimportpath) == 0) { + yyerror("import \"%Z\": package depends on \"%Z\" (import cycle)", importpkg->path, z); + errorexit(); + } } void @@ -361,24 +407,23 @@ importconst(Sym *s, Type *t, Node *n) { Node *n1; - if(!exportname(s->name) && !mypackage(s)) - return; importsym(s, OLITERAL); convlit(&n, t); - if(s->def != N) { - // TODO: check if already the same. + + if(s->def != N) // TODO: check if already the same. return; - } if(n->op != OLITERAL) { yyerror("expression must be a constant"); return; } + if(n->sym != S) { n1 = nod(OXXX, N, N); *n1 = *n; n = n1; } + n->orig = newname(s); n->sym = s; declare(n, PEXTERN); @@ -387,23 +432,19 @@ importconst(Sym *s, Type *t, Node *n) } void -importvar(Sym *s, Type *t, int ctxt) +importvar(Sym *s, Type *t) { Node *n; - if(!exportname(s->name) && !initname(s->name) && !mypackage(s)) - return; - importsym(s, ONAME); if(s->def != N && s->def->op == ONAME) { if(eqtype(t, s->def->type)) return; - yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T", - s, s->def->type, t); + yyerror("inconsistent definition for var %S during import\n\t%T\n\t%T", s, s->def->type, t); } n = newname(s); n->type = t; - declare(n, ctxt); + declare(n, PEXTERN); if(debug['E']) print("import var %S %lT\n", s, t); @@ -412,17 +453,27 @@ importvar(Sym *s, Type *t, int ctxt) void importtype(Type *pt, Type *t) { - if(pt != T && t != T) - typedcl2(pt, t); + Node *n; + + // override declaration in unsafe.go for Pointer. + // there is no way in Go code to define unsafe.Pointer + // so we have to supply it. + if(incannedimport && + strcmp(importpkg->name, "unsafe") == 0 && + strcmp(pt->nod->sym->name, "Pointer") == 0) { + t = types[TUNSAFEPTR]; + } + + if(pt->etype == TFORW) { + n = pt->nod; + copytype(pt->nod, t); + pt->nod = n; // unzero nod + pt->sym->lastlineno = parserline(); + declare(n, PEXTERN); + checkwidth(pt); + } else if(!eqtype(pt->orig, t)) + yyerror("inconsistent definition for type %S during import\n\t%lT\n\t%lT", pt->sym, pt, t); if(debug['E']) print("import type %T %lT\n", pt, t); } - -void -importmethod(Sym *s, Type *t) -{ - checkwidth(t); - addmethod(s, t, 0); -} - diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c new file mode 100644 index 000000000..5672c0010 --- /dev/null +++ b/src/cmd/gc/fmt.c @@ -0,0 +1,1639 @@ +// Copyright 2011 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. + +#include <u.h> +#include <libc.h> +#include "go.h" +#include "opnames.h" + +// +// Format conversions +// %L int Line numbers +// +// %E int etype values (aka 'Kind') +// +// %O int Node Opcodes +// Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg) +// +// %J Node* Node details +// Flags: "%hJ" supresses things not relevant until walk. +// +// %V Val* Constant values +// +// %S Sym* Symbols +// Flags: +,- #: mode (see below) +// "%hS" unqualified identifier in any mode +// "%hhS" in export mode: unqualified identifier if exported, qualified if not +// +// %T Type* Types +// Flags: +,- #: mode (see below) +// 'l' definition instead of name. +// 'h' omit "func" and receiver in function types +// 'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix. +// +// %N Node* Nodes +// Flags: +,- #: mode (see below) +// 'h' (only in +/debug mode) suppress recursion +// 'l' (only in Error mode) print "foo (type Bar)" +// +// %H NodeList* NodeLists +// Flags: those of %N +// ',' separate items with ',' instead of ';' +// +// %Z Strlit* String literals +// +// In mparith1.c: +// %B Mpint* Big integers +// %F Mpflt* Big floats +// +// %S, %T and %N obey use the following flags to set the format mode: +enum { + FErr, // error mode (default) + FDbg, // "%+N" debug mode + FExp, // "%#N" export mode + FTypeId, // "%-N" turning-types-into-symbols-mode: identical types give identical strings +}; +static int fmtmode; +static int fmtpkgpfx; // %uT stickyness +// +// E.g. for %S: %+S %#S %-S print an identifier properly qualified for debug/export/internal mode. +// +// The mode flags +, - and # are sticky, meaning they persist through +// recursions of %N, %T and %S, but not the h and l flags. The u flag is +// sticky only on %T recursions and only used in %-/Sym mode. + +// +// Useful format combinations: +// +// %+N %+H multiline recursive debug dump of node/nodelist +// %+hN %+hH non recursive debug dump +// +// %#N %#T export format +// %#lT type definition instead of name +// %#hT omit"func" and receiver in function signature +// +// %lN "foo (type Bar)" for error messages +// +// %-T type identifiers +// %-hT type identifiers without "func" and arg names in type signatures (methodsym) +// %-uT type identifiers with package name instead of prefix (typesym, dcommontype, typehash) +// + + +static int +setfmode(unsigned long *flags) +{ + int fm; + + fm = fmtmode; + if(*flags & FmtSign) + fmtmode = FDbg; + else if(*flags & FmtSharp) + fmtmode = FExp; + else if(*flags & FmtLeft) + fmtmode = FTypeId; + + *flags &= ~(FmtSharp|FmtLeft|FmtSign); + return fm; +} + +// Fmt "%L": Linenumbers +static int +Lconv(Fmt *fp) +{ + struct + { + Hist* incl; /* start of this include file */ + int32 idel; /* delta line number to apply to include */ + Hist* line; /* start of this #line directive */ + int32 ldel; /* delta line number to apply to #line */ + } a[HISTSZ]; + int32 lno, d; + int i, n; + Hist *h; + + lno = va_arg(fp->args, int32); + + n = 0; + for(h=hist; h!=H; h=h->link) { + if(h->offset < 0) + continue; + if(lno < h->line) + break; + if(h->name) { + if(h->offset > 0) { + // #line directive + if(n > 0 && n < HISTSZ) { + a[n-1].line = h; + a[n-1].ldel = h->line - h->offset + 1; + } + } else { + // beginning of file + if(n < HISTSZ) { + a[n].incl = h; + a[n].idel = h->line; + a[n].line = 0; + } + n++; + } + continue; + } + n--; + if(n > 0 && n < HISTSZ) { + d = h->line - a[n].incl->line; + a[n-1].ldel += d; + a[n-1].idel += d; + } + } + + if(n > HISTSZ) + n = HISTSZ; + + for(i=n-1; i>=0; i--) { + if(i != n-1) { + if(fp->flags & ~(FmtWidth|FmtPrec)) + break; + fmtprint(fp, " "); + } + if(debug['L'] || (fp->flags&FmtLong)) + fmtprint(fp, "%s/", pathname); + if(a[i].line) + fmtprint(fp, "%s:%d[%s:%d]", + a[i].line->name, lno-a[i].ldel+1, + a[i].incl->name, lno-a[i].idel+1); + else + fmtprint(fp, "%s:%d", + a[i].incl->name, lno-a[i].idel+1); + lno = a[i].incl->line - 1; // now print out start of this file + } + if(n == 0) + fmtprint(fp, "<epoch>"); + + return 0; +} + +static char* +goopnames[] = +{ + [OADDR] = "&", + [OADD] = "+", + [OADDSTR] = "+", + [OANDAND] = "&&", + [OANDNOT] = "&^", + [OAND] = "&", + [OAPPEND] = "append", + [OAS] = "=", + [OAS2] = "=", + [OBREAK] = "break", + [OCALL] = "function call", // not actual syntax + [OCAP] = "cap", + [OCASE] = "case", + [OCLOSE] = "close", + [OCOMPLEX] = "complex", + [OCOM] = "^", + [OCONTINUE] = "continue", + [OCOPY] = "copy", + [ODEC] = "--", + [ODELETE] = "delete", + [ODEFER] = "defer", + [ODIV] = "/", + [OEQ] = "==", + [OFALL] = "fallthrough", + [OFOR] = "for", + [OGE] = ">=", + [OGOTO] = "goto", + [OGT] = ">", + [OIF] = "if", + [OIMAG] = "imag", + [OINC] = "++", + [OIND] = "*", + [OLEN] = "len", + [OLE] = "<=", + [OLSH] = "<<", + [OLT] = "<", + [OMAKE] = "make", + [OMINUS] = "-", + [OMOD] = "%", + [OMUL] = "*", + [ONEW] = "new", + [ONE] = "!=", + [ONOT] = "!", + [OOROR] = "||", + [OOR] = "|", + [OPANIC] = "panic", + [OPLUS] = "+", + [OPRINTN] = "println", + [OPRINT] = "print", + [ORANGE] = "range", + [OREAL] = "real", + [ORECV] = "<-", + [ORETURN] = "return", + [ORSH] = ">>", + [OSELECT] = "select", + [OSEND] = "<-", + [OSUB] = "-", + [OSWITCH] = "switch", + [OXOR] = "^", +}; + +// Fmt "%O": Node opcodes +static int +Oconv(Fmt *fp) +{ + int o; + + o = va_arg(fp->args, int); + if((fp->flags & FmtSharp) || fmtmode != FDbg) + if(o >= 0 && o < nelem(goopnames) && goopnames[o] != nil) + return fmtstrcpy(fp, goopnames[o]); + + if(o >= 0 && o < nelem(opnames) && opnames[o] != nil) + return fmtstrcpy(fp, opnames[o]); + + return fmtprint(fp, "O-%d", o); +} + +static const char* classnames[] = { + "Pxxx", + "PEXTERN", + "PAUTO", + "PPARAM", + "PPARAMOUT", + "PPARAMREF", + "PFUNC", +}; + +// Fmt "%J": Node details. +static int +Jconv(Fmt *fp) +{ + Node *n; + char *s; + int c; + + n = va_arg(fp->args, Node*); + + c = fp->flags&FmtShort; + + if(!c && n->ullman != 0) + fmtprint(fp, " u(%d)", n->ullman); + + if(!c && n->addable != 0) + fmtprint(fp, " a(%d)", n->addable); + + if(!c && n->vargen != 0) + fmtprint(fp, " g(%d)", n->vargen); + + if(n->lineno != 0) + fmtprint(fp, " l(%d)", n->lineno); + + if(!c && n->xoffset != BADWIDTH) + fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta); + + if(n->class != 0) { + s = ""; + if(n->class & PHEAP) s = ",heap"; + if((n->class & ~PHEAP) < nelem(classnames)) + fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s); + else + fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s); + } + + if(n->colas != 0) + fmtprint(fp, " colas(%d)", n->colas); + + if(n->funcdepth != 0) + fmtprint(fp, " f(%d)", n->funcdepth); + + switch(n->esc) { + case EscUnknown: + break; + case EscHeap: + fmtprint(fp, " esc(h)"); + break; + case EscScope: + fmtprint(fp, " esc(s)"); + break; + case EscNone: + fmtprint(fp, " esc(no)"); + break; + case EscNever: + if(!c) + fmtprint(fp, " esc(N)"); + break; + default: + fmtprint(fp, " esc(%d)", n->esc); + break; + } + + if(n->escloopdepth) + fmtprint(fp, " ld(%d)", n->escloopdepth); + + if(!c && n->typecheck != 0) + fmtprint(fp, " tc(%d)", n->typecheck); + + if(!c && n->dodata != 0) + fmtprint(fp, " dd(%d)", n->dodata); + + if(n->isddd != 0) + fmtprint(fp, " isddd(%d)", n->isddd); + + if(n->implicit != 0) + fmtprint(fp, " implicit(%d)", n->implicit); + + if(n->embedded != 0) + fmtprint(fp, " embedded(%d)", n->embedded); + + if(!c && n->used != 0) + fmtprint(fp, " used(%d)", n->used); + return 0; +} + +// Fmt "%V": Values +static int +Vconv(Fmt *fp) +{ + Val *v; + vlong x; + + v = va_arg(fp->args, Val*); + + switch(v->ctype) { + case CTINT: + return fmtprint(fp, "%B", v->u.xval); + case CTRUNE: + x = mpgetfix(v->u.xval); + if(' ' <= x && x < 0x80 && x != '\\' && x != '\'') + return fmtprint(fp, "'%c'", (int)x); + if(0 <= x && x < (1<<16)) + return fmtprint(fp, "'\\u%04ux'", (int)x); + if(0 <= x && x <= Runemax) + return fmtprint(fp, "'\\U%08llux'", x); + return fmtprint(fp, "('\\x00' + %B)", v->u.xval); + case CTFLT: + if((fp->flags & FmtSharp) || fmtmode == FExp) + return fmtprint(fp, "%F", v->u.fval); + return fmtprint(fp, "%#F", v->u.fval); + case CTCPLX: + if((fp->flags & FmtSharp) || fmtmode == FExp) + return fmtprint(fp, "(%F+%F)", &v->u.cval->real, &v->u.cval->imag); + return fmtprint(fp, "(%#F + %#Fi)", &v->u.cval->real, &v->u.cval->imag); + case CTSTR: + return fmtprint(fp, "\"%Z\"", v->u.sval); + case CTBOOL: + if( v->u.bval) + return fmtstrcpy(fp, "true"); + return fmtstrcpy(fp, "false"); + case CTNIL: + return fmtstrcpy(fp, "nil"); + } + return fmtprint(fp, "<%d>", v->ctype); +} + +// Fmt "%Z": escaped string literals +static int +Zconv(Fmt *fp) +{ + Rune r; + Strlit *sp; + char *s, *se; + int n; + + sp = va_arg(fp->args, Strlit*); + if(sp == nil) + return fmtstrcpy(fp, "<nil>"); + + s = sp->s; + se = s + sp->len; + while(s < se) { + n = chartorune(&r, s); + s += n; + switch(r) { + case Runeerror: + if(n == 1) { + fmtprint(fp, "\\x%02x", (uchar)*(s-1)); + break; + } + // fall through + default: + if(r < ' ') { + fmtprint(fp, "\\x%02x", r); + break; + } + fmtrune(fp, r); + break; + case '\t': + fmtstrcpy(fp, "\\t"); + break; + case '\n': + fmtstrcpy(fp, "\\n"); + break; + case '\"': + case '\\': + fmtrune(fp, '\\'); + fmtrune(fp, r); + break; + } + } + return 0; +} + +/* +s%,%,\n%g +s%\n+%\n%g +s%^[ ]*T%%g +s%,.*%%g +s%.+% [T&] = "&",%g +s%^ ........*\]%&~%g +s%~ %%g +*/ + +static char* +etnames[] = +{ + [TINT] = "INT", + [TUINT] = "UINT", + [TINT8] = "INT8", + [TUINT8] = "UINT8", + [TINT16] = "INT16", + [TUINT16] = "UINT16", + [TINT32] = "INT32", + [TUINT32] = "UINT32", + [TINT64] = "INT64", + [TUINT64] = "UINT64", + [TUINTPTR] = "UINTPTR", + [TFLOAT32] = "FLOAT32", + [TFLOAT64] = "FLOAT64", + [TCOMPLEX64] = "COMPLEX64", + [TCOMPLEX128] = "COMPLEX128", + [TBOOL] = "BOOL", + [TPTR32] = "PTR32", + [TPTR64] = "PTR64", + [TFUNC] = "FUNC", + [TARRAY] = "ARRAY", + [TSTRUCT] = "STRUCT", + [TCHAN] = "CHAN", + [TMAP] = "MAP", + [TINTER] = "INTER", + [TFORW] = "FORW", + [TFIELD] = "FIELD", + [TSTRING] = "STRING", + [TANY] = "ANY", +}; + +// Fmt "%E": etype +static int +Econv(Fmt *fp) +{ + int et; + + et = va_arg(fp->args, int); + if(et >= 0 && et < nelem(etnames) && etnames[et] != nil) + return fmtstrcpy(fp, etnames[et]); + return fmtprint(fp, "E-%d", et); +} + +// Fmt "%S": syms +static int +symfmt(Fmt *fp, Sym *s) +{ + char *p; + + if(s->pkg && !(fp->flags&FmtShort)) { + switch(fmtmode) { + case FErr: // This is for the user + if(s->pkg == localpkg) + return fmtstrcpy(fp, s->name); + // If the name was used by multiple packages, display the full path, + if(s->pkg->name && pkglookup(s->pkg->name, nil)->npkg > 1) + return fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name); + return fmtprint(fp, "%s.%s", s->pkg->name, s->name); + case FDbg: + return fmtprint(fp, "%s.%s", s->pkg->name, s->name); + case FTypeId: + if(fp->flags&FmtUnsigned) + return fmtprint(fp, "%s.%s", s->pkg->name, s->name); // dcommontype, typehash + return fmtprint(fp, "%s.%s", s->pkg->prefix, s->name); // (methodsym), typesym, weaksym + case FExp: + if(s->pkg != builtinpkg) + return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, s->name); + } + } + + if(fp->flags&FmtByte) { // FmtByte (hh) implies FmtShort (h) + // skip leading "type." in method name + p = utfrrune(s->name, '.'); + if(p) + p++; + else + p = s->name; + + // exportname needs to see the name without the prefix too. + if((fmtmode == FExp && !exportname(p)) || fmtmode == FDbg) + return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, p); + + return fmtstrcpy(fp, p); + } + + return fmtstrcpy(fp, s->name); +} + +static char* +basicnames[] = +{ + [TINT] = "int", + [TUINT] = "uint", + [TINT8] = "int8", + [TUINT8] = "uint8", + [TINT16] = "int16", + [TUINT16] = "uint16", + [TINT32] = "int32", + [TUINT32] = "uint32", + [TINT64] = "int64", + [TUINT64] = "uint64", + [TUINTPTR] = "uintptr", + [TFLOAT32] = "float32", + [TFLOAT64] = "float64", + [TCOMPLEX64] = "complex64", + [TCOMPLEX128] = "complex128", + [TBOOL] = "bool", + [TANY] = "any", + [TSTRING] = "string", + [TNIL] = "nil", + [TIDEAL] = "ideal", + [TBLANK] = "blank", +}; + +static int +typefmt(Fmt *fp, Type *t) +{ + Type *t1; + Sym *s; + + if(t == T) + return fmtstrcpy(fp, "<T>"); + + if (t == bytetype || t == runetype) { + // in %-T mode collapse rune and byte with their originals. + if(fmtmode != FTypeId) + return fmtprint(fp, "%hS", t->sym); + t = types[t->etype]; + } + + if(t == errortype) + return fmtstrcpy(fp, "error"); + + // Unless the 'l' flag was specified, if the type has a name, just print that name. + if(!(fp->flags&FmtLong) && t->sym && t->etype != TFIELD && t != types[t->etype]) { + switch(fmtmode) { + case FTypeId: + if(fp->flags&FmtShort) + return fmtprint(fp, "%hS", t->sym); + if(fp->flags&FmtUnsigned) + return fmtprint(fp, "%uS", t->sym); + // fallthrough + case FExp: + if(t->sym->pkg == localpkg && t->vargen) + return fmtprint(fp, "%S·%d", t->sym, t->vargen); + break; + } + return fmtprint(fp, "%S", t->sym); + } + + if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) { + if(fmtmode == FErr && (t == idealbool || t == idealstring)) + fmtstrcpy(fp, "ideal "); + return fmtstrcpy(fp, basicnames[t->etype]); + } + + if(fmtmode == FDbg) + fmtprint(fp, "%E-", t->etype); + + switch(t->etype) { + case TPTR32: + case TPTR64: + if(fmtmode == FTypeId && (fp->flags&FmtShort)) + return fmtprint(fp, "*%hT", t->type); + return fmtprint(fp, "*%T", t->type); + + case TARRAY: + if(t->bound >= 0) + return fmtprint(fp, "[%d]%T", (int)t->bound, t->type); + if(t->bound == -100) + return fmtprint(fp, "[...]%T", t->type); + return fmtprint(fp, "[]%T", t->type); + + case TCHAN: + switch(t->chan) { + case Crecv: + return fmtprint(fp, "<-chan %T", t->type); + case Csend: + return fmtprint(fp, "chan<- %T", t->type); + } + + if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv) + return fmtprint(fp, "chan (%T)", t->type); + return fmtprint(fp, "chan %T", t->type); + + case TMAP: + return fmtprint(fp, "map[%T]%T", t->down, t->type); + + case TINTER: + fmtstrcpy(fp, "interface {"); + for(t1=t->type; t1!=T; t1=t1->down) + if(exportname(t1->sym->name)) { + if(t1->down) + fmtprint(fp, " %hS%hT;", t1->sym, t1->type); + else + fmtprint(fp, " %hS%hT ", t1->sym, t1->type); + } else { + // non-exported method names must be qualified + if(t1->down) + fmtprint(fp, " %uS%hT;", t1->sym, t1->type); + else + fmtprint(fp, " %uS%hT ", t1->sym, t1->type); + } + fmtstrcpy(fp, "}"); + return 0; + + case TFUNC: + if(fp->flags & FmtShort) { + fmtprint(fp, "%T", getinargx(t)); + } else { + if(t->thistuple) + fmtprint(fp, "method%T func%T", getthisx(t), getinargx(t)); + else + fmtprint(fp, "func%T", getinargx(t)); + } + switch(t->outtuple) { + case 0: + break; + case 1: + if(fmtmode != FExp) { + fmtprint(fp, " %T", getoutargx(t)->type->type); // struct->field->field's type + break; + } + default: + fmtprint(fp, " %T", getoutargx(t)); + break; + } + return 0; + + case TSTRUCT: + if(t->funarg) { + fmtstrcpy(fp, "("); + if(fmtmode == FTypeId || fmtmode == FErr) { // no argument names on function signature, and no "noescape" tags + for(t1=t->type; t1!=T; t1=t1->down) + if(t1->down) + fmtprint(fp, "%hT, ", t1); + else + fmtprint(fp, "%hT", t1); + } else { + for(t1=t->type; t1!=T; t1=t1->down) + if(t1->down) + fmtprint(fp, "%T, ", t1); + else + fmtprint(fp, "%T", t1); + } + fmtstrcpy(fp, ")"); + } else { + fmtstrcpy(fp, "struct {"); + for(t1=t->type; t1!=T; t1=t1->down) + if(t1->down) + fmtprint(fp, " %lT;", t1); + else + fmtprint(fp, " %lT ", t1); + fmtstrcpy(fp, "}"); + } + return 0; + + case TFIELD: + if(!(fp->flags&FmtShort)) { + s = t->sym; + // Take the name from the original, lest we substituted it with .anon%d + if (t->nname && (fmtmode == FErr || fmtmode == FExp)) + s = t->nname->orig->sym; + + if(s != S && !t->embedded) { + if(fp->flags&FmtLong) + fmtprint(fp, "%hhS ", s); // qualify non-exported names (used on structs, not on funarg) + else + fmtprint(fp, "%S ", s); + } else if(fmtmode == FExp) { + // TODO(rsc) this breaks on the eliding of unused arguments in the backend + // when this is fixed, the special case in dcl.c checkarglist can go. + //if(t->funarg) + // fmtstrcpy(fp, "_ "); + //else + fmtstrcpy(fp, "? "); + } + } + + if(t->isddd) + fmtprint(fp, "...%T", t->type->type); + else + fmtprint(fp, "%T", t->type); + + if(!(fp->flags&FmtShort) && t->note) + fmtprint(fp, " \"%Z\"", t->note); + return 0; + + case TFORW: + if(t->sym) + return fmtprint(fp, "undefined %S", t->sym); + return fmtstrcpy(fp, "undefined"); + + case TUNSAFEPTR: + if(fmtmode == FExp) + return fmtprint(fp, "@\"unsafe\".Pointer"); + return fmtprint(fp, "unsafe.Pointer"); + } + + if(fmtmode == FExp) + fatal("missing %E case during export", t->etype); + // Don't know how to handle - fall back to detailed prints. + return fmtprint(fp, "%E <%S> %T", t->etype, t->sym, t->type); +} + +// Statements which may be rendered with a simplestmt as init. +static int +stmtwithinit(int op) +{ + switch(op) { + case OIF: + case OFOR: + case OSWITCH: + return 1; + } + return 0; +} + +static int +stmtfmt(Fmt *f, Node *n) +{ + int complexinit, simpleinit, extrablock; + + // some statements allow for an init, but at most one, + // but we may have an arbitrary number added, eg by typecheck + // and inlining. If it doesn't fit the syntax, emit an enclosing + // block starting with the init statements. + + // if we can just say "for" n->ninit; ... then do so + simpleinit = n->ninit && !n->ninit->next && !n->ninit->n->ninit && stmtwithinit(n->op); + // otherwise, print the inits as separate statements + complexinit = n->ninit && !simpleinit && (fmtmode != FErr); + // but if it was for if/for/switch, put in an extra surrounding block to limit the scope + extrablock = complexinit && stmtwithinit(n->op); + + if(extrablock) + fmtstrcpy(f, "{"); + + if(complexinit) + fmtprint(f, " %H; ", n->ninit); + + switch(n->op){ + case ODCL: + fmtprint(f, "var %S %T", n->left->sym, n->left->type); + break; + + case ODCLFIELD: + if(n->left) + fmtprint(f, "%N %N", n->left, n->right); + else + fmtprint(f, "%N", n->right); + break; + + case OAS: + if(n->colas && !complexinit) + fmtprint(f, "%N := %N", n->left, n->right); + else + fmtprint(f, "%N = %N", n->left, n->right); + break; + + case OASOP: + fmtprint(f, "%N %#O= %N", n->left, n->etype, n->right); + break; + + case OAS2: + if(n->colas && !complexinit) { + fmtprint(f, "%,H := %,H", n->list, n->rlist); + break; + } + // fallthrough + case OAS2DOTTYPE: + case OAS2FUNC: + case OAS2MAPR: + case OAS2RECV: + fmtprint(f, "%,H = %,H", n->list, n->rlist); + break; + + case ORETURN: + fmtprint(f, "return %,H", n->list); + break; + + case OPROC: + fmtprint(f, "go %N", n->left); + break; + + case ODEFER: + fmtprint(f, "defer %N", n->left); + break; + + case OIF: + if(simpleinit) + fmtprint(f, "if %N; %N { %H }", n->ninit->n, n->ntest, n->nbody); + else + fmtprint(f, "if %N { %H }", n->ntest, n->nbody); + if(n->nelse) + fmtprint(f, " else { %H }", n->nelse); + break; + + case OFOR: + if(fmtmode == FErr) { // TODO maybe only if FmtShort, same below + fmtstrcpy(f, "for loop"); + break; + } + + fmtstrcpy(f, "for"); + if(simpleinit) + fmtprint(f, " %N;", n->ninit->n); + else if(n->nincr) + fmtstrcpy(f, " ;"); + + if(n->ntest) + fmtprint(f, " %N", n->ntest); + + if(n->nincr) + fmtprint(f, "; %N", n->nincr); + else if(simpleinit) + fmtstrcpy(f, ";"); + + + fmtprint(f, " { %H }", n->nbody); + break; + + case ORANGE: + if(fmtmode == FErr) { + fmtstrcpy(f, "for loop"); + break; + } + + fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody); + break; + + case OSELECT: + case OSWITCH: + if(fmtmode == FErr) { + fmtprint(f, "%O statement", n->op); + break; + } + + fmtprint(f, "%#O", n->op); + if(simpleinit) + fmtprint(f, " %N;", n->ninit->n); + if(n->ntest) + fmtprint(f, "%N", n->ntest); + + fmtprint(f, " { %H }", n->list); + break; + + case OCASE: + case OXCASE: + if(n->list) + fmtprint(f, "case %,H: %H", n->list, n->nbody); + else + fmtprint(f, "default: %H", n->nbody); + break; + + case OBREAK: + case OCONTINUE: + case OGOTO: + case OFALL: + case OXFALL: + if(n->left) + fmtprint(f, "%#O %N", n->op, n->left); + else + fmtprint(f, "%#O", n->op); + break; + + case OEMPTY: + break; + + case OLABEL: + fmtprint(f, "%N: ", n->left); + break; + + } + + if(extrablock) + fmtstrcpy(f, "}"); + + return 0; +} + + +static int opprec[] = { + [OAPPEND] = 8, + [OARRAYBYTESTR] = 8, + [OARRAYLIT] = 8, + [OARRAYRUNESTR] = 8, + [OCALLFUNC] = 8, + [OCALLINTER] = 8, + [OCALLMETH] = 8, + [OCALL] = 8, + [OCAP] = 8, + [OCLOSE] = 8, + [OCONVIFACE] = 8, + [OCONVNOP] = 8, + [OCONV] = 8, + [OCOPY] = 8, + [ODELETE] = 8, + [OLEN] = 8, + [OLITERAL] = 8, + [OMAKESLICE] = 8, + [OMAKE] = 8, + [OMAPLIT] = 8, + [ONAME] = 8, + [ONEW] = 8, + [ONONAME] = 8, + [OPACK] = 8, + [OPANIC] = 8, + [OPAREN] = 8, + [OPRINTN] = 8, + [OPRINT] = 8, + [ORECV] = 8, + [ORUNESTR] = 8, + [OSTRARRAYBYTE] = 8, + [OSTRARRAYRUNE] = 8, + [OSTRUCTLIT] = 8, + [OTARRAY] = 8, + [OTCHAN] = 8, + [OTFUNC] = 8, + [OTINTER] = 8, + [OTMAP] = 8, + [OTPAREN] = 8, + [OTSTRUCT] = 8, + + [OINDEXMAP] = 8, + [OINDEX] = 8, + [OSLICE] = 8, + [OSLICESTR] = 8, + [OSLICEARR] = 8, + [ODOTINTER] = 8, + [ODOTMETH] = 8, + [ODOTPTR] = 8, + [ODOTTYPE2] = 8, + [ODOTTYPE] = 8, + [ODOT] = 8, + [OXDOT] = 8, + + [OPLUS] = 7, + [ONOT] = 7, + [OCOM] = 7, + [OMINUS] = 7, + [OADDR] = 7, + [OIND] = 7, + + [OMUL] = 6, + [ODIV] = 6, + [OMOD] = 6, + [OLSH] = 6, + [ORSH] = 6, + [OAND] = 6, + [OANDNOT] = 6, + + [OADD] = 5, + [OSUB] = 5, + [OOR] = 5, + [OXOR] = 5, + + [OEQ] = 4, + [OLT] = 4, + [OLE] = 4, + [OGE] = 4, + [OGT] = 4, + [ONE] = 4, + [OCMPSTR] = 4, + [OCMPIFACE] = 4, + + [OSEND] = 3, + [OANDAND] = 2, + [OOROR] = 1, + + // Statements handled by stmtfmt + [OAS] = -1, + [OAS2] = -1, + [OAS2DOTTYPE] = -1, + [OAS2FUNC] = -1, + [OAS2MAPR] = -1, + [OAS2RECV] = -1, + [OASOP] = -1, + [OBREAK] = -1, + [OCASE] = -1, + [OCONTINUE] = -1, + [ODCL] = -1, + [ODCLFIELD] = -1, + [ODEFER] = -1, + [OEMPTY] = -1, + [OFALL] = -1, + [OFOR] = -1, + [OIF] = -1, + [OLABEL] = -1, + [OPROC] = -1, + [ORANGE] = -1, + [ORETURN] = -1, + [OSELECT] = -1, + [OSWITCH] = -1, + [OXCASE] = -1, + [OXFALL] = -1, + + [OEND] = 0 +}; + +static int +exprfmt(Fmt *f, Node *n, int prec) +{ + int nprec; + NodeList *l; + Type *t; + + while(n && n->implicit && (n->op == OIND || n->op == OADDR)) + n = n->left; + + if(n == N) + return fmtstrcpy(f, "<N>"); + + nprec = opprec[n->op]; + if(n->op == OTYPE && n->sym != S) + nprec = 8; + + if(prec > nprec) + return fmtprint(f, "(%N)", n); + + switch(n->op) { + case OPAREN: + return fmtprint(f, "(%N)", n->left); + + case ODDDARG: + return fmtprint(f, "... argument"); + + case OREGISTER: + return fmtprint(f, "%R", n->val.u.reg); + + case OLITERAL: // this is a bit of a mess + if(fmtmode == FErr && n->sym != S) + return fmtprint(f, "%S", n->sym); + if(n->val.ctype == CTNIL) + n = n->orig; // if this node was a nil decorated with at type, print the original naked nil + if(n->type != types[n->type->etype] && n->type != idealbool && n->type != idealstring) { + // Need parens when type begins with what might + // be misinterpreted as a unary operator: * or <-. + if(isptr[n->type->etype] || (n->type->etype == TCHAN && n->type->chan == Crecv)) + return fmtprint(f, "(%T)(%V)", n->type, &n->val); + else + return fmtprint(f, "%T(%V)", n->type, &n->val); + } + return fmtprint(f, "%V", &n->val); + + case ONAME: + // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method, + // but for export, this should be rendered as (*pkg.T).meth. + // These nodes have the special property that they are names with a left OTYPE and a right ONAME. + if(fmtmode == FExp && n->left && n->left->op == OTYPE && n->right && n->right->op == ONAME) { + if(isptr[n->left->type->etype]) + return fmtprint(f, "(%T).%hhS", n->left->type, n->right->sym); + else + return fmtprint(f, "%T.%hhS", n->left->type, n->right->sym); + } + //fallthrough + case OPACK: + case ONONAME: + return fmtprint(f, "%S", n->sym); + + case OTYPE: + if(n->type == T && n->sym != S) + return fmtprint(f, "%S", n->sym); + return fmtprint(f, "%T", n->type); + + case OTARRAY: + if(n->left) + return fmtprint(f, "[]%N", n->left); + return fmtprint(f, "[]%N", n->right); // happens before typecheck + + case OTPAREN: + return fmtprint(f, "(%N)", n->left); + + case OTMAP: + return fmtprint(f, "map[%N]%N", n->left, n->right); + + case OTCHAN: + switch(n->etype) { + case Crecv: + return fmtprint(f, "<-chan %N", n->left); + case Csend: + return fmtprint(f, "chan<- %N", n->left); + default: + if(n->left != N && n->left->op == TCHAN && n->left->sym == S && n->left->etype == Crecv) + return fmtprint(f, "chan (%N)", n->left); + else + return fmtprint(f, "chan %N", n->left); + } + + case OTSTRUCT: + return fmtprint(f, "<struct>"); + + case OTINTER: + return fmtprint(f, "<inter>"); + + case OTFUNC: + return fmtprint(f, "<func>"); + + case OCLOSURE: + if(fmtmode == FErr) + return fmtstrcpy(f, "func literal"); + return fmtprint(f, "%T { %H }", n->type, n->nbody); + + case OCOMPLIT: + if(fmtmode == FErr) + return fmtstrcpy(f, "composite literal"); + return fmtprint(f, "%N{ %,H }", n->right, n->list); + + case OPTRLIT: + if(fmtmode == FExp && n->left->implicit) + return fmtprint(f, "%N", n->left); + return fmtprint(f, "&%N", n->left); + + case OSTRUCTLIT: + if(fmtmode == FExp) { // requires special handling of field names + if(n->implicit) + fmtstrcpy(f, "{"); + else + fmtprint(f, "%T{", n->type); + for(l=n->list; l; l=l->next) { + // another special case: if n->left is an embedded field of builtin type, + // it needs to be non-qualified. Can't figure that out in %S, so do it here + if(l->n->left->type->embedded) { + t = l->n->left->type->type; + if(t->sym == S) + t = t->type; + fmtprint(f, " %T:%N", t, l->n->right); + } else + fmtprint(f, " %hhS:%N", l->n->left->sym, l->n->right); + + if(l->next) + fmtstrcpy(f, ","); + else + fmtstrcpy(f, " "); + } + return fmtstrcpy(f, "}"); + } + // fallthrough + + case OARRAYLIT: + case OMAPLIT: + if(fmtmode == FErr) + return fmtprint(f, "%T literal", n->type); + if(fmtmode == FExp && n->implicit) + return fmtprint(f, "{ %,H }", n->list); + return fmtprint(f, "%T{ %,H }", n->type, n->list); + + case OKEY: + if(n->left && n->right) + return fmtprint(f, "%N:%N", n->left, n->right); + if(!n->left && n->right) + return fmtprint(f, ":%N", n->right); + if(n->left && !n->right) + return fmtprint(f, "%N:", n->left); + return fmtstrcpy(f, ":"); + + case OXDOT: + case ODOT: + case ODOTPTR: + case ODOTINTER: + case ODOTMETH: + exprfmt(f, n->left, nprec); + if(n->right == N || n->right->sym == S) + fmtstrcpy(f, ".<nil>"); + return fmtprint(f, ".%hhS", n->right->sym); + + case ODOTTYPE: + case ODOTTYPE2: + exprfmt(f, n->left, nprec); + if(n->right != N) + return fmtprint(f, ".(%N)", n->right); + return fmtprint(f, ".(%T)", n->type); + + case OINDEX: + case OINDEXMAP: + case OSLICE: + case OSLICESTR: + case OSLICEARR: + exprfmt(f, n->left, nprec); + return fmtprint(f, "[%N]", n->right); + + case OCOPY: + case OCOMPLEX: + return fmtprint(f, "%#O(%N, %N)", n->op, n->left, n->right); + + case OCONV: + case OCONVIFACE: + case OCONVNOP: + case OARRAYBYTESTR: + case OARRAYRUNESTR: + case OSTRARRAYBYTE: + case OSTRARRAYRUNE: + case ORUNESTR: + if(n->type == T || n->type->sym == S) + return fmtprint(f, "(%T)(%N)", n->type, n->left); + if(n->left) + return fmtprint(f, "%T(%N)", n->type, n->left); + return fmtprint(f, "%T(%,H)", n->type, n->list); + + case OREAL: + case OIMAG: + case OAPPEND: + case OCAP: + case OCLOSE: + case ODELETE: + case OLEN: + case OMAKE: + case ONEW: + case OPANIC: + case OPRINT: + case OPRINTN: + if(n->left) + return fmtprint(f, "%#O(%N)", n->op, n->left); + if(n->isddd) + return fmtprint(f, "%#O(%,H...)", n->op, n->list); + return fmtprint(f, "%#O(%,H)", n->op, n->list); + + case OCALL: + case OCALLFUNC: + case OCALLINTER: + case OCALLMETH: + exprfmt(f, n->left, nprec); + if(n->isddd) + return fmtprint(f, "(%,H...)", n->list); + return fmtprint(f, "(%,H)", n->list); + + case OMAKEMAP: + case OMAKECHAN: + case OMAKESLICE: + if(n->list) // pre-typecheck + return fmtprint(f, "make(%T, %,H)", n->type, n->list); + if(n->right) + return fmtprint(f, "make(%T, %N, %N)", n->type, n->left, n->right); + if(n->left) + return fmtprint(f, "make(%T, %N)", n->type, n->left); + return fmtprint(f, "make(%T)", n->type); + + // Unary + case OPLUS: + case OMINUS: + case OADDR: + case OCOM: + case OIND: + case ONOT: + case ORECV: + if(n->left->op == n->op) + fmtprint(f, "%#O ", n->op); + else + fmtprint(f, "%#O", n->op); + return exprfmt(f, n->left, nprec+1); + + // Binary + case OADD: + case OADDSTR: + case OAND: + case OANDAND: + case OANDNOT: + case ODIV: + case OEQ: + case OGE: + case OGT: + case OLE: + case OLT: + case OLSH: + case OMOD: + case OMUL: + case ONE: + case OOR: + case OOROR: + case ORSH: + case OSEND: + case OSUB: + case OXOR: + exprfmt(f, n->left, nprec); + fmtprint(f, " %#O ", n->op); + exprfmt(f, n->right, nprec+1); + return 0; + + case OCMPSTR: + case OCMPIFACE: + exprfmt(f, n->left, nprec); + fmtprint(f, " %#O ", n->etype); + exprfmt(f, n->right, nprec+1); + return 0; + } + + return fmtprint(f, "<node %O>", n->op); +} + +static int +nodefmt(Fmt *f, Node *n) +{ + Type *t; + + t = n->type; + + // we almost always want the original, except in export mode for literals + // this saves the importer some work, and avoids us having to redo some + // special casing for package unsafe + if((fmtmode != FExp || n->op != OLITERAL) && n->orig != N) + n = n->orig; + + if(f->flags&FmtLong && t != T) { + if(t->etype == TNIL) + return fmtprint(f, "nil"); + else + return fmtprint(f, "%N (type %T)", n, t); + } + + // TODO inlining produces expressions with ninits. we can't print these yet. + + if(opprec[n->op] < 0) + return stmtfmt(f, n); + + return exprfmt(f, n, 0); +} + +static int dumpdepth; + +static void +indent(Fmt *fp) +{ + int i; + + fmtstrcpy(fp, "\n"); + for(i = 0; i < dumpdepth; ++i) + fmtstrcpy(fp, ". "); +} + +static int +nodedump(Fmt *fp, Node *n) +{ + int recur; + + if(n == N) + return 0; + + recur = !(fp->flags&FmtShort); + + if(recur) { + indent(fp); + if(dumpdepth > 10) + return fmtstrcpy(fp, "..."); + + if(n->ninit != nil) { + fmtprint(fp, "%O-init%H", n->op, n->ninit); + indent(fp); + } + } + +// fmtprint(fp, "[%p]", n); + + switch(n->op) { + default: + fmtprint(fp, "%O%J", n->op, n); + break; + case OREGISTER: + fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n); + break; + case OLITERAL: + fmtprint(fp, "%O-%V%J", n->op, &n->val, n); + break; + case ONAME: + case ONONAME: + if(n->sym != S) + fmtprint(fp, "%O-%S%J", n->op, n->sym, n); + else + fmtprint(fp, "%O%J", n->op, n); + break; + case OASOP: + fmtprint(fp, "%O-%O%J", n->op, n->etype, n); + break; + case OTYPE: + fmtprint(fp, "%O %S%J type=%T", n->op, n->sym, n, n->type); + if(recur && n->type == T && n->ntype) { + indent(fp); + fmtprint(fp, "%O-ntype%N", n->op, n->ntype); + } + break; + } + + if(n->sym != S && n->op != ONAME) + fmtprint(fp, " %S G%d", n->sym, n->vargen); + + if(n->type != T) + fmtprint(fp, " %T", n->type); + + if(recur) { + if(n->left) + fmtprint(fp, "%N", n->left); + if(n->right) + fmtprint(fp, "%N", n->right); + if(n->list) { + indent(fp); + fmtprint(fp, "%O-list%H", n->op, n->list); + } + if(n->rlist) { + indent(fp); + fmtprint(fp, "%O-rlist%H", n->op, n->rlist); + } + if(n->ntest) { + indent(fp); + fmtprint(fp, "%O-test%N", n->op, n->ntest); + } + if(n->nbody) { + indent(fp); + fmtprint(fp, "%O-body%H", n->op, n->nbody); + } + if(n->nelse) { + indent(fp); + fmtprint(fp, "%O-else%H", n->op, n->nelse); + } + if(n->nincr) { + indent(fp); + fmtprint(fp, "%O-incr%N", n->op, n->nincr); + } + } + + return 0; +} + +// Fmt "%S": syms +// Flags: "%hS" suppresses qualifying with package +static int +Sconv(Fmt *fp) +{ + Sym *s; + int r, sm; + unsigned long sf; + + s = va_arg(fp->args, Sym*); + if(s == S) + return fmtstrcpy(fp, "<S>"); + + if(s->name && s->name[0] == '_' && s->name[1] == '\0') + return fmtstrcpy(fp, "_"); + + sf = fp->flags; + sm = setfmode(&fp->flags); + r = symfmt(fp, s); + fp->flags = sf; + fmtmode = sm; + return r; +} + +// Fmt "%T": types. +// Flags: 'l' print definition, not name +// 'h' omit 'func' and receiver from function types, short type names +// 'u' package name, not prefix (FTypeId mode, sticky) +static int +Tconv(Fmt *fp) +{ + Type *t; + int r, sm; + unsigned long sf; + + t = va_arg(fp->args, Type*); + if(t == T) + return fmtstrcpy(fp, "<T>"); + + if(t->trecur > 4) + return fmtstrcpy(fp, "<...>"); + + t->trecur++; + sf = fp->flags; + sm = setfmode(&fp->flags); + + if(fmtmode == FTypeId && (sf&FmtUnsigned)) + fmtpkgpfx++; + if(fmtpkgpfx) + fp->flags |= FmtUnsigned; + + r = typefmt(fp, t); + + if(fmtmode == FTypeId && (sf&FmtUnsigned)) + fmtpkgpfx--; + + fp->flags = sf; + fmtmode = sm; + t->trecur--; + return r; +} + +// Fmt '%N': Nodes. +// Flags: 'l' suffix with "(type %T)" where possible +// '+h' in debug mode, don't recurse, no multiline output +static int +Nconv(Fmt *fp) +{ + Node *n; + int r, sm; + unsigned long sf; + + n = va_arg(fp->args, Node*); + if(n == N) + return fmtstrcpy(fp, "<N>"); + sf = fp->flags; + sm = setfmode(&fp->flags); + + r = -1; + switch(fmtmode) { + case FErr: + case FExp: + r = nodefmt(fp, n); + break; + case FDbg: + dumpdepth++; + r = nodedump(fp, n); + dumpdepth--; + break; + default: + fatal("unhandled %%N mode"); + } + + fp->flags = sf; + fmtmode = sm; + return r; +} + +// Fmt '%H': NodeList. +// Flags: all those of %N plus ',': separate with comma's instead of semicolons. +static int +Hconv(Fmt *fp) +{ + NodeList *l; + int r, sm; + unsigned long sf; + char *sep; + + l = va_arg(fp->args, NodeList*); + + if(l == nil && fmtmode == FDbg) + return fmtstrcpy(fp, "<nil>"); + + sf = fp->flags; + sm = setfmode(&fp->flags); + r = 0; + sep = "; "; + if(fmtmode == FDbg) + sep = "\n"; + else if(fp->flags & FmtComma) + sep = ", "; + + for(;l; l=l->next) { + r += fmtprint(fp, "%N", l->n); + if(l->next) + r += fmtstrcpy(fp, sep); + } + + fp->flags = sf; + fmtmode = sm; + return r; +} + +void +fmtinstallgo(void) +{ + fmtmode = FErr; + fmtinstall('E', Econv); // etype opcodes + fmtinstall('J', Jconv); // all the node flags + fmtinstall('H', Hconv); // node lists + fmtinstall('L', Lconv); // line number + fmtinstall('N', Nconv); // node pointer + fmtinstall('O', Oconv); // node opcodes + fmtinstall('S', Sconv); // sym pointer + fmtinstall('T', Tconv); // type pointer + fmtinstall('V', Vconv); // val pointer + fmtinstall('Z', Zconv); // escaped string + + // These are in mparith1.c + fmtinstall('B', Bconv); // big numbers + fmtinstall('F', Fconv); // big float numbers + +} + +void +dumplist(char *s, NodeList *l) +{ + print("%s\n%+H\n", s, l); +} + +void +dump(char *s, Node *n) +{ + print("%s [%p]\n%+N\n", s, n, n); +} diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index cb66921ba..694a10ab5 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -7,11 +7,13 @@ * mainly statements and control flow. */ +#include <u.h> +#include <libc.h> #include "go.h" static void cgen_dcl(Node *n); static void cgen_proc(Node *n, int proc); -static void checkgoto(Node*, Node*); +static void checkgoto(Node*, Node*); static Label *labellist; static Label *lastlabel; @@ -26,50 +28,93 @@ sysfunc(char *name) return n; } +/* + * the address of n has been taken and might be used after + * the current function returns. mark any local vars + * as needing to move to the heap. + */ void -allocparams(void) +addrescapes(Node *n) { - NodeList *l; - Node *n; - uint32 w; - Sym *s; - int lno; + char buf[100]; + Node *oldfn; + + switch(n->op) { + default: + // probably a type error already. + // dump("addrescapes", n); + break; + + case ONAME: + if(n == nodfp) + break; + + // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping. + // on PPARAM it means something different. + if(n->class == PAUTO && n->esc == EscNever) + break; + + if(debug['N'] && n->esc != EscUnknown) + fatal("without escape analysis, only PAUTO's should have esc: %N", n); - if(stksize < 0) - fatal("allocparams not during code generation"); - - /* - * allocate (set xoffset) the stack - * slots for all automatics. - * allocated starting at -w down. - */ - lno = lineno; - for(l=curfn->dcl; l; l=l->next) { - n = l->n; - if(n->op == ONAME && n->class == PHEAP-1) { - // heap address variable; finish the job - // started in addrescapes. - s = n->sym; - tempname(n, n->type); - n->sym = s; + switch(n->class) { + case PPARAMREF: + addrescapes(n->defn); + break; + case PPARAM: + case PPARAMOUT: + // if func param, need separate temporary + // to hold heap pointer. + // the function type has already been checked + // (we're in the function body) + // so the param already has a valid xoffset. + + // expression to refer to stack copy + n->stackparam = nod(OPARAM, n, N); + n->stackparam->type = n->type; + n->stackparam->addable = 1; + if(n->xoffset == BADWIDTH) + fatal("addrescapes before param assignment"); + n->stackparam->xoffset = n->xoffset; + // fallthrough + + case PAUTO: + n->class |= PHEAP; + n->addable = 0; + n->ullman = 2; + n->xoffset = 0; + + // create stack variable to hold pointer to heap + oldfn = curfn; + curfn = n->curfn; + n->heapaddr = temp(ptrto(n->type)); + snprint(buf, sizeof buf, "&%S", n->sym); + n->heapaddr->sym = lookup(buf); + n->heapaddr->orig->sym = n->heapaddr->sym; + if(!debug['N']) + n->esc = EscHeap; + if(debug['m']) + print("%L: moved to heap: %N\n", n->lineno, n); + curfn = oldfn; + break; } - if(n->op != ONAME || n->class != PAUTO) - continue; - if (n->xoffset != BADWIDTH) - continue; - if(n->type == T) - continue; - dowidth(n->type); - w = n->type->width; - if(w >= MAXWIDTH) - fatal("bad width"); - stksize += w; - stksize = rnd(stksize, n->type->align); - if(thechar == '5') - stksize = rnd(stksize, widthptr); - n->xoffset = -stksize; + break; + + case OIND: + case ODOTPTR: + break; + + case ODOT: + case OINDEX: + // ODOTPTR has already been introduced, + // so these are the non-pointer ODOT and OINDEX. + // In &x[0], if x is a slice, then x does not + // escape--the pointer inside x does, but that + // is always a heap pointer anyway. + if(!isslice(n->left->type)) + addrescapes(n->left); + break; } - lineno = lno; } void @@ -197,7 +242,7 @@ stmtlabel(Node *n) if(n->sym != S) if((lab = n->sym->label) != L) if(lab->def != N) - if(lab->def->right == n) + if(lab->def->defn == n) return lab; return L; } @@ -227,7 +272,6 @@ gen(Node *n) if(n == N) goto ret; - p3 = pc; // save pc for loop labels if(n->ninit) genlist(n->ninit); @@ -266,13 +310,13 @@ gen(Node *n) if(lab->labelpc == P) lab->labelpc = pc; - if(n->right) { - switch(n->right->op) { + if(n->defn) { + switch(n->defn->op) { case OFOR: case OSWITCH: case OSELECT: // so stmtlabel can find the label - n->right->sym = lab->sym; + n->defn->sym = lab->sym; } } break; @@ -486,7 +530,7 @@ cgen_callmeth(Node *n, int proc) /* * generate code to start new proc running call n. */ -void +static void cgen_proc(Node *n, int proc) { switch(n->left->op) { @@ -598,15 +642,12 @@ cgen_as(Node *nl, Node *nr) Type *tl; int iszer; - if(nl == N) - return; - if(debug['g']) { dump("cgen_as", nl); dump("cgen_as = ", nr); } - if(isblank(nl)) { + if(nl == N || isblank(nl)) { cgen_discard(nr); return; } @@ -748,12 +789,8 @@ tempname(Node *nn, Type *t) { Node *n; Sym *s; - uint32 w; - if(stksize < 0) - fatal("tempname not during code generation"); - - if (curfn == N) + if(curfn == N) fatal("no curfn for tempname"); if(t == T) { @@ -768,23 +805,27 @@ tempname(Node *nn, Type *t) s = lookup(namebuf); n = nod(ONAME, N, N); n->sym = s; + s->def = n; n->type = t; n->class = PAUTO; n->addable = 1; n->ullman = 1; - n->noescape = 1; + n->esc = EscNever; n->curfn = curfn; curfn->dcl = list(curfn->dcl, n); dowidth(t); - w = t->width; - stksize += w; - stksize = rnd(stksize, t->align); - if(thechar == '5') - stksize = rnd(stksize, widthptr); - n->xoffset = -stksize; - - // print("\ttmpname (%d): %N\n", stksize, n); - + n->xoffset = 0; *nn = *n; } + +Node* +temp(Type *t) +{ + Node *n; + + n = nod(OXXX, N, N); + tempname(n, t); + n->sym->def->used = 1; + return n; +} diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors index b5af4678c..e29cfff5b 100644 --- a/src/cmd/gc/go.errors +++ b/src/cmd/gc/go.errors @@ -67,4 +67,7 @@ static struct { % loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME "nested func not allowed", + + % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';' + "else must be followed by if or statement block" }; diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index da0fb5146..8c4fff15a 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#include <u.h> -#include <libc.h> #include <bio.h> #undef OAPPEND @@ -18,6 +16,12 @@ #undef BUFSIZ +// The parser's maximum stack size. +// We have to use a #define macro here since yacc +// or bison will check for its definition and use +// a potentially smaller value if it is undefined. +#define YYMAXDEPTH 500 + enum { NHUNK = 50000, @@ -25,7 +29,6 @@ enum NSYMB = 500, NHASH = 1024, STRINGSZ = 200, - YYMAXDEPTH = 500, MAXALIGN = 7, UINF = 100, HISTSZ = 10, @@ -34,23 +37,30 @@ enum AUNK = 100, - // these values are known by runtime + // These values are known by runtime. + // The MEMx and NOEQx values must run in parallel. See algtype. AMEM = 0, - ANOEQ, - ASTRING, - AINTER, - ANILINTER, - ASLICE, + AMEM0, AMEM8, AMEM16, AMEM32, AMEM64, AMEM128, + ANOEQ, + ANOEQ0, ANOEQ8, ANOEQ16, ANOEQ32, ANOEQ64, ANOEQ128, + ASTRING, + AINTER, + ANILINTER, + ASLICE, + AFLOAT32, + AFLOAT64, + ACPLX64, + ACPLX128, BADWIDTH = -1000000000, }; @@ -69,33 +79,6 @@ struct Strlit char s[3]; // variable }; -/* - * note this is the runtime representation - * of hashmap iterator. it is probably - * insafe to use it this way, but it puts - * all the changes in one place. - * only flag is referenced from go. - * actual placement does not matter as long - * as the size is >= actual size. - */ -typedef struct Hiter Hiter; -struct Hiter -{ - uchar data[8]; // return val from next - int32 elemsize; // size of elements in table */ - int32 changes; // number of changes observed last time */ - int32 i; // stack pointer in subtable_state */ - uchar last[8]; // last hash value returned */ - uchar h[8]; // the hash table */ - struct - { - uchar sub[8]; // pointer into subtable */ - uchar start[8]; // pointer into start of subtable */ - uchar end[8]; // pointer into end of subtable */ - uchar pad[8]; - } sub[4]; -}; - enum { Mpscale = 29, // safely smaller than bits in a long @@ -137,7 +120,7 @@ struct Val { short reg; // OREGISTER short bval; // bool value CTBOOL - Mpint* xval; // int CTINT + Mpint* xval; // int CTINT, rune CTRUNE Mpflt* fval; // float CTFLT Mpcplx* cval; // float CTCPLX Strlit* sval; // string CTSTR @@ -155,17 +138,16 @@ struct Type { uchar etype; uchar chan; - uchar recur; // to detect loops uchar trecur; // to detect loops uchar printed; uchar embedded; // TFIELD embedded type uchar siggen; - uchar funarg; + uchar funarg; // on TSTRUCT and TFIELD uchar copyany; uchar local; // created in this file uchar deferwidth; uchar broke; - uchar isddd; // TFIELD is ... argument + uchar isddd; // TFIELD is ... argument uchar align; Node* nod; // canonical OTYPE node @@ -203,8 +185,50 @@ struct Type }; #define T ((Type*)0) +typedef struct InitEntry InitEntry; +typedef struct InitPlan InitPlan; + +struct InitEntry +{ + vlong xoffset; // struct, array only + Node *key; // map only + Node *expr; +}; + +struct InitPlan +{ + vlong lit; // bytes of initialized non-zero literals + vlong zero; // bytes of zeros + vlong expr; // bytes of run-time computed expressions + + InitEntry *e; + int len; + int cap; +}; + +enum +{ + EscUnknown, + EscHeap, + EscScope, + EscNone, + EscNever, +}; + struct Node { + // Tree structure. + // Generic recursive walks should follow these fields. + Node* left; + Node* right; + Node* ntest; + Node* nincr; + NodeList* ninit; + NodeList* nbody; + NodeList* nelse; + NodeList* list; + NodeList* rlist; + uchar op; uchar ullman; // sethi/ullman number uchar addable; // type of addressability - 0 is not addressable @@ -215,41 +239,26 @@ struct Node uchar embedded; // ODCLFIELD embedded type uchar colas; // OAS resulting from := uchar diag; // already printed error about this - uchar noescape; // ONAME never move to heap + uchar esc; // EscXXX uchar funcdepth; uchar builtin; // built-in name, like len or close uchar walkdef; uchar typecheck; uchar local; + uchar dodata; uchar initorder; - uchar dodata; // compile literal assignment as data statement uchar used; uchar isddd; - uchar pun; // don't registerize variable ONAME uchar readonly; - uchar implicit; // don't show in printout + uchar implicit; + uchar addrtaken; // address taken, even if not moved to heap + uchar dupok; // duplicate definitions ok (for func) // most nodes - Node* left; - Node* right; Type* type; Type* realtype; // as determined by typecheck - NodeList* list; - NodeList* rlist; Node* orig; // original form, for printing, and tracking copies of ONAMEs - // for-body - NodeList* ninit; - Node* ntest; - Node* nincr; - NodeList* nbody; - - // if-body - NodeList* nelse; - - // cases - Node* ncase; - // func Node* nname; Node* shortname; @@ -257,15 +266,17 @@ struct Node NodeList* exit; NodeList* cvars; // closure params NodeList* dcl; // autodcl for this func/closure + NodeList* inl; // copy of the body for use in inlining // OLITERAL/OREGISTER Val val; // ONAME Node* ntype; - Node* defn; + Node* defn; // ONAME: initializing assignment; OLABEL: labeled statement Node* pack; // real package for import . names Node* curfn; // function for local variables + Type* paramfld; // TFIELD for this PPARAM // ONAME func param with PHEAP Node* heapaddr; // temp holding heap address of param @@ -276,8 +287,18 @@ struct Node Node* outer; // outer PPARAMREF in nested closure Node* closure; // ONAME/PHEAP <-> ONAME/PPARAMREF + // ONAME substitute while inlining + Node* inlvar; + // OPACK Pkg* pkg; + + // OARRAYLIT, OMAPLIT, OSTRUCTLIT. + InitPlan* initplan; + + // Escape analysis. + NodeList* escflowsrc; // flow(this, src) + int escloopdepth; // -1: global, 0: not set, function top level:1, increased inside function for every loop or label to mark scopes Sym* sym; // various int32 vargen; // unique name for OTYPE/ONAME @@ -287,9 +308,25 @@ struct Node int32 stkdelta; // offset added by stack frame compaction phase. int32 ostk; int32 iota; + uint32 walkgen; }; #define N ((Node*)0) -EXTERN int32 walkgen; + +/* + * Every node has a walkgen field. + * If you want to do a traversal of a node graph that + * might contain duplicates and want to avoid + * visiting the same nodes twice, increment walkgen + * before starting. Then before processing a node, do + * + * if(n->walkgen == walkgen) + * return; + * n->walkgen = walkgen; + * + * Such a walk cannot call another such walk recursively, + * because of the use of the global walkgen. + */ +EXTERN uint32 walkgen; struct NodeList { @@ -300,9 +337,9 @@ struct NodeList enum { - SymExport = 1<<0, + SymExport = 1<<0, // to be exported SymPackage = 1<<1, - SymExported = 1<<2, + SymExported = 1<<2, // already written out by export SymUniq = 1<<3, SymSiggen = 1<<4, }; @@ -329,10 +366,10 @@ EXTERN Sym* dclstack; struct Pkg { - char* name; - Strlit* path; + char* name; // package name + Strlit* path; // string literal used in import statement Sym* pathsym; - char* prefix; + char* prefix; // escaped path for use in symbol table Pkg* link; char exported; // import line written in export data char direct; // imported directly @@ -374,20 +411,21 @@ enum OADDR, OANDAND, OAPPEND, - OARRAY, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, - OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP, + OAS, OAS2, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, + OASOP, OBAD, OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OCAP, OCLOSE, OCLOSURE, OCMPIFACE, OCMPSTR, - OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, + OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT, OPTRLIT, OCONV, OCONVIFACE, OCONVNOP, OCOPY, ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE, + ODELETE, ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT, ODOTTYPE, ODOTTYPE2, @@ -444,6 +482,9 @@ enum // misc ODDD, + ODDDARG, + OINLCALL, // intermediary representation of an inlined call + OITAB, // itable word of interface value // for back ends OCMP, ODEC, OEXTEND, OINC, OREGISTER, OINDREG, @@ -500,6 +541,7 @@ enum CTxxx, CTINT, + CTRUNE, CTFLT, CTCPLX, CTSTR, @@ -561,7 +603,6 @@ typedef struct Var Var; struct Var { vlong offset; - Sym* sym; Sym* gotype; Node* node; int width; @@ -644,6 +685,7 @@ struct Magic }; typedef struct Prog Prog; +#pragma incomplete Prog struct Label { @@ -722,16 +764,22 @@ EXTERN Pkg* gostringpkg; // fake pkg for Go strings EXTERN Pkg* runtimepkg; // package runtime EXTERN Pkg* stringpkg; // fake package for C strings EXTERN Pkg* typepkg; // fake package for runtime type info +EXTERN Pkg* weaktypepkg; // weak references to runtime type info EXTERN Pkg* unsafepkg; // package unsafe EXTERN Pkg* phash[128]; EXTERN int tptr; // either TPTR32 or TPTR64 extern char* runtimeimport; extern char* unsafeimport; +EXTERN char* myimportpath; EXTERN Idir* idirs; +EXTERN char* localimport; EXTERN Type* types[NTYPE]; EXTERN Type* idealstring; EXTERN Type* idealbool; +EXTERN Type* bytetype; +EXTERN Type* runetype; +EXTERN Type* errortype; EXTERN uchar simtype[NTYPE]; EXTERN uchar isptr[NTYPE]; EXTERN uchar isforw[NTYPE]; @@ -763,7 +811,7 @@ EXTERN NodeList* xtop; EXTERN NodeList* externdcl; EXTERN NodeList* closures; EXTERN NodeList* exportlist; -EXTERN NodeList* typelist; +EXTERN NodeList* importlist; // imported functions and methods with inlinable bodies EXTERN int dclcontext; // PEXTERN/PAUTO EXTERN int incannedimport; EXTERN int statuniqgen; // name generator for static temps @@ -787,18 +835,13 @@ EXTERN Node* nblank; extern int thechar; extern char* thestring; + EXTERN char* hunk; EXTERN int32 nhunk; EXTERN int32 thunk; -EXTERN int exporting; -EXTERN int erroring; -EXTERN int noargnames; - EXTERN int funcdepth; EXTERN int typecheckok; -EXTERN int packagequotes; -EXTERN int longsymnames; EXTERN int compiling_runtime; /* @@ -883,7 +926,6 @@ void colasdefn(NodeList *left, Node *defn); NodeList* constiter(NodeList *vl, Node *t, NodeList *cl); Node* dclname(Sym *s); void declare(Node *n, int ctxt); -Type* dostruct(NodeList *l, int et); void dumpdcl(char *st); Node* embedded(Sym *s); Node* fakethis(void); @@ -904,30 +946,43 @@ void popdcl(void); void poptodcl(void); void redeclare(Sym *s, char *where); void testdclstack(void); +Type* tointerface(NodeList *l); +Type* tostruct(NodeList *l); Node* typedcl0(Sym *s); Node* typedcl1(Node *n, Node *t, int local); -void typedcl2(Type *pt, Type *t); Node* typenod(Type *t); NodeList* variter(NodeList *vl, Node *t, NodeList *el); /* + * esc.c + */ +void escapes(NodeList*); + +/* * export.c */ void autoexport(Node *n, int ctxt); void dumpexport(void); int exportname(char *s); void exportsym(Node *n); -void importconst(Sym *s, Type *t, Node *n); -void importmethod(Sym *s, Type *t); -Sym* importsym(Sym *s, int op); -void importtype(Type *pt, Type *t); -void importvar(Sym *s, Type *t, int ctxt); +void importconst(Sym *s, Type *t, Node *n); +void importimport(Sym *s, Strlit *z); +Sym* importsym(Sym *s, int op); +void importtype(Type *pt, Type *t); +void importvar(Sym *s, Type *t); Type* pkgtype(Sym *s); /* + * fmt.c + */ +void fmtinstallgo(void); +void dump(char *s, Node *n); +void dumplist(char *s, NodeList *l); + +/* * gen.c */ -void allocparams(void); +void addrescapes(Node *n); void cgen_as(Node *nl, Node *nr); void cgen_callmeth(Node *n, int proc); void clearlabels(void); @@ -937,12 +992,20 @@ void gen(Node *n); void genlist(NodeList *l); Node* sysfunc(char *name); void tempname(Node *n, Type *t); +Node* temp(Type*); /* * init.c */ void fninit(NodeList *n); -Node* renameinit(Node *n); +Sym* renameinit(void); + +/* + * inl.c + */ +void caninl(Node *fn); +void inlcalls(Node *fn); +void typecheckinl(Node *fn); /* * lex.c @@ -950,6 +1013,7 @@ Node* renameinit(Node *n); void cannedimports(char *file, char *cp); void importfile(Val *f, int line); char* lexname(int lex); +char* expstring(void); void mkpackage(char* pkgname); void unimportfile(void); int32 yylex(void); @@ -987,7 +1051,7 @@ void mpsubfltflt(Mpflt *a, Mpflt *b); /* * mparith2.c */ -void mpaddfixfix(Mpint *a, Mpint *b); +void mpaddfixfix(Mpint *a, Mpint *b, int); void mpandfixfix(Mpint *a, Mpint *b); void mpandnotfixfix(Mpint *a, Mpint *b); void mpdivfract(Mpint *a, Mpint *b); @@ -1032,10 +1096,9 @@ void ieeedtod(uint64 *ieee, double native); Sym* stringsym(char*, int); /* - * print.c + * order.c */ -void exprfmt(Fmt *f, Node *n, int prec); -void exprlistfmt(Fmt *f, NodeList *l); +void order(Node *fn); /* * range.c @@ -1050,6 +1113,8 @@ void dumptypestructs(void); Type* methodfunc(Type *f, Type*); Node* typename(Type *t); Sym* typesym(Type *t); +Sym* typesymprefix(char *prefix, Type *t); +int haspointers(Type *t); /* * select.c @@ -1069,19 +1134,12 @@ int stataddr(Node *nam, Node *n); /* * subr.c */ -int Econv(Fmt *fp); -int Jconv(Fmt *fp); -int Lconv(Fmt *fp); -int Nconv(Fmt *fp); -int Oconv(Fmt *fp); -int Sconv(Fmt *fp); -int Tconv(Fmt *fp); -int Tpretty(Fmt *fp, Type *t); -int Zconv(Fmt *fp); Node* adddot(Node *n); int adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase); +void addinit(Node**, NodeList*); Type* aindex(Node *b, Type *t); int algtype(Type *t); +int algtype1(Type *t, Type **bad); void argtype(Node *on, Type *t); Node* assignconv(Node *n, Type *t, char *context); int assignop(Type *src, Type *dst, char **why); @@ -1090,20 +1148,21 @@ int brcom(int a); int brrev(int a); NodeList* concat(NodeList *a, NodeList *b); int convertop(Type *src, Type *dst, char **why); +Node* copyexpr(Node*, Type*, NodeList**); int count(NodeList *l); int cplxsubtype(int et); -void dump(char *s, Node *n); -void dumplist(char *s, NodeList *l); int eqtype(Type *t1, Type *t2); int eqtypenoname(Type *t1, Type *t2); void errorexit(void); -void expandmeth(Sym *s, Type *t); +void expandmeth(Type *t); void fatal(char *fmt, ...); void flusherrors(void); void frame(int context); Type* funcfirst(Iter *s, Type *t); Type* funcnext(Iter *s); void genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface); +void genhash(Sym *sym, Type *t); +void geneq(Sym *sym, Type *t); Type** getinarg(Type *t); Type* getinargx(Type *t); Type** getoutarg(Type *t); @@ -1113,7 +1172,9 @@ Type* getthisx(Type *t); int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr); void importdot(Pkg *opkg, Node *pack); int is64(Type *t); +int isbadimport(Strlit *s); int isblank(Node *n); +int isblanksym(Sym *s); int isfixedarray(Type *t); int isideal(Type *t); int isinter(Type *t); @@ -1131,7 +1192,7 @@ NodeList* listtreecopy(NodeList *l); Sym* lookup(char *name); void* mal(int32 n); Type* maptype(Type *key, Type *val); -Type* methtype(Type *t); +Type* methtype(Type *t, int mustname); Pkg* mkpkg(Strlit *path); Sym* ngotype(Node *n); int noconv(Type *t1, Type *t2); @@ -1170,6 +1231,7 @@ uint32 typehash(Type *t); void ullmancalc(Node *n); void umagic(Magic *m); void warn(char *fmt, ...); +void warnl(int line, char *fmt, ...); void yyerror(char *fmt, ...); void yyerrorl(int line, char *fmt, ...); @@ -1182,7 +1244,6 @@ void walkswitch(Node *sw); /* * typecheck.c */ -int exportassignok(Type *t, char *desc); int islvalue(Node *n); Node* typecheck(Node **np, int top); void typechecklist(NodeList *l, int top); @@ -1195,6 +1256,7 @@ void queuemethod(Node *n); /* * unsafe.c */ +int isunsafebuiltin(Node *n); Node* unsafenmagic(Node *n); /* @@ -1211,6 +1273,7 @@ void walkexprlist(NodeList *l, NodeList **init); void walkexprlistsafe(NodeList *l, NodeList **init); void walkstmt(Node **np); void walkstmtlist(NodeList *l); +Node* conv(Node*, Type*); /* * arch-specific ggen.c/gsubr.c/gobj.c/pgen.c @@ -1274,6 +1337,30 @@ Prog* unpatch(Prog*); void zfile(Biobuf *b, char *p, int n); void zhist(Biobuf *b, int line, vlong offset); void zname(Biobuf *b, Sym *s, int t); -void data(void); -void text(void); +#pragma varargck type "A" int +#pragma varargck type "B" Mpint* +#pragma varargck type "D" Addr* +#pragma varargck type "lD" Addr* +#pragma varargck type "E" int +#pragma varargck type "E" uint +#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* +#pragma varargck type "lN" Node* +#pragma varargck type "O" uint +#pragma varargck type "P" Prog* +#pragma varargck type "Q" Bits +#pragma varargck type "R" int +#pragma varargck type "S" Sym* +#pragma varargck type "lS" Sym* +#pragma varargck type "T" Type* +#pragma varargck type "lT" Type* +#pragma varargck type "V" Val* +#pragma varargck type "Y" char* +#pragma varargck type "Z" Strlit* diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 4c7fe6068..f95058721 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -18,7 +18,9 @@ */ %{ +#include <u.h> #include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */ +#include <libc.h> #include "go.h" static void fixlbrace(int); @@ -29,13 +31,13 @@ static void fixlbrace(int); Type* type; Sym* sym; struct Val val; - int lint; + int i; } // |sed 's/.* //' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx /' %token <val> LLITERAL -%token <lint> LASOP +%token <i> LASOP %token <sym> LBREAK LCASE LCHAN LCOLAS LCONST LCONTINUE LDDD %token <sym> LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO %token <sym> LIF LIMPORT LINTERFACE LMAP LNAME @@ -45,7 +47,7 @@ static void fixlbrace(int); %token LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT %token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH -%type <lint> lbrace import_here +%type <i> lbrace import_here %type <sym> sym packname %type <val> oliteral @@ -54,8 +56,8 @@ static void fixlbrace(int); %type <node> case caseblock %type <node> compound_stmt dotname embed expr complitexpr %type <node> expr_or_type -%type <node> fndcl fnliteral -%type <node> for_body for_header for_stmt if_header if_stmt non_dcl_stmt +%type <node> fndcl hidden_fndcl fnliteral +%type <node> for_body for_header for_stmt if_header if_stmt else non_dcl_stmt %type <node> interfacedcl keyval labelname name %type <node> name_or_type non_expr_type %type <node> new_name dcl_name oexpr typedclname @@ -64,7 +66,7 @@ static void fixlbrace(int); %type <node> pseudocall range_stmt select_stmt %type <node> simple_stmt %type <node> switch_stmt uexpr -%type <node> xfndcl typedcl +%type <node> xfndcl typedcl start_complit %type <list> xdcl fnbody fnres loop_body dcl_name_list %type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list @@ -76,12 +78,10 @@ static void fixlbrace(int); %type <node> indcl interfacetype structtype ptrtype %type <node> recvchantype non_recvchantype othertype fnret_type fntype -%type <val> hidden_tag - %type <sym> hidden_importsym hidden_pkg_importsym -%type <node> hidden_constant hidden_literal hidden_dcl -%type <node> hidden_interfacedcl hidden_structdcl hidden_opt_sym +%type <node> hidden_constant hidden_literal hidden_funarg +%type <node> hidden_interfacedcl hidden_structdcl %type <list> hidden_funres %type <list> ohidden_funres @@ -205,7 +205,15 @@ import_stmt: my->lastlineno = $1; my->block = 1; // at top level } - +| import_here import_there + { + // When an invalid import path is passed to importfile, + // it calls yyerror and then sets up a fake import with + // no package statement. This allows us to test more + // than one invalid import statement in a single file. + if(nerrors == 0) + fatal("phase error in import"); + } import_stmt_list: import_stmt @@ -235,17 +243,17 @@ import_here: } import_package: - LPACKAGE sym import_safety ';' + LPACKAGE LNAME import_safety ';' { if(importpkg->name == nil) { importpkg->name = $2->name; pkglookup($2->name, nil)->npkg++; } else if(strcmp(importpkg->name, $2->name) != 0) - yyerror("conflicting names %s and %s for package %Z", importpkg->name, $2->name, importpkg->path); + yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, $2->name, importpkg->path); importpkg->direct = 1; if(safemode && !curio.importsafe) - yyerror("cannot import unsafe package %Z", importpkg->path); + yyerror("cannot import unsafe package \"%Z\"", importpkg->path); } import_safety: @@ -418,18 +426,15 @@ simple_stmt: | expr_list LCOLAS expr_list { if($3->n->op == OTYPESW) { - Node *n; - - n = N; + $$ = nod(OTYPESW, N, $3->n->right); if($3->next != nil) yyerror("expr.(type) must be alone in list"); if($1->next != nil) yyerror("argument count mismatch: %d = %d", count($1), 1); - else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME) - yyerror("invalid variable name %#N in type switch", $1->n); + else if(($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME) || isblank($1->n)) + yyerror("invalid variable name %N in type switch", $1->n); else - n = $1->n; - $$ = nod(OTYPESW, n, $3->n->right); + $$->left = dclname($1->n->sym); // it's a colas, so must not re-use an oldname. break; } $$ = colas($1, $3); @@ -448,7 +453,7 @@ simple_stmt: case: LCASE expr_or_type_list ':' { - Node *n; + Node *n, *nn; // will be converted to OCASE // right will point to next case @@ -458,12 +463,13 @@ case: $$->list = $2; if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { // type switch - declare variable - n = newname(n->sym); - n->used = 1; // TODO(rsc): better job here - declare(n, dclcontext); - $$->nname = n; + nn = newname(n->sym); + declare(nn, dclcontext); + $$->nname = nn; + + // keep track of the instances for reporting unused + nn->defn = typesw->right; } - break; } | LCASE expr_or_type_list '=' expr ':' { @@ -494,16 +500,18 @@ case: } | LDEFAULT ':' { - Node *n; + Node *n, *nn; markdcl(); $$ = nod(OXCASE, N, N); if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { // type switch - declare variable - n = newname(n->sym); - n->used = 1; // TODO(rsc): better job here - declare(n, dclcontext); - $$->nname = n; + nn = newname(n->sym); + declare(nn, dclcontext); + $$->nname = nn; + + // keep track of the instances for reporting unused + nn->defn = typesw->right; } } @@ -638,6 +646,7 @@ if_header: $$->ntest = $3; } +/* IF cond body (ELSE IF cond body)* (ELSE block)? */ if_stmt: LIF { @@ -650,9 +659,27 @@ if_stmt: } loop_body { + $3->nbody = $5; + } + else + { + popdcl(); $$ = $3; - $$->nbody = $5; - // no popdcl; maybe there's an LELSE + if($7 != N) + $$->nelse = list1($7); + } + +else: + { + $$ = N; + } +| LELSE if_stmt + { + $$ = $2; + } +| LELSE compound_stmt + { + $$ = $2; } switch_stmt: @@ -785,7 +812,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 { @@ -874,29 +908,35 @@ pexpr_no_paren: $$ = nod(OCALL, $1, N); $$->list = list1($3); } -| comptype lbrace braced_keyval_list '}' +| comptype lbrace start_complit braced_keyval_list '}' { - // composite expression - $$ = nod(OCOMPLIT, N, $1); - $$->list = $3; - + $$ = $3; + $$->right = $1; + $$->list = $4; fixlbrace($2); } -| pexpr_no_paren '{' braced_keyval_list '}' +| pexpr_no_paren '{' start_complit braced_keyval_list '}' { - // composite expression - $$ = nod(OCOMPLIT, N, $1); - $$->list = $3; + $$ = $3; + $$->right = $1; + $$->list = $4; } -| '(' expr_or_type ')' '{' braced_keyval_list '}' +| '(' expr_or_type ')' '{' start_complit braced_keyval_list '}' { yyerror("cannot parenthesize type in composite literal"); - // composite expression - $$ = nod(OCOMPLIT, N, $2); - $$->list = $5; + $$ = $5; + $$->right = $2; + $$->list = $6; } | fnliteral +start_complit: + { + // composite expression. + // make node early so we get the right line number. + $$ = nod(OCOMPLIT, N, N); + } + keyval: expr ':' complitexpr { @@ -905,10 +945,10 @@ keyval: complitexpr: expr -| '{' braced_keyval_list '}' +| '{' start_complit braced_keyval_list '}' { - $$ = nod(OCOMPLIT, N, N); - $$->list = $2; + $$ = $2; + $$->list = $3; } pexpr: @@ -955,7 +995,10 @@ lbrace: new_name: sym { - $$ = newname($1); + if($1 == S) + $$ = N; + else + $$ = newname($1); } dcl_name: @@ -972,6 +1015,26 @@ onew_name: sym: LNAME + { + $$ = $1; + // during imports, unqualified non-exported identifiers are from builtinpkg + if(importpkg != nil && !exportname($1->name)) + $$ = pkglookup($1->name, builtinpkg); + } +| hidden_importsym +| '?' + { + $$ = S; + } + +hidden_importsym: + '@' LLITERAL '.' LNAME + { + if($2.u.sval->len == 0) + $$ = pkglookup($4->name, importpkg); + else + $$ = pkglookup($4->name, mkpkg($2.u.sval)); + } name: sym %prec NotParen @@ -1144,38 +1207,43 @@ xfndcl: } fndcl: - dcl_name '(' oarg_type_list_ocomma ')' fnres + sym '(' oarg_type_list_ocomma ')' fnres { - Node *n; + Node *t; + $$ = N; $3 = checkarglist($3, 1); - $$ = nod(ODCLFUNC, N, N); - $$->nname = $1; - n = nod(OTFUNC, N, N); - n->list = $3; - n->rlist = $5; - if(strcmp($1->sym->name, "init") == 0) { - $$->nname = renameinit($1); + + if(strcmp($1->name, "init") == 0) { + $1 = renameinit(); if($3 != nil || $5 != nil) yyerror("func init must have no arguments and no return values"); } - if(strcmp(localpkg->name, "main") == 0 && strcmp($1->sym->name, "main") == 0) { + if(strcmp(localpkg->name, "main") == 0 && strcmp($1->name, "main") == 0) { if($3 != nil || $5 != nil) yyerror("func main must have no arguments and no return values"); } - // TODO: check if nname already has an ntype - $$->nname->ntype = n; + + t = nod(OTFUNC, N, N); + t->list = $3; + t->rlist = $5; + + $$ = nod(ODCLFUNC, N, N); + $$->nname = newname($1); + $$->nname->defn = $$; + $$->nname->ntype = t; // TODO: check if nname already has an ntype + declare($$->nname, PFUNC); + funchdr($$); } | '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres { Node *rcvr, *t; - Node *name; - - name = newname($4); + + $$ = N; $2 = checkarglist($2, 0); $6 = checkarglist($6, 1); - $$ = N; + if($2 == nil) { yyerror("method has no receiver"); break; @@ -1192,16 +1260,60 @@ fndcl: if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN)) yyerror("cannot parenthesize receiver type"); - $$ = nod(ODCLFUNC, N, N); - $$->nname = methodname1(name, rcvr->right); t = nod(OTFUNC, rcvr, N); t->list = $6; t->rlist = $8; + + $$ = nod(ODCLFUNC, N, N); + $$->shortname = newname($4); + $$->nname = methodname1($$->shortname, rcvr->right); + $$->nname->defn = $$; $$->nname->ntype = t; - $$->shortname = name; + declare($$->nname, PFUNC); + funchdr($$); } +hidden_fndcl: + hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres + { + Sym *s; + Type *t; + + $$ = N; + + s = $1; + t = functype(N, $3, $5); + + importsym(s, ONAME); + if(s->def != N && s->def->op == ONAME) { + if(eqtype(t, s->def->type)) + break; + yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t); + } + + $$ = newname(s); + $$->type = t; + declare($$, PFUNC); + + funchdr($$); + } +| '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres + { + $$ = methodname1(newname($4), $2->n->right); + $$->type = functype($2->n, $6, $8); + + checkwidth($$->type); + addmethod($4, $$->type, 0); + funchdr($$); + + // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as + // (dotmeth's type)->nname->inl, and dotmeth's type has been pulled + // out by typecheck's lookdot as this $$->ttype. So by providing + // this back link here we avoid special casing there. + $$->type->nname = $$; + } + fntype: LFUNC '(' oarg_type_list_ocomma ')' fnres { @@ -1317,6 +1429,20 @@ structdcl: { NodeList *l; + Node *n; + l = $1; + if(l != nil && l->next == nil && l->n == nil) { + // ? symbol, during import + n = $2; + if(n->op == OIND) + n = n->left; + n = embedded(n->sym); + n->right = $2; + n->val = $3; + $$ = list1(n); + break; + } + for(l=$1; l; l=l->next) { l->n = nod(ODCLFIELD, l->n, $2); l->n->val = $3; @@ -1472,19 +1598,6 @@ non_dcl_stmt: | switch_stmt | select_stmt | if_stmt - { - popdcl(); - $$ = $1; - } -| if_stmt LELSE stmt - { - if($3->op != OIF && $3->op != OBLOCK) - yyerror("missing { } after else"); - - popdcl(); - $$ = $1; - $$->nelse = list1($3); - } | labelname ':' { $1 = nod(OLABEL, $1, N); @@ -1494,7 +1607,7 @@ non_dcl_stmt: { NodeList *l; - $1->right = $4; + $1->defn = $4; l = list1($1); if($4) l = list(l, $4); @@ -1530,6 +1643,18 @@ non_dcl_stmt: { $$ = nod(ORETURN, N, N); $$->list = $2; + if($$->list == nil && curfn != N) { + NodeList *l; + + for(l=curfn->dcl; l; l=l->next) { + if(l->n->class == PPARAM) + continue; + if(l->n->class != PPARAMOUT) + break; + if(l->n->sym->def != l->n) + yyerror("%s is shadowed during return", l->n->sym->name); + } + } } stmt_list: @@ -1668,27 +1793,16 @@ oliteral: | LLITERAL /* - * import syntax from header of - * an output package + * import syntax from package header */ hidden_import: - LIMPORT sym LLITERAL ';' + LIMPORT LNAME LLITERAL ';' { - // Informational: record package name - // associated with import path, for use in - // human-readable messages. - Pkg *p; - - p = mkpkg($3.u.sval); - if(p->name == nil) { - p->name = $2->name; - pkglookup($2->name, nil)->npkg++; - } else if(strcmp(p->name, $2->name) != 0) - yyerror("conflicting names %s and %s for package %Z", p->name, $2->name, p->path); + importimport($2, $3.u.sval); } | LVAR hidden_pkg_importsym hidden_type ';' { - importvar($2, $3, PEXTERN); + importvar($2, $3); } | LCONST hidden_pkg_importsym '=' hidden_constant ';' { @@ -1702,17 +1816,28 @@ hidden_import: { importtype($2, $3); } -| LFUNC hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres ';' +| LFUNC hidden_fndcl fnbody ';' { - importvar($2, functype(N, $4, $6), PFUNC); + if($2 == N) + break; + + $2->inl = $3; + + funcbody($2); + importlist = list(importlist, $2); + + if(debug['E']) { + print("import [%Z] func %lN \n", importpkg->path, $2); + if(debug['l'] > 2 && $2->inl) + print("inl body:%+H\n", $2->inl); + } } -| LFUNC '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres ';' + +hidden_pkg_importsym: + hidden_importsym { - if($3->next != nil || $3->n->op != ODCLFIELD) { - yyerror("bad receiver in method"); - YYERROR; - } - importmethod($5, functype($3->n, $7, $9)); + $$ = $1; + structpkg = $$->pkg; } hidden_pkgtype: @@ -1722,6 +1847,10 @@ hidden_pkgtype: importsym($1, OTYPE); } +/* + * importing types + */ + hidden_type: hidden_type_misc | hidden_type_recv_chan @@ -1760,11 +1889,11 @@ hidden_type_misc: } | LSTRUCT '{' ohidden_structdcl_list '}' { - $$ = dostruct($3, TSTRUCT); + $$ = tostruct($3); } | LINTERFACE '{' ohidden_interfacedcl_list '}' { - $$ = dostruct($3, TINTER); + $$ = tointerface($3); } | '*' hidden_type { @@ -1803,61 +1932,45 @@ hidden_type_func: $$ = functype(nil, $3, $5); } -hidden_opt_sym: - sym - { - $$ = newname($1); - } -| '?' - { - $$ = N; - } - -hidden_dcl: - hidden_opt_sym hidden_type hidden_tag +hidden_funarg: + sym hidden_type oliteral { - $$ = nod(ODCLFIELD, $1, typenod($2)); + $$ = nod(ODCLFIELD, N, typenod($2)); + if($1) + $$->left = newname($1); $$->val = $3; } -| hidden_opt_sym LDDD hidden_type hidden_tag +| sym LDDD hidden_type oliteral { Type *t; - + t = typ(TARRAY); t->bound = -1; t->type = $3; - $$ = nod(ODCLFIELD, $1, typenod(t)); + + $$ = nod(ODCLFIELD, N, typenod(t)); + if($1) + $$->left = newname($1); $$->isddd = 1; $$->val = $4; } hidden_structdcl: - sym hidden_type hidden_tag - { - $$ = nod(ODCLFIELD, newname($1), typenod($2)); - $$->val = $3; - } -| '?' hidden_type hidden_tag + sym hidden_type oliteral { Sym *s; - s = $2->sym; - if(s == S && isptr[$2->etype]) - s = $2->type->sym; - if(s && s->pkg == builtinpkg) - s = lookup(s->name); - $$ = embedded(s); - $$->right = typenod($2); - $$->val = $3; - } - -hidden_tag: - { - $$.ctype = CTxxx; - } -| ':' LLITERAL // extra colon avoids conflict with "" looking like beginning of "".typename - { - $$ = $2; + if($1 != S) { + $$ = nod(ODCLFIELD, newname($1), typenod($2)); + $$->val = $3; + } else { + s = $2->sym; + if(s == S && isptr[$2->etype]) + s = $2->type->sym; + $$ = embedded(s); + $$->right = typenod($2); + $$->val = $3; + } } hidden_interfacedcl: @@ -1865,9 +1978,9 @@ hidden_interfacedcl: { $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5))); } -| hidden_importsym '(' ohidden_funarg_list ')' ohidden_funres +| hidden_type { - $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5))); + $$ = nod(ODCLFIELD, N, typenod($1)); } ohidden_funres: @@ -1886,6 +1999,10 @@ hidden_funres: $$ = list1(nod(ODCLFIELD, N, typenod($1))); } +/* + * importing constants + */ + hidden_literal: LLITERAL { @@ -1896,6 +2013,7 @@ hidden_literal: $$ = nodlit($2); switch($$->val.ctype){ case CTINT: + case CTRUNE: mpnegfix($$->val.u.xval); break; case CTFLT: @@ -1916,37 +2034,23 @@ hidden_constant: hidden_literal | '(' hidden_literal '+' hidden_literal ')' { + if($2->val.ctype == CTRUNE && $4->val.ctype == CTINT) { + $$ = $2; + mpaddfixfix($2->val.u.xval, $4->val.u.xval, 0); + break; + } $$ = nodcplxlit($2->val, $4->val); } -hidden_importsym: - LLITERAL '.' sym - { - Pkg *p; - - if($1.u.sval->len == 0) - p = importpkg; - else - p = mkpkg($1.u.sval); - $$ = pkglookup($3->name, p); - } - -hidden_pkg_importsym: - hidden_importsym - { - $$ = $1; - structpkg = $$->pkg; - } - hidden_import_list: | hidden_import_list hidden_import hidden_funarg_list: - hidden_dcl + hidden_funarg { $$ = list1($1); } -| hidden_funarg_list ',' hidden_dcl +| hidden_funarg_list ',' hidden_funarg { $$ = list($1, $3); } diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c index 8818db08c..be402cc0c 100644 --- a/src/cmd/gc/init.c +++ b/src/cmd/gc/init.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" /* @@ -11,21 +13,13 @@ * package and also uncallable, the name, * normally "pkg.init", is altered to "pkg.init·1". */ -Node* -renameinit(Node *n) +Sym* +renameinit(void) { - Sym *s; static int initgen; - s = n->sym; - if(s == S) - return n; - if(strcmp(s->name, "init") != 0) - return n; - snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen); - s = lookup(namebuf); - return newname(s); + return lookup(namebuf); } /* @@ -123,7 +117,9 @@ fninit(NodeList *n) fn = nod(ODCLFUNC, N, N); initsym = lookup(namebuf); fn->nname = newname(initsym); + fn->nname->defn = fn; fn->nname->ntype = nod(OTFUNC, N, N); + declare(fn->nname, PFUNC); funchdr(fn); // (3) diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c new file mode 100644 index 000000000..efce56057 --- /dev/null +++ b/src/cmd/gc/inl.c @@ -0,0 +1,842 @@ +// Copyright 2011 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. +// +// The inlining facility makes 2 passes: first caninl determines which +// functions are suitable for inlining, and for those that are it +// saves a copy of the body. Then inlcalls walks each function body to +// expand calls to inlinable functions. +// +// The debug['l'] flag controls the agressiveness. Note that main() swaps level 0 and 1, +// making 1 the default and -l disable. -ll and more is useful to flush out bugs. +// These additional levels (beyond -l) may be buggy and are not supported. +// 0: disabled +// 1: 40-nodes leaf functions, oneliners, lazy typechecking (default) +// 2: early typechecking of all imported bodies +// 3: +// 4: allow non-leaf functions , (breaks runtime.Caller) +// 5: transitive inlining +// +// At some point this may get another default and become switch-offable with -N. +// +// The debug['m'] flag enables diagnostic output. a single -m is useful for verifying +// which calls get inlined or not, more is for debugging, and may go away at any point. +// +// TODO: +// - inline functions with ... args +// - handle T.meth(f()) with func f() (t T, arg, arg, ) + +#include <u.h> +#include <libc.h> +#include "go.h" + +// Used by caninl. +static Node* inlcopy(Node *n); +static NodeList* inlcopylist(NodeList *ll); +static int ishairy(Node *n, int *budget); +static int ishairylist(NodeList *ll, int *budget); + +// Used by inlcalls +static void inlnodelist(NodeList *l); +static void inlnode(Node **np); +static void mkinlcall(Node **np, Node *fn); +static Node* inlvar(Node *n); +static Node* retvar(Type *n, int i); +static Node* newlabel(void); +static Node* inlsubst(Node *n); +static NodeList* inlsubstlist(NodeList *l); + +static void setlno(Node*, int); + +// Used during inlsubst[list] +static Node *inlfn; // function currently being inlined +static Node *inlretlabel; // target of the goto substituted in place of a return +static NodeList *inlretvars; // temp out variables + +// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods +// the ->sym can be re-used in the local package, so peel it off the receiver's type. +static Pkg* +fnpkg(Node *fn) +{ + Type *rcvr; + + if(fn->type->thistuple) { + // method + rcvr = getthisx(fn->type)->type->type; + if(isptr[rcvr->etype]) + rcvr = rcvr->type; + if(!rcvr->sym) + fatal("receiver with no sym: [%S] %lN (%T)", fn->sym, fn, rcvr); + return rcvr->sym->pkg; + } + // non-method + return fn->sym->pkg; +} + +// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck +// because they're a copy of an already checked body. +void +typecheckinl(Node *fn) +{ + Node *savefn; + Pkg *pkg; + int save_safemode, lno; + + if(fn->typecheck) + return; + + lno = setlineno(fn); + + if (debug['m']>2) + print("typecheck import [%S] %lN { %#H }\n", fn->sym, fn, fn->inl); + + // typecheckinl is only used for imported functions; + // their bodies may refer to unsafe as long as the package + // was marked safe during import (which was checked then). + pkg = fnpkg(fn); + if (pkg == localpkg || pkg == nil) + fatal("typecheckinl on local function %lN", fn); + + save_safemode = safemode; + safemode = 0; + + savefn = curfn; + curfn = fn; + typechecklist(fn->inl, Etop); + fn->typecheck = 1; + curfn = savefn; + + safemode = save_safemode; + + lineno = lno; +} + +// Caninl determines whether fn is inlineable. Currently that means: +// fn is exactly 1 statement, either a return or an assignment, and +// some temporary constraints marked TODO. If fn is inlineable, saves +// fn->nbody in fn->inl and substitutes it with a copy. +void +caninl(Node *fn) +{ + Node *savefn; + Type *t; + int budget; + + if(fn->op != ODCLFUNC) + fatal("caninl %N", fn); + if(!fn->nname) + fatal("caninl no nname %+N", fn); + + // If fn has no body (is defined outside of Go), cannot inline it. + if(fn->nbody == nil) + return; + + // can't handle ... args yet + for(t=fn->type->type->down->down->type; t; t=t->down) + if(t->isddd) + return; + + budget = 40; // allowed hairyness + if(ishairylist(fn->nbody, &budget)) + return; + + savefn = curfn; + curfn = fn; + + fn->nname->inl = fn->nbody; + fn->nbody = inlcopylist(fn->nname->inl); + // nbody will have been typechecked, so we can set this: + fn->typecheck = 1; + + // hack, TODO, check for better way to link method nodes back to the thing with the ->inl + // this is so export can find the body of a method + fn->type->nname = fn->nname; + + if(debug['m'] > 1) + print("%L: can inline %#N as: %#T { %#H }\n", fn->lineno, fn->nname, fn->type, fn->nname->inl); + else if(debug['m']) + print("%L: can inline %N\n", fn->lineno, fn->nname); + + curfn = savefn; +} + +// Look for anything we want to punt on. +static int +ishairylist(NodeList *ll, int* budget) +{ + for(;ll;ll=ll->next) + if(ishairy(ll->n, budget)) + return 1; + return 0; +} + +static int +ishairy(Node *n, int *budget) +{ + if(!n) + return 0; + + // Things that are too hairy, irrespective of the budget + switch(n->op) { + case OCALL: + case OCALLFUNC: + case OCALLINTER: + case OCALLMETH: + case OPANIC: + case ORECOVER: + if(debug['l'] < 4) + return 1; + break; + + case OCLOSURE: + case ORANGE: + case OFOR: + case OSELECT: + case OSWITCH: + case OPROC: + case ODEFER: + case ODCL: // declares locals as globals b/c of @"". qualification + case ODCLTYPE: // can't print yet + case ODCLCONST: // can't print yet + return 1; + + break; + case OAS: + // x = <N> zero initializing assignments aren't representible in export yet. + // alternatively we may just skip them in printing and hope their DCL printed + // as a var will regenerate it + if(n->right == N) + return 1; + break; + } + + (*budget)--; + + return *budget < 0 || + ishairy(n->left, budget) || + ishairy(n->right, budget) || + ishairylist(n->list, budget) || + ishairylist(n->rlist, budget) || + ishairylist(n->ninit, budget) || + ishairy(n->ntest, budget) || + ishairy(n->nincr, budget) || + ishairylist(n->nbody, budget) || + ishairylist(n->nelse, budget); +} + +// Inlcopy and inlcopylist recursively copy the body of a function. +// Any name-like node of non-local class is marked for re-export by adding it to +// the exportlist. +static NodeList* +inlcopylist(NodeList *ll) +{ + NodeList *l; + + l = nil; + for(; ll; ll=ll->next) + l = list(l, inlcopy(ll->n)); + return l; +} + +static Node* +inlcopy(Node *n) +{ + Node *m; + + if(n == N) + return N; + + switch(n->op) { + case ONAME: + case OTYPE: + case OLITERAL: + return n; + } + + m = nod(OXXX, N, N); + *m = *n; + m->inl = nil; + m->left = inlcopy(n->left); + m->right = inlcopy(n->right); + m->list = inlcopylist(n->list); + m->rlist = inlcopylist(n->rlist); + m->ninit = inlcopylist(n->ninit); + m->ntest = inlcopy(n->ntest); + m->nincr = inlcopy(n->nincr); + m->nbody = inlcopylist(n->nbody); + m->nelse = inlcopylist(n->nelse); + + return m; +} + + +// Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any +// calls made to inlineable functions. This is the external entry point. +void +inlcalls(Node *fn) +{ + Node *savefn; + + savefn = curfn; + curfn = fn; + inlnode(&fn); + if(fn != curfn) + fatal("inlnode replaced curfn"); + curfn = savefn; +} + +// Turn an OINLCALL into a statement. +static void +inlconv2stmt(Node *n) +{ + n->op = OBLOCK; + // n->ninit stays + n->list = n->nbody; + n->nbody = nil; + n->rlist = nil; +} + +// Turn an OINLCALL into a single valued expression. +static void +inlconv2expr(Node **np) +{ + Node *n, *r; + n = *np; + r = n->rlist->n; + addinit(&r, concat(n->ninit, n->nbody)); + *np = r; +} + +// Turn the rlist (with the return values) of the OINLCALL in +// n into an expression list lumping the ninit and body +// containing the inlined statements on the first list element so +// order will be preserved Used in return, oas2func and call +// statements. +static NodeList* +inlconv2list(Node *n) +{ + NodeList *l; + + if(n->op != OINLCALL || n->rlist == nil) + fatal("inlconv2list %+N\n", n); + + l = n->rlist; + addinit(&l->n, concat(n->ninit, n->nbody)); + return l; +} + +static void +inlnodelist(NodeList *l) +{ + for(; l; l=l->next) + inlnode(&l->n); +} + +// inlnode recurses over the tree to find inlineable calls, which will +// be turned into OINLCALLs by mkinlcall. When the recursion comes +// back up will examine left, right, list, rlist, ninit, ntest, nincr, +// nbody and nelse and use one of the 4 inlconv/glue functions above +// to turn the OINLCALL into an expression, a statement, or patch it +// in to this nodes list or rlist as appropriate. +// NOTE it makes no sense to pass the glue functions down the +// recursion to the level where the OINLCALL gets created because they +// have to edit /this/ n, so you'd have to push that one down as well, +// but then you may as well do it here. so this is cleaner and +// shorter and less complicated. +static void +inlnode(Node **np) +{ + Node *n; + NodeList *l; + int lno; + + if(*np == nil) + return; + + n = *np; + + switch(n->op) { + case ODEFER: + case OPROC: + // inhibit inlining of their argument + switch(n->left->op) { + case OCALLFUNC: + case OCALLMETH: + n->left->etype = n->op; + } + + case OCLOSURE: + // TODO do them here instead of in lex.c phase 6b, so escape analysis + // can avoid more heapmoves. + return; + } + + lno = setlineno(n); + + inlnodelist(n->ninit); + for(l=n->ninit; l; l=l->next) + if(l->n->op == OINLCALL) + inlconv2stmt(l->n); + + inlnode(&n->left); + if(n->left && n->left->op == OINLCALL) + inlconv2expr(&n->left); + + inlnode(&n->right); + if(n->right && n->right->op == OINLCALL) + inlconv2expr(&n->right); + + inlnodelist(n->list); + switch(n->op) { + case OBLOCK: + for(l=n->list; l; l=l->next) + if(l->n->op == OINLCALL) + inlconv2stmt(l->n); + break; + + case ORETURN: + case OCALLFUNC: + case OCALLMETH: + case OCALLINTER: + // if we just replaced arg in f(arg()) or return arg with an inlined call + // and arg returns multiple values, glue as list + if(count(n->list) == 1 && n->list->n->op == OINLCALL && count(n->list->n->rlist) > 1) { + n->list = inlconv2list(n->list->n); + break; + } + + // fallthrough + default: + for(l=n->list; l; l=l->next) + if(l->n->op == OINLCALL) + inlconv2expr(&l->n); + } + + inlnodelist(n->rlist); + switch(n->op) { + case OAS2FUNC: + if(n->rlist->n->op == OINLCALL) { + n->rlist = inlconv2list(n->rlist->n); + n->op = OAS2; + n->typecheck = 0; + typecheck(np, Etop); + break; + } + + // fallthrough + default: + for(l=n->rlist; l; l=l->next) + if(l->n->op == OINLCALL) + inlconv2expr(&l->n); + + } + + inlnode(&n->ntest); + if(n->ntest && n->ntest->op == OINLCALL) + inlconv2expr(&n->ntest); + + inlnode(&n->nincr); + if(n->nincr && n->nincr->op == OINLCALL) + inlconv2stmt(n->nincr); + + inlnodelist(n->nbody); + for(l=n->nbody; l; l=l->next) + if(l->n->op == OINLCALL) + inlconv2stmt(l->n); + + inlnodelist(n->nelse); + for(l=n->nelse; l; l=l->next) + if(l->n->op == OINLCALL) + inlconv2stmt(l->n); + + // with all the branches out of the way, it is now time to + // transmogrify this node itself unless inhibited by the + // switch at the top of this function. + switch(n->op) { + case OCALLFUNC: + case OCALLMETH: + if (n->etype == OPROC || n->etype == ODEFER) + return; + } + + switch(n->op) { + case OCALLFUNC: + if(debug['m']>3) + print("%L:call to func %+N\n", n->lineno, n->left); + if(n->left->inl) // normal case + mkinlcall(np, n->left); + else if(n->left->op == ONAME && n->left->left && n->left->left->op == OTYPE && n->left->right && n->left->right->op == ONAME) // methods called as functions + if(n->left->sym->def) + mkinlcall(np, n->left->sym->def); + break; + + case OCALLMETH: + if(debug['m']>3) + print("%L:call to meth %lN\n", n->lineno, n->left->right); + // typecheck should have resolved ODOTMETH->type, whose nname points to the actual function. + if(n->left->type == T) + fatal("no function type for [%p] %+N\n", n->left, n->left); + + if(n->left->type->nname == N) + fatal("no function definition for [%p] %+T\n", n->left->type, n->left->type); + + mkinlcall(np, n->left->type->nname); + + break; + } + + lineno = lno; +} + +static void mkinlcall1(Node **np, Node *fn); + +static void +mkinlcall(Node **np, Node *fn) +{ + int save_safemode; + Pkg *pkg; + + save_safemode = safemode; + + // imported functions may refer to unsafe as long as the + // package was marked safe during import (already checked). + pkg = fnpkg(fn); + if(pkg != localpkg && pkg != nil) + safemode = 0; + mkinlcall1(np, fn); + safemode = save_safemode; +} +// if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL. +// On return ninit has the parameter assignments, the nbody is the +// inlined function body and list, rlist contain the input, output +// parameters. +static void +mkinlcall1(Node **np, Node *fn) +{ + int i; + Node *n, *call, *saveinlfn, *as, *m; + NodeList *dcl, *ll, *ninit, *body; + Type *t; + + if (fn->inl == nil) + return; + + if (fn == curfn || fn->defn == curfn) + return; + + if(debug['l']<2) + typecheckinl(fn); + + n = *np; + + // Bingo, we have a function node, and it has an inlineable body + if(debug['m']>1) + print("%L: inlining call to %S %#T { %#H }\n", n->lineno, fn->sym, fn->type, fn->inl); + else if(debug['m']) + print("%L: inlining call to %N\n", n->lineno, fn); + + if(debug['m']>2) + print("%L: Before inlining: %+N\n", n->lineno, n); + + saveinlfn = inlfn; + inlfn = fn; + + ninit = n->ninit; + + if (fn->defn) // local function + dcl = fn->defn->dcl; + else // imported function + dcl = fn->dcl; + + inlretvars = nil; + i = 0; + // Make temp names to use instead of the originals + for(ll = dcl; ll; ll=ll->next) + if(ll->n->op == ONAME) { + ll->n->inlvar = inlvar(ll->n); + ninit = list(ninit, nod(ODCL, ll->n->inlvar, N)); // otherwise gen won't emit the allocations for heapallocs + if (ll->n->class == PPARAMOUT) // we rely on the order being correct here + inlretvars = list(inlretvars, ll->n->inlvar); + } + + // anonymous return values, synthesize names for use in assignment that replaces return + if(inlretvars == nil && fn->type->outtuple > 0) + for(t = getoutargx(fn->type)->type; t; t = t->down) { + m = retvar(t, i++); + ninit = list(ninit, nod(ODCL, m, N)); + inlretvars = list(inlretvars, m); + } + + // assign arguments to the parameters' temp names + as = N; + if(fn->type->thistuple) { + t = getthisx(fn->type)->type; + if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar) + fatal("missing inlvar for %N\n", t->nname); + + if(n->left->op == ODOTMETH) { + if(!n->left->left) + fatal("method call without receiver: %+N", n); + if(t == T) + fatal("method call unknown receiver type: %+N", n); + if(t->nname != N && !isblank(t->nname)) + as = nod(OAS, t->nname->inlvar, n->left->left); + else + as = nod(OAS, temp(t->type), n->left->left); + } else { // non-method call to method + if (!n->list) + fatal("non-method call to method without first arg: %+N", n); + if(t != T && t->nname != N && !isblank(t->nname)) + as = nod(OAS, t->nname->inlvar, n->list->n); + } + + if(as != N) { + typecheck(&as, Etop); + ninit = list(ninit, as); + } + } + + as = nod(OAS2, N, N); + if(fn->type->intuple > 1 && n->list && !n->list->next) { + // TODO check that n->list->n is a call? + // TODO: non-method call to T.meth(f()) where f returns t, args... + as->rlist = n->list; + for(t = getinargx(fn->type)->type; t; t=t->down) { + if(t->nname && !isblank(t->nname)) { + if(!t->nname->inlvar) + fatal("missing inlvar for %N\n", t->nname); + as->list = list(as->list, t->nname->inlvar); + } else { + as->list = list(as->list, temp(t->type)); + } + } + } else { + ll = n->list; + if(fn->type->thistuple && n->left->op != ODOTMETH) // non method call to method + ll=ll->next; // was handled above in if(thistuple) + + for(t = getinargx(fn->type)->type; t && ll; t=t->down) { + if(t->nname && !isblank(t->nname)) { + if(!t->nname->inlvar) + fatal("missing inlvar for %N\n", t->nname); + as->list = list(as->list, t->nname->inlvar); + as->rlist = list(as->rlist, ll->n); + } + ll=ll->next; + } + if(ll || t) + fatal("arg count mismatch: %#T vs %,H\n", getinargx(fn->type), n->list); + } + + if (as->rlist) { + typecheck(&as, Etop); + ninit = list(ninit, as); + } + + // zero the outparams + for(ll = inlretvars; ll; ll=ll->next) { + as = nod(OAS, ll->n, N); + typecheck(&as, Etop); + ninit = list(ninit, as); + } + + inlretlabel = newlabel(); + body = inlsubstlist(fn->inl); + + body = list(body, nod(OGOTO, inlretlabel, N)); // avoid 'not used' when function doesnt have return + body = list(body, nod(OLABEL, inlretlabel, N)); + + typechecklist(body, Etop); + + call = nod(OINLCALL, N, N); + call->ninit = ninit; + call->nbody = body; + call->rlist = inlretvars; + call->type = n->type; + call->typecheck = 1; + + setlno(call, n->lineno); + + *np = call; + + inlfn = saveinlfn; + + // transitive inlining + // TODO do this pre-expansion on fn->inl directly. requires + // either supporting exporting statemetns with complex ninits + // or saving inl and making inlinl + if(debug['l'] >= 5) { + body = fn->inl; + fn->inl = nil; // prevent infinite recursion + inlnodelist(call->nbody); + for(ll=call->nbody; ll; ll=ll->next) + if(ll->n->op == OINLCALL) + inlconv2stmt(ll->n); + fn->inl = body; + } + + if(debug['m']>2) + print("%L: After inlining %+N\n\n", n->lineno, *np); + +} + +// Every time we expand a function we generate a new set of tmpnames, +// PAUTO's in the calling functions, and link them off of the +// PPARAM's, PAUTOS and PPARAMOUTs of the called function. +static Node* +inlvar(Node *var) +{ + Node *n; + + if(debug['m']>3) + print("inlvar %+N\n", var); + + n = newname(var->sym); + n->type = var->type; + n->class = PAUTO; + n->used = 1; + n->curfn = curfn; // the calling function, not the called one + curfn->dcl = list(curfn->dcl, n); + return n; +} + +// Synthesize a variable to store the inlined function's results in. +static Node* +retvar(Type *t, int i) +{ + Node *n; + + snprint(namebuf, sizeof(namebuf), ".r%d", i); + n = newname(lookup(namebuf)); + n->type = t->type; + n->class = PAUTO; + n->used = 1; + n->curfn = curfn; // the calling function, not the called one + curfn->dcl = list(curfn->dcl, n); + return n; +} + +static Node* +newlabel(void) +{ + Node *n; + static int label; + + label++; + snprint(namebuf, sizeof(namebuf), ".inlret%.6d", label); + n = newname(lookup(namebuf)); + n->etype = 1; // flag 'safe' for escape analysis (no backjumps) + return n; +} + +// inlsubst and inlsubstlist recursively copy the body of the saved +// pristine ->inl body of the function while substituting references +// to input/output parameters with ones to the tmpnames, and +// substituting returns with assignments to the output. +static NodeList* +inlsubstlist(NodeList *ll) +{ + NodeList *l; + + l = nil; + for(; ll; ll=ll->next) + l = list(l, inlsubst(ll->n)); + return l; +} + +static Node* +inlsubst(Node *n) +{ + Node *m, *as; + NodeList *ll; + + if(n == N) + return N; + + switch(n->op) { + case ONAME: + if(n->inlvar) { // These will be set during inlnode + if (debug['m']>2) + print ("substituting name %+N -> %+N\n", n, n->inlvar); + return n->inlvar; + } + if (debug['m']>2) + print ("not substituting name %+N\n", n); + return n; + + case OLITERAL: + case OTYPE: + return n; + + case ORETURN: + // Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function. + +// dump("Return before substitution", n); + m = nod(OGOTO, inlretlabel, N); + m->ninit = inlsubstlist(n->ninit); + + if(inlretvars && n->list) { + as = nod(OAS2, N, N); + // shallow copy or OINLCALL->rlist will be the same list, and later walk and typecheck may clobber that. + for(ll=inlretvars; ll; ll=ll->next) + as->list = list(as->list, ll->n); + as->rlist = inlsubstlist(n->list); + typecheck(&as, Etop); + m->ninit = list(m->ninit, as); + } + + typechecklist(m->ninit, Etop); + typecheck(&m, Etop); +// dump("Return after substitution", m); + return m; + } + + + m = nod(OXXX, N, N); + *m = *n; + m->ninit = nil; + + if(n->op == OCLOSURE) + fatal("cannot inline function containing closure: %+N", n); + + m->left = inlsubst(n->left); + m->right = inlsubst(n->right); + m->list = inlsubstlist(n->list); + m->rlist = inlsubstlist(n->rlist); + m->ninit = concat(m->ninit, inlsubstlist(n->ninit)); + m->ntest = inlsubst(n->ntest); + m->nincr = inlsubst(n->nincr); + m->nbody = inlsubstlist(n->nbody); + m->nelse = inlsubstlist(n->nelse); + + return m; +} + +// Plaster over linenumbers +static void +setlnolist(NodeList *ll, int lno) +{ + for(;ll;ll=ll->next) + setlno(ll->n, lno); +} + +static void +setlno(Node *n, int lno) +{ + if(!n) + return; + + // don't clobber names, unless they're freshly synthesized + if(n->op != ONAME || n->lineno == 0) + n->lineno = lno; + + setlno(n->left, lno); + setlno(n->right, lno); + setlnolist(n->list, lno); + setlnolist(n->rlist, lno); + setlnolist(n->ninit, lno); + setlno(n->ntest, lno); + setlno(n->nincr, lno); + setlnolist(n->nbody, lno); + setlnolist(n->nelse, lno); +} diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 29b6d27ff..e71fd3848 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -2,7 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -#define EXTERN +#include <u.h> +#include <libc.h> #include "go.h" #include "y.tab.h" #include <ar.h> @@ -18,6 +19,7 @@ int yyprev; int yylast; static void lexinit(void); +static void lexinit1(void); static void lexfini(void); static void yytinit(void); static int getc(void); @@ -28,6 +30,61 @@ static void addidir(char*); static int getlinepragma(void); static char *goos, *goarch, *goroot; +// Compiler experiments. +// These are controlled by the GOEXPERIMENT environment +// variable recorded when the compiler is built. +static struct { + char *name; + int *val; +} exper[] = { +// {"rune32", &rune32}, + {nil, nil}, +}; + +static void +addexp(char *s) +{ + int i; + + for(i=0; exper[i].name != nil; i++) { + if(strcmp(exper[i].name, s) == 0) { + *exper[i].val = 1; + return; + } + } + + print("unknown experiment %s\n", s); + exits("unknown experiment"); +} + +static void +setexp(void) +{ + char *f[20]; + int i, nf; + + // The makefile #defines GOEXPERIMENT for us. + nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ","); + for(i=0; i<nf; i++) + addexp(f[i]); +} + +char* +expstring(void) +{ + int i; + static char buf[512]; + + strcpy(buf, "X"); + for(i=0; exper[i].name != nil; i++) + if(*exper[i].val) + seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name); + if(strlen(buf) == 1) + strcpy(buf, "X,none"); + buf[1] = ':'; + return buf; +} + // Our own isdigit, isspace, isalpha, isalnum that take care // of EOF and other out of range arguments. static int @@ -64,7 +121,7 @@ yy_isalnum(int c) #define isalpha use_yy_isalpha_instead_of_isalpha #define isalnum use_yy_isalnum_instead_of_isalnum -#define DBG if(!debug['x']);else print +#define DBG if(!debug['x']){}else print enum { EOF = -1, @@ -75,24 +132,48 @@ usage(void) { print("gc: usage: %cg [flags] file.go...\n", thechar); print("flags:\n"); - // -A is allow use of "any" type, for bootstrapping + // -A allow use of "any" type, for bootstrapping + // -B disable bounds checking + // -E print imported declarations + // -K warn when lineno is zero + // -M print arguments to gmove + // -P print peephole diagnostics + // -R print optimizer diagnostics + // -g print code generation diagnostics + // -i print line history + // -j print variables to be initialized at runtime + // -r print generated helper functions + // -s print redundant types in composite literals + // -v print more information with -P or -R + // -y print declarations in cannedimports (used with -d) + // -% print non-static initializers + // -+ indicate that the runtime is being compiled + print(" -D PATH interpret local imports relative to this import path\n"); print(" -I DIR search for packages in DIR\n"); + print(" -L show full path in file:line prints\n"); + print(" -N disable optimizations\n"); + print(" -S print the assembly language\n"); + print(" -V print the compiler version\n"); + print(" -W print the parse tree after typing\n"); print(" -d print declarations\n"); print(" -e no limit on number of errors printed\n"); print(" -f print stack frame structure\n"); print(" -h panic on an error\n"); + print(" -l disable inlining\n"); + print(" -m print optimization decisions\n"); print(" -o file specify output file\n"); - print(" -S print the assembly language\n"); - print(" -V print the compiler version\n"); + print(" -p assumed import path for this code\n"); print(" -u disable package unsafe\n"); - print(" -w print the parse tree after typing\n"); + print(" -w print type checking details\n"); print(" -x print lex tokens\n"); - exit(0); + exits("usage"); } void fault(int s) { + USED(s); + // If we've already complained about things // in the program, don't bother complaining // about the seg fault too; let the user clean up @@ -106,11 +187,13 @@ int main(int argc, char *argv[]) { int i, c; - NodeList *l; + NodeList *l, *batch; char *p; - + +#ifdef SIGBUS signal(SIGBUS, fault); signal(SIGSEGV, fault); +#endif localpkg = mkpkg(strlit("")); localpkg->prefix = "\"\""; @@ -127,12 +210,18 @@ main(int argc, char *argv[]) typepkg = mkpkg(strlit("type")); typepkg->name = "type"; + weaktypepkg = mkpkg(strlit("weak.type")); + weaktypepkg->name = "weak.type"; + weaktypepkg->prefix = "weak.type"; // not weak%2etype + unsafepkg = mkpkg(strlit("unsafe")); unsafepkg->name = "unsafe"; goroot = getgoroot(); goos = getgoos(); goarch = thestring; + + setexp(); outfile = nil; ARGBEGIN { @@ -145,19 +234,37 @@ main(int argc, char *argv[]) case 'o': outfile = EARGF(usage()); break; - - case 'I': - addidir(EARGF(usage())); - break; + case 'p': + myimportpath = EARGF(usage()); + break; + case 'u': safemode = 1; break; + case 'D': + localimport = EARGF(usage()); + break; + + case 'I': + addidir(EARGF(usage())); + break; + case 'V': - print("%cg version %s\n", thechar, getgoversion()); - exit(0); + p = expstring(); + if(strcmp(p, "X:none") == 0) + p = ""; + print("%cg version %s%s%s\n", thechar, getgoversion(), *p ? " " : "", p); + exits(0); } ARGEND + + // enable inlining. for now: + // default: inlining on. (debug['l'] == 1) + // -l: inlining off (debug['l'] == 0) + // -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1) + if(debug['l'] <= 1) + debug['l'] = 1 - debug['l']; if(argc < 1) usage(); @@ -179,23 +286,14 @@ main(int argc, char *argv[]) *p = '/'; } - fmtinstall('O', Oconv); // node opcodes - fmtinstall('E', Econv); // etype opcodes - fmtinstall('J', Jconv); // all the node flags - fmtinstall('S', Sconv); // sym pointer - fmtinstall('T', Tconv); // type pointer - fmtinstall('N', Nconv); // node pointer - fmtinstall('Z', Zconv); // escaped string - fmtinstall('L', Lconv); // line number - fmtinstall('B', Bconv); // big numbers - fmtinstall('F', Fconv); // big float numbers - + fmtinstallgo(); betypeinit(); if(widthptr == 0) fatal("betypeinit failed"); lexinit(); typeinit(); + lexinit1(); yytinit(); blockgen = 1; @@ -236,24 +334,24 @@ main(int argc, char *argv[]) if(debug['f']) frame(1); - // Process top-level declarations in four phases. + // Process top-level declarations in phases. // Phase 1: const, type, and names and types of funcs. // This will gather all the information about types // and methods but doesn't depend on any of it. - // Phase 2: Variable assignments. - // To check interface assignments, depends on phase 1. - // Phase 3: Type check function bodies. - // Phase 4: Compile function bodies. defercheckwidth(); for(l=xtop; l; l=l->next) if(l->n->op != ODCL && l->n->op != OAS) typecheck(&l->n, Etop); + + // Phase 2: Variable assignments. + // To check interface assignments, depends on phase 1. for(l=xtop; l; l=l->next) if(l->n->op == ODCL || l->n->op == OAS) typecheck(&l->n, Etop); resumetypecopy(); resumecheckwidth(); + // Phase 3: Type check function bodies. for(l=xtop; l; l=l->next) { if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) { curfn = l->n; @@ -269,6 +367,37 @@ main(int argc, char *argv[]) if(nsavederrors+nerrors) errorexit(); + // Phase 4: Inlining + if (debug['l'] > 1) { + // Typecheck imported function bodies if debug['l'] > 1, + // otherwise lazily when used or re-exported. + for(l=importlist; l; l=l->next) + if (l->n->inl) { + saveerrors(); + typecheckinl(l->n); + } + + if(nsavederrors+nerrors) + errorexit(); + } + + if (debug['l']) { + // Find functions that can be inlined and clone them before walk expands them. + for(l=xtop; l; l=l->next) + if(l->n->op == ODCLFUNC) + caninl(l->n); + + // Expand inlineable calls in all functions + for(l=xtop; l; l=l->next) + if(l->n->op == ODCLFUNC) + inlcalls(l->n); + } + + // Phase 5: escape analysis. + if(!debug['N']) + escapes(xtop); + + // Phase 6: Compile top level functions. for(l=xtop; l; l=l->next) if(l->n->op == ODCLFUNC) funccompile(l->n, 0); @@ -276,14 +405,21 @@ main(int argc, char *argv[]) if(nsavederrors+nerrors == 0) fninit(xtop); + // Phase 6b: Compile all closures. + // Can generate more closures, so run in batches. while(closures) { - l = closures; + batch = closures; closures = nil; - for(; l; l=l->next) { + if(debug['l']) + for(l=batch; l; l=l->next) + inlcalls(l->n); + if(!debug['N']) + escapes(batch); + for(l=batch; l; l=l->next) funccompile(l->n, 1); - } } + // Phase 7: check external declarations. for(l=externdcl; l; l=l->next) if(l->n->op == ONAME) typecheck(&l->n, Erv); @@ -297,7 +433,7 @@ main(int argc, char *argv[]) errorexit(); flusherrors(); - exit(0); + exits(0); return 0; } @@ -308,18 +444,30 @@ saveerrors(void) nerrors = 0; } +/* + * macro to portably read/write archive header. + * 'cmd' is read/write/Bread/Bwrite, etc. + */ +#define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\ + || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\ + || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\ + || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\ + || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\ + || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\ + || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag) + static int arsize(Biobuf *b, char *name) { - struct ar_hdr *a; + struct ar_hdr a; - if((a = Brdline(b, '\n')) == nil) + if (HEADER_IO(Bread, b, a)) return -1; - if(Blinelen(b) != sizeof(struct ar_hdr)) - return -1; - if(strncmp(a->name, name, strlen(name)) != 0) + + if(strncmp(a.name, name, strlen(name)) != 0) return -1; - return atoi(a->size); + + return atoi(a.size); } static int @@ -366,15 +514,19 @@ addidir(char* dir) static int islocalname(Strlit *name) { - if(!windows && name->len >= 1 && name->s[0] == '/') + if(name->len >= 1 && name->s[0] == '/') return 1; if(windows && name->len >= 3 && yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/') return 1; if(name->len >= 2 && strncmp(name->s, "./", 2) == 0) return 1; + if(name->len == 1 && strncmp(name->s, ".", 1) == 0) + return 1; if(name->len >= 3 && strncmp(name->s, "../", 3) == 0) return 1; + if(name->len == 2 && strncmp(name->s, "..", 2) == 0) + return 1; return 0; } @@ -400,8 +552,8 @@ findpkg(Strlit *name) } // local imports should be canonicalized already. - // don't want to see "container/../container/vector" - // as different from "container/vector". + // don't want to see "encoding/../encoding/base64" + // as different from "encoding/base64". q = mal(name->len+1); memmove(q, name->s, name->len); q[name->len] = '\0'; @@ -430,6 +582,13 @@ findpkg(Strlit *name) return 0; } +static void +fakeimport(void) +{ + importpkg = mkpkg(strlit("fake")); + cannedimports("fake.6", "$$\n"); +} + void importfile(Val *f, int line) { @@ -438,18 +597,27 @@ importfile(Val *f, int line) int32 c; int len; Strlit *path; - char *cleanbuf; + char *cleanbuf, *prefix; + + USED(line); // TODO(rsc): don't bother reloading imports more than once? if(f->ctype != CTSTR) { yyerror("import statement not a string"); + fakeimport(); return; } - if(strlen(f->u.sval->s) != f->u.sval->len) { - yyerror("import path contains NUL"); - errorexit(); + if(f->u.sval->len == 0) { + yyerror("import path is empty"); + fakeimport(); + return; + } + + if(isbadimport(f->u.sval)) { + fakeimport(); + return; } // The package name main is no longer reserved, @@ -461,6 +629,11 @@ importfile(Val *f, int line) errorexit(); } + if(myimportpath != nil && strcmp(f->u.sval->s, myimportpath) == 0) { + yyerror("import \"%Z\" while compiling that package (import cycle)", f->u.sval); + errorexit(); + } + if(strcmp(f->u.sval->s, "unsafe") == 0) { if(safemode) { yyerror("cannot import package unsafe"); @@ -473,8 +646,16 @@ importfile(Val *f, int line) path = f->u.sval; if(islocalname(path)) { - cleanbuf = mal(strlen(pathname) + strlen(path->s) + 2); - strcpy(cleanbuf, pathname); + if(path->s[0] == '/') { + yyerror("import path cannot be absolute path"); + fakeimport(); + return; + } + prefix = pathname; + if(localimport != nil) + prefix = localimport; + cleanbuf = mal(strlen(prefix) + strlen(path->s) + 2); + strcpy(cleanbuf, prefix); strcat(cleanbuf, "/"); strcat(cleanbuf, path->s); cleanname(cleanbuf); @@ -482,14 +663,14 @@ importfile(Val *f, int line) } if(!findpkg(path)) { - yyerror("can't find import: %Z", f->u.sval); + yyerror("can't find import: \"%Z\"", f->u.sval); errorexit(); } importpkg = mkpkg(path); imp = Bopen(namebuf, OREAD); if(imp == nil) { - yyerror("can't open import: %Z: %r", f->u.sval); + yyerror("can't open import: \"%Z\": %r", f->u.sval); errorexit(); } file = strdup(namebuf); @@ -509,7 +690,7 @@ importfile(Val *f, int line) yyerror("import %s: not a go object file", file); errorexit(); } - q = smprint("%s %s %s", getgoos(), thestring, getgoversion()); + q = smprint("%s %s %s %s", getgoos(), thestring, getgoversion(), expstring()); if(strcmp(p+10, q) != 0) { yyerror("import %s: object is [%s] expected [%s]", file, p+10, q); errorexit(); @@ -546,7 +727,7 @@ importfile(Val *f, int line) continue; return; } - yyerror("no import in: %Z", f->u.sval); + yyerror("no import in \"%Z\"", f->u.sval); unimportfile(); } @@ -665,7 +846,6 @@ l0: ep = lexbuf+sizeof lexbuf; *cp++ = c; c = c1; - c1 = 0; goto casedot; } if(c1 == '.') { @@ -717,6 +897,8 @@ l0: ncp += ncp; } c = getr(); + if(c == '\r') + continue; if(c == EOF) { yyerror("eof in string"); break; @@ -750,7 +932,7 @@ l0: } yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval)); mpmovecfix(yylval.val.u.xval, v); - yylval.val.ctype = CTINT; + yylval.val.ctype = CTRUNE; DBG("lex: codepoint literal\n"); strcpy(litbuf, "string literal"); return LLITERAL; @@ -1008,7 +1190,7 @@ lx: return c; asop: - yylval.lint = c; // rathole to hold which asop + yylval.i = c; // rathole to hold which asop DBG("lex: TOKEN ASOP %c\n", c); return LASOP; @@ -1056,7 +1238,6 @@ talph: return s->lexical; tnum: - c1 = 0; cp = lexbuf; ep = lexbuf+sizeof lexbuf; if(c != '0') { @@ -1247,7 +1428,7 @@ static int getlinepragma(void) { int i, c, n; - char *cp, *ep; + char *cp, *ep, *linep; Hist *h; for(i=0; i<5; i++) { @@ -1258,32 +1439,36 @@ getlinepragma(void) cp = lexbuf; ep = lexbuf+sizeof(lexbuf)-5; + linep = nil; for(;;) { c = getr(); - if(c == '\n' || c == EOF) + if(c == EOF) goto out; + if(c == '\n') + break; if(c == ' ') continue; if(c == ':') - break; + linep = cp; if(cp < ep) *cp++ = c; } *cp = 0; + if(linep == nil || linep >= ep) + goto out; + *linep++ = '\0'; n = 0; - for(;;) { - c = getr(); - if(!yy_isdigit(c)) - break; - n = n*10 + (c-'0'); + for(cp=linep; *cp; cp++) { + if(*cp < '0' || *cp > '9') + goto out; + n = n*10 + *cp - '0'; if(n > 1e8) { yyerror("line number out of range"); errorexit(); } } - - if(c != '\n' || n <= 0) + if(n <= 0) goto out; // try to avoid allocating file name over and over @@ -1334,7 +1519,7 @@ yylex(void) // Track last two tokens returned by yylex. yyprev = yylast; yylast = lx; - return lx; + return lx; } static int @@ -1561,7 +1746,6 @@ static struct "complex128", LNAME, TCOMPLEX128, OXXX, "bool", LNAME, TBOOL, OXXX, - "byte", LNAME, TUINT8, OXXX, "string", LNAME, TSTRING, OXXX, "any", LNAME, TANY, OXXX, @@ -1592,11 +1776,12 @@ static struct "type", LTYPE, Txxx, OXXX, "var", LVAR, Txxx, OXXX, - "append", LNAME, Txxx, OAPPEND, + "append", LNAME, Txxx, OAPPEND, "cap", LNAME, Txxx, OCAP, "close", LNAME, Txxx, OCLOSE, "complex", LNAME, Txxx, OCOMPLEX, "copy", LNAME, Txxx, OCOPY, + "delete", LNAME, Txxx, ODELETE, "imag", LNAME, Txxx, OIMAG, "len", LNAME, Txxx, OLEN, "make", LNAME, Txxx, OMAKE, @@ -1621,6 +1806,7 @@ lexinit(void) Sym *s, *s1; Type *t; int etype; + Val v; /* * initialize basic types array @@ -1649,6 +1835,16 @@ lexinit(void) s1->def = typenod(t); continue; } + + etype = syms[i].op; + if(etype != OXXX) { + s1 = pkglookup(syms[i].name, builtinpkg); + s1->lexical = LNAME; + s1->def = nod(ONAME, N, N); + s1->def->sym = s1; + s1->def->etype = etype; + s1->def->builtin = 1; + } } // logically, the type of a string literal. @@ -1676,6 +1872,77 @@ lexinit(void) types[TBLANK] = typ(TBLANK); s->def->type = types[TBLANK]; nblank = s->def; + + s = pkglookup("_", builtinpkg); + s->block = -100; + s->def = nod(ONAME, N, N); + s->def->sym = s; + types[TBLANK] = typ(TBLANK); + s->def->type = types[TBLANK]; + + types[TNIL] = typ(TNIL); + s = pkglookup("nil", builtinpkg); + v.ctype = CTNIL; + s->def = nodlit(v); + s->def->sym = s; +} + +static void +lexinit1(void) +{ + Sym *s, *s1; + Type *t, *f, *rcvr, *in, *out; + + // t = interface { Error() string } + rcvr = typ(TSTRUCT); + rcvr->type = typ(TFIELD); + rcvr->type->type = ptrto(typ(TSTRUCT)); + rcvr->funarg = 1; + in = typ(TSTRUCT); + in->funarg = 1; + out = typ(TSTRUCT); + out->type = typ(TFIELD); + out->type->type = types[TSTRING]; + out->funarg = 1; + f = typ(TFUNC); + *getthis(f) = rcvr; + *getoutarg(f) = out; + *getinarg(f) = in; + f->thistuple = 1; + f->intuple = 0; + f->outnamed = 0; + f->outtuple = 1; + t = typ(TINTER); + t->type = typ(TFIELD); + t->type->sym = lookup("Error"); + t->type->type = f; + + // error type + s = lookup("error"); + s->lexical = LNAME; + errortype = t; + errortype->sym = s; + s1 = pkglookup("error", builtinpkg); + s1->lexical = LNAME; + s1->def = typenod(errortype); + + // byte alias + s = lookup("byte"); + s->lexical = LNAME; + bytetype = typ(TUINT8); + bytetype->sym = s; + s1 = pkglookup("byte", builtinpkg); + s1->lexical = LNAME; + s1->def = typenod(bytetype); + + // rune alias + s = lookup("rune"); + s->lexical = LNAME; + runetype = typ(TINT32); + runetype->sym = s; + s1 = pkglookup("rune", builtinpkg); + s1->lexical = LNAME; + s1->def = typenod(runetype); } static void @@ -1713,7 +1980,18 @@ lexfini(void) // there's only so much table-driven we can handle. // these are special cases. - types[TNIL] = typ(TNIL); + s = lookup("byte"); + if(s->def == N) + s->def = typenod(bytetype); + + s = lookup("error"); + if(s->def == N) + s->def = typenod(errortype); + + s = lookup("rune"); + if(s->def == N) + s->def = typenod(runetype); + s = lookup("nil"); if(s->def == N) { v.ctype = CTNIL; @@ -1740,7 +2018,6 @@ lexfini(void) } nodfp = nod(ONAME, N, N); - nodfp->noescape = 1; nodfp->type = types[TINT32]; nodfp->xoffset = 0; nodfp->class = PPARAM; @@ -1923,7 +2200,7 @@ mkpackage(char* pkgname) // errors if a conflicting top-level name is // introduced by a different file. if(!s->def->used && !nsyntaxerrors) - yyerrorl(s->def->lineno, "imported and not used: %Z", s->def->pkg->path); + yyerrorl(s->def->lineno, "imported and not used: \"%Z\"", s->def->pkg->path); s->def = N; continue; } @@ -1931,7 +2208,7 @@ mkpackage(char* pkgname) // throw away top-level name left over // from previous import . "x" if(s->def->pack != N && !s->def->pack->used && !nsyntaxerrors) { - yyerrorl(s->def->pack->lineno, "imported and not used: %Z", s->def->pack->pkg->path); + yyerrorl(s->def->pack->lineno, "imported and not used: \"%Z\"", s->def->pack->pkg->path); s->def->pack->used = 1; } s->def = N; diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c index 7cea1a6cf..5856aab51 100644 --- a/src/cmd/gc/md5.c +++ b/src/cmd/gc/md5.c @@ -5,6 +5,8 @@ // 64-bit MD5 (does full MD5 but returns 64 bits only). // Translation of ../../pkg/crypto/md5/md5*.go. +#include <u.h> +#include <libc.h> #include "go.h" #include "md5.h" diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin index cfd6e59c1..2f76e6f06 100755 --- a/src/cmd/gc/mkbuiltin +++ b/src/cmd/gc/mkbuiltin @@ -3,29 +3,29 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -# Generate builtin.c and builtin.c.boot from $* (runtime.go and unsafe.go). +# Generate builtin.c from $* (runtime.go and unsafe.go). # Run this after changing runtime.go and unsafe.go # or after changing the export metadata format in the compiler. # Either way, you need to have a working compiler binary first. set -e -eval $(gomake --no-print-directory -f ../../Make.inc go-env) -if [ -z "$GC" ]; then - echo 'missing $GC - gomake failed?' 1>&2 +eval $(go tool dist env) +if [ -z "$GOCHAR" ]; then + echo 'missing $GOCHAR - go tool dist failed?' 1>&2 exit 1 fi -gomake mkbuiltin1 +GC=${GOCHAR}g +gcc -o mkbuiltin1 mkbuiltin1.c rm -f _builtin.c for i in runtime unsafe do - $GC -A $i.go - O=$O ./mkbuiltin1 $i >>_builtin.c + go tool $GC -A $i.go + O=$GOCHAR ./mkbuiltin1 $i >>_builtin.c done -# If _builtin.c has changed vs builtin.c.boot, +# If _builtin.c has changed vs builtin.c, # check in the new change. -cmp -s _builtin.c builtin.c.boot || cp _builtin.c builtin.c.boot - -mv _builtin.c builtin.c +cmp -s _builtin.c builtin.c || cp _builtin.c builtin.c +rm _builtin.c mkbuiltin1 unsafe.$GOCHAR runtime.$GOCHAR diff --git a/src/cmd/gc/mkbuiltin1.c b/src/cmd/gc/mkbuiltin1.c index ad83c0346..f8f61c278 100644 --- a/src/cmd/gc/mkbuiltin1.c +++ b/src/cmd/gc/mkbuiltin1.c @@ -2,15 +2,21 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build ignore + // Compile .go file, import data from .6 file, and generate C string version. -#include <u.h> -#include <libc.h> #include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> void esc(char*); +void fatal(char*, ...); -void +int main(int argc, char **argv) { char *name; @@ -19,7 +25,7 @@ main(int argc, char **argv) if(argc != 2) { fprintf(stderr, "usage: mkbuiltin1 sys\n"); - sysfatal("in file $1.6 s/PACKAGE/$1/\n"); + fatal("in file $1.6 s/PACKAGE/$1/"); } name = argv[1]; @@ -27,14 +33,14 @@ main(int argc, char **argv) snprintf(buf, sizeof(buf), "%s.%s", name, getenv("O")); if((fin = fopen(buf, "r")) == NULL) { - sysfatal("open %s: %r\n", buf); + fatal("open %s: %s", buf, strerror(errno)); } // look for $$ that introduces imports while(fgets(buf, sizeof buf, fin) != NULL) if(strstr(buf, "$$")) goto begin; - sysfatal("did not find beginning of imports\n"); + fatal("did not find beginning of imports"); begin: printf("char *%simport =\n", name); @@ -66,11 +72,11 @@ begin: esc(p); printf("\\n\"\n"); } - sysfatal("did not find end of imports\n"); + fatal("did not find end of imports"); end: printf("\t\"$$\\n\";\n"); - exits(0); + return 0; } void @@ -82,3 +88,15 @@ esc(char *p) putchar(*p); } } + +void +fatal(char *msg, ...) +{ + va_list arg; + + va_start(arg, msg); + fprintf(stderr, "fatal: "); + vfprintf(stderr, msg, arg); + fprintf(stderr, "\n"); + exit(2); +} diff --git a/src/cmd/gc/mkopnames b/src/cmd/gc/mkopnames index fb2ceec81..d3f27e815 100755 --- a/src/cmd/gc/mkopnames +++ b/src/cmd/gc/mkopnames @@ -14,8 +14,8 @@ echo '{' sed -n '/OXXX/,/OEND/p' go.h | cpp | sed 's!//.*!!; /^#/d' | - tr ' ' '\n' | - tr -d ' \t,' | + tr ' ' '\012' | + tr -d ' \011,' | grep . | sort | grep -v '^OEND$' | diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c index 6cd4e2500..33fa90e2e 100644 --- a/src/cmd/gc/mparith1.c +++ b/src/cmd/gc/mparith1.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" /// uses arithmetic @@ -70,7 +72,7 @@ void mpsubfixfix(Mpint *a, Mpint *b) { mpnegfix(a); - mpaddfixfix(a, b); + mpaddfixfix(a, b, 0); mpnegfix(a); } @@ -88,7 +90,7 @@ mpaddcfix(Mpint *a, vlong c) Mpint b; mpmovecfix(&b, c); - mpaddfixfix(a, &b); + mpaddfixfix(a, &b, 0); } void @@ -300,7 +302,7 @@ mpatoflt(Mpflt *a, char *as) if(c >= '0' && c <= '9') { ex = ex*10 + (c-'0'); if(ex > 1e8) { - yyerror("exponent out of range"); + yyerror("constant exponent out of range: %s", as); errorexit(); } continue; @@ -341,7 +343,7 @@ out: return; bad: - yyerror("set ovf in mpatof"); + yyerror("constant too large: %s", as); mpmovecflt(a, 0.0); } @@ -429,7 +431,7 @@ out: return; bad: - yyerror("set ovf in mpatov: %s", as); + yyerror("constant too large: %s", as); mpmovecfix(a, 0); } diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c index 403255005..8e52ff216 100644 --- a/src/cmd/gc/mparith2.c +++ b/src/cmd/gc/mparith2.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" // @@ -25,10 +27,10 @@ mplen(Mpint *a) // // left shift mpint by one -// ignores sign and overflow +// ignores sign // static void -mplsh(Mpint *a) +mplsh(Mpint *a, int quiet) { long *a1, x; int i, c; @@ -44,19 +46,27 @@ mplsh(Mpint *a) } *a1++ = x; } + a->ovf = c; + if(a->ovf && !quiet) + yyerror("constant shift overflow"); } // // left shift mpint by Mpscale -// ignores sign and overflow +// ignores sign // static void -mplshw(Mpint *a) +mplshw(Mpint *a, int quiet) { long *a1; int i; a1 = &a->a[Mpprec-1]; + if(*a1) { + a->ovf = 1; + if(!quiet) + yyerror("constant shift overflow"); + } for(i=1; i<Mpprec; i++) { a1[0] = a1[-1]; a1--; @@ -119,7 +129,8 @@ mpcmp(Mpint *a, Mpint *b) int i; if(a->ovf || b->ovf) { - yyerror("ovf in cmp"); + if(nsavederrors+nerrors == 0) + yyerror("ovf in cmp"); return 0; } @@ -165,11 +176,11 @@ mpshiftfix(Mpint *a, int s) { if(s >= 0) { while(s >= Mpscale) { - mplshw(a); + mplshw(a, 0); s -= Mpscale; } while(s > 0) { - mplsh(a); + mplsh(a, 0); s--; } } else { @@ -188,13 +199,14 @@ mpshiftfix(Mpint *a, int s) /// implements fix arihmetic void -mpaddfixfix(Mpint *a, Mpint *b) +mpaddfixfix(Mpint *a, Mpint *b, int quiet) { int i, c; long x, *a1, *b1; if(a->ovf || b->ovf) { - yyerror("ovf in mpaddxx"); + if(nsavederrors+nerrors == 0) + yyerror("ovf in mpaddxx"); a->ovf = 1; return; } @@ -216,8 +228,8 @@ mpaddfixfix(Mpint *a, Mpint *b) *a1++ = x; } a->ovf = c; - if(a->ovf) - yyerror("set ovf in mpaddxx"); + if(a->ovf && !quiet) + yyerror("constant addition overflow"); return; @@ -264,7 +276,8 @@ mpmulfixfix(Mpint *a, Mpint *b) Mpint s, q; if(a->ovf || b->ovf) { - yyerror("ovf in mpmulfixfix"); + if(nsavederrors+nerrors == 0) + yyerror("ovf in mpmulfixfix"); a->ovf = 1; return; } @@ -288,8 +301,8 @@ mpmulfixfix(Mpint *a, Mpint *b) x = *a1++; for(j=0; j<Mpscale; j++) { if(x & 1) - mpaddfixfix(&q, &s); - mplsh(&s); + mpaddfixfix(&q, &s, 1); + mplsh(&s, 1); x >>= 1; } } @@ -297,7 +310,7 @@ mpmulfixfix(Mpint *a, Mpint *b) q.neg = a->neg ^ b->neg; mpmovefixfix(a, &q); if(a->ovf) - yyerror("set ovf in mpmulfixfix"); + yyerror("constant multiplication overflow"); } void @@ -309,7 +322,8 @@ mpmulfract(Mpint *a, Mpint *b) Mpint s, q; if(a->ovf || b->ovf) { - yyerror("ovf in mpmulflt"); + if(nsavederrors+nerrors == 0) + yyerror("ovf in mpmulflt"); a->ovf = 1; return; } @@ -332,7 +346,7 @@ mpmulfract(Mpint *a, Mpint *b) for(j=0; j<Mpscale; j++) { x <<= 1; if(x & Mpbase) - mpaddfixfix(&q, &s); + mpaddfixfix(&q, &s, 1); mprsh(&s); } } @@ -340,7 +354,7 @@ mpmulfract(Mpint *a, Mpint *b) q.neg = a->neg ^ b->neg; mpmovefixfix(a, &q); if(a->ovf) - yyerror("set ovf in mpmulflt"); + yyerror("constant multiplication overflow"); } void @@ -349,8 +363,10 @@ mporfixfix(Mpint *a, Mpint *b) int i; long x, *a1, *b1; + x = 0; if(a->ovf || b->ovf) { - yyerror("ovf in mporfixfix"); + if(nsavederrors+nerrors == 0) + yyerror("ovf in mporfixfix"); mpmovecfix(a, 0); a->ovf = 1; return; @@ -383,8 +399,10 @@ mpandfixfix(Mpint *a, Mpint *b) int i; long x, *a1, *b1; + x = 0; if(a->ovf || b->ovf) { - yyerror("ovf in mpandfixfix"); + if(nsavederrors+nerrors == 0) + yyerror("ovf in mpandfixfix"); mpmovecfix(a, 0); a->ovf = 1; return; @@ -417,8 +435,10 @@ mpandnotfixfix(Mpint *a, Mpint *b) int i; long x, *a1, *b1; + x = 0; if(a->ovf || b->ovf) { - yyerror("ovf in mpandnotfixfix"); + if(nsavederrors+nerrors == 0) + yyerror("ovf in mpandnotfixfix"); mpmovecfix(a, 0); a->ovf = 1; return; @@ -451,8 +471,10 @@ mpxorfixfix(Mpint *a, Mpint *b) int i; long x, *a1, *b1; + x = 0; if(a->ovf || b->ovf) { - yyerror("ovf in mporfixfix"); + if(nsavederrors+nerrors == 0) + yyerror("ovf in mporfixfix"); mpmovecfix(a, 0); a->ovf = 1; return; @@ -485,7 +507,8 @@ mplshfixfix(Mpint *a, Mpint *b) vlong s; if(a->ovf || b->ovf) { - yyerror("ovf in mporfixfix"); + if(nsavederrors+nerrors == 0) + yyerror("ovf in mporfixfix"); mpmovecfix(a, 0); a->ovf = 1; return; @@ -506,7 +529,8 @@ mprshfixfix(Mpint *a, Mpint *b) vlong s; if(a->ovf || b->ovf) { - yyerror("ovf in mprshfixfix"); + if(nsavederrors+nerrors == 0) + yyerror("ovf in mprshfixfix"); mpmovecfix(a, 0); a->ovf = 1; return; @@ -536,7 +560,8 @@ mpgetfix(Mpint *a) vlong v; if(a->ovf) { - yyerror("constant overflow"); + if(nsavederrors+nerrors == 0) + yyerror("constant overflow"); return 0; } @@ -589,7 +614,7 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d) for(i=0; i<Mpprec*Mpscale; i++) { if(mpcmp(d, r) > 0) break; - mplsh(d); + mplsh(d, 1); } // if it never happens @@ -599,7 +624,7 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d) r->ovf = 1; n->neg = ns; d->neg = ds; - yyerror("set ovf in mpdivmodfixfix"); + yyerror("constant division overflow"); return; } @@ -608,7 +633,7 @@ mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d) // when done the remaining numerator // will be the remainder for(; i>0; i--) { - mplsh(q); + mplsh(q, 1); mprsh(d); if(mpcmp(d, r) <= 0) { mpaddcfix(q, 1); diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c index b11a4f5f1..f8344c9b4 100644 --- a/src/cmd/gc/mparith3.c +++ b/src/cmd/gc/mparith3.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" /* @@ -87,17 +89,17 @@ mpaddfltflt(Mpflt *a, Mpflt *b) // a is larger, shift b right mpmovefltflt(&c, b); mpshiftfix(&c.val, -s); - mpaddfixfix(&a->val, &c.val); + mpaddfixfix(&a->val, &c.val, 0); goto out; } if(s < 0) { // b is larger, shift a right mpshiftfix(&a->val, s); a->exp -= s; - mpaddfixfix(&a->val, &b->val); + mpaddfixfix(&a->val, &b->val, 0); goto out; } - mpaddfixfix(&a->val, &b->val); + mpaddfixfix(&a->val, &b->val, 0); out: mpnorm(a); @@ -151,7 +153,7 @@ mpdivfltflt(Mpflt *a, Mpflt *b) a->exp = 0; a->val.neg = 0; a->val.ovf = 1; - yyerror("mpdivfltflt divide by zero"); + yyerror("constant division by zero"); return; } @@ -183,7 +185,7 @@ mpgetflt(Mpflt *a) uvlong v, vm; double f; - if(a->val.ovf) + if(a->val.ovf && nsavederrors+nerrors == 0) yyerror("mpgetflt ovf"); s = sigfig(a); diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index f99f93bda..e45b4e0d4 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" /* @@ -21,7 +23,7 @@ dumpobj(void) errorexit(); } - Bprint(bout, "go object %s %s %s\n", getgoos(), thestring, getgoversion()); + Bprint(bout, "go object %s %s %s %s\n", getgoos(), thestring, getgoversion(), expstring()); Bprint(bout, " exports automatically generated from\n"); Bprint(bout, " %s in package \"%s\"\n", curio.infile, localpkg->name); dumpexport(); @@ -29,10 +31,6 @@ dumpobj(void) outhist(bout); - // add nil plist w AEND to catch - // auto-generated trampolines, data - newplist(); - dumpglobls(); dumptypestructs(); dumpdata(); @@ -54,7 +52,7 @@ dumpglobls(void) continue; if(n->type == T) - fatal("external %#N nil type\n", n); + fatal("external %N nil type\n", n); if(n->class == PFUNC) continue; if(n->sym->pkg != localpkg) @@ -128,10 +126,37 @@ outhist(Biobuf *b) { Hist *h; char *p, ds[] = {'c', ':', '/', 0}; + char *tofree; + int n; + static int first = 1; + static char *goroot, *goroot_final; + + if(first) { + // Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL. + first = 0; + goroot = getenv("GOROOT"); + goroot_final = getenv("GOROOT_FINAL"); + if(goroot == nil) + goroot = ""; + if(goroot_final == nil) + goroot_final = goroot; + if(strcmp(goroot, goroot_final) == 0) { + goroot = nil; + goroot_final = nil; + } + } + tofree = nil; for(h = hist; h != H; h = h->link) { p = h->name; if(p) { + if(goroot != nil) { + n = strlen(goroot); + if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') { + tofree = smprint("%s%s", goroot_final, p+n); + p = tofree; + } + } if(windows) { // if windows variable is set, then, we know already, // pathname is started with windows drive specifier @@ -163,9 +188,12 @@ outhist(Biobuf *b) outzfile(b, p); } } - } zhist(b, h->line, h->offset); + if(tofree) { + free(tofree); + tofree = nil; + } } } @@ -260,7 +288,7 @@ stringsym(char *s, int len) tmp.lit.len = len; memmove(tmp.lit.s, s, len); tmp.lit.s[len] = '\0'; - snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp); + snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp.lit); pkg = gostringpkg; } sym = pkglookup(namebuf, pkg); @@ -269,8 +297,8 @@ stringsym(char *s, int len) if(sym->flags & SymUniq) return sym; sym->flags |= SymUniq; - - data(); + sym->def = newname(sym); + off = 0; // string header @@ -287,7 +315,6 @@ stringsym(char *s, int len) off = duint8(sym, off, 0); // terminating NUL for runtime off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment ggloblsym(sym, off, 1); - text(); - + return sym; } diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c new file mode 100644 index 000000000..2cab5fb95 --- /dev/null +++ b/src/cmd/gc/order.c @@ -0,0 +1,358 @@ +// 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. + +// Rewrite tree to use separate statements to enforce +// order of evaluation. Makes walk easier, because it +// can (after this runs) reorder at will within an expression. + +#include <u.h> +#include <libc.h> +#include "go.h" + +static void orderstmt(Node*, NodeList**); +static void orderstmtlist(NodeList*, NodeList**); +static void orderblock(NodeList **l); +static void orderexpr(Node**, NodeList**); +static void orderexprlist(NodeList*, NodeList**); + +void +order(Node *fn) +{ + orderblock(&fn->nbody); +} + +static void +orderstmtlist(NodeList *l, NodeList **out) +{ + for(; l; l=l->next) + orderstmt(l->n, out); +} + +// Order the block of statements *l onto a new list, +// and then replace *l with that list. +static void +orderblock(NodeList **l) +{ + NodeList *out; + + out = nil; + orderstmtlist(*l, &out); + *l = out; +} + +// Order the side effects in *np and leave them as +// the init list of the final *np. +static void +orderexprinplace(Node **np) +{ + Node *n; + NodeList *out; + + n = *np; + out = nil; + orderexpr(&n, &out); + addinit(&n, out); + *np = n; +} + +// Like orderblock, but applied to a single statement. +static void +orderstmtinplace(Node **np) +{ + Node *n; + NodeList *out; + + n = *np; + out = nil; + orderstmt(n, &out); + *np = liststmt(out); +} + +// Move n's init list to *out. +static void +orderinit(Node *n, NodeList **out) +{ + orderstmtlist(n->ninit, out); + n->ninit = nil; +} + +// Is the list l actually just f() for a multi-value function? +static int +ismulticall(NodeList *l) +{ + Node *n; + + // one arg only + if(l == nil || l->next != nil) + return 0; + n = l->n; + + // must be call + switch(n->op) { + default: + return 0; + case OCALLFUNC: + case OCALLMETH: + case OCALLINTER: + break; + } + + // call must return multiple values + return n->left->type->outtuple > 1; +} + +// n is a multi-value function call. Add t1, t2, .. = n to out +// and return the list t1, t2, ... +static NodeList* +copyret(Node *n, NodeList **out) +{ + Type *t; + Node *tmp, *as; + NodeList *l1, *l2; + Iter tl; + + if(n->type->etype != TSTRUCT || !n->type->funarg) + fatal("copyret %T %d", n->type, n->left->type->outtuple); + + l1 = nil; + l2 = nil; + for(t=structfirst(&tl, &n->type); t; t=structnext(&tl)) { + tmp = temp(t->type); + l1 = list(l1, tmp); + l2 = list(l2, tmp); + } + + as = nod(OAS2, N, N); + as->list = l1; + as->rlist = list1(n); + typecheck(&as, Etop); + orderstmt(as, out); + + return l2; +} + +static void +ordercallargs(NodeList **l, NodeList **out) +{ + if(ismulticall(*l)) { + // return f() where f() is multiple values. + *l = copyret((*l)->n, out); + } else { + orderexprlist(*l, out); + } +} + +static void +ordercall(Node *n, NodeList **out) +{ + orderexpr(&n->left, out); + ordercallargs(&n->list, out); +} + +static void +orderstmt(Node *n, NodeList **out) +{ + int lno; + NodeList *l; + Node *r; + + if(n == N) + return; + + lno = setlineno(n); + + orderinit(n, out); + + switch(n->op) { + default: + fatal("orderstmt %O", n->op); + + case OAS2: + case OAS2DOTTYPE: + case OAS2MAPR: + case OAS: + case OASOP: + case OCLOSE: + case OCOPY: + case ODELETE: + case OPANIC: + case OPRINT: + case OPRINTN: + case ORECOVER: + case ORECV: + case OSEND: + orderexpr(&n->left, out); + orderexpr(&n->right, out); + orderexprlist(n->list, out); + orderexprlist(n->rlist, out); + *out = list(*out, n); + break; + + case OAS2FUNC: + // Special: avoid copy of func call n->rlist->n. + orderexprlist(n->list, out); + ordercall(n->rlist->n, out); + *out = list(*out, n); + break; + + case OAS2RECV: + // Special: avoid copy of receive. + orderexprlist(n->list, out); + orderexpr(&n->rlist->n->left, out); // arg to recv + *out = list(*out, n); + break; + + case OBLOCK: + case OEMPTY: + // Special: does not save n onto out. + orderstmtlist(n->list, out); + break; + + case OBREAK: + case OCONTINUE: + case ODCL: + case ODCLCONST: + case ODCLTYPE: + case OFALL: + case_OFALL: + case OGOTO: + case OLABEL: + // Special: n->left is not an expression; save as is. + *out = list(*out, n); + break; + + case OCALLFUNC: + case OCALLINTER: + case OCALLMETH: + // Special: handle call arguments. + ordercall(n, out); + *out = list(*out, n); + break; + + case ODEFER: + case OPROC: + // Special: order arguments to inner call but not call itself. + ordercall(n->left, out); + *out = list(*out, n); + break; + + case OFOR: + orderexprinplace(&n->ntest); + orderstmtinplace(&n->nincr); + orderblock(&n->nbody); + *out = list(*out, n); + break; + + case OIF: + orderexprinplace(&n->ntest); + orderblock(&n->nbody); + orderblock(&n->nelse); + *out = list(*out, n); + break; + + case ORANGE: + orderexpr(&n->right, out); + for(l=n->list; l; l=l->next) + orderexprinplace(&l->n); + orderblock(&n->nbody); + *out = list(*out, n); + break; + + case ORETURN: + ordercallargs(&n->list, out); + *out = list(*out, n); + break; + + case OSELECT: + for(l=n->list; l; l=l->next) { + if(l->n->op != OXCASE) + fatal("order select case %O", l->n->op); + r = l->n->left; + if(r == nil) + continue; + switch(r->op) { + case OSELRECV: + case OSELRECV2: + orderexprinplace(&r->left); + orderexprinplace(&r->ntest); + orderexpr(&r->right->left, out); + break; + case OSEND: + orderexpr(&r->left, out); + orderexpr(&r->right, out); + break; + } + } + *out = list(*out, n); + break; + + case OSWITCH: + orderexpr(&n->ntest, out); + for(l=n->list; l; l=l->next) { + if(l->n->op != OXCASE) + fatal("order switch case %O", l->n->op); + orderexpr(&l->n->left, &l->n->ninit); + } + *out = list(*out, n); + break; + + case OXFALL: + yyerror("fallthrough statement out of place"); + n->op = OFALL; + goto case_OFALL; + } + + lineno = lno; +} + +static void +orderexprlist(NodeList *l, NodeList **out) +{ + for(; l; l=l->next) + orderexpr(&l->n, out); +} + +static void +orderexpr(Node **np, NodeList **out) +{ + Node *n; + int lno; + + n = *np; + if(n == N) + return; + + lno = setlineno(n); + orderinit(n, out); + + switch(n->op) { + default: + orderexpr(&n->left, out); + orderexpr(&n->right, out); + orderexprlist(n->list, out); + orderexprlist(n->rlist, out); + break; + + case OANDAND: + case OOROR: + orderexpr(&n->left, out); + orderexprinplace(&n->right); + break; + + case OCALLFUNC: + case OCALLMETH: + case OCALLINTER: + ordercall(n, out); + n = copyexpr(n, n->type, out); + break; + + case ORECV: + n = copyexpr(n, n->type, out); + break; + } + + lineno = lno; + + *np = n; +} diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c index abe8ea892..f2b75d61b 100644 --- a/src/cmd/gc/pgen.c +++ b/src/cmd/gc/pgen.c @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "gg.h" #include "opt.h" -static void compactframe(Prog* p); +static void allocauto(Prog* p); void compile(Node *fn) @@ -52,14 +54,16 @@ compile(Node *fn) t = structnext(&save); } } - + + order(curfn); + if(nerrors != 0) + goto ret; + hasdefer = 0; walk(curfn); if(nerrors != 0) goto ret; - allocparams(); - continpc = P; breakpc = P; @@ -70,6 +74,8 @@ compile(Node *fn) nodconst(&nod1, types[TINT32], 0); ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1); + if(fn->dupok) + ptxt->TEXTFLAG = DUPOK; afunclit(&ptxt->from); ginit(); @@ -113,9 +119,13 @@ compile(Node *fn) } oldstksize = stksize; - compactframe(ptxt); + allocauto(ptxt); if(0) - print("compactframe: %ld to %ld\n", oldstksize, stksize); + print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize); + + setlineno(curfn); + if((int64)stksize+maxarg > (1ULL<<31)) + yyerror("stack frame too large (>2GB)"); defframe(ptxt); @@ -145,13 +155,13 @@ cmpstackvar(Node *a, Node *b) // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. static void -compactframe(Prog* ptxt) +allocauto(Prog* ptxt) { NodeList *ll; Node* n; vlong w; - if (stksize == 0) + if(curfn->dcl == nil) return; // Mark the PAUTO's unused. @@ -188,6 +198,7 @@ compactframe(Prog* ptxt) if (n->class != PAUTO || n->op != ONAME) continue; + dowidth(n->type); w = n->type->width; if(w >= MAXWIDTH || w < 0) fatal("bad width"); diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c deleted file mode 100644 index 5913e848a..000000000 --- a/src/cmd/gc/print.c +++ /dev/null @@ -1,480 +0,0 @@ -// Copyright 2009 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. - -#include "go.h" - -enum -{ - PFIXME = 0, -}; - -void -exprlistfmt(Fmt *f, NodeList *l) -{ - for(; l; l=l->next) { - exprfmt(f, l->n, 0); - if(l->next) - fmtprint(f, ", "); - } -} - -void -exprfmt(Fmt *f, Node *n, int prec) -{ - int nprec; - char *p; - - nprec = 0; - if(n == nil) { - fmtprint(f, "<nil>"); - return; - } - - if(n->implicit) { - exprfmt(f, n->left, prec); - return; - } - - switch(n->op) { - case OAPPEND: - case ONAME: - case ONONAME: - case OPACK: - case OLITERAL: - case ODOT: - case ODOTPTR: - case ODOTINTER: - case ODOTMETH: - case ODOTTYPE: - case ODOTTYPE2: - case OXDOT: - case OARRAYBYTESTR: - case OCAP: - case OCLOSE: - case OCOPY: - case OLEN: - case OMAKE: - case ONEW: - case OPANIC: - case OPRINT: - case OPRINTN: - case OCALL: - case OCALLMETH: - case OCALLINTER: - case OCALLFUNC: - case OCONV: - case OCONVNOP: - case OMAKESLICE: - case ORUNESTR: - case OADDR: - case OCOM: - case OIND: - case OMINUS: - case ONOT: - case OPLUS: - case ORECV: - case OCONVIFACE: - case OTPAREN: - case OINDEX: - case OINDEXMAP: - case OPAREN: - nprec = 7; - break; - - case OMUL: - case ODIV: - case OMOD: - case OLSH: - case ORSH: - case OAND: - case OANDNOT: - nprec = 6; - break; - - case OADD: - case OSUB: - case OOR: - case OXOR: - nprec = 5; - break; - - case OEQ: - case OLT: - case OLE: - case OGE: - case OGT: - case ONE: - nprec = 4; - break; - - case OSEND: - nprec = 3; - break; - - case OANDAND: - nprec = 2; - break; - - case OOROR: - nprec = 1; - break; - - case OTYPE: - if(n->sym != S) - nprec = 7; - break; - } - - if(prec > nprec) - fmtprint(f, "("); - - switch(n->op) { - default: - bad: - fmtprint(f, "(node %O)", n->op); - break; - - case OPAREN: - fmtprint(f, "(%#N)", n->left); - break; - - case OREGISTER: - fmtprint(f, "%R", n->val.u.reg); - break; - - case OLITERAL: - if(n->sym != S) { - fmtprint(f, "%S", n->sym); - break; - } - switch(n->val.ctype) { - default: - goto bad; - case CTINT: - fmtprint(f, "%B", n->val.u.xval); - break; - case CTBOOL: - if(n->val.u.bval) - fmtprint(f, "true"); - else - fmtprint(f, "false"); - break; - case CTCPLX: - fmtprint(f, "%.17g+%.17gi", - mpgetflt(&n->val.u.cval->real), - mpgetflt(&n->val.u.cval->imag)); - break; - case CTFLT: - fmtprint(f, "%.17g", mpgetflt(n->val.u.fval)); - break; - case CTSTR: - fmtprint(f, "\"%Z\"", n->val.u.sval); - break; - case CTNIL: - fmtprint(f, "nil"); - break; - } - break; - - case ONAME: - case OPACK: - case ONONAME: - fmtprint(f, "%S", n->sym); - break; - - case OTYPE: - if(n->type == T && n->sym != S) { - fmtprint(f, "%S", n->sym); - break; - } - fmtprint(f, "%T", n->type); - break; - - case OTARRAY: - fmtprint(f, "[]"); - exprfmt(f, n->left, PFIXME); - break; - - case OTPAREN: - fmtprint(f, "("); - exprfmt(f, n->left, 0); - fmtprint(f, ")"); - break; - - case OTMAP: - fmtprint(f, "map["); - exprfmt(f, n->left, 0); - fmtprint(f, "] "); - exprfmt(f, n->right, 0); - break; - - case OTCHAN: - if(n->etype == Crecv) - fmtprint(f, "<-"); - fmtprint(f, "chan"); - if(n->etype == Csend) { - fmtprint(f, "<- "); - exprfmt(f, n->left, 0); - } else { - fmtprint(f, " "); - if(n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) { - fmtprint(f, "("); - exprfmt(f, n->left, 0); - fmtprint(f, ")"); - } else - exprfmt(f, n->left, 0); - } - break; - - case OTSTRUCT: - fmtprint(f, "<struct>"); - break; - - case OTINTER: - fmtprint(f, "<inter>"); - break; - - case OTFUNC: - fmtprint(f, "<func>"); - break; - - case OAS: - exprfmt(f, n->left, 0); - fmtprint(f, " = "); - exprfmt(f, n->right, 0); - break; - - case OASOP: - exprfmt(f, n->left, 0); - fmtprint(f, " %#O= ", n->etype); - exprfmt(f, n->right, 0); - break; - - case OAS2: - case OAS2DOTTYPE: - case OAS2FUNC: - case OAS2MAPR: - case OAS2MAPW: - case OAS2RECV: - exprlistfmt(f, n->list); - fmtprint(f, " = "); - exprlistfmt(f, n->rlist); - break; - - case OADD: - case OANDAND: - case OANDNOT: - case ODIV: - case OEQ: - case OGE: - case OGT: - case OLE: - case OLT: - case OLSH: - case OMOD: - case OMUL: - case ONE: - case OOR: - case OOROR: - case ORSH: - case OSEND: - case OSUB: - case OXOR: - exprfmt(f, n->left, nprec); - fmtprint(f, " %#O ", n->op); - exprfmt(f, n->right, nprec+1); - break; - - case OADDR: - case OCOM: - case OIND: - case OMINUS: - case ONOT: - case OPLUS: - case ORECV: - fmtprint(f, "%#O", n->op); - if((n->op == OMINUS || n->op == OPLUS) && n->left->op == n->op) - fmtprint(f, " "); - exprfmt(f, n->left, 0); - break; - - case OCLOSURE: - fmtprint(f, "func literal"); - break; - - case OCOMPLIT: - fmtprint(f, "composite literal"); - break; - - case OARRAYLIT: - if(isslice(n->type)) - fmtprint(f, "slice literal"); - else - fmtprint(f, "array literal"); - break; - - case OMAPLIT: - fmtprint(f, "map literal"); - break; - - case OSTRUCTLIT: - fmtprint(f, "struct literal"); - break; - - case OXDOT: - case ODOT: - case ODOTPTR: - case ODOTINTER: - case ODOTMETH: - exprfmt(f, n->left, 7); - if(n->right == N || n->right->sym == S) - fmtprint(f, ".<nil>"); - else { - // skip leading type· in method name - p = utfrrune(n->right->sym->name, 0xb7); - if(p) - p+=2; - else - p = n->right->sym->name; - fmtprint(f, ".%s", p); - } - break; - - case ODOTTYPE: - case ODOTTYPE2: - exprfmt(f, n->left, 7); - fmtprint(f, ".("); - if(n->right != N) - exprfmt(f, n->right, 0); - else - fmtprint(f, "%T", n->type); - fmtprint(f, ")"); - break; - - case OINDEX: - case OINDEXMAP: - exprfmt(f, n->left, 7); - fmtprint(f, "["); - exprfmt(f, n->right, 0); - fmtprint(f, "]"); - break; - - case OSLICE: - case OSLICESTR: - case OSLICEARR: - exprfmt(f, n->left, 7); - fmtprint(f, "["); - if(n->right->left != N) - exprfmt(f, n->right->left, 0); - fmtprint(f, ":"); - if(n->right->right != N) - exprfmt(f, n->right->right, 0); - fmtprint(f, "]"); - break; - - case OCALL: - case OCALLFUNC: - case OCALLINTER: - case OCALLMETH: - exprfmt(f, n->left, 7); - fmtprint(f, "("); - exprlistfmt(f, n->list); - if(n->isddd) - fmtprint(f, "..."); - fmtprint(f, ")"); - break; - - case OCOMPLEX: - fmtprint(f, "complex("); - exprfmt(f, n->left, 0); - fmtprint(f, ", "); - exprfmt(f, n->right, 0); - fmtprint(f, ")"); - break; - - case OREAL: - fmtprint(f, "real("); - exprfmt(f, n->left, 0); - fmtprint(f, ")"); - break; - - case OIMAG: - fmtprint(f, "imag("); - exprfmt(f, n->left, 0); - fmtprint(f, ")"); - break; - - case OCONV: - case OCONVIFACE: - case OCONVNOP: - case OARRAYBYTESTR: - case OSTRARRAYBYTE: - case ORUNESTR: - if(n->type == T || n->type->sym == S) - fmtprint(f, "(%T)(", n->type); - else - fmtprint(f, "%T(", n->type); - if(n->left == N) - exprlistfmt(f, n->list); - else - exprfmt(f, n->left, 0); - fmtprint(f, ")"); - break; - - case OAPPEND: - case OCAP: - case OCLOSE: - case OLEN: - case OCOPY: - case OMAKE: - case ONEW: - case OPANIC: - case OPRINT: - case OPRINTN: - fmtprint(f, "%#O(", n->op); - if(n->left) - exprfmt(f, n->left, 0); - else - exprlistfmt(f, n->list); - fmtprint(f, ")"); - break; - - case OMAKESLICE: - fmtprint(f, "make(%#T, ", n->type); - exprfmt(f, n->left, 0); - if(count(n->list) > 2) { - fmtprint(f, ", "); - exprfmt(f, n->right, 0); - } - fmtprint(f, ")"); - break; - - case OMAKEMAP: - case OMAKECHAN: - fmtprint(f, "make(%#T)", n->type); - break; - - // Some statements - - case ODCL: - fmtprint(f, "var %S %#T", n->left->sym, n->left->type); - break; - - case ORETURN: - fmtprint(f, "return "); - exprlistfmt(f, n->list); - break; - - case OPROC: - fmtprint(f, "go %#N", n->left); - break; - - case ODEFER: - fmtprint(f, "defer %#N", n->left); - break; - } - - if(prec > nprec) - fmtprint(f, ")"); -} diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c index 5ce693ae3..9bcd833a7 100644 --- a/src/cmd/gc/range.c +++ b/src/cmd/gc/range.c @@ -6,6 +6,8 @@ * range */ +#include <u.h> +#include <libc.h> #include "go.h" void @@ -30,7 +32,7 @@ typecheckrange(Node *n) switch(t->etype) { default: - yyerror("cannot range over %+N", n->right); + yyerror("cannot range over %lN", n->right); goto out; case TARRAY: @@ -44,6 +46,10 @@ typecheckrange(Node *n) break; case TCHAN: + if(!(t->chan & Crecv)) { + yyerror("invalid operation: range %N (receive from send-only type %T)", n->right, n->right->type); + goto out; + } t1 = t->type; t2 = nil; if(count(n->list) == 2) @@ -52,7 +58,7 @@ typecheckrange(Node *n) case TSTRING: t1 = types[TINT]; - t2 = types[TINT]; + t2 = runetype; break; } @@ -69,12 +75,12 @@ typecheckrange(Node *n) if(v1->defn == n) v1->type = t1; else if(v1->type != T && assignop(t1, v1->type, &why) == 0) - yyerror("cannot assign type %T to %+N in range%s", t1, v1, why); + yyerror("cannot assign type %T to %lN in range%s", t1, v1, why); if(v2) { if(v2->defn == n) v2->type = t2; else if(v2->type != T && assignop(t2, v2->type, &why) == 0) - yyerror("cannot assign type %T to %+N in range%s", t2, v2, why); + yyerror("cannot assign type %T to %lN in range%s", t2, v2, why); } out: @@ -111,8 +117,6 @@ walkrange(Node *n) } v1 = n->list->n; - hv1 = N; - v2 = N; if(n->list->next) v2 = n->list->next->n; @@ -123,8 +127,7 @@ walkrange(Node *n) // no need to make a potentially expensive copy. ha = a; } else { - ha = nod(OXXX, N, N); - tempname(ha, a->type); + ha = temp(a->type); init = list(init, nod(OAS, ha, a)); } @@ -133,17 +136,14 @@ walkrange(Node *n) fatal("walkrange"); case TARRAY: - hv1 = nod(OXXX, N, n); - tempname(hv1, types[TINT]); - hn = nod(OXXX, N, N); - tempname(hn, types[TINT]); + hv1 = temp(types[TINT]); + hn = temp(types[TINT]); hp = nil; init = list(init, nod(OAS, hv1, N)); init = list(init, nod(OAS, hn, nod(OLEN, ha, N))); if(v2) { - hp = nod(OXXX, N, N); - tempname(hp, ptrto(n->type->type)); + hp = temp(ptrto(n->type->type)); tmp = nod(OINDEX, ha, nodintconst(0)); tmp->etype = 1; // no bounds check init = list(init, nod(OAS, hp, nod(OADDR, tmp, N))); @@ -167,9 +167,10 @@ walkrange(Node *n) case TMAP: th = typ(TARRAY); th->type = ptrto(types[TUINT8]); - th->bound = (sizeof(struct Hiter) + widthptr - 1) / widthptr; - hit = nod(OXXX, N, N); - tempname(hit, th); + // see ../../pkg/runtime/hashmap.h:/hash_iter + // Size in words. + th->bound = 5 + 4*3 + 4*4/widthptr; + hit = temp(th); fn = syslook("mapiterinit", 1); argtype(fn, t->down); @@ -200,10 +201,8 @@ walkrange(Node *n) break; case TCHAN: - hv1 = nod(OXXX, N, n); - tempname(hv1, t->type); - hb = nod(OXXX, N, N); - tempname(hb, types[TBOOL]); + hv1 = temp(t->type); + hb = temp(types[TBOOL]); n->ntest = nod(ONE, hb, nodbool(0)); a = nod(OAS2RECV, N, N); @@ -215,18 +214,15 @@ walkrange(Node *n) break; case TSTRING: - ohv1 = nod(OXXX, N, N); - tempname(ohv1, types[TINT]); + ohv1 = temp(types[TINT]); - hv1 = nod(OXXX, N, N); - tempname(hv1, types[TINT]); + hv1 = temp(types[TINT]); init = list(init, nod(OAS, hv1, N)); if(v2 == N) a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1)); else { - hv2 = nod(OXXX, N, N); - tempname(hv2, types[TINT]); + hv2 = temp(runetype); a = nod(OAS2, N, N); a->list = list(list1(hv1), hv2); fn = syslook("stringiter2", 0); diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 810787d30..07b426508 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" /* @@ -11,6 +13,7 @@ static NodeList* signatlist; static Sym* dtypesym(Type*); static Sym* weaktypesym(Type*); +static Sym* dalgsym(Type*); static int sigcmp(Sig *a, Sig *b) @@ -140,13 +143,12 @@ methods(Type *t) Type *f, *mt, *it, *this; Sig *a, *b; Sym *method; - Prog *oldlist; - // named method type - mt = methtype(t); + // method type + mt = methtype(t, 0); if(mt == T) return nil; - expandmeth(mt->sym, mt); + expandmeth(mt); // type stored in interface word it = t; @@ -156,12 +158,14 @@ methods(Type *t) // make list of methods for t, // generating code if necessary. a = nil; - oldlist = nil; for(f=mt->xmethod; f; f=f->down) { - if(f->type->etype != TFUNC) - continue; if(f->etype != TFIELD) - fatal("methods: not field"); + fatal("methods: not field %T", f); + if (f->type->etype != TFUNC || f->type->thistuple == 0) + fatal("non-method on %T method %S %T\n", mt, f->sym, f); + if (!getthisx(f->type)->type) + fatal("receiver with no type on %T method %S %T\n", mt, f->sym, f); + method = f->sym; if(method == nil) continue; @@ -195,8 +199,6 @@ methods(Type *t) if(!(a->isym->flags & SymSiggen)) { a->isym->flags |= SymSiggen; if(!eqtype(this, it) || this->width < types[tptr]->width) { - if(oldlist == nil) - oldlist = pc; // Is okay to call genwrapper here always, // but we can generate more efficient code // using genembedtramp if all that is necessary @@ -212,8 +214,6 @@ methods(Type *t) if(!(a->tsym->flags & SymSiggen)) { a->tsym->flags |= SymSiggen; if(!eqtype(this, t)) { - if(oldlist == nil) - oldlist = pc; if(isptr[t->etype] && isptr[this->etype] && f->embedded && !isifacemethod(f->type)) genembedtramp(t, f, a->tsym, 0); @@ -223,16 +223,6 @@ methods(Type *t) } } - // restore data output - if(oldlist) { - // old list ended with AEND; change to ANOP - // so that the trampolines that follow can be found. - nopout(oldlist); - - // start new data list - newplist(); - } - return lsort(a, sigcmp); } @@ -245,11 +235,9 @@ imethods(Type *t) Sig *a, *all, *last; Type *f; Sym *method, *isym; - Prog *oldlist; all = nil; last = nil; - oldlist = nil; for(f=t->type; f; f=f->down) { if(f->etype != TFIELD) fatal("imethods: not field"); @@ -287,21 +275,9 @@ imethods(Type *t) isym = methodsym(method, t, 0); if(!(isym->flags & SymSiggen)) { isym->flags |= SymSiggen; - if(oldlist == nil) - oldlist = pc; genwrapper(t, f, isym, 0); } } - - if(oldlist) { - // old list ended with AEND; change to ANOP - // so that the trampolines that follow can be found. - nopout(oldlist); - - // start new data list - newplist(); - } - return all; } @@ -381,7 +357,7 @@ dextratype(Sym *sym, int off, Type *t, int ptroff) s = sym; if(t->sym) { ot = dgostringptr(s, ot, t->sym->name); - if(t != types[t->etype]) + if(t != types[t->etype] && t != errortype) ot = dgopkgpath(s, ot, t->sym->pkg); else ot = dgostringptr(s, ot, nil); @@ -478,57 +454,20 @@ kinds[] = [TUNSAFEPTR] = KindUnsafePointer, }; -static char* -structnames[] = -{ - [TINT] = "*runtime.IntType", - [TUINT] = "*runtime.UintType", - [TINT8] = "*runtime.IntType", - [TUINT8] = "*runtime.UintType", - [TINT16] = "*runtime.IntType", - [TUINT16] = "*runtime.UintType", - [TINT32] = "*runtime.IntType", - [TUINT32] = "*runtime.UintType", - [TINT64] = "*runtime.IntType", - [TUINT64] = "*runtime.UintType", - [TUINTPTR] = "*runtime.UintType", - [TCOMPLEX64] = "*runtime.ComplexType", - [TCOMPLEX128] = "*runtime.ComplexType", - [TFLOAT32] = "*runtime.FloatType", - [TFLOAT64] = "*runtime.FloatType", - [TBOOL] = "*runtime.BoolType", - [TSTRING] = "*runtime.StringType", - [TUNSAFEPTR] = "*runtime.UnsafePointerType", - - [TPTR32] = "*runtime.PtrType", - [TPTR64] = "*runtime.PtrType", - [TSTRUCT] = "*runtime.StructType", - [TINTER] = "*runtime.InterfaceType", - [TCHAN] = "*runtime.ChanType", - [TMAP] = "*runtime.MapType", - [TARRAY] = "*runtime.ArrayType", - [TFUNC] = "*runtime.FuncType", -}; - static Sym* typestruct(Type *t) { - char *name; - int et; - - et = t->etype; - if(et < 0 || et >= nelem(structnames) || (name = structnames[et]) == nil) { - fatal("typestruct %lT", t); - return nil; // silence gcc - } - - if(isslice(t)) - name = "*runtime.SliceType"; - - return pkglookup(name, typepkg); + // We use a weak reference to the reflect type + // to avoid requiring package reflect in every binary. + // If package reflect is available, the interface{} holding + // a runtime type will contain a *reflect.commonType. + // Otherwise it will use a nil type word but still be usable + // by package runtime (because we always use the memory + // after the interface value, not the interface value itself). + return pkglookup("*reflect.commonType", weaktypepkg); } -static int +int haspointers(Type *t) { Type *t1; @@ -578,13 +517,20 @@ haspointers(Type *t) static int dcommontype(Sym *s, int ot, Type *t) { - int i; - Sym *sptr; + int i, alg, sizeofAlg; + Sym *sptr, *algsym; + static Sym *algarray; char *p; + sizeofAlg = 4*widthptr; + if(algarray == nil) + algarray = pkglookup("algarray", runtimepkg); + alg = algtype(t); + algsym = S; + if(alg < 0) + algsym = dalgsym(t); + dowidth(t); - - sptr = nil; if(t->sym != nil && !isptr[t->etype]) sptr = dtypesym(ptrto(t)); else @@ -597,7 +543,7 @@ dcommontype(Sym *s, int ot, Type *t) ot = dsymptr(s, ot, typestruct(t), 0); ot = dsymptr(s, ot, s, 2*widthptr); - // ../../pkg/runtime/type.go:/commonType + // ../../pkg/reflect/type.go:/^type.commonType // actual type structure // type commonType struct { // size uintptr; @@ -612,7 +558,7 @@ dcommontype(Sym *s, int ot, Type *t) // } ot = duintptr(s, ot, t->width); ot = duint32(s, ot, typehash(t)); - ot = duint8(s, ot, algtype(t)); + ot = duint8(s, ot, 0); // unused ot = duint8(s, ot, t->align); // align ot = duint8(s, ot, t->align); // fieldAlign i = kinds[t->etype]; @@ -621,9 +567,12 @@ dcommontype(Sym *s, int ot, Type *t) if(!haspointers(t)) i |= KindNoPointers; ot = duint8(s, ot, i); // kind - longsymnames = 1; - p = smprint("%-T", t); - longsymnames = 0; + if(alg >= 0) + ot = dsymptr(s, ot, algarray, alg*sizeofAlg); + else + ot = dsymptr(s, ot, algsym, 0); + p = smprint("%-uT", t); + //print("dcommontype: %s\n", p); ot = dgostringptr(s, ot, p); // string free(p); @@ -643,8 +592,22 @@ typesym(Type *t) char *p; Sym *s; - p = smprint("%#-T", t); + p = smprint("%-T", t); s = pkglookup(p, typepkg); + //print("typesym: %s -> %+S\n", p, s); + free(p); + return s; +} + +Sym* +typesymprefix(char *prefix, Type *t) +{ + char *p; + Sym *s; + + p = smprint("%s.%-T", prefix, t); + s = pkglookup(p, typepkg); + //print("algsym: %s -> %+S\n", p, s); free(p); return s; } @@ -683,16 +646,10 @@ weaktypesym(Type *t) { char *p; Sym *s; - static Pkg *weak; - - if(weak == nil) { - weak = mkpkg(strlit("weak.type")); - weak->name = "weak.type"; - weak->prefix = "weak.type"; // not weak%2etype - } - - p = smprint("%#-T", t); - s = pkglookup(p, weak); + + p = smprint("%-T", t); + s = pkglookup(p, weaktypepkg); + //print("weaktypesym: %s -> %+S\n", p, s); free(p); return s; } @@ -721,8 +678,13 @@ dtypesym(Type *t) tbase = t->type; dupok = tbase->sym == S; - if(compiling_runtime && tbase == types[tbase->etype]) // int, float, etc + if(compiling_runtime && + (tbase == types[tbase->etype] || + tbase == bytetype || + tbase == runetype || + tbase == errortype)) { // int, float, etc goto ok; + } // named types from other files are defined only by those files if(tbase->sym && !tbase->local) @@ -931,9 +893,56 @@ dumptypestructs(void) dtypesym(ptrto(types[i])); dtypesym(ptrto(types[TSTRING])); dtypesym(ptrto(types[TUNSAFEPTR])); + + // emit type structs for error and func(error) string. + // The latter is the type of an auto-generated wrapper. + dtypesym(ptrto(errortype)); + dtypesym(functype(nil, + list1(nod(ODCLFIELD, N, typenod(errortype))), + list1(nod(ODCLFIELD, N, typenod(types[TSTRING]))))); // add paths for runtime and main, which 6l imports implicitly. dimportpath(runtimepkg); dimportpath(mkpkg(strlit("main"))); } } + +static Sym* +dalgsym(Type *t) +{ + int ot; + Sym *s, *hash, *eq; + char buf[100]; + + // dalgsym is only called for a type that needs an algorithm table, + // which implies that the type is comparable (or else it would use ANOEQ). + + s = typesymprefix(".alg", t); + hash = typesymprefix(".hash", t); + genhash(hash, t); + eq = typesymprefix(".eq", t); + geneq(eq, t); + + // ../../pkg/runtime/runtime.h:/Alg + ot = 0; + ot = dsymptr(s, ot, hash, 0); + ot = dsymptr(s, ot, eq, 0); + ot = dsymptr(s, ot, pkglookup("memprint", runtimepkg), 0); + switch(t->width) { + default: + ot = dsymptr(s, ot, pkglookup("memcopy", runtimepkg), 0); + break; + case 1: + case 2: + case 4: + case 8: + case 16: + snprint(buf, sizeof buf, "memcopy%d", (int)t->width*8); + ot = dsymptr(s, ot, pkglookup(buf, runtimepkg), 0); + break; + } + + ggloblsym(s, ot, 1); + return s; +} + diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go index 549f7abe3..15a61d9ef 100644 --- a/src/cmd/gc/runtime.go +++ b/src/cmd/gc/runtime.go @@ -3,14 +3,16 @@ // license that can be found in the LICENSE file. // NOTE: If you change this file you must run "./mkbuiltin" -// to update builtin.c.boot. This is not done automatically +// to update builtin.c. This is not done automatically // to avoid depending on having a working compiler binary. +// +build ignore + package PACKAGE // emitted by compiler, not referred to by go programs -func new(int32) *any +func new(typ *byte) *any func panicindex() func panicslice() func throwreturn() @@ -40,18 +42,19 @@ func concatstring() // filled in by compiler: Type*, int n, Slice, ... func append() func appendslice(typ *byte, x any, y []any) any +func appendstr(typ *byte, x []byte, y string) []byte func cmpstring(string, string) int func slicestring(string, int, int) string func slicestring1(string, int) string func intstring(int64) string func slicebytetostring([]byte) string -func sliceinttostring([]int) string +func slicerunetostring([]rune) string func stringtoslicebyte(string) []byte -func stringtosliceint(string) []int +func stringtoslicerune(string) []rune func stringiter(string, int) int -func stringiter2(string, int) (retk int, retv int) -func slicecopy(to any, fr any, wid uint32) int +func stringiter2(string, int) (retk int, retv rune) +func copy(to any, fr any, wid uint32) int func slicestringcopy(to any, fr any) int // interface conversions @@ -79,6 +82,8 @@ func efaceeq(i1 any, i2 any) (ret bool) func ifacethash(i1 any) (ret uint32) func efacethash(i1 any) (ret uint32) +func equal(typ *byte, x1, x2 any) (ret bool) + // *byte is really *runtime.Type func makemap(mapType *byte, hint int64) (hmap map[any]any) func mapaccess1(mapType *byte, hmap map[any]any, key any) (val any) @@ -86,6 +91,7 @@ func mapaccess2(mapType *byte, hmap map[any]any, key any) (val any, pres bool) func mapassign1(mapType *byte, hmap map[any]any, key any, val any) func mapassign2(mapType *byte, hmap map[any]any, key any, val any, pres bool) func mapiterinit(mapType *byte, hmap map[any]any, hiter *any) +func mapdelete(mapType *byte, hmap map[any]any, key any) func mapiternext(hiter *any) func mapiter1(hiter *any) (key any) func mapiter2(hiter *any) (key any, val any) @@ -117,6 +123,13 @@ func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary [ func closure() // has args, but compiler fills in +func memequal(eq *bool, size uintptr, x, y *any) +func memequal8(eq *bool, size uintptr, x, y *any) +func memequal16(eq *bool, size uintptr, x, y *any) +func memequal32(eq *bool, size uintptr, x, y *any) +func memequal64(eq *bool, size uintptr, x, y *any) +func memequal128(eq *bool, size uintptr, x, y *any) + // only used on 32-bit func int64div(int64, int64) int64 func uint64div(uint64, uint64) uint64 diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c index 909ad3aa4..8ace1d4ee 100644 --- a/src/cmd/gc/select.c +++ b/src/cmd/gc/select.c @@ -6,6 +6,8 @@ * select */ +#include <u.h> +#include <libc.h> #include "go.h" void @@ -59,7 +61,7 @@ typecheckselect(Node *sel) break; case OAS2RECV: - // convert x, ok = <-c into OSELRECV(x, <-c) with ntest=ok + // convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok if(n->right->op != ORECV) { yyerror("select assignment must have receive on right hand side"); break; @@ -73,6 +75,7 @@ typecheckselect(Node *sel) case ORECV: // convert <-c into OSELRECV(N, <-c) n = nod(OSELRECV, N, n); + n->typecheck = 1; ncase->left = n; break; @@ -191,8 +194,7 @@ walkselect(Node *sel) n->ntest->etype = 1; // pointer does not escape typecheck(&n->ntest, Erv); } else { - tmp = nod(OXXX, N, N); - tempname(tmp, types[TBOOL]); + tmp = temp(types[TBOOL]); a = nod(OADDR, tmp, N); a->etype = 1; // pointer does not escape typecheck(&a, Erv); @@ -212,8 +214,7 @@ walkselect(Node *sel) n->left->etype = 1; // pointer does not escape typecheck(&n->left, Erv); } else { - tmp = nod(OXXX, N, N); - tempname(tmp, ch->type->type); + tmp = temp(ch->type->type); a = nod(OADDR, tmp, N); a->etype = 1; // pointer does not escape typecheck(&a, Erv); @@ -284,8 +285,7 @@ walkselect(Node *sel) // generate sel-struct setlineno(sel); - var = nod(OXXX, N, N); - tempname(var, ptrto(types[TUINT8])); + var = temp(ptrto(types[TUINT8])); r = nod(OAS, var, mkcall("newselect", var->type, nil, nodintconst(sel->xoffset))); typecheck(&r, Etop); init = list(init, r); diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index 917e2ae6d..c8796f8b7 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -6,11 +6,24 @@ * static initialization */ +#include <u.h> +#include <libc.h> #include "go.h" +enum +{ + InitNotStarted = 0, + InitDone = 1, + InitPending = 2, +}; + +static int iszero(Node*); +static void initplan(Node*); static NodeList *initlist; static void init2(Node*, NodeList**); static void init2list(NodeList*, NodeList**); +static int staticinit(Node*, NodeList**); +static Node *staticname(Type*, int); static void init1(Node *n, NodeList **out) @@ -31,16 +44,16 @@ init1(Node *n, NodeList **out) case PFUNC: break; default: - if(isblank(n) && n->defn != N && !n->defn->initorder) { - n->defn->initorder = 1; + if(isblank(n) && n->defn != N && n->defn->initorder == InitNotStarted) { + n->defn->initorder = InitDone; *out = list(*out, n->defn); } return; } - if(n->initorder == 1) + if(n->initorder == InitDone) return; - if(n->initorder == 2) { + if(n->initorder == InitPending) { if(n->class == PFUNC) return; @@ -52,7 +65,7 @@ init1(Node *n, NodeList **out) if(nerrors > 0) errorexit(); - print("initialization loop:\n"); + print("%L: initialization loop:\n", n->lineno); for(l=initlist;; l=l->next) { if(l->next == nil) break; @@ -63,7 +76,7 @@ init1(Node *n, NodeList **out) print("\t%L %S\n", n->lineno, n->sym); errorexit(); } - n->initorder = 2; + n->initorder = InitPending; l = malloc(sizeof *l); l->next = initlist; l->n = n; @@ -84,20 +97,38 @@ init1(Node *n, NodeList **out) case OAS: if(n->defn->left != n) goto bad; + /* n->defn->dodata = 1; init1(n->defn->right, out); if(debug['j']) print("%S\n", n->sym); *out = list(*out, n->defn); break; + */ + if(1) { + init2(n->defn->right, out); + if(debug['j']) + print("%S\n", n->sym); + if(!staticinit(n, out)) { +if(debug['%']) dump("nonstatic", n->defn); + *out = list(*out, n->defn); + } + } else if(0) { + n->defn->dodata = 1; + init1(n->defn->right, out); + if(debug['j']) + print("%S\n", n->sym); + *out = list(*out, n->defn); + } + break; case OAS2FUNC: case OAS2MAPR: case OAS2DOTTYPE: case OAS2RECV: - if(n->defn->initorder) + if(n->defn->initorder != InitNotStarted) break; - n->defn->initorder = 1; + n->defn->initorder = InitDone; for(l=n->defn->rlist; l; l=l->next) init1(l->n, out); *out = list(*out, n->defn); @@ -109,7 +140,7 @@ init1(Node *n, NodeList **out) if(l->n != n) fatal("bad initlist"); free(l); - n->initorder = 1; + n->initorder = InitDone; return; bad: @@ -121,8 +152,12 @@ bad: static void init2(Node *n, NodeList **out) { - if(n == N || n->initorder == 1) + if(n == N || n->initorder == InitDone) return; + + if(n->op == ONAME && n->ninit) + fatal("name %S with ninit: %+N\n", n->sym, n); + init1(n, out); init2(n->left, out); init2(n->right, out); @@ -141,7 +176,6 @@ init2list(NodeList *l, NodeList **out) init2(l->n, out); } - static void initreorder(NodeList *l, NodeList **out) { @@ -165,13 +199,235 @@ NodeList* initfix(NodeList *l) { NodeList *lout; + int lno; lout = nil; + lno = lineno; initreorder(l, &lout); + lineno = lno; return lout; } /* + * compilation of top-level (static) assignments + * into DATA statements if at all possible. + */ + +static int staticassign(Node*, Node*, NodeList**); + +static int +staticinit(Node *n, NodeList **out) +{ + Node *l, *r; + + if(n->op != ONAME || n->class != PEXTERN || n->defn == N || n->defn->op != OAS) + fatal("staticinit"); + + lineno = n->lineno; + l = n->defn->left; + r = n->defn->right; + return staticassign(l, r, out); +} + +// like staticassign but we are copying an already +// initialized value r. +static int +staticcopy(Node *l, Node *r, NodeList **out) +{ + int i; + InitEntry *e; + InitPlan *p; + Node *a, *ll, *rr, *orig, n1; + + if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg) + return 0; + if(r->defn == N) // zeroed + return 1; + if(r->defn->op != OAS) + return 0; + orig = r; + r = r->defn->right; + + switch(r->op) { + case ONAME: + if(staticcopy(l, r, out)) + return 1; + *out = list(*out, nod(OAS, l, r)); + return 1; + + case OLITERAL: + if(iszero(r)) + return 1; + gdata(l, r, l->type->width); + return 1; + + case OADDR: + switch(r->left->op) { + 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: + // copy pointer + gdata(l, nod(OADDR, r->nname, N), l->type->width); + return 1; + } + break; + + case OARRAYLIT: + if(isslice(r->type)) { + // copy slice + a = r->nname; + n1 = *l; + n1.xoffset = l->xoffset + Array_array; + gdata(&n1, nod(OADDR, a, N), widthptr); + n1.xoffset = l->xoffset + Array_nel; + gdata(&n1, r->right, 4); + n1.xoffset = l->xoffset + Array_cap; + gdata(&n1, r->right, 4); + return 1; + } + // fall through + case OSTRUCTLIT: + p = r->initplan; + n1 = *l; + for(i=0; i<p->len; i++) { + e = &p->e[i]; + n1.xoffset = l->xoffset + e->xoffset; + n1.type = e->expr->type; + if(e->expr->op == OLITERAL) + gdata(&n1, e->expr, n1.type->width); + else { + ll = nod(OXXX, N, N); + *ll = n1; + if(!staticassign(ll, e->expr, out)) { + // Requires computation, but we're + // copying someone else's computation. + rr = nod(OXXX, N, N); + *rr = *orig; + rr->type = ll->type; + rr->xoffset += e->xoffset; + *out = list(*out, nod(OAS, ll, rr)); + } + } + } + return 1; + } + return 0; +} + +static int +staticassign(Node *l, Node *r, NodeList **out) +{ + Node *a, n1; + Type *ta; + InitPlan *p; + InitEntry *e; + int i; + + switch(r->op) { + default: + //dump("not static", r); + break; + + case ONAME: + if(r->class == PEXTERN && r->sym->pkg == localpkg) + return staticcopy(l, r, out); + break; + + case OLITERAL: + if(iszero(r)) + return 1; + gdata(l, r, l->type->width); + return 1; + + case OADDR: + switch(r->left->op) { + default: + //dump("not static addr", r); + break; + + 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: + // Init pointer. + a = staticname(r->left->type, 1); + r->nname = a; + gdata(l, nod(OADDR, a, N), l->type->width); + // Init underlying literal. + if(!staticassign(a, r->left, out)) + *out = list(*out, nod(OAS, a, r->left)); + return 1; + } + break; + + case OARRAYLIT: + initplan(r); + if(isslice(r->type)) { + // Init slice. + ta = typ(TARRAY); + ta->type = r->type->type; + ta->bound = mpgetfix(r->right->val.u.xval); + a = staticname(ta, 1); + r->nname = a; + n1 = *l; + n1.xoffset = l->xoffset + Array_array; + gdata(&n1, nod(OADDR, a, N), widthptr); + n1.xoffset = l->xoffset + Array_nel; + gdata(&n1, r->right, 4); + n1.xoffset = l->xoffset + Array_cap; + gdata(&n1, r->right, 4); + // Fall through to init underlying array. + l = a; + } + // fall through + case OSTRUCTLIT: + initplan(r); + p = r->initplan; + n1 = *l; + for(i=0; i<p->len; i++) { + e = &p->e[i]; + n1.xoffset = l->xoffset + e->xoffset; + n1.type = e->expr->type; + if(e->expr->op == OLITERAL) + gdata(&n1, e->expr, n1.type->width); + else { + a = nod(OXXX, N, N); + *a = n1; + if(!staticassign(a, e->expr, out)) + *out = list(*out, nod(OAS, a, e->expr)); + } + } + return 1; + + case OMAPLIT: + // TODO: Table-driven map insert. + break; + } + return 0; +} + +/* * from here down is the walk analysis * of composite literals. * most of the work is to generate @@ -408,7 +664,6 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init) dowidth(t); if(ctxt != 0) { - // put everything into static array vstat = staticname(t, ctxt); arraylit(ctxt, 1, n, vstat, init); @@ -452,12 +707,18 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init) } // make new auto *array (3 declare) - vauto = nod(OXXX, N, N); - tempname(vauto, ptrto(t)); + vauto = temp(ptrto(t)); - // set auto to point at new heap (3 assign) - a = nod(ONEW, N, N); - a->list = list1(typenod(t)); + // set auto to point at new temp or heap (3 assign) + if(n->esc == EscNone) { + a = nod(OAS, temp(t), N); + typecheck(&a, Etop); + *init = list(*init, a); // zero new temp + a = nod(OADDR, a->left, N); + } else { + a = nod(ONEW, N, N); + a->list = list1(typenod(t)); + } a = nod(OAS, vauto, a); typecheck(&a, Etop); walkexpr(&a, init); @@ -522,6 +783,7 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init) Node *vstat, *index, *value; Sym *syma, *symb; +USED(ctxt); ctxt = 0; // make the map var @@ -545,7 +807,6 @@ ctxt = 0; b++; } - t = T; if(b != 0) { // build type [count]struct { a Tindex, b Tvalue } t = n->type; @@ -615,8 +876,7 @@ ctxt = 0; // for i = 0; i < len(vstat); i++ { // map[vstat[i].a] = vstat[i].b // } - index = nod(OXXX, N, N); - tempname(index, types[TINT]); + index = temp(types[TINT]); a = nod(OINDEX, vstat, index); a->etype = 1; // no bounds checking @@ -677,6 +937,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"); @@ -917,18 +1190,15 @@ gen_as_init(Node *n) case TPTR64: case TFLOAT32: case TFLOAT64: - gused(N); // in case the data is the dest of a goto gdata(&nam, nr, nr->type->width); break; case TCOMPLEX64: case TCOMPLEX128: - gused(N); // in case the data is the dest of a goto gdatacomplex(&nam, nr->val.u.cval); break; case TSTRING: - gused(N); // in case the data is the dest of a goto gdatastring(&nam, nr->val.u.sval); break; } @@ -969,3 +1239,152 @@ no: return 0; } +static int iszero(Node*); +static int isvaluelit(Node*); +static InitEntry* entry(InitPlan*); +static void addvalue(InitPlan*, vlong, Node*, Node*); + +static void +initplan(Node *n) +{ + InitPlan *p; + Node *a; + NodeList *l; + + if(n->initplan != nil) + return; + p = mal(sizeof *p); + n->initplan = p; + switch(n->op) { + default: + fatal("initplan"); + case OARRAYLIT: + for(l=n->list; l; l=l->next) { + a = l->n; + if(a->op != OKEY || !smallintconst(a->left)) + fatal("initplan arraylit"); + addvalue(p, n->type->type->width*mpgetfix(a->left->val.u.xval), N, a->right); + } + break; + case OSTRUCTLIT: + for(l=n->list; l; l=l->next) { + a = l->n; + if(a->op != OKEY || a->left->type == T) + fatal("initplan structlit"); + addvalue(p, a->left->type->width, N, a->right); + } + break; + case OMAPLIT: + for(l=n->list; l; l=l->next) { + a = l->n; + if(a->op != OKEY) + fatal("initplan maplit"); + addvalue(p, -1, a->left, a->right); + } + break; + } +} + +static void +addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n) +{ + int i; + InitPlan *q; + InitEntry *e; + + USED(key); + + // special case: zero can be dropped entirely + if(iszero(n)) { + p->zero += n->type->width; + return; + } + + // special case: inline struct and array (not slice) literals + if(isvaluelit(n)) { + initplan(n); + q = n->initplan; + for(i=0; i<q->len; i++) { + e = entry(p); + *e = q->e[i]; + e->xoffset += xoffset; + } + return; + } + + // add to plan + if(n->op == OLITERAL) + p->lit += n->type->width; + else + p->expr += n->type->width; + + e = entry(p); + e->xoffset = xoffset; + e->expr = n; +} + +static int +iszero(Node *n) +{ + NodeList *l; + + switch(n->op) { + case OLITERAL: + switch(n->val.ctype) { + default: + dump("unexpected literal", n); + fatal("iszero"); + + case CTNIL: + return 1; + + case CTSTR: + return n->val.u.sval == nil || n->val.u.sval->len == 0; + + case CTBOOL: + return n->val.u.bval == 0; + + case CTINT: + case CTRUNE: + return mpcmpfixc(n->val.u.xval, 0) == 0; + + case CTFLT: + return mpcmpfltc(n->val.u.fval, 0) == 0; + + case CTCPLX: + return mpcmpfltc(&n->val.u.cval->real, 0) == 0 && mpcmpfltc(&n->val.u.cval->imag, 0) == 0; + } + break; + case OARRAYLIT: + if(isslice(n->type)) + break; + // fall through + case OSTRUCTLIT: + for(l=n->list; l; l=l->next) + if(!iszero(l->n->right)) + return 0; + return 1; + } + return 0; +} + +static int +isvaluelit(Node *n) +{ + return (n->op == OARRAYLIT && isfixedarray(n->type)) || n->op == OSTRUCTLIT; +} + +static InitEntry* +entry(InitPlan *p) +{ + if(p->len >= p->cap) { + if(p->cap == 0) + p->cap = 4; + else + p->cap *= 2; + p->e = realloc(p->e, p->cap*sizeof p->e[0]); + if(p->e == nil) + fatal("out of memory"); + } + return &p->e[p->len++]; +} diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 1a05d43d0..681c023a0 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" #include "md5.h" #include "y.tab.h" -#include "opnames.h" #include "yerr.h" -static void dodump(Node*, int); - typedef struct Error Error; struct Error { @@ -27,7 +26,7 @@ errorexit(void) flusherrors(); if(outfile) remove(outfile); - exit(1); + exits("error"); } extern int yychar; @@ -45,12 +44,10 @@ adderr(int line, char *fmt, va_list arg) Fmt f; Error *p; - erroring++; fmtstrinit(&f); fmtprint(&f, "%L: ", line); fmtvprint(&f, fmt, arg); fmtprint(&f, "\n"); - erroring--; if(nerr >= merr) { if(merr == 0) @@ -106,7 +103,7 @@ hcrash(void) if(debug['h']) { flusherrors(); if(outfile) - unlink(outfile); + remove(outfile); *(volatile int*)0 = 0; } } @@ -122,7 +119,7 @@ yyerrorl(int line, char *fmt, ...) hcrash(); nerrors++; - if(nerrors >= 10 && !debug['e']) { + if(nsavederrors+nerrors >= 10 && !debug['e']) { flusherrors(); print("%L: too many errors\n", line); errorexit(); @@ -190,7 +187,7 @@ yyerror(char *fmt, ...) hcrash(); nerrors++; - if(nerrors >= 10 && !debug['e']) { + if(nsavederrors+nerrors >= 10 && !debug['e']) { flusherrors(); print("%L: too many errors\n", parserline()); errorexit(); @@ -210,6 +207,16 @@ warn(char *fmt, ...) } void +warnl(int line, char *fmt, ...) +{ + va_list arg; + + va_start(arg, fmt); + adderr(line, fmt, arg); + va_end(arg); +} + +void fatal(char *fmt, ...) { va_list arg; @@ -393,7 +400,7 @@ importdot(Pkg *opkg, Node *pack) } if(n == 0) { // can't possibly be used - there were no symbols - yyerrorl(pack->lineno, "imported and not used: %Z", opkg->path); + yyerrorl(pack->lineno, "imported and not used: \"%Z\"", opkg->path); } } @@ -483,49 +490,125 @@ nod(int op, Node *nleft, Node *nright) n->lineno = parserline(); n->xoffset = BADWIDTH; n->orig = n; + n->curfn = curfn; return n; } int +algtype1(Type *t, Type **bad) +{ + int a, ret; + Type *t1; + + if(bad) + *bad = T; + + switch(t->etype) { + case TINT8: + case TUINT8: + case TINT16: + case TUINT16: + case TINT32: + case TUINT32: + case TINT64: + case TUINT64: + case TINT: + case TUINT: + case TUINTPTR: + case TBOOL: + case TPTR32: + case TPTR64: + case TCHAN: + case TUNSAFEPTR: + return AMEM; + + case TFUNC: + case TMAP: + if(bad) + *bad = t; + return ANOEQ; + + case TFLOAT32: + return AFLOAT32; + + case TFLOAT64: + return AFLOAT64; + + case TCOMPLEX64: + return ACPLX64; + + case TCOMPLEX128: + return ACPLX128; + + case TSTRING: + return ASTRING; + + case TINTER: + if(isnilinter(t)) + return ANILINTER; + return AINTER; + + case TARRAY: + if(isslice(t)) { + if(bad) + *bad = t; + return ANOEQ; + } + if(t->bound == 0) + return AMEM; + a = algtype1(t->type, bad); + if(a == ANOEQ || a == AMEM) { + if(a == ANOEQ && bad) + *bad = t; + return a; + } + return -1; // needs special compare + + case TSTRUCT: + if(t->type != T && t->type->down == T) { + // One-field struct is same as that one field alone. + return algtype1(t->type->type, bad); + } + ret = AMEM; + for(t1=t->type; t1!=T; t1=t1->down) { + if(isblanksym(t1->sym)) + continue; + a = algtype1(t1->type, bad); + if(a == ANOEQ) + return ANOEQ; // not comparable + if(a != AMEM) + ret = -1; // needs special compare + } + return ret; + } + + fatal("algtype1: unexpected type %T", t); + return 0; +} + +int algtype(Type *t) { int a; - - if(issimple[t->etype] || isptr[t->etype] || - t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) { - if(t->width == 1) - a = AMEM8; - else if(t->width == 2) - a = AMEM16; - else if(t->width == 4) - a = AMEM32; - else if(t->width == 8) - a = AMEM64; - else if(t->width == 16) - a = AMEM128; - else - a = AMEM; // just bytes (int, ptr, etc) - } else if(t->etype == TSTRING) - a = ASTRING; // string - else if(isnilinter(t)) - a = ANILINTER; // nil interface - else if(t->etype == TINTER) - a = AINTER; // interface - else if(isslice(t)) - a = ASLICE; // slice - else { - if(t->width == 1) - a = ANOEQ8; - else if(t->width == 2) - a = ANOEQ16; - else if(t->width == 4) - a = ANOEQ32; - else if(t->width == 8) - a = ANOEQ64; - else if(t->width == 16) - a = ANOEQ128; - else - a = ANOEQ; // just bytes, but no hash/eq + + a = algtype1(t, nil); + if(a == AMEM || a == ANOEQ) { + if(isslice(t)) + return ASLICE; + switch(t->width) { + case 0: + return a + AMEM0 - AMEM; + case 1: + return a + AMEM8 - AMEM; + case 2: + return a + AMEM16 - AMEM; + case 4: + return a + AMEM32 - AMEM; + case 8: + return a + AMEM64 - AMEM; + case 16: + return a + AMEM128 - AMEM; + } } return a; } @@ -535,9 +618,16 @@ maptype(Type *key, Type *val) { Type *t; - - if(key != nil && key->etype != TANY && algtype(key) == ANOEQ) { - if(key->etype == TFORW) { + if(key != nil) { + switch(key->etype) { + default: + if(algtype1(key, nil) == ANOEQ) + yyerror("invalid map key type %T", key); + break; + case TANY: + // will be resolved later. + break; + case TFORW: // map[key] used during definition of key. // postpone check until key is fully defined. // if there are multiple uses of map[key] @@ -546,8 +636,8 @@ maptype(Type *key, Type *val) // good enough. if(key->maplineno == 0) key->maplineno = lineno; - } else - yyerror("invalid map key type %T", key); + break; + } } t = typ(TMAP); t->down = key; @@ -696,6 +786,7 @@ aindex(Node *b, Type *t) yyerror("array bound must be an integer expression"); break; case CTINT: + case CTRUNE: bound = mpgetfix(b->val.u.xval); if(bound < 0) yyerror("array bound must be non negative"); @@ -710,892 +801,6 @@ aindex(Node *b, Type *t) return r; } -static void -indent(int dep) -{ - int i; - - for(i=0; i<dep; i++) - print(". "); -} - -static void -dodumplist(NodeList *l, int dep) -{ - for(; l; l=l->next) - dodump(l->n, dep); -} - -static void -dodump(Node *n, int dep) -{ - if(n == N) - return; - - indent(dep); - if(dep > 10) { - print("...\n"); - return; - } - - if(n->ninit != nil) { - print("%O-init\n", n->op); - dodumplist(n->ninit, dep+1); - indent(dep); - } - - switch(n->op) { - default: - print("%N\n", n); - dodump(n->left, dep+1); - dodump(n->right, dep+1); - break; - - case OTYPE: - print("%O %S type=%T\n", n->op, n->sym, n->type); - if(n->type == T && n->ntype) { - indent(dep); - print("%O-ntype\n", n->op); - dodump(n->ntype, dep+1); - } - break; - - case OIF: - print("%O%J\n", n->op, n); - dodump(n->ntest, dep+1); - if(n->nbody != nil) { - indent(dep); - print("%O-then\n", n->op); - dodumplist(n->nbody, dep+1); - } - if(n->nelse != nil) { - indent(dep); - print("%O-else\n", n->op); - dodumplist(n->nelse, dep+1); - } - break; - - case OSELECT: - print("%O%J\n", n->op, n); - dodumplist(n->nbody, dep+1); - break; - - case OSWITCH: - case OFOR: - print("%O%J\n", n->op, n); - dodump(n->ntest, dep+1); - - if(n->nbody != nil) { - indent(dep); - print("%O-body\n", n->op); - dodumplist(n->nbody, dep+1); - } - - if(n->nincr != N) { - indent(dep); - print("%O-incr\n", n->op); - dodump(n->nincr, dep+1); - } - break; - - case OCASE: - // the right side points to label of the body - if(n->right != N && n->right->op == OGOTO && n->right->left->op == ONAME) - print("%O%J GOTO %N\n", n->op, n, n->right->left); - else - print("%O%J\n", n->op, n); - dodump(n->left, dep+1); - break; - - case OXCASE: - print("%N\n", n); - dodump(n->left, dep+1); - dodump(n->right, dep+1); - indent(dep); - print("%O-nbody\n", n->op); - dodumplist(n->nbody, dep+1); - break; - } - - if(0 && n->ntype != nil) { - indent(dep); - print("%O-ntype\n", n->op); - dodump(n->ntype, dep+1); - } - if(n->list != nil) { - indent(dep); - print("%O-list\n", n->op); - dodumplist(n->list, dep+1); - } - if(n->rlist != nil) { - indent(dep); - print("%O-rlist\n", n->op); - dodumplist(n->rlist, dep+1); - } - if(n->op != OIF && n->nbody != nil) { - indent(dep); - print("%O-nbody\n", n->op); - dodumplist(n->nbody, dep+1); - } -} - -void -dumplist(char *s, NodeList *l) -{ - print("%s\n", s); - dodumplist(l, 1); -} - -void -dump(char *s, Node *n) -{ - print("%s [%p]\n", s, n); - dodump(n, 1); -} - -static char* -goopnames[] = -{ - [OADDR] = "&", - [OADD] = "+", - [OANDAND] = "&&", - [OANDNOT] = "&^", - [OAND] = "&", - [OAPPEND] = "append", - [OAS] = "=", - [OAS2] = "=", - [OBREAK] = "break", - [OCALL] = "function call", - [OCAP] = "cap", - [OCASE] = "case", - [OCLOSE] = "close", - [OCOMPLEX] = "complex", - [OCOM] = "^", - [OCONTINUE] = "continue", - [OCOPY] = "copy", - [ODEC] = "--", - [ODEFER] = "defer", - [ODIV] = "/", - [OEQ] = "==", - [OFALL] = "fallthrough", - [OFOR] = "for", - [OGE] = ">=", - [OGOTO] = "goto", - [OGT] = ">", - [OIF] = "if", - [OIMAG] = "imag", - [OINC] = "++", - [OIND] = "*", - [OLEN] = "len", - [OLE] = "<=", - [OLSH] = "<<", - [OLT] = "<", - [OMAKE] = "make", - [OMINUS] = "-", - [OMOD] = "%", - [OMUL] = "*", - [ONEW] = "new", - [ONE] = "!=", - [ONOT] = "!", - [OOROR] = "||", - [OOR] = "|", - [OPANIC] = "panic", - [OPLUS] = "+", - [OPRINTN] = "println", - [OPRINT] = "print", - [ORANGE] = "range", - [OREAL] = "real", - [ORECV] = "<-", - [ORETURN] = "return", - [ORSH] = ">>", - [OSELECT] = "select", - [OSEND] = "<-", - [OSUB] = "-", - [OSWITCH] = "switch", - [OXOR] = "^", -}; - -int -Oconv(Fmt *fp) -{ - int o; - - o = va_arg(fp->args, int); - if((fp->flags & FmtSharp) && o >= 0 && o < nelem(goopnames) && goopnames[o] != nil) - return fmtstrcpy(fp, goopnames[o]); - if(o < 0 || o >= nelem(opnames) || opnames[o] == nil) - return fmtprint(fp, "O-%d", o); - return fmtstrcpy(fp, opnames[o]); -} - -int -Lconv(Fmt *fp) -{ - struct - { - Hist* incl; /* start of this include file */ - int32 idel; /* delta line number to apply to include */ - Hist* line; /* start of this #line directive */ - int32 ldel; /* delta line number to apply to #line */ - } a[HISTSZ]; - int32 lno, d; - int i, n; - Hist *h; - - lno = va_arg(fp->args, int32); - - n = 0; - for(h=hist; h!=H; h=h->link) { - if(h->offset < 0) - continue; - if(lno < h->line) - break; - if(h->name) { - if(h->offset > 0) { - // #line directive - if(n > 0 && n < HISTSZ) { - a[n-1].line = h; - a[n-1].ldel = h->line - h->offset + 1; - } - } else { - // beginning of file - if(n < HISTSZ) { - a[n].incl = h; - a[n].idel = h->line; - a[n].line = 0; - } - n++; - } - continue; - } - n--; - if(n > 0 && n < HISTSZ) { - d = h->line - a[n].incl->line; - a[n-1].ldel += d; - a[n-1].idel += d; - } - } - - if(n > HISTSZ) - n = HISTSZ; - - for(i=n-1; i>=0; i--) { - if(i != n-1) { - if(fp->flags & ~(FmtWidth|FmtPrec)) - break; - fmtprint(fp, " "); - } - if(debug['L']) - fmtprint(fp, "%s/", pathname); - if(a[i].line) - fmtprint(fp, "%s:%d[%s:%d]", - a[i].line->name, lno-a[i].ldel+1, - a[i].incl->name, lno-a[i].idel+1); - else - fmtprint(fp, "%s:%d", - a[i].incl->name, lno-a[i].idel+1); - lno = a[i].incl->line - 1; // now print out start of this file - } - if(n == 0) - fmtprint(fp, "<epoch>"); - - return 0; -} - -/* -s%,%,\n%g -s%\n+%\n%g -s%^[ ]*T%%g -s%,.*%%g -s%.+% [T&] = "&",%g -s%^ ........*\]%&~%g -s%~ %%g -*/ - -static char* -etnames[] = -{ - [TINT] = "INT", - [TUINT] = "UINT", - [TINT8] = "INT8", - [TUINT8] = "UINT8", - [TINT16] = "INT16", - [TUINT16] = "UINT16", - [TINT32] = "INT32", - [TUINT32] = "UINT32", - [TINT64] = "INT64", - [TUINT64] = "UINT64", - [TUINTPTR] = "UINTPTR", - [TFLOAT32] = "FLOAT32", - [TFLOAT64] = "FLOAT64", - [TCOMPLEX64] = "COMPLEX64", - [TCOMPLEX128] = "COMPLEX128", - [TBOOL] = "BOOL", - [TPTR32] = "PTR32", - [TPTR64] = "PTR64", - [TFUNC] = "FUNC", - [TARRAY] = "ARRAY", - [TSTRUCT] = "STRUCT", - [TCHAN] = "CHAN", - [TMAP] = "MAP", - [TINTER] = "INTER", - [TFORW] = "FORW", - [TFIELD] = "FIELD", - [TSTRING] = "STRING", - [TANY] = "ANY", -}; - -int -Econv(Fmt *fp) -{ - int et; - - et = va_arg(fp->args, int); - if(et < 0 || et >= nelem(etnames) || etnames[et] == nil) - return fmtprint(fp, "E-%d", et); - return fmtstrcpy(fp, etnames[et]); -} - -static const char* classnames[] = { - "Pxxx", - "PEXTERN", - "PAUTO", - "PPARAM", - "PPARAMOUT", - "PPARAMREF", - "PFUNC", -}; - -int -Jconv(Fmt *fp) -{ - Node *n; - char *s; - int c; - - n = va_arg(fp->args, Node*); - - c = fp->flags&FmtShort; - - if(!c && n->ullman != 0) - fmtprint(fp, " u(%d)", n->ullman); - - if(!c && n->addable != 0) - fmtprint(fp, " a(%d)", n->addable); - - if(!c && n->vargen != 0) - fmtprint(fp, " g(%d)", n->vargen); - - if(n->lineno != 0) - fmtprint(fp, " l(%d)", n->lineno); - - if(!c && n->xoffset != BADWIDTH) - fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta); - - if(n->class != 0) { - s = ""; - if (n->class & PHEAP) s = ",heap"; - if ((n->class & ~PHEAP) < nelem(classnames)) - fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s); - else - fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s); - } - - if(n->colas != 0) - fmtprint(fp, " colas(%d)", n->colas); - - if(n->funcdepth != 0) - fmtprint(fp, " f(%d)", n->funcdepth); - - if(n->noescape != 0) - fmtprint(fp, " ne(%d)", n->noescape); - - if(!c && n->typecheck != 0) - fmtprint(fp, " tc(%d)", n->typecheck); - - if(!c && n->dodata != 0) - fmtprint(fp, " dd(%d)", n->dodata); - - if(n->isddd != 0) - fmtprint(fp, " isddd(%d)", n->isddd); - - if(n->implicit != 0) - fmtprint(fp, " implicit(%d)", n->implicit); - - if(!c && n->pun != 0) - fmtprint(fp, " pun(%d)", n->pun); - - if(!c && n->used != 0) - fmtprint(fp, " used(%d)", n->used); - return 0; -} - -int -Sconv(Fmt *fp) -{ - Sym *s; - - s = va_arg(fp->args, Sym*); - if(s == S) { - fmtstrcpy(fp, "<S>"); - return 0; - } - - if(fp->flags & FmtShort) - goto shrt; - - if(exporting || (fp->flags & FmtSharp)) { - if(packagequotes) - fmtprint(fp, "\"%Z\"", s->pkg->path); - else - fmtprint(fp, "%s", s->pkg->prefix); - fmtprint(fp, ".%s", s->name); - return 0; - } - - if(s->pkg && s->pkg != localpkg || longsymnames || (fp->flags & FmtLong)) { - // This one is for the user. If the package name - // was used by multiple packages, give the full - // import path to disambiguate. - if(erroring && pkglookup(s->pkg->name, nil)->npkg > 1) { - fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name); - return 0; - } - fmtprint(fp, "%s.%s", s->pkg->name, s->name); - return 0; - } - -shrt: - fmtstrcpy(fp, s->name); - return 0; -} - -static char* -basicnames[] = -{ - [TINT] = "int", - [TUINT] = "uint", - [TINT8] = "int8", - [TUINT8] = "uint8", - [TINT16] = "int16", - [TUINT16] = "uint16", - [TINT32] = "int32", - [TUINT32] = "uint32", - [TINT64] = "int64", - [TUINT64] = "uint64", - [TUINTPTR] = "uintptr", - [TFLOAT32] = "float32", - [TFLOAT64] = "float64", - [TCOMPLEX64] = "complex64", - [TCOMPLEX128] = "complex128", - [TBOOL] = "bool", - [TANY] = "any", - [TSTRING] = "string", - [TNIL] = "nil", - [TIDEAL] = "ideal", - [TBLANK] = "blank", -}; - -int -Tpretty(Fmt *fp, Type *t) -{ - Type *t1; - Sym *s; - - if(0 && debug['r']) { - debug['r'] = 0; - fmtprint(fp, "%T (orig=%T)", t, t->orig); - debug['r'] = 1; - return 0; - } - - if(t->etype != TFIELD - && t->sym != S - && !(fp->flags&FmtLong)) { - s = t->sym; - if(t == types[t->etype] && t->etype != TUNSAFEPTR) - return fmtprint(fp, "%s", s->name); - if(exporting) { - if(fp->flags & FmtShort) - fmtprint(fp, "%hS", s); - else - fmtprint(fp, "%S", s); - if(s->pkg != localpkg) - return 0; - if(t->vargen) - fmtprint(fp, "·%d", t->vargen); - return 0; - } - return fmtprint(fp, "%S", s); - } - - if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) { - if(isideal(t) && t->etype != TIDEAL && t->etype != TNIL) - fmtprint(fp, "ideal "); - return fmtprint(fp, "%s", basicnames[t->etype]); - } - - switch(t->etype) { - case TPTR32: - case TPTR64: - if(fp->flags&FmtShort) // pass flag thru for methodsym - return fmtprint(fp, "*%hT", t->type); - return fmtprint(fp, "*%T", t->type); - - case TCHAN: - switch(t->chan) { - case Crecv: - return fmtprint(fp, "<-chan %T", t->type); - case Csend: - return fmtprint(fp, "chan<- %T", t->type); - } - if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv) - return fmtprint(fp, "chan (%T)", t->type); - return fmtprint(fp, "chan %T", t->type); - - case TMAP: - return fmtprint(fp, "map[%T] %T", t->down, t->type); - - case TFUNC: - // t->type is method struct - // t->type->down is result struct - // t->type->down->down is arg struct - if(t->thistuple && !(fp->flags&FmtSharp) && !(fp->flags&FmtShort)) { - fmtprint(fp, "method("); - for(t1=getthisx(t)->type; t1; t1=t1->down) { - fmtprint(fp, "%T", t1); - if(t1->down) - fmtprint(fp, ", "); - } - fmtprint(fp, ")"); - } - - if(!(fp->flags&FmtByte)) - fmtprint(fp, "func"); - fmtprint(fp, "("); - for(t1=getinargx(t)->type; t1; t1=t1->down) { - if(noargnames && t1->etype == TFIELD) { - if(t1->isddd) - fmtprint(fp, "...%T", t1->type->type); - else - fmtprint(fp, "%T", t1->type); - } else - fmtprint(fp, "%T", t1); - if(t1->down) - fmtprint(fp, ", "); - } - fmtprint(fp, ")"); - switch(t->outtuple) { - case 0: - break; - case 1: - t1 = getoutargx(t)->type; - if(t1 == T) { - // failure to typecheck earlier; don't know the type - fmtprint(fp, " ?unknown-type?"); - break; - } - if(t1->etype == TFIELD) - t1 = t1->type; - fmtprint(fp, " %T", t1); - break; - default: - t1 = getoutargx(t)->type; - fmtprint(fp, " ("); - for(; t1; t1=t1->down) { - if(noargnames && t1->etype == TFIELD) - fmtprint(fp, "%T", t1->type); - else - fmtprint(fp, "%T", t1); - if(t1->down) - fmtprint(fp, ", "); - } - fmtprint(fp, ")"); - break; - } - return 0; - - case TARRAY: - if(t->bound >= 0) - return fmtprint(fp, "[%d]%T", (int)t->bound, t->type); - if(t->bound == -100) - return fmtprint(fp, "[...]%T", t->type); - return fmtprint(fp, "[]%T", t->type); - - case TINTER: - fmtprint(fp, "interface {"); - for(t1=t->type; t1!=T; t1=t1->down) { - fmtprint(fp, " "); - if(exportname(t1->sym->name)) - fmtprint(fp, "%hS", t1->sym); - else - fmtprint(fp, "%S", t1->sym); - fmtprint(fp, "%hhT", t1->type); - if(t1->down) - fmtprint(fp, ";"); - } - return fmtprint(fp, " }"); - - case TSTRUCT: - if(t->funarg) { - fmtprint(fp, "("); - for(t1=t->type; t1!=T; t1=t1->down) { - fmtprint(fp, "%T", t1); - if(t1->down) - fmtprint(fp, ", "); - } - return fmtprint(fp, ")"); - } - fmtprint(fp, "struct {"); - for(t1=t->type; t1!=T; t1=t1->down) { - fmtprint(fp, " %T", t1); - if(t1->down) - fmtprint(fp, ";"); - } - return fmtprint(fp, " }"); - - case TFIELD: - if(t->sym == S || t->embedded) { - if(exporting) - fmtprint(fp, "? "); - } else - fmtprint(fp, "%hS ", t->sym); - if(t->isddd) - fmtprint(fp, "...%T", t->type->type); - else - fmtprint(fp, "%T", t->type); - if(t->note) { - fmtprint(fp, " "); - if(exporting) - fmtprint(fp, ":"); - fmtprint(fp, "\"%Z\"", t->note); - } - return 0; - - case TFORW: - if(exporting) - yyerror("undefined type %S", t->sym); - if(t->sym) - return fmtprint(fp, "undefined %S", t->sym); - return fmtprint(fp, "undefined"); - - case TUNSAFEPTR: - if(exporting) - return fmtprint(fp, "\"unsafe\".Pointer"); - return fmtprint(fp, "unsafe.Pointer"); - } - - // Don't know how to handle - fall back to detailed prints. - return -1; -} - -int -Tconv(Fmt *fp) -{ - Type *t, *t1; - int r, et, sharp, minus; - - sharp = (fp->flags & FmtSharp); - minus = (fp->flags & FmtLeft); - fp->flags &= ~(FmtSharp|FmtLeft); - - t = va_arg(fp->args, Type*); - if(t == T) - return fmtstrcpy(fp, "<T>"); - - t->trecur++; - if(t->trecur > 5) { - fmtprint(fp, "..."); - goto out; - } - - if(!debug['t']) { - if(sharp) - exporting++; - if(minus) - noargnames++; - r = Tpretty(fp, t); - if(sharp) - exporting--; - if(minus) - noargnames--; - if(r >= 0) { - t->trecur--; - return 0; - } - } - - if(sharp || exporting) - fatal("missing %E case during export", t->etype); - - et = t->etype; - fmtprint(fp, "%E ", et); - if(t->sym != S) - fmtprint(fp, "<%S>", t->sym); - - switch(et) { - default: - if(t->type != T) - fmtprint(fp, " %T", t->type); - break; - - case TFIELD: - fmtprint(fp, "%T", t->type); - break; - - case TFUNC: - if(fp->flags & FmtLong) - fmtprint(fp, "%d%d%d(%lT,%lT)%lT", - t->thistuple, t->intuple, t->outtuple, - t->type, t->type->down->down, t->type->down); - else - fmtprint(fp, "%d%d%d(%T,%T)%T", - t->thistuple, t->intuple, t->outtuple, - t->type, t->type->down->down, t->type->down); - break; - - case TINTER: - fmtprint(fp, "{"); - if(fp->flags & FmtLong) - for(t1=t->type; t1!=T; t1=t1->down) - fmtprint(fp, "%lT;", t1); - fmtprint(fp, "}"); - break; - - case TSTRUCT: - fmtprint(fp, "{"); - if(fp->flags & FmtLong) - for(t1=t->type; t1!=T; t1=t1->down) - fmtprint(fp, "%lT;", t1); - fmtprint(fp, "}"); - break; - - case TMAP: - fmtprint(fp, "[%T]%T", t->down, t->type); - break; - - case TARRAY: - if(t->bound >= 0) - fmtprint(fp, "[%d]%T", t->bound, t->type); - else - fmtprint(fp, "[]%T", t->type); - break; - - case TPTR32: - case TPTR64: - fmtprint(fp, "%T", t->type); - break; - } - -out: - t->trecur--; - return 0; -} - -int -Nconv(Fmt *fp) -{ - char buf1[500]; - Node *n; - - n = va_arg(fp->args, Node*); - if(n == N) { - fmtprint(fp, "<N>"); - goto out; - } - - if(fp->flags & FmtSign) { - if(n->type == T) - fmtprint(fp, "%#N", n); - else if(n->type->etype == TNIL) - fmtprint(fp, "nil"); - else - fmtprint(fp, "%#N (type %T)", n, n->type); - goto out; - } - - if(fp->flags & FmtSharp) { - if(n->orig != N) - n = n->orig; - exprfmt(fp, n, 0); - goto out; - } - - switch(n->op) { - default: - if (fp->flags & FmtShort) - fmtprint(fp, "%O%hJ", n->op, n); - else - fmtprint(fp, "%O%J", n->op, n); - break; - - case ONAME: - case ONONAME: - if(n->sym == S) { - if (fp->flags & FmtShort) - fmtprint(fp, "%O%hJ", n->op, n); - else - fmtprint(fp, "%O%J", n->op, n); - break; - } - if (fp->flags & FmtShort) - fmtprint(fp, "%O-%S%hJ", n->op, n->sym, n); - else - fmtprint(fp, "%O-%S%J", n->op, n->sym, n); - goto ptyp; - - case OREGISTER: - fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n); - break; - - case OLITERAL: - switch(n->val.ctype) { - default: - snprint(buf1, sizeof(buf1), "LITERAL-ctype=%d", n->val.ctype); - break; - case CTINT: - snprint(buf1, sizeof(buf1), "I%B", n->val.u.xval); - break; - case CTFLT: - snprint(buf1, sizeof(buf1), "F%g", mpgetflt(n->val.u.fval)); - break; - case CTCPLX: - snprint(buf1, sizeof(buf1), "(F%g+F%gi)", - mpgetflt(&n->val.u.cval->real), - mpgetflt(&n->val.u.cval->imag)); - break; - case CTSTR: - snprint(buf1, sizeof(buf1), "S\"%Z\"", n->val.u.sval); - break; - case CTBOOL: - snprint(buf1, sizeof(buf1), "B%d", n->val.u.bval); - break; - case CTNIL: - snprint(buf1, sizeof(buf1), "N"); - break; - } - fmtprint(fp, "%O-%s%J", n->op, buf1, n); - break; - - case OASOP: - fmtprint(fp, "%O-%O%J", n->op, n->etype, n); - break; - - case OTYPE: - fmtprint(fp, "%O %T", n->op, n->type); - break; - } - if(n->sym != S) - fmtprint(fp, " %S G%d", n->sym, n->vargen); - -ptyp: - if(n->type != T) - fmtprint(fp, " %T", n->type); - -out: - return 0; -} - Node* treecopy(Node *n) { @@ -1636,52 +841,6 @@ treecopy(Node *n) return m; } -int -Zconv(Fmt *fp) -{ - Rune r; - Strlit *sp; - char *s, *se; - int n; - - sp = va_arg(fp->args, Strlit*); - if(sp == nil) - return fmtstrcpy(fp, "<nil>"); - - s = sp->s; - se = s + sp->len; - while(s < se) { - n = chartorune(&r, s); - s += n; - switch(r) { - case Runeerror: - if(n == 1) { - fmtprint(fp, "\\x%02x", (uchar)*(s-1)); - break; - } - // fall through - default: - if(r < ' ') { - fmtprint(fp, "\\x%02x", r); - break; - } - fmtrune(fp, r); - break; - case '\t': - fmtstrcpy(fp, "\\t"); - break; - case '\n': - fmtstrcpy(fp, "\\n"); - break; - case '\"': - case '\\': - fmtrune(fp, '\\'); - fmtrune(fp, r); - break; - } - } - return 0; -} int isnil(Node *n) @@ -1731,11 +890,19 @@ isslice(Type *t) int isblank(Node *n) { + if(n == N) + return 0; + return isblanksym(n->sym); +} + +int +isblanksym(Sym *s) +{ char *p; - if(n == N || n->sym == S) + if(s == S) return 0; - p = n->sym->name; + p = s->name; if(p == nil) return 0; return p[0] == '_' && p[1] == '\0'; @@ -1777,7 +944,7 @@ isideal(Type *t) * return type to hang methods off (r). */ Type* -methtype(Type *t) +methtype(Type *t, int mustname) { if(t == T) return T; @@ -1792,7 +959,7 @@ methtype(Type *t) } // need a type name - if(t->sym == S) + if(t->sym == S && (mustname || t->etype != TSTRUCT)) return T; // check types @@ -1837,6 +1004,25 @@ eqnote(Strlit *a, Strlit *b) return memcmp(a->s, b->s, a->len) == 0; } +typedef struct TypePairList TypePairList; +struct TypePairList +{ + Type *t1; + Type *t2; + TypePairList *next; +}; + +static int +onlist(TypePairList *l, Type *t1, Type *t2) +{ + for(; l; l=l->next) + if((l->t1 == t1 && l->t2 == t2) || (l->t1 == t2 && l->t2 == t1)) + return 1; + return 0; +} + +static int eqtype1(Type*, Type*, TypePairList*); + // Return 1 if t1 and t2 are identical, following the spec rules. // // Any cyclic type must go through a named type, and if one is @@ -1846,10 +1032,40 @@ eqnote(Strlit *a, Strlit *b) int eqtype(Type *t1, Type *t2) { + return eqtype1(t1, t2, nil); +} + +static int +eqtype1(Type *t1, Type *t2, TypePairList *assumed_equal) +{ + TypePairList l; + if(t1 == t2) return 1; - if(t1 == T || t2 == T || t1->etype != t2->etype || t1->sym || t2->sym) + if(t1 == T || t2 == T || t1->etype != t2->etype) return 0; + if(t1->sym || t2->sym) { + // Special case: we keep byte and uint8 separate + // for error messages. Treat them as equal. + switch(t1->etype) { + case TUINT8: + if((t1 == types[TUINT8] || t1 == bytetype) && (t2 == types[TUINT8] || t2 == bytetype)) + return 1; + break; + case TINT: + case TINT32: + if((t1 == types[runetype->etype] || t1 == runetype) && (t2 == types[runetype->etype] || t2 == runetype)) + return 1; + break; + } + return 0; + } + + if(onlist(assumed_equal, t1, t2)) + return 1; + l.next = assumed_equal; + l.t1 = t1; + l.t2 = t2; switch(t1->etype) { case TINTER: @@ -1857,10 +1073,12 @@ eqtype(Type *t1, Type *t2) for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) { if(t1->etype != TFIELD || t2->etype != TFIELD) fatal("struct/interface missing field: %T %T", t1, t2); - if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype(t1->type, t2->type) || !eqnote(t1->note, t2->note)) - return 0; + if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype1(t1->type, t2->type, &l) || !eqnote(t1->note, t2->note)) + goto no; } - return t1 == T && t2 == T; + if(t1 == T && t2 == T) + goto yes; + goto no; case TFUNC: // Loop over structs: receiver, in, out. @@ -1874,26 +1092,36 @@ eqtype(Type *t1, Type *t2) for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) { if(ta->etype != TFIELD || tb->etype != TFIELD) fatal("func struct missing field: %T %T", ta, tb); - if(ta->isddd != tb->isddd || !eqtype(ta->type, tb->type)) - return 0; + if(ta->isddd != tb->isddd || !eqtype1(ta->type, tb->type, &l)) + goto no; } if(ta != T || tb != T) - return 0; + goto no; } - return t1 == T && t2 == T; + if(t1 == T && t2 == T) + goto yes; + goto no; case TARRAY: if(t1->bound != t2->bound) - return 0; + goto no; break; case TCHAN: if(t1->chan != t2->chan) - return 0; + goto no; break; } - return eqtype(t1->down, t2->down) && eqtype(t1->type, t2->type); + if(eqtype1(t1->down, t2->down, &l) && eqtype1(t1->type, t2->type, &l)) + goto yes; + goto no; + +yes: + return 1; + +no: + return 0; } // Are t1 and t2 equal struct types when field names are ignored? @@ -1920,9 +1148,6 @@ eqtypenoname(Type *t1, Type *t2) // Is type src assignment compatible to type dst? // If so, return op code to use in conversion. // If not, return 0. -// -// It is the caller's responsibility to call exportassignok -// to check for assignments to other packages' unexported fields, int assignop(Type *src, Type *dst, char **why) { @@ -1932,7 +1157,9 @@ assignop(Type *src, Type *dst, char **why) if(why != nil) *why = ""; - if(safemode && src != T && src->etype == TUNSAFEPTR) { + // TODO(rsc,lvd): This behaves poorly in the presence of inlining. + // https://code.google.com/p/go/issues/detail?id=2795 + if(safemode && importpkg == nil && src != T && src->etype == TUNSAFEPTR) { yyerror("cannot use unsafe.Pointer"); errorexit(); } @@ -1956,6 +1183,11 @@ assignop(Type *src, Type *dst, char **why) if(dst->etype == TINTER && src->etype != TNIL) { if(implements(src, dst, &missing, &have, &ptr)) return OCONVIFACE; + + // we'll have complained about this method anyway, supress spurious messages. + if(have && have->sym == missing->sym && (have->type->broke || missing->type->broke)) + return OCONVIFACE; + if(why != nil) { if(isptrto(src, TINTER)) *why = smprint(":\n\t%T is pointer to interface, not interface", src); @@ -2072,29 +1304,25 @@ convertop(Type *src, Type *dst, char **why) return OCONV; } - // 6. src is an integer or has type []byte or []int + // 6. src is an integer or has type []byte or []rune // and dst is a string type. if(isint[src->etype] && dst->etype == TSTRING) return ORUNESTR; - if(isslice(src) && src->sym == nil && src->type == types[src->type->etype] && dst->etype == TSTRING) { - switch(src->type->etype) { - case TUINT8: + if(isslice(src) && dst->etype == TSTRING) { + if(src->type->etype == bytetype->etype) return OARRAYBYTESTR; - case TINT: + if(src->type->etype == runetype->etype) return OARRAYRUNESTR; - } } - // 7. src is a string and dst is []byte or []int. + // 7. src is a string and dst is []byte or []rune. // String to slice. - if(src->etype == TSTRING && isslice(dst) && dst->sym == nil && dst->type == types[dst->type->etype]) { - switch(dst->type->etype) { - case TUINT8: + if(src->etype == TSTRING && isslice(dst)) { + if(dst->type->etype == bytetype->etype) return OSTRARRAYBYTE; - case TINT: + if(dst->type->etype == runetype->etype) return OSTRARRAYRUNE; - } } // 8. src is a pointer or uintptr and dst is unsafe.Pointer. @@ -2126,13 +1354,24 @@ assignconv(Node *n, Type *t, char *context) if(t->etype == TBLANK) return n; - exportassignok(n->type, context); + // Convert ideal bool from comparison to plain bool + // if the next step is non-bool (like interface{}). + if(n->type == idealbool && t->etype != TBOOL) { + if(n->op == ONAME || n->op == OLITERAL) { + r = nod(OCONVNOP, n, N); + r->type = types[TBOOL]; + r->typecheck = 1; + r->implicit = 1; + n = r; + } + } + if(eqtype(n->type, t)) return n; op = assignop(n->type, t, &why); if(op == 0) { - yyerror("cannot use %+N as type %T in %s%s", n, t, context, why); + yyerror("cannot use %lN as type %T in %s%s", n, t, context, why); op = OCONV; } @@ -2357,7 +1596,7 @@ syslook(char *name, int copy) * compute a hash value for type t. * if t is a method type, ignore the receiver * so that the hash can be used in interface checks. - * %-T (which calls Tpretty, above) already contains + * %T already contains * all the necessary logic to generate a representation * of the type that completely describes it. * using smprint here avoids duplicating that code. @@ -2371,15 +1610,14 @@ typehash(Type *t) char *p; MD5 d; - longsymnames = 1; if(t->thistuple) { // hide method receiver from Tpretty t->thistuple = 0; - p = smprint("%-T", t); + p = smprint("%-uT", t); t->thistuple = 1; - }else - p = smprint("%-T", t); - longsymnames = 0; + } else + p = smprint("%-uT", t); + //print("typehash: %s\n", p); md5reset(&d); md5write(&d, (uchar*)p, strlen(p)); free(p); @@ -2392,7 +1630,7 @@ ptrto(Type *t) Type *t1; if(tptr == 0) - fatal("ptrto: nil"); + fatal("ptrto: no tptr"); t1 = typ(tptr); t1->type = t; t1->width = widthptr; @@ -2452,6 +1690,11 @@ ullmancalc(Node *n) if(n == N) return; + if(n->ninit != nil) { + ul = UINF; + goto out; + } + switch(n->op) { case OREGISTER: case OLITERAL: @@ -2749,13 +1992,12 @@ safeexpr(Node *n, NodeList **init) return cheapexpr(n, init); } -static Node* +Node* copyexpr(Node *n, Type *t, NodeList **init) { Node *a, *l; - l = nod(OXXX, N, N); - tempname(l, t); + l = temp(t); a = nod(OAS, l, n); typecheck(&a, Etop); walkexpr(&a, init); @@ -2806,10 +2048,12 @@ setmaxarg(Type *t) maxarg = w; } -/* unicode-aware case-insensitive strcmp */ +/* + * unicode-aware case-insensitive strcmp + */ static int -cistrcmp(char *p, char *q) +ucistrcmp(char *p, char *q) { Rune rp, rq; @@ -2851,16 +2095,16 @@ lookdot0(Sym *s, Type *t, Type **save, int ignorecase) c = 0; if(u->etype == TSTRUCT || u->etype == TINTER) { for(f=u->type; f!=T; f=f->down) - if(f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0)) { + if(f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0)) { if(save) *save = f; c++; } } - u = methtype(t); + u = methtype(t, 0); if(u != T) { for(f=u->method; f!=T; f=f->down) - if(f->embedded == 0 && (f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0))) { + if(f->embedded == 0 && (f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0))) { if(save) *save = f; c++; @@ -2869,7 +2113,7 @@ lookdot0(Sym *s, Type *t, Type **save, int ignorecase) return c; } -// search depth d -- +// search depth d for field/method s -- // return count of fields+methods // found at search depth. // answer is in dotlist array and @@ -2946,8 +2190,11 @@ adddot(Node *n) goto ret; out: - if(c > 1) - yyerror("ambiguous DOT reference %T.%S", t, s); + if(c > 1) { + yyerror("ambiguous selector %N", n); + n->left = N; + return n; + } // rebuild elided dots for(c=d-1; c>=0; c--) @@ -2992,8 +2239,6 @@ expand0(Type *t, int followptr) if(u->etype == TINTER) { for(f=u->type; f!=T; f=f->down) { - if(!exportname(f->sym->name) && f->sym->pkg != localpkg) - continue; if(f->sym->flags & SymUniq) continue; f->sym->flags |= SymUniq; @@ -3006,11 +2251,9 @@ expand0(Type *t, int followptr) return; } - u = methtype(t); + u = methtype(t, 0); if(u != T) { for(f=u->method; f!=T; f=f->down) { - if(!exportname(f->sym->name) && f->sym->pkg != localpkg) - continue; if(f->sym->flags & SymUniq) continue; f->sym->flags |= SymUniq; @@ -3058,14 +2301,12 @@ out: } void -expandmeth(Sym *s, Type *t) +expandmeth(Type *t) { Symlink *sl; Type *f; int c, d; - if(s == S) - return; if(t == T || t->xmethod != nil) return; @@ -3086,8 +2327,11 @@ expandmeth(Sym *s, Type *t) if(c == 0) continue; if(c == 1) { - sl->good = 1; - sl->field = f; + // addot1 may have dug out arbitrary fields, we only want methods. + if(f->type->etype == TFUNC && f->type->thistuple > 0) { + sl->good = 1; + sl->field = f; + } } break; } @@ -3128,13 +2372,12 @@ structargs(Type **tl, int mustname) gen = 0; for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) { n = N; - if(t->sym) - n = newname(t->sym); - else if(mustname) { - // have to give it a name so we can refer to it in trampoline + if(mustname && (t->sym == nil || strcmp(t->sym->name, "_") == 0)) { + // invent a name so that we can refer to it in the trampoline snprint(buf, sizeof buf, ".anon%d", gen++); n = newname(lookup(buf)); - } + } else if(t->sym) + n = newname(t->sym); a = nod(ODCLFIELD, n, typenod(t->type)); a->isddd = t->isddd; if(n != N) @@ -3190,8 +2433,6 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) in = structargs(getinarg(method->type), 1); out = structargs(getoutarg(method->type), 0); - fn = nod(ODCLFUNC, N, N); - fn->nname = newname(newnam); t = nod(OTFUNC, N, N); l = list1(this); if(iface && rcvr->width < types[tptr]->width) { @@ -3208,7 +2449,12 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) } t->list = concat(l, in); t->rlist = out; + + fn = nod(ODCLFUNC, N, N); + fn->nname = newname(newnam); + fn->nname->defn = fn; fn->nname->ntype = t; + declare(fn->nname, PFUNC); funchdr(fn); // arg list @@ -3262,6 +2508,448 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) funccompile(fn, 0); } +static Node* +hashmem(Type *t) +{ + Node *tfn, *n; + Sym *sym; + + sym = pkglookup("memhash", runtimepkg); + + n = newname(sym); + n->class = PFUNC; + tfn = nod(OTFUNC, N, N); + tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR])))); + tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); + tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); + typecheck(&tfn, Etype); + n->type = tfn->type; + return n; +} + +static Node* +hashfor(Type *t) +{ + int a; + Sym *sym; + Node *tfn, *n; + + a = algtype1(t, nil); + switch(a) { + case AMEM: + return hashmem(t); + case AINTER: + sym = pkglookup("interhash", runtimepkg); + break; + case ANILINTER: + sym = pkglookup("nilinterhash", runtimepkg); + break; + case ASTRING: + sym = pkglookup("strhash", runtimepkg); + break; + case AFLOAT32: + sym = pkglookup("f32hash", runtimepkg); + break; + case AFLOAT64: + sym = pkglookup("f64hash", runtimepkg); + break; + case ACPLX64: + sym = pkglookup("c64hash", runtimepkg); + break; + case ACPLX128: + sym = pkglookup("c128hash", runtimepkg); + break; + default: + sym = typesymprefix(".hash", t); + break; + } + + n = newname(sym); + n->class = PFUNC; + tfn = nod(OTFUNC, N, N); + tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(types[TUINTPTR])))); + tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); + tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); + typecheck(&tfn, Etype); + n->type = tfn->type; + return n; +} + +/* + * Generate a helper function to compute the hash of a value of type t. + */ +void +genhash(Sym *sym, Type *t) +{ + Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn; + Node *hashel; + Type *first, *t1; + int old_safemode; + int64 size, mul; + + if(debug['r']) + print("genhash %S %T\n", sym, t); + + lineno = 1; // less confusing than end of input + dclcontext = PEXTERN; + markdcl(); + + // func sym(h *uintptr, s uintptr, p *T) + fn = nod(ODCLFUNC, N, N); + fn->nname = newname(sym); + fn->nname->class = PFUNC; + tfn = nod(OTFUNC, N, N); + fn->nname->ntype = tfn; + + n = nod(ODCLFIELD, newname(lookup("h")), typenod(ptrto(types[TUINTPTR]))); + tfn->list = list(tfn->list, n); + nh = n->left; + n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR])); + tfn->list = list(tfn->list, n); + n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t))); + tfn->list = list(tfn->list, n); + np = n->left; + + funchdr(fn); + typecheck(&fn->nname->ntype, Etype); + + // genhash is only called for types that have equality but + // cannot be handled by the standard algorithms, + // so t must be either an array or a struct. + switch(t->etype) { + default: + fatal("genhash %T", t); + case TARRAY: + if(isslice(t)) + fatal("genhash %T", t); + // An array of pure memory would be handled by the + // standard algorithm, so the element type must not be + // pure memory. + hashel = hashfor(t->type); + n = nod(ORANGE, N, nod(OIND, np, N)); + ni = newname(lookup("i")); + ni->type = types[TINT]; + n->list = list1(ni); + n->colas = 1; + colasdefn(n->list, n); + ni = n->list->n; + + // *h = *h<<3 | *h>>61 + n->nbody = list(n->nbody, + nod(OAS, + nod(OIND, nh, N), + nod(OOR, + nod(OLSH, nod(OIND, nh, N), nodintconst(3)), + nod(ORSH, nod(OIND, nh, N), nodintconst(widthptr*8-3))))); + + // *h *= mul + // Same multipliers as in runtime.memhash. + if(widthptr == 4) + mul = 3267000013LL; + else + mul = 23344194077549503LL; + n->nbody = list(n->nbody, + nod(OAS, + nod(OIND, nh, N), + nod(OMUL, nod(OIND, nh, N), nodintconst(mul)))); + + // hashel(h, sizeof(p[i]), &p[i]) + call = nod(OCALL, hashel, N); + call->list = list(call->list, nh); + call->list = list(call->list, nodintconst(t->type->width)); + nx = nod(OINDEX, np, ni); + nx->etype = 1; // no bounds check + na = nod(OADDR, nx, N); + na->etype = 1; // no escape to heap + call->list = list(call->list, na); + n->nbody = list(n->nbody, call); + + fn->nbody = list(fn->nbody, n); + break; + + case TSTRUCT: + // Walk the struct using memhash for runs of AMEM + // and calling specific hash functions for the others. + first = T; + for(t1=t->type;; t1=t1->down) { + if(t1 != T && (isblanksym(t1->sym) || algtype1(t1->type, nil) == AMEM)) { + if(first == T) + first = t1; + continue; + } + // Run memhash for fields up to this one. + while(first != T && isblanksym(first->sym)) + first = first->down; + if(first != T) { + if(first->down == t1) + size = first->type->width; + else if(t1 == T) + size = t->width - first->width; // first->width is offset + else + size = t1->width - first->width; // both are offsets + hashel = hashmem(first->type); + // hashel(h, size, &p.first) + call = nod(OCALL, hashel, N); + call->list = list(call->list, nh); + call->list = list(call->list, nodintconst(size)); + nx = nod(OXDOT, np, newname(first->sym)); // TODO: fields from other packages? + na = nod(OADDR, nx, N); + na->etype = 1; // no escape to heap + call->list = list(call->list, na); + fn->nbody = list(fn->nbody, call); + + first = T; + } + if(t1 == T) + break; + + // Run hash for this field. + hashel = hashfor(t1->type); + // hashel(h, size, &p.t1) + call = nod(OCALL, hashel, N); + call->list = list(call->list, nh); + call->list = list(call->list, nodintconst(t1->type->width)); + nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages? + na = nod(OADDR, nx, N); + na->etype = 1; // no escape to heap + call->list = list(call->list, na); + fn->nbody = list(fn->nbody, call); + } + break; + } + + if(debug['r']) + dumplist("genhash body", fn->nbody); + + funcbody(fn); + curfn = fn; + fn->dupok = 1; + typecheck(&fn, Etop); + typechecklist(fn->nbody, Etop); + curfn = nil; + + // Disable safemode while compiling this code: the code we + // generate internally can refer to unsafe.Pointer. + // In this case it can happen if we need to generate an == + // for a struct containing a reflect.Value, which itself has + // an unexported field of type unsafe.Pointer. + old_safemode = safemode; + safemode = 0; + funccompile(fn, 0); + safemode = old_safemode; +} + +// Return node for +// if p.field != q.field { *eq = false; return } +static Node* +eqfield(Node *p, Node *q, Node *field, Node *eq) +{ + Node *nif, *nx, *ny; + + nx = nod(OXDOT, p, field); + ny = nod(OXDOT, q, field); + nif = nod(OIF, N, N); + nif->ntest = nod(ONE, nx, ny); + nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, eq, N), nodbool(0))); + nif->nbody = list(nif->nbody, nod(ORETURN, N, N)); + return nif; +} + +static Node* +eqmemfunc(vlong size, Type *type) +{ + char buf[30]; + Node *fn; + + switch(size) { + default: + fn = syslook("memequal", 1); + break; + case 1: + case 2: + case 4: + case 8: + case 16: + snprint(buf, sizeof buf, "memequal%d", (int)size*8); + fn = syslook(buf, 1); + break; + } + argtype(fn, type); + argtype(fn, type); + return fn; +} + +// Return node for +// if memequal(size, &p.field, &q.field, eq); !*eq { return } +static Node* +eqmem(Node *p, Node *q, Node *field, vlong size, Node *eq) +{ + Node *nif, *nx, *ny, *call; + + nx = nod(OADDR, nod(OXDOT, p, field), N); + nx->etype = 1; // does not escape + ny = nod(OADDR, nod(OXDOT, q, field), N); + ny->etype = 1; // does not escape + typecheck(&nx, Erv); + typecheck(&ny, Erv); + + call = nod(OCALL, eqmemfunc(size, nx->type->type), N); + call->list = list(call->list, eq); + call->list = list(call->list, nodintconst(size)); + call->list = list(call->list, nx); + call->list = list(call->list, ny); + + nif = nod(OIF, N, N); + nif->ninit = list(nif->ninit, call); + nif->ntest = nod(ONOT, nod(OIND, eq, N), N); + nif->nbody = list(nif->nbody, nod(ORETURN, N, N)); + return nif; +} + +/* + * Generate a helper function to check equality of two values of type t. + */ +void +geneq(Sym *sym, Type *t) +{ + Node *n, *fn, *np, *neq, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange; + Type *t1, *first; + int old_safemode; + int64 size; + + if(debug['r']) + print("geneq %S %T\n", sym, t); + + lineno = 1; // less confusing than end of input + dclcontext = PEXTERN; + markdcl(); + + // func sym(eq *bool, s uintptr, p, q *T) + fn = nod(ODCLFUNC, N, N); + fn->nname = newname(sym); + fn->nname->class = PFUNC; + tfn = nod(OTFUNC, N, N); + fn->nname->ntype = tfn; + + n = nod(ODCLFIELD, newname(lookup("eq")), typenod(ptrto(types[TBOOL]))); + tfn->list = list(tfn->list, n); + neq = n->left; + n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR])); + tfn->list = list(tfn->list, n); + n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t))); + tfn->list = list(tfn->list, n); + np = n->left; + n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t))); + tfn->list = list(tfn->list, n); + nq = n->left; + + funchdr(fn); + + // geneq is only called for types that have equality but + // cannot be handled by the standard algorithms, + // so t must be either an array or a struct. + switch(t->etype) { + default: + fatal("geneq %T", t); + case TARRAY: + if(isslice(t)) + fatal("geneq %T", t); + // An array of pure memory would be handled by the + // standard memequal, so the element type must not be + // pure memory. Even if we unrolled the range loop, + // each iteration would be a function call, so don't bother + // unrolling. + nrange = nod(ORANGE, N, nod(OIND, np, N)); + ni = newname(lookup("i")); + ni->type = types[TINT]; + nrange->list = list1(ni); + nrange->colas = 1; + colasdefn(nrange->list, nrange); + ni = nrange->list->n; + + // if p[i] != q[i] { *eq = false; return } + nx = nod(OINDEX, np, ni); + nx->etype = 1; // no bounds check + ny = nod(OINDEX, nq, ni); + ny->etype = 1; // no bounds check + + nif = nod(OIF, N, N); + nif->ntest = nod(ONE, nx, ny); + nif->nbody = list(nif->nbody, nod(OAS, nod(OIND, neq, N), nodbool(0))); + nif->nbody = list(nif->nbody, nod(ORETURN, N, N)); + nrange->nbody = list(nrange->nbody, nif); + fn->nbody = list(fn->nbody, nrange); + + // *eq = true; + fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1))); + break; + + case TSTRUCT: + // Walk the struct using memequal for runs of AMEM + // and calling specific equality tests for the others. + first = T; + for(t1=t->type;; t1=t1->down) { + if(t1 != T && (isblanksym(t1->sym) || algtype1(t1->type, nil) == AMEM)) { + if(first == T) + first = t1; + continue; + } + // Run memequal for fields up to this one. + // TODO(rsc): All the calls to newname are wrong for + // cross-package unexported fields. + while(first != T && isblanksym(first->sym)) + first = first->down; + if(first != T) { + if(first->down == t1) { + fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); + } else if(first->down->down == t1) { + fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); + first = first->down; + if(!isblanksym(first->sym)) + fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym), neq)); + } else { + // More than two fields: use memequal. + if(t1 == T) + size = t->width - first->width; // first->width is offset + else + size = t1->width - first->width; // both are offsets + fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size, neq)); + } + first = T; + } + if(t1 == T) + break; + + // Check this field, which is not just memory. + fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym), neq)); + } + + // *eq = true; + fn->nbody = list(fn->nbody, nod(OAS, nod(OIND, neq, N), nodbool(1))); + break; + } + + if(debug['r']) + dumplist("geneq body", fn->nbody); + + funcbody(fn); + curfn = fn; + fn->dupok = 1; + typecheck(&fn, Etop); + typechecklist(fn->nbody, Etop); + curfn = nil; + + // Disable safemode while compiling this code: the code we + // generate internally can refer to unsafe.Pointer. + // In this case it can happen if we need to generate an == + // for a struct containing a reflect.Value, which itself has + // an unexported field of type unsafe.Pointer. + old_safemode = safemode; + safemode = 0; + funccompile(fn, 0); + safemode = old_safemode; +} + static Type* ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase) { @@ -3331,9 +3019,9 @@ implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr) return 1; } - t = methtype(t); + t = methtype(t, 0); if(t != T) - expandmeth(t->sym, t); + expandmeth(t); for(im=iface->type; im; im=im->down) { imtype = methodfunc(im->type, 0); tm = ifacelookdot(im->sym, t, &followptr, 0); @@ -3410,8 +3098,13 @@ list1(Node *n) if(n == nil) return nil; - if(n->op == OBLOCK && n->ninit == nil) - return n->list; + if(n->op == OBLOCK && n->ninit == nil) { + // Flatten list and steal storage. + // Poison pointer to catch errant uses. + l = n->list; + n->list = (NodeList*)1; + return l; + } l = mal(sizeof *l); l->n = n; l->end = l; @@ -3453,7 +3146,7 @@ listsort(NodeList** l, int(*f)(Node*, Node*)) listsort(&l1, f); listsort(&l2, f); - if ((*f)(l1->n, l2->n) < 0) { + if((*f)(l1->n, l2->n) < 0) { *l = l1; } else { *l = l2; @@ -3469,7 +3162,7 @@ listsort(NodeList** l, int(*f)(Node*, Node*)) // l1 is last one from l1 that is < l2 le = l1->next; // le is the rest of l1, first one that is >= l2 - if (le != nil) + if(le != nil) le->end = (*l)->end; (*l)->end = l1; // cut *l at l1 @@ -3814,21 +3507,31 @@ ngotype(Node *n) } /* - * Convert raw string to the prefix that will be used in the symbol table. - * Invalid bytes turn into %xx. Right now the only bytes that need - * escaping are %, ., and ", but we escape all control characters too. + * Convert raw string to the prefix that will be used in the symbol + * table. All control characters, space, '%' and '"', as well as + * non-7-bit clean bytes turn into %xx. The period needs escaping + * only in the last segment of the path, and it makes for happier + * users if we escape that as little as possible. + * + * If you edit this, edit ../ld/lib.c:/^pathtoprefix copy too. */ static char* pathtoprefix(char *s) { static char hex[] = "0123456789abcdef"; - char *p, *r, *w; + char *p, *r, *w, *l; int n; + // find first character past the last slash, if any. + l = s; + for(r=s; *r; r++) + if(*r == '/') + l = r+1; + // check for chars that need escaping n = 0; for(r=s; *r; r++) - if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') + if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) n++; // quick exit @@ -3838,7 +3541,7 @@ pathtoprefix(char *s) // escape p = mal((r-s)+1+2*n); for(r=s, w=p; *r; r++) { - if(*r <= ' ' || *r == '.' || *r == '%' || *r == '"') { + if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) { *w++ = '%'; *w++ = hex[(*r>>4)&0xF]; *w++ = hex[*r&0xF]; @@ -3854,11 +3557,9 @@ mkpkg(Strlit *path) { Pkg *p; int h; - - if(strlen(path->s) != path->len) { - yyerror("import path contains NUL byte"); + + if(isbadimport(path)) errorexit(); - } h = stringhash(path->s) & (nelem(phash)-1); for(p=phash[h]; p; p=p->link) @@ -3883,3 +3584,65 @@ strlit(char *s) t->len = strlen(s); return t; } + +void +addinit(Node **np, NodeList *init) +{ + Node *n; + + if(init == nil) + return; + + n = *np; + switch(n->op) { + case ONAME: + case OLITERAL: + // There may be multiple refs to this node; + // introduce OCONVNOP to hold init list. + n = nod(OCONVNOP, n, N); + n->type = n->left->type; + n->typecheck = 1; + *np = n; + break; + } + n->ninit = concat(init, n->ninit); + n->ullman = UINF; +} + +int +isbadimport(Strlit *path) +{ + char *s; + Rune r; + + if(strlen(path->s) != path->len) { + yyerror("import path contains NUL"); + return 1; + } + + s = path->s; + while(*s) { + s += chartorune(&r, s); + if(r == Runeerror) { + yyerror("import path contains invalid UTF-8 sequence: \"%Z\"", path); + return 1; + } + if(r < 0x20 || r == 0x7f) { + yyerror("import path contains control character: \"%Z\"", path); + return 1; + } + if(r == '\\') { + yyerror("import path contains backslash; use slash: \"%Z\"", path); + return 1; + } + if(isspacerune(r)) { + yyerror("import path contains space character: \"%Z\"", path); + return 1; + } + if(utfrune("!\"#$%&'()*,:;<=>?[]^`{|}", r)) { + yyerror("import path contains invalid character '%C': \"%Z\"", r, path); + return 1; + } + } + return 0; +} diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c index c2968c44b..f1a95587f 100644 --- a/src/cmd/gc/swt.c +++ b/src/cmd/gc/swt.c @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" enum @@ -130,6 +132,7 @@ exprcmp(Case *c1, Case *c2) n = mpcmpfltflt(n1->val.u.fval, n2->val.u.fval); break; case CTINT: + case CTRUNE: n = mpcmpfixfix(n1->val.u.xval, n2->val.u.xval); break; case CTSTR: @@ -378,6 +381,7 @@ mkcaselist(Node *sw, int arg) switch(consttype(n->left)) { case CTFLT: case CTINT: + case CTRUNE: case CTSTR: c->type = Texprconst; } @@ -513,8 +517,7 @@ exprswitch(Node *sw) exprname = N; cas = nil; if(arg != Strue && arg != Sfalse) { - exprname = nod(OXXX, N, N); - tempname(exprname, sw->ntest->type); + exprname = temp(sw->ntest->type); cas = list1(nod(OAS, exprname, sw->ntest)); typechecklist(cas, Etop); } @@ -537,7 +540,7 @@ loop: } // deal with the variables one-at-a-time - if(c0->type != Texprconst) { + if(!okforcmp[t->etype] || c0->type != Texprconst) { a = exprbsw(c0, 1, arg); cas = list(cas, a); c0 = c0->link; @@ -671,20 +674,17 @@ typeswitch(Node *sw) * predeclare temporary variables * and the boolean var */ - facename = nod(OXXX, N, N); - tempname(facename, sw->ntest->right->type); + facename = temp(sw->ntest->right->type); a = nod(OAS, facename, sw->ntest->right); typecheck(&a, Etop); cas = list(cas, a); casebody(sw, facename); - boolname = nod(OXXX, N, N); - tempname(boolname, types[TBOOL]); + boolname = temp(types[TBOOL]); typecheck(&boolname, Erv); - hashname = nod(OXXX, N, N); - tempname(hashname, types[TUINT32]); + hashname = temp(types[TUINT32]); typecheck(&hashname, Erv); t = sw->ntest->right->type; @@ -792,7 +792,6 @@ walkswitch(Node *sw) * cases have OGOTO into statements. * both have inserted OBREAK statements */ - walkstmtlist(sw->ninit); if(sw->ntest == N) { sw->ntest = nodbool(1); typecheck(&sw->ntest, Erv); @@ -812,14 +811,16 @@ walkswitch(Node *sw) void typecheckswitch(Node *n) { - int top, lno; - Type *t; + int top, lno, ptr; + char *nilonly; + Type *t, *missing, *have; NodeList *l, *ll; Node *ncase, *nvar; Node *def; lno = lineno; typechecklist(n->ninit, Etop); + nilonly = nil; if(n->ntest != N && n->ntest->op == OTYPESW) { // type switch @@ -827,7 +828,7 @@ typecheckswitch(Node *n) typecheck(&n->ntest->right, Erv); t = n->ntest->right->type; if(t != T && t->etype != TINTER) - yyerror("cannot type switch on non-interface value %+N", n->ntest->right); + yyerror("cannot type switch on non-interface value %lN", n->ntest->right); } else { // value switch top = Erv; @@ -837,6 +838,16 @@ typecheckswitch(Node *n) t = n->ntest->type; } else t = types[TBOOL]; + if(t) { + if(!okforeq[t->etype] || isfixedarray(t)) + yyerror("cannot switch on %lN", n->ntest); + else if(t->etype == TARRAY) + nilonly = "slice"; + else if(t->etype == TFUNC) + nilonly = "func"; + else if(t->etype == TMAP) + nilonly = "map"; + } } n->type = t; @@ -856,21 +867,37 @@ typecheckswitch(Node *n) typecheck(&ll->n, Erv | Etype); if(ll->n->type == T || t == T) continue; + setlineno(ncase); switch(top) { case Erv: // expression switch defaultlit(&ll->n, t); if(ll->n->op == OTYPE) yyerror("type %T is not an expression", ll->n->type); - else if(ll->n->type != T && !eqtype(ll->n->type, t)) - yyerror("case %+N in %T switch", ll->n, t); + else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) { + if(n->ntest) + yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t); + else + yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type); + } else if(nilonly && !isconst(ll->n, CTNIL)) { + yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest); + } break; case Etype: // type switch - if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) + if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) { ; - else if(ll->n->op != OTYPE && ll->n->type != T) { - yyerror("%#N is not a type", ll->n); + } else if(ll->n->op != OTYPE && ll->n->type != T) { // should this be ||? + yyerror("%lN is not a type", ll->n); // reset to original type ll->n = n->ntest->right; + } else if(ll->n->type->etype != TINTER && !implements(ll->n->type, t, &missing, &have, &ptr)) { + if(have && !missing->broke && !have->broke) + yyerror("impossible type switch case: %lN cannot have dynamic type %T" + " (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT", + n->ntest->right, ll->n->type, missing->sym, have->sym, have->type, + missing->sym, missing->type); + else if(!missing->broke) + yyerror("impossible type switch case: %lN cannot have dynamic type %T" + " (missing %S method)", n->ntest->right, ll->n->type, missing->sym); } break; } diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 78cdb5bf2..e98d53857 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -10,6 +10,8 @@ * rewrites n->op to be more specific in some cases. */ +#include <u.h> +#include <libc.h> #include "go.h" static void implicitstar(Node**); @@ -18,10 +20,9 @@ static int twoarg(Node*); static int lookdot(Node*, Type*, int); static int looktypedot(Node*, Type*, int); static void typecheckaste(int, Node*, int, Type*, NodeList*, char*); -static Type* lookdot1(Sym *s, Type *t, Type *f, int); +static Type* lookdot1(Node*, Sym *s, Type *t, Type *f, int); static int nokeys(NodeList*); static void typecheckcomplit(Node**); -static void addrescapes(Node*); static void typecheckas2(Node*); static void typecheckas(Node*); static void typecheckfunc(Node*); @@ -37,12 +38,12 @@ static NodeList* typecheckdefstack; /* * resolve ONONAME to definition, if any. */ -Node* +static Node* resolve(Node *n) { Node *r; - if(n != N && n->op == ONONAME && (r = n->sym->def) != N) { + if(n != N && n->op == ONONAME && n->sym != S && (r = n->sym->def) != N) { if(r->op != OIOTA) n = r; else if(n->iota >= 0) @@ -78,6 +79,7 @@ static char* _typekind[] = { [TSTRING] = "string", [TPTR32] = "pointer", [TPTR64] = "pointer", + [TUNSAFEPTR] = "unsafe.Pointer", [TSTRUCT] = "struct", [TINTER] = "interface", [TCHAN] = "chan", @@ -89,11 +91,15 @@ static char* _typekind[] = { }; static char* -typekind(int et) +typekind(Type *t) { + int et; static char buf[50]; char *s; + if(isslice(t)) + return "slice"; + et = t->etype; if(0 <= et && et < nelem(_typekind) && (s=_typekind[et]) != nil) return s; snprint(buf, sizeof buf, "etype=%d", et); @@ -105,17 +111,15 @@ typekind(int et) * replaces *np with a new pointer in some cases. * returns the final value of *np as a convenience. */ +static void typecheck1(Node **, int); Node* typecheck(Node **np, int top) { - int et, aop, op, ptr; - Node *n, *l, *r; - NodeList *args; - int lno, ok, ntop; - Type *t, *tp, *ft, *missing, *have; - Sym *sym; - Val v; - char *why; + Node *n; + int lno; + Fmt fmt; + NodeList *l; + static NodeList *tcstack, *tcfree; // cannot type check until all the source has been parsed if(!typecheckok) @@ -152,11 +156,92 @@ typecheck(Node **np, int top) } if(n->typecheck == 2) { - yyerror("typechecking loop"); + if(nsavederrors+nerrors == 0) { + fmtstrinit(&fmt); + for(l=tcstack; l; l=l->next) + fmtprint(&fmt, "\n\t%L %N", l->n->lineno, l->n); + yyerror("typechecking loop involving %N%s", n, fmtstrflush(&fmt)); + } lineno = lno; return n; } n->typecheck = 2; + + if(tcfree != nil) { + l = tcfree; + tcfree = l->next; + } else + l = mal(sizeof *l); + l->next = tcstack; + l->n = n; + tcstack = l; + + typecheck1(&n, top); + *np = n; + n->typecheck = 1; + + if(tcstack != l) + fatal("typecheck stack out of sync"); + tcstack = l->next; + l->next = tcfree; + tcfree = l; + + lineno = lno; + return n; +} + +/* + * does n contain a call or receive operation? + */ +static int callrecvlist(NodeList*); + +static int +callrecv(Node *n) +{ + if(n == nil) + return 0; + + switch(n->op) { + case OCALL: + case OCALLMETH: + case OCALLINTER: + case OCALLFUNC: + case ORECV: + return 1; + } + + return callrecv(n->left) || + callrecv(n->right) || + callrecv(n->ntest) || + callrecv(n->nincr) || + callrecvlist(n->ninit) || + callrecvlist(n->nbody) || + callrecvlist(n->nelse) || + callrecvlist(n->list) || + callrecvlist(n->rlist); +} + +static int +callrecvlist(NodeList *l) +{ + for(; l; l=l->next) + if(callrecv(l->n)) + return 1; + return 0; +} + +static void +typecheck1(Node **np, int top) +{ + int et, aop, op, ptr; + Node *n, *l, *r; + NodeList *args; + int ok, ntop; + Type *t, *tp, *ft, *missing, *have, *badtype; + Val v; + char *why; + + n = *np; if(n->sym) { if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) { @@ -209,6 +294,10 @@ reswitch: } n->used = 1; } + if(!(top &Ecall) && isunsafebuiltin(n)) { + yyerror("%N is not an expression, must be called", n); + goto error; + } ok |= Erv; goto ret; @@ -253,13 +342,14 @@ reswitch: l = typecheck(&n->left, Erv); switch(consttype(l)) { case CTINT: + case CTRUNE: v = l->val; break; case CTFLT: v = toint(l->val); break; default: - yyerror("invalid array bound %#N", l); + yyerror("invalid array bound %N", l); goto error; } t->bound = mpgetfix(v.u.xval); @@ -310,7 +400,7 @@ reswitch: case OTSTRUCT: ok |= Etype; n->op = OTYPE; - n->type = dostruct(n->list, TSTRUCT); + n->type = tostruct(n->list); if(n->type == T) goto error; n->list = nil; @@ -319,7 +409,7 @@ reswitch: case OTINTER: ok |= Etype; n->op = OTYPE; - n->type = dostruct(n->list, TINTER); + n->type = tointerface(n->list); if(n->type == T) goto error; break; @@ -337,8 +427,9 @@ reswitch: */ case OIND: ntop = Erv | Etype; - if(!(top & Eaddr)) + 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; @@ -350,7 +441,7 @@ reswitch: goto ret; } if(!isptr[t->etype]) { - yyerror("invalid indirect of %+N", n->left); + yyerror("invalid indirect of %lN", n->left); goto error; } ok |= Erv; @@ -413,15 +504,25 @@ reswitch: if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) { // comparison is okay as long as one side is // assignable to the other. convert so they have - // the same type. (the only conversion that isn't - // a no-op is concrete == interface.) + // the same type. + // + // the only conversion that isn't a no-op is concrete == interface. + // in that case, check comparability of the concrete type. if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) { + if(isinter(r->type) && !isinter(l->type) && algtype1(l->type, nil) == ANOEQ) { + yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(l->type)); + goto error; + } l = nod(aop, l, N); l->type = r->type; l->typecheck = 1; n->left = l; t = l->type; } else if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) { + if(isinter(l->type) && !isinter(r->type) && algtype1(r->type, nil) == ANOEQ) { + yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(r->type)); + goto error; + } r = nod(aop, r, N); r->type = l->type; r->typecheck = 1; @@ -432,28 +533,40 @@ reswitch: } if(t->etype != TIDEAL && !eqtype(l->type, r->type)) { defaultlit2(&l, &r, 1); - yyerror("invalid operation: %#N (mismatched types %T and %T)", n, l->type, r->type); + yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type); goto error; } if(!okfor[op][et]) { - notokfor: - yyerror("invalid operation: %#N (operator %#O not defined on %s)", n, op, typekind(et)); + yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(t)); + goto error; + } + // okfor allows any array == array, map == map, func == func. + // restrict to slice/map/func == nil and nil == slice/map/func. + if(isfixedarray(l->type) && algtype1(l->type, nil) == ANOEQ) { + yyerror("invalid operation: %N (%T cannot be compared)", n, l->type); goto error; } - // okfor allows any array == array; - // restrict to slice == nil and nil == slice. - if(l->type->etype == TARRAY && !isslice(l->type)) - goto notokfor; - if(r->type->etype == TARRAY && !isslice(r->type)) - goto notokfor; if(isslice(l->type) && !isnil(l) && !isnil(r)) { - yyerror("invalid operation: %#N (slice can only be compared to nil)", n); + yyerror("invalid operation: %N (slice can only be compared to nil)", n); goto error; } + if(l->type->etype == TMAP && !isnil(l) && !isnil(r)) { + yyerror("invalid operation: %N (map can only be compared to nil)", n); + goto error; + } + if(l->type->etype == TFUNC && !isnil(l) && !isnil(r)) { + yyerror("invalid operation: %N (func can only be compared to nil)", n); + goto error; + } + if(l->type->etype == TSTRUCT && algtype1(l->type, &badtype) == ANOEQ) { + yyerror("invalid operation: %N (struct containing %T cannot be compared)", n, badtype); + goto error; + } + t = l->type; if(iscmp[n->op]) { evconst(n); - t = types[TBOOL]; + t = idealbool; if(n->op != OLITERAL) { defaultlit2(&l, &r, 1); n->left = l; @@ -487,12 +600,12 @@ reswitch: n->right = r; t = r->type; if(!isint[t->etype] || issigned[t->etype]) { - yyerror("invalid operation: %#N (shift count type %T, must be unsigned integer)", n, r->type); + yyerror("invalid operation: %N (shift count type %T, must be unsigned integer)", n, r->type); goto error; } t = l->type; if(t != T && t->etype != TIDEAL && !isint[t->etype]) { - yyerror("invalid operation: %#N (shift of type %T)", n, t); + yyerror("invalid operation: %N (shift of type %T)", n, t); goto error; } // no defaultlit for left @@ -509,7 +622,7 @@ reswitch: if((t = l->type) == T) goto error; if(!okfor[n->op][t->etype]) { - yyerror("invalid operation: %#O %T", n->op, t); + yyerror("invalid operation: %O %T", n->op, t); goto error; } n->type = t; @@ -523,19 +636,17 @@ reswitch: typecheck(&n->left, Erv | Eaddr); if(n->left->type == T) goto error; - switch(n->left->op) { - case OMAPLIT: - case OSTRUCTLIT: - case OARRAYLIT: - 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; defaultlit(&n->left, T); l = n->left; if((t = l->type) == T) goto error; - if(!(top & Eindir) && !n->etype) + // 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['N'] && !(top & Eindir) && !n->etype) addrescapes(n->left); n->type = ptrto(t); goto ret; @@ -550,40 +661,40 @@ reswitch: case OXDOT: n = adddot(n); n->op = ODOT; + if(n->left == N) + goto error; // fall through case ODOT: typecheck(&n->left, Erv|Etype); defaultlit(&n->left, T); - l = n->left; - if((t = l->type) == T) + if((t = n->left->type) == T) goto error; if(n->right->op != ONAME) { yyerror("rhs of . must be a name"); // impossible goto error; } - sym = n->right->sym; - if(l->op == OTYPE) { + + if(n->left->op == OTYPE) { if(!looktypedot(n, t, 0)) { if(looktypedot(n, t, 1)) - yyerror("%#N undefined (cannot refer to unexported method %S)", n, n->right->sym); + yyerror("%N undefined (cannot refer to unexported method %S)", n, n->right->sym); else - yyerror("%#N undefined (type %T has no method %S)", n, t, n->right->sym); + yyerror("%N undefined (type %T has no method %S)", n, t, n->right->sym); goto error; } if(n->type->etype != TFUNC || n->type->thistuple != 1) { - yyerror("type %T has no method %hS", n->left->type, sym); + yyerror("type %T has no method %hS", n->left->type, n->right->sym); n->type = T; goto error; } n->op = ONAME; - n->sym = methodsym(sym, l->type, 0); - n->type = methodfunc(n->type, l->type); + n->sym = n->right->sym; + n->type = methodfunc(n->type, n->left->type); n->xoffset = 0; n->class = PFUNC; ok = Erv; goto ret; } - tp = t; if(isptr[t->etype] && t->type->etype != TINTER) { t = t->type; if(t == T) @@ -593,9 +704,9 @@ reswitch: } if(!lookdot(n, t, 0)) { if(lookdot(n, t, 1)) - yyerror("%#N undefined (cannot refer to unexported field or method %S)", n, n->right->sym); + yyerror("%N undefined (cannot refer to unexported field or method %S)", n, n->right->sym); else - yyerror("%#N undefined (type %T has no field or method %S)", n, tp, n->right->sym); + yyerror("%N undefined (type %T has no field or method %S)", n, n->left->type, n->right->sym); goto error; } switch(n->op) { @@ -617,7 +728,7 @@ reswitch: if((t = l->type) == T) goto error; if(!isinter(t)) { - yyerror("invalid type assertion: %#N (non-interface type %T on left)", n, t); + yyerror("invalid type assertion: %N (non-interface type %T on left)", n, t); goto error; } if(n->right != N) { @@ -630,12 +741,12 @@ reswitch: if(n->type != T && n->type->etype != TINTER) if(!implements(n->type, t, &missing, &have, &ptr)) { if(have) - yyerror("impossible type assertion: %+N cannot have dynamic type %T" - " (wrong type for %S method)\n\thave %S%hhT\n\twant %S%hhT", + yyerror("impossible type assertion: %lN cannot have dynamic type %T" + " (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT", l, n->type, missing->sym, have->sym, have->type, missing->sym, missing->type); else - yyerror("impossible type assertion: %+N cannot have dynamic type %T" + yyerror("impossible type assertion: %lN cannot have dynamic type %T" " (missing %S method)", l, n->type, missing->sym); goto error; } @@ -653,13 +764,13 @@ reswitch: goto error; switch(t->etype) { default: - yyerror("invalid operation: %#N (index of type %T)", n, t); + yyerror("invalid operation: %N (index of type %T)", n, t); goto error; case TARRAY: defaultlit(&n->right, T); if(n->right->type != T && !isint[n->right->type->etype]) - yyerror("non-integer array index %#N", n->right); + yyerror("non-integer array index %N", n->right); n->type = t->type; break; @@ -675,7 +786,7 @@ reswitch: case TSTRING: defaultlit(&n->right, types[TUINT]); if(n->right->type != T && !isint[n->right->type->etype]) - yyerror("non-integer string index %#N", n->right); + yyerror("non-integer string index %N", n->right); n->type = types[TUINT8]; break; } @@ -689,11 +800,11 @@ reswitch: if((t = l->type) == T) goto error; if(t->etype != TCHAN) { - yyerror("invalid operation: %#N (receive from non-chan type %T)", n, t); + yyerror("invalid operation: %N (receive from non-chan type %T)", n, t); goto error; } if(!(t->chan & Crecv)) { - yyerror("invalid operation: %#N (receive from send-only type %T)", n, t); + yyerror("invalid operation: %N (receive from send-only type %T)", n, t); goto error; } n->type = t->type; @@ -701,7 +812,7 @@ reswitch: case OSEND: if(top & Erv) { - yyerror("send statement %#N used as value; use select for non-blocking send", n); + yyerror("send statement %N used as value; use select for non-blocking send", n); goto error; } ok |= Etop | Erv; @@ -712,16 +823,16 @@ reswitch: if((t = l->type) == T) goto error; if(t->etype != TCHAN) { - yyerror("invalid operation: %#N (send to non-chan type %T)", n, t); + yyerror("invalid operation: %N (send to non-chan type %T)", n, t); goto error; } if(!(t->chan & Csend)) { - yyerror("invalid operation: %#N (send to receive-only type %T)", n, t); + yyerror("invalid operation: %N (send to receive-only type %T)", n, t); goto error; } defaultlit(&n->right, t->type); r = n->right; - if((t = r->type) == T) + if(r->type == T) goto error; r = assignconv(r, l->type->type, "send"); // TODO: more aggressive @@ -738,14 +849,19 @@ reswitch: defaultlit(&n->right->left, T); defaultlit(&n->right->right, T); if(isfixedarray(n->left->type)) { + if(!islvalue(n->left)) { + yyerror("invalid operation %N (slice of unaddressable value)", n); + goto error; + } n->left = nod(OADDR, n->left, N); - typecheck(&n->left, top); + n->left->implicit = 1; + typecheck(&n->left, Erv); } if(n->right->left != N) { if((t = n->right->left->type) == T) goto error; if(!isint[t->etype]) { - yyerror("invalid slice index %#N (type %T)", n->right->left, t); + yyerror("invalid slice index %N (type %T)", n->right->left, t); goto error; } } @@ -753,7 +869,7 @@ reswitch: if((t = n->right->right->type) == T) goto error; if(!isint[t->etype]) { - yyerror("invalid slice index %#N (type %T)", n->right->right, t); + yyerror("invalid slice index %N (type %T)", n->right->right, t); goto error; } } @@ -777,7 +893,7 @@ reswitch: n->type = t; goto ret; } - yyerror("cannot slice %#N (type %T)", l, t); + yyerror("cannot slice %N (type %T)", l, t); goto error; /* @@ -787,7 +903,7 @@ reswitch: l = n->left; if(l->op == ONAME && (r = unsafenmagic(n)) != N) { if(n->isddd) - yyerror("invalid use of ... with builtin %#N", l); + yyerror("invalid use of ... with builtin %N", l); n = r; goto reswitch; } @@ -795,7 +911,7 @@ reswitch: l = n->left; if(l->op == ONAME && l->etype != 0) { if(n->isddd && l->etype != OAPPEND) - yyerror("invalid use of ... with builtin %#N", l); + yyerror("invalid use of ... with builtin %N", l); // builtin: OLEN, OCAP, etc. n->op = l->etype; n->left = n->right; @@ -845,7 +961,7 @@ reswitch: default: n->op = OCALLFUNC; if(t->etype != TFUNC) { - yyerror("cannot call non-function %#N (type %T)", l, t); + yyerror("cannot call non-function %N (type %T)", l, t); goto error; } break; @@ -866,7 +982,7 @@ reswitch: } // multiple return if(!(top & (Efnstruct | Etop))) { - yyerror("multiple-value %#N() in single-value context", l); + yyerror("multiple-value %N() in single-value context", l); goto ret; } n->type = getoutargx(l->type); @@ -877,7 +993,7 @@ reswitch: case OREAL: case OIMAG: ok |= Erv; - if(onearg(n, "%#O", n->op) < 0) + if(onearg(n, "%O", n->op) < 0) goto error; typecheck(&n->left, Erv); defaultlit(&n->left, T); @@ -919,12 +1035,14 @@ reswitch: } break; case TARRAY: - if(t->bound >= 0 && l->op == ONAME) { - r = nod(OXXX, N, N); - nodconst(r, types[TINT], t->bound); - r->orig = n; - n = r; - } + if(t->bound < 0) // slice + break; + if(callrecv(l)) // has call or receive + break; + r = nod(OXXX, N, N); + nodconst(r, types[TINT], t->bound); + r->orig = n; + n = r; break; } n->type = types[TINT]; @@ -943,7 +1061,7 @@ reswitch: n->right = r; if(l->type->etype != r->type->etype) { badcmplx: - yyerror("invalid operation: %#N (complex of types %T, %T)", n, l->type, r->type); + yyerror("invalid operation: %N (complex of types %T, %T)", n, l->type, r->type); goto error; } switch(l->type->etype) { @@ -967,7 +1085,7 @@ reswitch: goto ret; case OCLOSE: - if(onearg(n, "%#O", n->op) < 0) + if(onearg(n, "%O", n->op) < 0) goto error; typecheck(&n->left, Erv); defaultlit(&n->left, T); @@ -975,12 +1093,41 @@ reswitch: if((t = l->type) == T) goto error; if(t->etype != TCHAN) { - yyerror("invalid operation: %#N (non-chan type %T)", n, t); + yyerror("invalid operation: %N (non-chan type %T)", n, t); + goto error; + } + if(!(t->chan & Csend)) { + yyerror("invalid operation: %N (cannot close receive-only channel)", n); goto error; } ok |= Etop; goto ret; + case ODELETE: + args = n->list; + if(args == nil) { + yyerror("missing arguments to delete"); + goto error; + } + if(args->next == nil) { + yyerror("missing second (key) argument to delete"); + goto error; + } + if(args->next->next != nil) { + yyerror("too many arguments to delete"); + goto error; + } + ok |= Etop; + typechecklist(args, Erv); + l = args->n; + r = args->next->n; + if(l->type != T && l->type->etype != TMAP) { + yyerror("first argument to delete must be map; have %lT", l->type); + goto error; + } + args->next->n = assignconv(r, l->type->down, "delete"); + goto ret; + case OAPPEND: ok |= Erv; args = n->list; @@ -996,6 +1143,7 @@ reswitch: yyerror("first argument to append must be slice; have %lT", t); goto error; } + if(n->isddd) { if(args->next == nil) { yyerror("cannot use ... on first argument to append"); @@ -1005,6 +1153,10 @@ reswitch: yyerror("too many arguments to append"); goto error; } + if(istype(t->type, TUINT8) && istype(args->next->n->type, TSTRING)) { + defaultlit(&args->next->n, types[TSTRING]); + goto ret; + } args->next->n = assignconv(args->next->n, t->orig, "append"); goto ret; } @@ -1028,6 +1180,7 @@ reswitch: } n->left = args->n; n->right = args->next->n; + n->list = nil; n->type = types[TINT]; typecheck(&n->left, Erv); typecheck(&n->right, Erv); @@ -1035,15 +1188,15 @@ reswitch: goto error; defaultlit(&n->left, T); defaultlit(&n->right, T); - + // copy([]byte, string) if(isslice(n->left->type) && n->right->type->etype == TSTRING) { - if (n->left->type->type == types[TUINT8]) + if(eqtype(n->left->type->type, bytetype)) goto ret; yyerror("arguments to copy have different element types: %lT and string", n->left->type); goto error; } - + if(!isslice(n->left->type) || !isslice(n->right->type)) { if(!isslice(n->left->type) && !isslice(n->right->type)) yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type); @@ -1067,8 +1220,8 @@ reswitch: if((t = n->left->type) == T || n->type == T) goto error; if((n->op = convertop(t, n->type, &why)) == 0) { - yyerror("cannot convert %+N to type %T%s", n->left, n->type, why); - op = OCONV; + yyerror("cannot convert %lN to type %T%s", n->left, n->type, why); + n->op = OCONV; } switch(n->op) { case OCONVNOP: @@ -1092,6 +1245,7 @@ reswitch: yyerror("missing argument to make"); goto error; } + n->list = nil; l = args->n; args = args->next; typecheck(&l, Etype); @@ -1205,6 +1359,13 @@ reswitch: case OPRINTN: ok |= Etop; typechecklist(n->list, Erv | Eindir); // Eindir: address does not escape + for(args=n->list; args; args=args->next) { + // Special case for print: int constant is int64, not int. + if(isconst(args->n, CTINT)) + defaultlit(&args->n, types[TINT64]); + else + defaultlit(&args->n, T); + } goto ret; case OPANIC: @@ -1232,6 +1393,16 @@ reswitch: if(n->type == T) goto error; goto ret; + + case OITAB: + ok |= Erv; + typecheck(&n->left, Erv); + if((t = n->left->type) == T) + goto error; + if(t->etype != TINTER) + fatal("OITAB of %T", t); + n->type = ptrto(types[TUINTPTR]); + goto ret; /* * statements @@ -1271,7 +1442,7 @@ reswitch: typechecklist(n->ninit, Etop); typecheck(&n->ntest, Erv); if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL) - yyerror("non-bool %+N used as for condition", n->ntest); + yyerror("non-bool %lN used as for condition", n->ntest); typecheck(&n->nincr, Etop); typechecklist(n->nbody, Etop); goto ret; @@ -1281,14 +1452,17 @@ reswitch: typechecklist(n->ninit, Etop); typecheck(&n->ntest, Erv); if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL) - yyerror("non-bool %+N used as if condition", n->ntest); + yyerror("non-bool %lN used as if condition", n->ntest); typechecklist(n->nbody, Etop); typechecklist(n->nelse, Etop); goto ret; case ORETURN: ok |= Etop; - typechecklist(n->list, Erv | Efnstruct); + if(count(n->list) == 1) + typechecklist(n->list, Erv | Efnstruct); + else + typechecklist(n->list, Erv); if(curfn == N) { yyerror("return outside function"); goto error; @@ -1368,21 +1542,21 @@ ret: goto error; } if((top & (Erv|Etype)) == Etype && n->op != OTYPE) { - yyerror("%#N is not a type", n); + yyerror("%N is not a type", n); goto error; } if((ok & Ecall) && !(top & Ecall)) { - yyerror("method %#N is not an expression, must be called", n); + yyerror("method %N is not an expression, must be called", n); goto error; } // TODO(rsc): simplify if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) { - yyerror("%#N used as value", n); + yyerror("%N used as value", n); goto error; } if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) { if(n->diag == 0) { - yyerror("%#N not used", n); + yyerror("%N not used", n); n->diag = 1; } goto error; @@ -1395,17 +1569,14 @@ ret: goto out; badcall1: - yyerror("invalid argument %#N (type %T) for %#O", n->left, n->left->type, n->op); + yyerror("invalid argument %lN for %O", n->left, n->op); goto error; error: n->type = T; out: - lineno = lno; - n->typecheck = 1; *np = n; - return n; } static void @@ -1425,6 +1596,7 @@ implicitstar(Node **nn) if(!isfixedarray(t)) return; n = nod(OIND, n, N); + n->implicit = 1; typecheck(&n, Erv); *nn = n; } @@ -1441,14 +1613,14 @@ onearg(Node *n, char *f, ...) va_start(arg, f); p = vsmprint(f, arg); va_end(arg); - yyerror("missing argument to %s: %#N", p, n); + yyerror("missing argument to %s: %N", p, n); return -1; } if(n->list->next != nil) { va_start(arg, f); p = vsmprint(f, arg); va_end(arg); - yyerror("too many arguments to %s: %#N", p, n); + yyerror("too many arguments to %s: %N", p, n); n->left = n->list->n; n->list = nil; return -1; @@ -1464,17 +1636,17 @@ twoarg(Node *n) if(n->left != N) return 0; if(n->list == nil) { - yyerror("missing argument to %#O - %#N", n->op, n); + yyerror("missing argument to %O - %N", n->op, n); return -1; } n->left = n->list->n; if(n->list->next == nil) { - yyerror("missing argument to %#O - %#N", n->op, n); + yyerror("missing argument to %O - %N", n->op, n); n->list = nil; return -1; } if(n->list->next->next != nil) { - yyerror("too many arguments to %#O - %#N", n->op, n); + yyerror("too many arguments to %O - %N", n->op, n); n->list = nil; return -1; } @@ -1484,7 +1656,7 @@ twoarg(Node *n) } static Type* -lookdot1(Sym *s, Type *t, Type *f, int dostrcmp) +lookdot1(Node *errnode, Sym *s, Type *t, Type *f, int dostrcmp) { Type *r; @@ -1495,7 +1667,12 @@ lookdot1(Sym *s, Type *t, Type *f, int dostrcmp) if(f->sym != s) continue; if(r != T) { - yyerror("ambiguous DOT reference %T.%S", t, s); + if(errnode) + yyerror("ambiguous selector %N", errnode); + else if(isptr[t->etype]) + yyerror("ambiguous selector (%T).%S", t, s); + else + yyerror("ambiguous selector %T.%S", t, s); break; } r = f; @@ -1512,7 +1689,7 @@ looktypedot(Node *n, Type *t, int dostrcmp) s = n->right->sym; if(t->etype == TINTER) { - f1 = lookdot1(s, t, t->type, dostrcmp); + f1 = lookdot1(n, s, t, t->type, dostrcmp); if(f1 == T) return 0; @@ -1529,12 +1706,12 @@ looktypedot(Node *n, Type *t, int dostrcmp) if(t->sym == S && isptr[t->etype]) tt = t->type; - f2 = methtype(tt); + f2 = methtype(tt, 0); if(f2 == T) return 0; - expandmeth(f2->sym, f2); - f2 = lookdot1(s, f2, f2->xmethod, dostrcmp); + expandmeth(f2); + f2 = lookdot1(n, s, f2, f2->xmethod, dostrcmp); if(f2 == T) return 0; @@ -1543,7 +1720,7 @@ looktypedot(Node *n, Type *t, int dostrcmp) && !isptr[t->etype] && f2->embedded != 2 && !isifacemethod(f2->type)) { - yyerror("invalid method expression %#N (needs pointer receiver: (*%T).%s)", n, t, f2->sym->name); + yyerror("invalid method expression %N (needs pointer receiver: (*%T).%hS)", n, t, f2->sym); return 0; } @@ -1554,6 +1731,14 @@ looktypedot(Node *n, Type *t, int dostrcmp) return 1; } +static Type* +derefall(Type* t) +{ + while(t && t->etype == tptr) + t = t->type; + return t; +} + static int lookdot(Node *n, Type *t, int dostrcmp) { @@ -1565,21 +1750,21 @@ lookdot(Node *n, Type *t, int dostrcmp) dowidth(t); f1 = T; if(t->etype == TSTRUCT || t->etype == TINTER) - f1 = lookdot1(s, t, t->type, dostrcmp); + f1 = lookdot1(n, s, t, t->type, dostrcmp); f2 = T; if(n->left->type == t || n->left->type->sym == S) { - f2 = methtype(t); + f2 = methtype(t, 0); if(f2 != T) { // Use f2->method, not f2->xmethod: adddot has // already inserted all the necessary embedded dots. - f2 = lookdot1(s, f2, f2->method, dostrcmp); + f2 = lookdot1(n, s, f2, f2->method, dostrcmp); } } if(f1 != T) { if(f2 != T) - yyerror("ambiguous DOT reference %S as both field and method", + yyerror("%S is both field and method", n->right->sym); if(f1->width == BADWIDTH) fatal("lookdot badwidth %T %p", f1, f1); @@ -1588,6 +1773,7 @@ lookdot(Node *n, Type *t, int dostrcmp) if(t->etype == TINTER) { if(isptr[n->left->type->etype]) { n->left = nod(OIND, n->left, N); // implicitstar + n->left->implicit = 1; typecheck(&n->left, Erv); } n->op = ODOTINTER; @@ -1602,7 +1788,8 @@ 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"); - addrescapes(n->left); + if(debug['N']) + addrescapes(n->left); n->left = nod(OADDR, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); @@ -1610,14 +1797,22 @@ lookdot(Node *n, Type *t, int dostrcmp) n->left = nod(OIND, n->left, N); n->left->implicit = 1; typecheck(&n->left, Etype|Erv); + } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), rcvr)) { + yyerror("calling method %N with receiver %lN requires explicit dereference", n->right, n->left); + while(tt->etype == tptr) { + n->left = nod(OIND, n->left, N); + n->left->implicit = 1; + typecheck(&n->left, Etype|Erv); + tt = tt->type; + } } else { - // method is attached to wrong type? fatal("method mismatch: %T for %T", rcvr, tt); } } n->right = methodname(n->right, n->left->type); n->xoffset = f2->width; n->type = f2->type; +// print("lookdot found [%p] %T\n", f2->type, f2->type); n->op = ODOTMETH; return 1; } @@ -1656,22 +1851,20 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char * for(tl=tstruct->type; tl; tl=tl->down) { if(tl->isddd) { for(; tn; tn=tn->down) { - exportassignok(tn->type, desc); if(assignop(tn->type, tl->type->type, &why) == 0) { if(call != N) - yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type->type, call, why); + yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type, call, why); else - yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why); + yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why); } } goto out; } if(tn == T) goto notenough; - exportassignok(tn->type, desc); if(assignop(tn->type, tl->type, &why) == 0) { if(call != N) - yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type, call, why); + yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type, call, why); else yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why); } @@ -1716,9 +1909,9 @@ typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char * goto toomany; if(isddd) { if(call != N) - yyerror("invalid use of ... in call to %#N", call); + yyerror("invalid use of ... in call to %N", call); else - yyerror("invalid use of ... in %#O", op); + yyerror("invalid use of ... in %O", op); } out: @@ -1727,80 +1920,20 @@ out: notenough: if(call != N) - yyerror("not enough arguments in call to %#N", call); + yyerror("not enough arguments in call to %N", call); else - yyerror("not enough arguments to %#O", op); + yyerror("not enough arguments to %O", op); goto out; toomany: if(call != N) - yyerror("too many arguments in call to %#N", call); + yyerror("too many arguments in call to %N", call); else - yyerror("too many arguments to %#O", op); + yyerror("too many arguments to %O", op); goto out; } /* - * do the export rules allow writing to this type? - * cannot be implicitly assigning to any type with - * an unavailable field. - */ -int -exportassignok(Type *t, char *desc) -{ - Type *f; - Sym *s; - - if(t == T) - return 1; - if(t->trecur) - return 1; - t->trecur = 1; - - switch(t->etype) { - default: - // most types can't contain others; they're all fine. - break; - case TSTRUCT: - for(f=t->type; f; f=f->down) { - if(f->etype != TFIELD) - fatal("structas: not field"); - s = f->sym; - // s == nil doesn't happen for embedded fields (they get the type symbol). - // it only happens for fields in a ... struct. - if(s != nil && !exportname(s->name) && s->pkg != localpkg) { - char *prefix; - - prefix = ""; - if(desc != nil) - prefix = " in "; - else - desc = ""; - yyerror("implicit assignment of unexported field '%s' of %T%s%s", s->name, t, prefix, desc); - goto no; - } - if(!exportassignok(f->type, desc)) - goto no; - } - break; - - case TARRAY: - if(t->bound < 0) // slices are pointers; that's fine - break; - if(!exportassignok(t->type, desc)) - goto no; - break; - } - t->trecur = 0; - return 1; - -no: - t->trecur = 0; - return 0; -} - - -/* * type check composite */ @@ -1845,6 +1978,7 @@ keydup(Node *n, Node *hash[], ulong nhash) b = 23; break; case CTINT: + case CTRUNE: b = mpgetfix(n->val.u.xval); break; case CTFLT: @@ -1872,7 +2006,7 @@ keydup(Node *n, Node *hash[], ulong nhash) b = cmp.val.u.bval; if(b) { // too lazy to print the literal - yyerror("duplicate key in map literal"); + yyerror("duplicate key %N in map literal", n); return; } } @@ -1953,13 +2087,52 @@ 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->implicit = 1; // don't print + n->right->implicit = 1; // * is okay + } + 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->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; @@ -1974,30 +2147,28 @@ 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 on the OIND. + 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) { @@ -2040,11 +2211,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; @@ -2068,13 +2239,14 @@ typecheckcomplit(Node **np) typecheck(&l->left, Erv); defaultlit(&l->left, t->down); l->left = assignconv(l->left, t->down, "map key"); - keydup(l->left, hash, nhash); + if (l->left->op != OCONV) + 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; @@ -2095,8 +2267,10 @@ 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; ll->n->left->typecheck = 1; f = f->down; } @@ -2117,26 +2291,31 @@ typecheckcomplit(Node **np) } s = l->left->sym; if(s == S) { - yyerror("invalid field name %#N in struct initializer", l->left); + yyerror("invalid field name %N in struct initializer", l->left); typecheck(&l->right, Erv); continue; } + // Sym might have resolved to name in other top-level // package, because of import dot. Redirect to correct sym // before we do the lookup. - if(s->pkg != localpkg) + if(s->pkg != localpkg && exportname(s->name)) s = lookup(s->name); - l->left = newname(s); - l->left->typecheck = 1; - f = lookdot1(s, t, t->type, 0); - typecheck(&l->right, Erv); + + f = lookdot1(nil, s, t, t->type, 0); if(f == nil) { - yyerror("unknown %T field '%s' in struct literal", t, s->name); + yyerror("unknown %T field '%S' in struct literal", t, s); continue; } + l->left = newname(s); + l->left->typecheck = 1; + l->left->type = f; s = f->sym; fielddup(newname(s), hash, nhash); - l->right = assignconv(l->right, f->type, "field value"); + r = l->right; + // No pushtype allowed here. Tried and rejected. + typecheck(&r, Erv); + l->right = assignconv(r, f->type, "field value"); } } n->op = OSTRUCTLIT; @@ -2144,7 +2323,14 @@ 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; + n->left->typecheck = 1; + } *np = n; lineno = lno; @@ -2157,82 +2343,6 @@ error: } /* - * the address of n has been taken and might be used after - * the current function returns. mark any local vars - * as needing to move to the heap. - */ -static void -addrescapes(Node *n) -{ - char buf[100]; - switch(n->op) { - default: - // probably a type error already. - // dump("addrescapes", n); - break; - - case ONAME: - if(n->noescape) - break; - switch(n->class) { - case PPARAMREF: - addrescapes(n->defn); - break; - case PPARAM: - case PPARAMOUT: - // if func param, need separate temporary - // to hold heap pointer. - // the function type has already been checked - // (we're in the function body) - // so the param already has a valid xoffset. - - // expression to refer to stack copy - n->stackparam = nod(OPARAM, n, N); - n->stackparam->type = n->type; - n->stackparam->addable = 1; - if(n->xoffset == BADWIDTH) - fatal("addrescapes before param assignment"); - n->stackparam->xoffset = n->xoffset; - n->xoffset = 0; - // fallthrough - case PAUTO: - - n->class |= PHEAP; - n->addable = 0; - n->ullman = 2; - n->xoffset = 0; - - // create stack variable to hold pointer to heap - n->heapaddr = nod(ONAME, N, N); - n->heapaddr->type = ptrto(n->type); - snprint(buf, sizeof buf, "&%S", n->sym); - n->heapaddr->sym = lookup(buf); - n->heapaddr->class = PHEAP-1; // defer tempname to allocparams - n->heapaddr->ullman = 1; - n->curfn->dcl = list(n->curfn->dcl, n->heapaddr); - - break; - } - break; - - case OIND: - case ODOTPTR: - break; - - case ODOT: - case OINDEX: - // ODOTPTR has already been introduced, - // so these are the non-pointer ODOT and OINDEX. - // In &x[0], if x is a slice, then x does not - // escape--the pointer inside x does, but that - // is always a heap pointer anyway. - if(!isslice(n->left->type)) - addrescapes(n->left); - break; - } -} - -/* * lvalue etc */ int @@ -2262,7 +2372,7 @@ static void checklvalue(Node *n, char *verb) { if(!islvalue(n)) - yyerror("cannot %s %#N", verb, n); + yyerror("cannot %s %N", verb, n); } static void @@ -2274,7 +2384,7 @@ checkassign(Node *n) n->etype = 1; return; } - yyerror("cannot assign to %#N", n); + yyerror("cannot assign to %N", n); } static void @@ -2309,8 +2419,6 @@ typecheckas(Node *n) if(n->right && n->right->type != T) { if(n->left->type != T) n->right = assignconv(n->right, n->left->type, "assignment"); - else if(!isblank(n->left)) - exportassignok(n->right->type, "assignment"); } if(n->left->defn == n && n->left->ntype == N) { defaultlit(&n->right, T); @@ -2331,10 +2439,9 @@ checkassignto(Type *src, Node *dst) char *why; if(assignop(src, dst->type, &why) == 0) { - yyerror("cannot assign %T to %+N in multiple assignment%s", src, dst, why); + yyerror("cannot assign %T to %lN in multiple assignment%s", src, dst, why); return; } - exportassignok(dst->type, "multiple assignment"); } static void @@ -2381,10 +2488,7 @@ typecheckas2(Node *n) if(cl == 1 && cr == 2 && l->op == OINDEXMAP) { if(l->type == T) goto out; - n->op = OAS2MAPW; - n->rlist->n = assignconv(r, l->type, "assignment"); - r = n->rlist->next->n; - n->rlist->next->n = assignconv(r, types[TBOOL], "assignment"); + yyerror("assignment count mismatch: %d = %d (use delete)", cl, cr); goto out; } @@ -2462,12 +2566,11 @@ typecheckfunc(Node *n) { Type *t, *rcvr; -//dump("nname", n->nname); typecheck(&n->nname, Erv | Easgn); if((t = n->nname->type) == T) return; n->type = t; - + t->nname = n->nname; rcvr = getthisx(t)->type; if(rcvr != nil && n->shortname != N && !isblank(n->shortname)) addmethod(n->shortname->sym, t, 1); @@ -2497,7 +2600,7 @@ stringtoarraylit(Node **np) while(p < ep) l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++))); } else { - // utf-8 []int + // utf-8 []rune while(p < ep) { p += chartorune(&r, p); l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r))); @@ -2514,7 +2617,7 @@ getforwtype(Node *n) { Node *f1, *f2; - for(f1=f2=n; ; n=n->ntype) { + for(f2=n; ; n=n->ntype) { if((n = resolve(n)) == N || n->op != OTYPE) return T; @@ -2537,6 +2640,7 @@ static void domethod(Node *n) { Node *nt; + Type *t; nt = n->type->nname; typecheck(&nt, Etype); @@ -2546,6 +2650,20 @@ domethod(Node *n) n->type->nod = N; return; } + + // If we have + // type I interface { + // M(_ int) + // } + // then even though I.M looks like it doesn't care about the + // value of its argument, a specific implementation of I may + // care. The _ would suppress the assignment to that argument + // while generating a call, so remove it. + for(t=getinargx(nt->type)->type; t; t=t->down) { + if(t->sym != nil && strcmp(t->sym->name, "_") == 0) + t->sym = nil; + } + *n->type = *nt->type; n->type->nod = N; checkwidth(n->type); @@ -2602,6 +2720,7 @@ copytype(Node *n, Type *t) t->vargen = n->vargen; t->siggen = 0; t->method = nil; + t->xmethod = nil; t->nod = N; t->printed = 0; t->deferwidth = 0; @@ -2759,7 +2878,7 @@ typecheckdef(Node *n) goto ret; } if(!isideal(e->type) && !eqtype(t, e->type)) { - yyerror("cannot use %+N as type %T in const initializer", e, t); + yyerror("cannot use %lN as type %T in const initializer", e, t); goto ret; } convlit(&e, t); @@ -2772,6 +2891,7 @@ typecheckdef(Node *n) if(n->ntype != N) { typecheck(&n->ntype, Etype); n->type = n->ntype->type; + if(n->type == T) { n->diag = 1; goto ret; @@ -2816,6 +2936,8 @@ typecheckdef(Node *n) } ret: + if(n->op != OLITERAL && n->type != T && isideal(n->type)) + fatal("got %T for %N", n->type, n); if(typecheckdefstack->n != n) fatal("typecheckdefstack mismatch"); l = typecheckdefstack; diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c index d304077c8..95200ad41 100644 --- a/src/cmd/gc/unsafe.c +++ b/src/cmd/gc/unsafe.c @@ -2,12 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" /* * look for * unsafe.Sizeof * unsafe.Offsetof + * unsafe.Alignof * rewrite with a constant */ Node* @@ -20,7 +23,7 @@ unsafenmagic(Node *nn) Val val; Node *fn; NodeList *args; - + fn = nn->left; args = nn->list; @@ -78,10 +81,10 @@ no: return N; bad: - yyerror("invalid expression %#N", nn); + yyerror("invalid expression %N", nn); v = 0; goto ret; - + yes: if(args->next != nil) yyerror("extra arguments for %S", s); @@ -91,7 +94,23 @@ ret: val.u.xval = mal(sizeof(*n->val.u.xval)); mpmovecfix(val.u.xval, v); n = nod(OLITERAL, N, N); + n->orig = nn; n->val = val; n->type = types[TUINTPTR]; + nn->type = types[TUINTPTR]; return n; } + +int +isunsafebuiltin(Node *n) +{ + if(n == N || n->op != ONAME || n->sym == S || n->sym->pkg != unsafepkg) + return 0; + if(strcmp(n->sym->name, "Sizeof") == 0) + return 1; + if(strcmp(n->sym->name, "Offsetof") == 0) + return 1; + if(strcmp(n->sym->name, "Alignof") == 0) + return 1; + return 0; +} diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go index db27d7425..c3c627815 100644 --- a/src/cmd/gc/unsafe.go +++ b/src/cmd/gc/unsafe.go @@ -6,6 +6,8 @@ // to update builtin.c.boot. This is not done automatically // to avoid depending on having a working compiler binary. +// +build ignore + package PACKAGE type Pointer uintptr // not really; filled in by compiler @@ -14,9 +16,3 @@ type Pointer uintptr // not really; filled in by compiler func Offsetof(any) uintptr func Sizeof(any) uintptr func Alignof(any) uintptr - -func Typeof(i interface{}) (typ interface{}) -func Reflect(i interface{}) (typ interface{}, addr Pointer) -func Unreflect(typ interface{}, addr Pointer) (ret interface{}) -func New(typ interface{}) Pointer -func NewArray(typ interface{}, n int) Pointer diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index 9cd4ee919..7dfd34a7a 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -2,16 +2,17 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +#include <u.h> +#include <libc.h> #include "go.h" static Node* walkprint(Node*, NodeList**, int); -static Node* conv(Node*, Type*); static Node* mapfn(char*, Type*); -static Node* makenewvar(Type*, NodeList**, Node**); +static Node* mapfndel(char*, Type*); static Node* ascompatee1(int, Node*, Node*, NodeList**); static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**); static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**); -static NodeList* ascompatte(int, int, Type**, NodeList*, int, NodeList**); +static NodeList* ascompatte(int, Node*, int, Type**, NodeList*, int, NodeList**); static Node* convas(Node*, NodeList**); static void heapmoves(void); static NodeList* paramstoheap(Type **argin, int out); @@ -20,6 +21,7 @@ static NodeList* reorder3(NodeList*); static Node* addstr(Node*, NodeList**); static Node* appendslice(Node*, NodeList**); static Node* append(Node*, NodeList**); +static void walkcompare(Node**, NodeList**); // can this code branch reach the end // without an unconditional RETURN @@ -60,7 +62,6 @@ walk(Node *fn) { char s[50]; NodeList *l; - Node *n; int lno; curfn = fn; @@ -74,15 +75,33 @@ walk(Node *fn) yyerror("function ends without a return statement"); lno = lineno; + + // Final typecheck for any unused variables. + // It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below. + for(l=fn->dcl; l; l=l->next) + if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO) + typecheck(&l->n, Erv | Easgn); + + // Propagate the used flag for typeswitch variables up to the NONAME in it's definition. + for(l=fn->dcl; l; l=l->next) + if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO && l->n->defn && l->n->defn->op == OTYPESW && l->n->used) + l->n->defn->left->used++; + for(l=fn->dcl; l; l=l->next) { - n = l->n; - if(n->op != ONAME || n->class != PAUTO) + if(l->n->op != ONAME || (l->n->class&~PHEAP) != PAUTO || l->n->sym->name[0] == '&' || l->n->used) continue; - lineno = n->lineno; - typecheck(&n, Erv | Easgn); // only needed for unused variables - if(!n->used && n->sym->name[0] != '&' && !nsyntaxerrors) - yyerror("%S declared and not used", n->sym); - } + if(l->n->defn && l->n->defn->op == OTYPESW) { + if(l->n->defn->left->used) + continue; + lineno = l->n->defn->left->lineno; + yyerror("%S declared and not used", l->n->sym); + l->n->defn->left->used = 1; // suppress repeats + } else { + lineno = l->n->lineno; + yyerror("%S declared and not used", l->n->sym); + } + } + lineno = lno; if(nerrors != 0) return; @@ -119,11 +138,12 @@ static int paramoutheap(Node *fn) { NodeList *l; - + for(l=fn->dcl; l; l=l->next) { switch(l->n->class) { + case PPARAMOUT: case PPARAMOUT|PHEAP: - return 1; + return l->n->addrtaken; case PAUTO: case PAUTO|PHEAP: // stop early - parameters are over @@ -147,6 +167,8 @@ walkstmt(Node **np) setlineno(n); + walkstmtlist(n->ninit); + switch(n->op) { default: if(n->op == ONAME) @@ -162,7 +184,6 @@ walkstmt(Node **np) case OAS2DOTTYPE: case OAS2RECV: case OAS2FUNC: - case OAS2MAPW: case OAS2MAPR: case OCLOSE: case OCOPY: @@ -170,6 +191,7 @@ walkstmt(Node **np) case OCALLINTER: case OCALL: case OCALLFUNC: + case ODELETE: case OSEND: case ORECV: case OPRINT: @@ -177,14 +199,12 @@ walkstmt(Node **np) case OPANIC: case OEMPTY: case ORECOVER: - if(n->typecheck == 0) { - dump("missing typecheck:", n); - fatal("missing typecheck"); - } + if(n->typecheck == 0) + fatal("missing typecheck: %+N", n); init = n->ninit; n->ninit = nil; walkexpr(&n, &init); - n->ninit = concat(init, n->ninit); + addinit(&n, init); break; case OBREAK: @@ -223,20 +243,18 @@ walkstmt(Node **np) break; case OFOR: - walkstmtlist(n->ninit); if(n->ntest != N) { walkstmtlist(n->ntest->ninit); init = n->ntest->ninit; n->ntest->ninit = nil; walkexpr(&n->ntest, &init); - n->ntest->ninit = concat(init, n->ntest->ninit); + addinit(&n->ntest, init); } walkstmt(&n->nincr); walkstmtlist(n->nbody); break; case OIF: - walkstmtlist(n->ninit); walkexpr(&n->ntest, &n->ninit); walkstmtlist(n->nbody); walkstmtlist(n->nelse); @@ -279,15 +297,18 @@ walkstmt(Node **np) // OAS2FUNC in disguise f = n->list->n; if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER) - fatal("expected return of call, have %#N", f); + fatal("expected return of call, have %N", f); n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit)); break; } + + // move function calls out, to make reorder3's job easier. + walkexprlistsafe(n->list, &n->ninit); ll = ascompatee(n->op, rl, n->list, &n->ninit); n->list = reorder3(ll); break; } - ll = ascompatte(n->op, 0, getoutarg(curfn->type), n->list, 1, &n->ninit); + ll = ascompatte(n->op, nil, 0, getoutarg(curfn->type), n->list, 1, &n->ninit); n->list = ll; break; @@ -309,6 +330,9 @@ walkstmt(Node **np) break; } + if(n->op == ONAME) + fatal("walkstmt ended up with name: %+N", n); + *np = n; } @@ -361,6 +385,12 @@ walkexpr(Node **np, NodeList **init) fatal("walkexpr init == &n->ninit"); } + if(n->ninit != nil) { + walkstmtlist(n->ninit); + *init = concat(*init, n->ninit); + n->ninit = nil; + } + // annoying case - not typechecked if(n->op == OKEY) { walkexpr(&n->left, init); @@ -373,19 +403,14 @@ walkexpr(Node **np, NodeList **init) if(debug['w'] > 1) dump("walk-before", n); - if(n->typecheck != 1) { - dump("missed typecheck", n); - fatal("missed typecheck"); - } - - t = T; - et = Txxx; + if(n->typecheck != 1) + fatal("missed typecheck: %+N\n", n); switch(n->op) { default: dump("walk", n); fatal("walkexpr: switch 1 unknown op %N", n); - goto ret; + break; case OTYPE: case ONONAME: @@ -407,10 +432,14 @@ walkexpr(Node **np, NodeList **init) walkexpr(&n->left, init); goto ret; + case OITAB: + walkexpr(&n->left, init); + goto ret; + case OLEN: case OCAP: walkexpr(&n->left, init); - + // replace len(*[10]int) with 10. // delayed until now to preserve side effects. t = n->left->type; @@ -422,7 +451,7 @@ walkexpr(Node **np, NodeList **init) n->typecheck = 1; } goto ret; - + case OLSH: case ORSH: case OAND: @@ -430,8 +459,6 @@ walkexpr(Node **np, NodeList **init) case OXOR: case OSUB: case OMUL: - case OEQ: - case ONE: case OLT: case OLE: case OGE: @@ -441,7 +468,14 @@ walkexpr(Node **np, NodeList **init) walkexpr(&n->left, init); walkexpr(&n->right, init); goto ret; - + + case OEQ: + case ONE: + walkexpr(&n->left, init); + walkexpr(&n->right, init); + walkcompare(&n, init); + goto ret; + case OANDAND: case OOROR: walkexpr(&n->left, init); @@ -450,7 +484,7 @@ walkexpr(Node **np, NodeList **init) // save elsewhere and store on the eventual n->right. ll = nil; walkexpr(&n->right, &ll); - n->right->ninit = concat(n->right->ninit, ll); + addinit(&n->right, ll); goto ret; case OPRINT: @@ -482,7 +516,7 @@ walkexpr(Node **np, NodeList **init) goto ret; walkexpr(&n->left, init); walkexprlist(n->list, init); - ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); + ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init); n->list = reorder1(ll); goto ret; @@ -499,7 +533,7 @@ walkexpr(Node **np, NodeList **init) walkexpr(&n->left, init); walkexprlist(n->list, init); - ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); + ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init); n->list = reorder1(ll); goto ret; @@ -509,8 +543,8 @@ walkexpr(Node **np, NodeList **init) goto ret; walkexpr(&n->left, init); walkexprlist(n->list, init); - ll = ascompatte(n->op, 0, getthis(t), list1(n->left->left), 0, init); - lr = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); + ll = ascompatte(n->op, n, 0, getthis(t), list1(n->left->left), 0, init); + lr = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init); ll = concat(ll, lr); n->left->left = N; ullmancalc(n->left); @@ -554,7 +588,7 @@ walkexpr(Node **np, NodeList **init) walkexprlistsafe(n->list, init); walkexpr(&r, init); l = n->list->n; - + // all the really hard stuff - explicit function calls and so on - // is gone, but map assignments remain. // if there are map assignments here, assign via @@ -563,8 +597,7 @@ walkexpr(Node **np, NodeList **init) // and map index has an implicit one. lpost = nil; if(l->op == OINDEXMAP) { - var = nod(OXXX, N, N); - tempname(var, l->type); + var = temp(l->type); n->list->n = var; a = nod(OAS, l, var); typecheck(&a, Etop); @@ -572,8 +605,7 @@ walkexpr(Node **np, NodeList **init) } l = n->list->next->n; if(l->op == OINDEXMAP) { - var = nod(OXXX, N, N); - tempname(var, l->type); + var = temp(l->type); n->list->next->n = var; a = nod(OAS, l, var); typecheck(&a, Etop); @@ -609,15 +641,13 @@ walkexpr(Node **np, NodeList **init) n->op = OAS2FUNC; goto as2func; - case OAS2MAPW: - // map[] = a,b - mapassign2 - // a,b = m[i]; + case ODELETE: *init = concat(*init, n->ninit); n->ninit = nil; - walkexprlistsafe(n->list, init); l = n->list->n; - t = l->left->type; - n = mkcall1(mapfn("mapassign2", t), T, init, typename(t), l->left, l->right, n->rlist->n, n->rlist->next->n); + r = n->list->next->n; + t = l->type; + n = mkcall1(mapfndel("mapdelete", t), t->down, init, typename(t), l, r); goto ret; case OAS2DOTTYPE: @@ -651,7 +681,7 @@ walkexpr(Node **np, NodeList **init) if(n->op == ODOTTYPE2) *p++ = '2'; *p = '\0'; - + fn = syslook(buf, 1); ll = list1(typename(n->type)); ll = list(ll, n->left); @@ -682,7 +712,7 @@ walkexpr(Node **np, NodeList **init) else *p++ = 'I'; *p = '\0'; - + fn = syslook(buf, 1); ll = nil; if(!isinter(n->left->type)) @@ -843,6 +873,7 @@ walkexpr(Node **np, NodeList **init) // delayed until now because "abc"[2] is not // an ideal constant. nodconst(n, n->type, n->left->val.u.sval->s[v]); + n->typecheck = 1; } } goto ret; @@ -897,7 +928,7 @@ walkexpr(Node **np, NodeList **init) } if(v1 >= 0 && v2 >= 0 && v1 > v2) yyerror("inverted slice range"); - + if(n->op == OSLICEARR) goto slicearray; @@ -928,7 +959,7 @@ walkexpr(Node **np, NodeList **init) l, nodintconst(t->type->width)); } - n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call. + n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call. goto ret; slicearray: @@ -953,29 +984,22 @@ 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; case ONEW: - n = callnew(n->type->type); + if(n->esc == EscNone && n->type->type->width < (1<<16)) { + r = temp(n->type->type); + r = nod(OAS, r, N); // zero temp + typecheck(&r, Etop); + *init = list(*init, r); + r = nod(OADDR, r->left, N); + typecheck(&r, Erv); + n = r; + } else { + n = callnew(n->type->type); + } goto ret; case OCMPSTR: @@ -987,6 +1011,7 @@ walkexpr(Node **np, NodeList **init) r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N)); typecheck(&r, Erv); walkexpr(&r, init); + r->type = n->type; n = r; goto ret; } @@ -999,6 +1024,7 @@ walkexpr(Node **np, NodeList **init) r = nod(n->etype, nod(OLEN, n->left->left, N), nodintconst(0)); typecheck(&r, Erv); walkexpr(&r, init); + r->type = n->type; n = r; goto ret; } @@ -1025,6 +1051,8 @@ walkexpr(Node **np, NodeList **init) walkexpr(&r, nil); } typecheck(&r, Erv); + if(n->type->etype != TBOOL) fatal("cmp %T", n->type); + r->type = n->type; n = r; goto ret; @@ -1049,10 +1077,14 @@ walkexpr(Node **np, NodeList **init) l); } goto ret; - + case OAPPEND: - if(n->isddd) - n = appendslice(n, init); + if(n->isddd) { + if(istype(n->type->type, TUINT8) && istype(n->list->next->n->type, TSTRING)) + n = mkcall("appendstr", n->type, init, typename(n->type), n->list->n, n->list->next->n); + else + n = appendslice(n, init); + } else n = append(n, init); goto ret; @@ -1061,7 +1093,7 @@ walkexpr(Node **np, NodeList **init) if(n->right->type->etype == TSTRING) fn = syslook("slicestringcopy", 1); else - fn = syslook("slicecopy", 1); + fn = syslook("copy", 1); argtype(fn, n->left->type); argtype(fn, n->right->type); n = mkcall1(fn, n->type, init, @@ -1121,8 +1153,8 @@ walkexpr(Node **np, NodeList **init) goto ret; case OARRAYRUNESTR: - // sliceinttostring([]int) string; - n = mkcall("sliceinttostring", n->type, init, n->left); + // slicerunetostring([]rune) string; + n = mkcall("slicerunetostring", n->type, init, n->left); goto ret; case OSTRARRAYBYTE: @@ -1131,8 +1163,8 @@ walkexpr(Node **np, NodeList **init) goto ret; case OSTRARRAYRUNE: - // stringtosliceint(string) []int - n = mkcall("stringtosliceint", n->type, init, n->left); + // stringtoslicerune(string) []rune + n = mkcall("stringtoslicerune", n->type, init, n->left); goto ret; case OCMPIFACE: @@ -1146,20 +1178,27 @@ walkexpr(Node **np, NodeList **init) argtype(fn, n->right->type); argtype(fn, n->left->type); r = mkcall1(fn, n->type, init, n->left, n->right); - if(n->etype == ONE) { + if(n->etype == ONE) r = nod(ONOT, r, N); - typecheck(&r, Erv); - } + + // check itable/type before full compare. + if(n->etype == OEQ) + r = nod(OANDAND, nod(OEQ, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r); + else + r = nod(OOROR, nod(ONE, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r); + typecheck(&r, Erv); + walkexpr(&r, nil); + r->type = n->type; n = r; goto ret; case OARRAYLIT: case OMAPLIT: case OSTRUCTLIT: - nvar = nod(OXXX, N, N); - tempname(nvar, 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: @@ -1173,34 +1212,20 @@ walkexpr(Node **np, NodeList **init) fatal("missing switch %O", n->op); ret: + ullmancalc(n); + if(debug['w'] && n != N) dump("walk", n); - ullmancalc(n); lineno = lno; *np = n; } static Node* -makenewvar(Type *t, NodeList **init, Node **nstar) -{ - Node *nvar, *nas; - - nvar = nod(OXXX, N, N); - tempname(nvar, 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) { + USED(op); + return convas(nod(OAS, l, r), init); } @@ -1227,7 +1252,7 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init) // cannot happen: caller checked that lists had same length if(ll || lr) - yyerror("error in shape across %O", op); + yyerror("error in shape across %+H %O %+H", nl, op, nr); return nn; } @@ -1257,6 +1282,8 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init) int ucount; NodeList *nn, *mm; + USED(op); + /* * check assign type list to * a expression list. called in @@ -1279,8 +1306,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init) // deferred until all the return arguments // have been pulled from the output arguments if(fncall(l, r->type)) { - tmp = nod(OXXX, N, N); - tempname(tmp, r->type); + tmp = temp(r->type); typecheck(&tmp, Erv); a = nod(OAS, l, tmp); a = convas(a, init); @@ -1298,10 +1324,11 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init) } if(ll != nil || r != T) - yyerror("assignment count mismatch: %d = %d", + yyerror("ascompatet: assignment count mismatch: %d = %d", count(nl), structcount(*nr)); + if(ucount) - fatal("reorder2: too many function calls evaluating parameters"); + fatal("ascompatet: too many function calls evaluating parameters"); return concat(nn, mm); } @@ -1309,7 +1336,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init) * package all the arguments that match a ... T parameter into a []T. */ static NodeList* -mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init) +mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, int esc) { Node *a, *n; Type *tslice; @@ -1318,12 +1345,18 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init) tslice->type = l->type->type; tslice->bound = -1; - n = nod(OCOMPLIT, N, typenod(tslice)); - n->list = lr0; - typecheck(&n, Erv); - if(n->type == T) - fatal("mkdotargslice: typecheck failed"); - walkexpr(&n, init); + if(count(lr0) == 0) { + n = nodnil(); + n->type = tslice; + } else { + n = nod(OCOMPLIT, N, typenod(tslice)); + n->list = lr0; + n->esc = esc; + typecheck(&n, Erv); + if(n->type == T) + fatal("mkdotargslice: typecheck failed"); + walkexpr(&n, init); + } a = nod(OAS, nodarg(l, fp), n); nn = list(nn, convas(a, init)); @@ -1343,7 +1376,6 @@ dumptypes(Type **nl, char *what) fmtstrinit(&fmt); fmtprint(&fmt, "\t"); - l = structfirst(&savel, nl); first = 1; for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) { if(first) @@ -1387,8 +1419,9 @@ dumpnodetypes(NodeList *l, char *what) * func(expr-list) */ static NodeList* -ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init) +ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init) { + int esc; Type *l, *ll; Node *r, *a; NodeList *nn, *lr0, *alist; @@ -1401,7 +1434,7 @@ ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init) if(lr) r = lr->n; nn = nil; - + // f(g()) where g has multiple return values if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) { // optimization - can do block copy @@ -1411,13 +1444,12 @@ ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init) nn = list1(convas(nod(OAS, a, r), init)); goto ret; } - + // conversions involved. // copy into temporaries. alist = nil; for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) { - a = nod(OXXX, N, N); - tempname(a, l->type); + a = temp(l->type); alist = list(alist, a); } a = nod(OAS2, N, N); @@ -1452,7 +1484,10 @@ loop: // normal case -- make a slice of all // remaining arguments and pass it to // the ddd parameter. - nn = mkdotargslice(lr, nn, l, fp, init); + esc = EscUnknown; + if(call->right) + esc = call->right->esc; + nn = mkdotargslice(lr, nn, l, fp, init, esc); goto ret; } @@ -1526,6 +1561,9 @@ walkprint(Node *nn, NodeList **init, int defer) n = l->n; if(n->op == OLITERAL) { switch(n->val.ctype) { + case CTRUNE: + defaultlit(&n, runetype); + break; case CTINT: defaultlit(&n, types[TINT64]); break; @@ -1668,7 +1706,7 @@ callnew(Type *t) dowidth(t); fn = syslook("new", 1); argtype(fn, t); - return mkcall1(fn, ptrto(t), nil, nodintconst(t->width)); + return mkcall1(fn, ptrto(t), nil, typename(t)); } static Node* @@ -1700,10 +1738,10 @@ convas(Node *n, NodeList **init) n->left->left, n->left->right, n->right); goto out; } - + if(eqtype(lt, rt)) goto out; - + n->right = assignconv(n->right, lt, "assignment"); walkexpr(&n->right, init); @@ -1720,7 +1758,7 @@ out: * then it is done first. otherwise must * make temp variables */ -NodeList* +static NodeList* reorder1(NodeList *all) { Node *f, *a, *n; @@ -1757,8 +1795,7 @@ reorder1(NodeList *all) } // make assignment of fncall to tempname - a = nod(OXXX, N, N); - tempname(a, n->right->type); + a = temp(n->right->type); a = nod(OAS, a, n->right); g = list(g, a); @@ -1773,28 +1810,242 @@ reorder1(NodeList *all) return concat(g, r); } +static void reorder3save(Node**, NodeList*, NodeList*, NodeList**); +static int aliased(Node*, NodeList*, NodeList*); + /* * from ascompat[ee] * a,b = c,d * simultaneous assignment. there cannot * be later use of an earlier lvalue. + * + * function calls have been removed. */ +static NodeList* +reorder3(NodeList *all) +{ + NodeList *list, *early; + Node *l; + + // If a needed expression may be affected by an + // earlier assignment, make an early copy of that + // expression and use the copy instead. + early = nil; + for(list=all; list; list=list->next) { + l = list->n->left; + + // Save subexpressions needed on left side. + // Drill through non-dereferences. + for(;;) { + if(l->op == ODOT || l->op == OPAREN) { + l = l->left; + continue; + } + if(l->op == OINDEX && isfixedarray(l->left->type)) { + reorder3save(&l->right, all, list, &early); + l = l->left; + continue; + } + break; + } + switch(l->op) { + default: + fatal("reorder3 unexpected lvalue %#O", l->op); + case ONAME: + break; + case OINDEX: + reorder3save(&l->left, all, list, &early); + reorder3save(&l->right, all, list, &early); + break; + case OIND: + case ODOTPTR: + reorder3save(&l->left, all, list, &early); + } + // Save expression on right side. + reorder3save(&list->n->right, all, list, &early); + } + + return concat(early, all); +} + +static int vmatch2(Node*, Node*); +static int varexpr(Node*); + +/* + * if the evaluation of *np would be affected by the + * assignments in all up to but not including stop, + * copy into a temporary during *early and + * replace *np with that temp. + */ +static void +reorder3save(Node **np, NodeList *all, NodeList *stop, NodeList **early) +{ + Node *n, *q; + + n = *np; + if(!aliased(n, all, stop)) + return; + + q = temp(n->type); + q = nod(OAS, q, n); + typecheck(&q, Etop); + *early = list(*early, q); + *np = q->left; +} + +/* + * what's the outer value that a write to n affects? + * outer value means containing struct or array. + */ +static Node* +outervalue(Node *n) +{ + for(;;) { + if(n->op == ODOT || n->op == OPAREN) { + n = n->left; + continue; + } + if(n->op == OINDEX && isfixedarray(n->left->type)) { + n = n->left; + continue; + } + break; + } + return n; +} + +/* + * Is it possible that the computation of n might be + * affected by writes in as up to but not including stop? + */ +static int +aliased(Node *n, NodeList *all, NodeList *stop) +{ + int memwrite, varwrite; + Node *a; + NodeList *l; + + if(n == N) + return 0; + + // Look for obvious aliasing: a variable being assigned + // during the all list and appearing in n. + // Also record whether there are any writes to main memory. + // Also record whether there are any writes to variables + // whose addresses have been taken. + memwrite = 0; + varwrite = 0; + for(l=all; l!=stop; l=l->next) { + a = outervalue(l->n->left); + if(a->op != ONAME) { + memwrite = 1; + continue; + } + switch(n->class) { + default: + varwrite = 1; + continue; + case PAUTO: + case PPARAM: + case PPARAMOUT: + if(n->addrtaken) { + varwrite = 1; + continue; + } + if(vmatch2(a, n)) { + // Direct hit. + return 1; + } + } + } + + // The variables being written do not appear in n. + // However, n might refer to computed addresses + // that are being written. + + // If no computed addresses are affected by the writes, no aliasing. + if(!memwrite && !varwrite) + return 0; + + // If n does not refer to computed addresses + // (that is, if n only refers to variables whose addresses + // have not been taken), no aliasing. + if(varexpr(n)) + return 0; + + // Otherwise, both the writes and n refer to computed memory addresses. + // Assume that they might conflict. + return 1; +} + +/* + * does the evaluation of n only refer to variables + * whose addresses have not been taken? + * (and no other memory) + */ +static int +varexpr(Node *n) +{ + if(n == N) + return 1; + + switch(n->op) { + case OLITERAL: + return 1; + case ONAME: + switch(n->class) { + case PAUTO: + case PPARAM: + case PPARAMOUT: + if(!n->addrtaken) + return 1; + } + return 0; + + case OADD: + case OSUB: + case OOR: + case OXOR: + case OMUL: + case ODIV: + case OMOD: + case OLSH: + case ORSH: + case OAND: + case OANDNOT: + case OPLUS: + case OMINUS: + case OCOM: + case OPAREN: + case OANDAND: + case OOROR: + case ODOT: // but not ODOTPTR + case OCONV: + case OCONVNOP: + case OCONVIFACE: + case ODOTTYPE: + return varexpr(n->left) && varexpr(n->right); + } + + // Be conservative. + return 0; +} + +/* + * is the name l mentioned in r? + */ static int vmatch2(Node *l, Node *r) { NodeList *ll; - /* - * isolate all right sides - */ if(r == N) return 0; switch(r->op) { case ONAME: // match each right given left - if(l == r) - return 1; + return l == r; case OLITERAL: return 0; } @@ -1808,6 +2059,10 @@ vmatch2(Node *l, Node *r) return 0; } +/* + * is any name mentioned in l also mentioned in r? + * called by sinit.c + */ int vmatch1(Node *l, Node *r) { @@ -1846,34 +2101,6 @@ vmatch1(Node *l, Node *r) return 0; } -NodeList* -reorder3(NodeList *all) -{ - Node *n1, *n2, *q; - int c1, c2; - NodeList *l1, *l2, *r; - - r = nil; - for(l1=all, c1=0; l1; l1=l1->next, c1++) { - n1 = l1->n; - for(l2=all, c2=0; l2; l2=l2->next, c2++) { - n2 = l2->n; - if(c2 > c1) { - if(vmatch1(n1->left, n2->right)) { - // delay assignment to n1->left - q = nod(OXXX, N, N); - tempname(q, n1->right->type); - q = nod(OAS, n1->left, q); - n1->left = q->right; - r = list(r, q); - break; - } - } - } - } - return concat(all, r); -} - /* * walk through argin parameters. * generate and return code to allocate @@ -1940,7 +2167,7 @@ heapmoves(void) { NodeList *nn; int32 lno; - + lno = lineno; lineno = curfn->lineno; nn = paramstoheap(getthis(curfn->type), 0); @@ -1960,7 +2187,7 @@ vmkcall(Node *fn, Type *t, NodeList **init, va_list va) NodeList *args; if(fn->type == T || fn->type->etype != TFUNC) - fatal("mkcall %#N %T", fn, fn->type); + fatal("mkcall %N %T", fn, fn->type); args = nil; n = fn->type->intuple; @@ -2002,7 +2229,7 @@ mkcall1(Node *fn, Type *t, NodeList **init, ...) return r; } -static Node* +Node* conv(Node *n, Type *t) { if(eqtype(n->type, t)) @@ -2043,12 +2270,26 @@ mapfn(char *name, Type *t) } static Node* +mapfndel(char *name, Type *t) +{ + Node *fn; + + if(t->etype != TMAP) + fatal("mapfn %T", t); + fn = syslook(name, 1); + argtype(fn, t->down); + argtype(fn, t->type); + argtype(fn, t->down); + return fn; +} + +static Node* addstr(Node *n, NodeList **init) { Node *r, *cat, *typstr; NodeList *in, *args; int i, count; - + count = 0; for(r=n; r->op == OADDSTR; r=r->left) count++; // r->right @@ -2077,7 +2318,7 @@ addstr(Node *n, NodeList **init) typecheck(&r, Erv); walkexpr(&r, init); r->type = n->type; - + return r; } @@ -2085,7 +2326,7 @@ static Node* appendslice(Node *n, NodeList **init) { Node *f; - + f = syslook("appendslice", 1); argtype(f, n->type); argtype(f, n->type->type); @@ -2099,7 +2340,7 @@ appendslice(Node *n, NodeList **init) // s := src // const argc = len(args) - 1 // if cap(s) - len(s) < argc { -// s = growslice(s, argc) +// s = growslice(s, argc) // } // n := len(s) // s = s[:n+argc] @@ -2117,6 +2358,12 @@ append(Node *n, NodeList **init) walkexprlistsafe(n->list, init); + // walkexprlistsafe will leave OINDEX (s[n]) alone if both s + // and n are name or literal, but those may index the slice we're + // modifying here. Fix explicitly. + for(l=n->list; l; l=l->next) + l->n = cheapexpr(l->n, init); + nsrc = n->list->n; argc = count(n->list) - 1; if (argc < 1) { @@ -2125,17 +2372,16 @@ append(Node *n, NodeList **init) l = nil; - ns = nod(OXXX, N, N); // var s - tempname(ns, nsrc->type); + ns = temp(nsrc->type); l = list(l, nod(OAS, ns, nsrc)); // s = src - na = nodintconst(argc); // const argc - nx = nod(OIF, N, N); // if cap(s) - len(s) < argc + na = nodintconst(argc); // const argc + nx = nod(OIF, N, N); // if cap(s) - len(s) < argc nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na); - fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T) - argtype(fn, ns->type->type); // 1 old []any - argtype(fn, ns->type->type); // 2 ret []any + fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T) + argtype(fn, ns->type->type); // 1 old []any + argtype(fn, ns->type->type); // 2 ret []any nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit, typename(ns->type), @@ -2143,18 +2389,17 @@ append(Node *n, NodeList **init) conv(na, types[TINT64])))); l = list(l, nx); - nn = nod(OXXX, N, N); // var n - tempname(nn, types[TINT]); - l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s) + nn = temp(types[TINT]); + l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s) - nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc] - nx->etype = 1; // disable bounds check - l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc] + nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc] + nx->etype = 1; // disable bounds check + l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc] - for (a = n->list->next; a != nil; a = a->next) { - nx = nod(OINDEX, ns, nn); // s[n] ... - nx->etype = 1; // disable bounds check - l = list(l, nod(OAS, nx, a->n)); // s[n] = arg + for (a = n->list->next; a != nil; a = a->next) { + nx = nod(OINDEX, ns, nn); // s[n] ... + nx->etype = 1; // disable bounds check + l = list(l, nod(OAS, nx, a->n)); // s[n] = arg if (a->next != nil) l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1 } @@ -2164,3 +2409,188 @@ append(Node *n, NodeList **init) *init = concat(*init, l); return ns; } + +static Node* +eqfor(Type *t) +{ + int a; + Node *n; + Node *ntype; + Sym *sym; + + // Should only arrive here with large memory or + // a struct/array containing a non-memory field/element. + // Small memory is handled inline, and single non-memory + // is handled during type check (OCMPSTR etc). + a = algtype1(t, nil); + if(a != AMEM && a != -1) + fatal("eqfor %T", t); + + if(a == AMEM) { + n = syslook("memequal", 1); + argtype(n, t); + argtype(n, t); + return n; + } + + sym = typesymprefix(".eq", t); + n = newname(sym); + n->class = PFUNC; + ntype = nod(OTFUNC, N, N); + ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(types[TBOOL])))); + ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); + ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); + ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); + typecheck(&ntype, Etype); + n->type = ntype->type; + return n; +} + +static int +countfield(Type *t) +{ + Type *t1; + int n; + + n = 0; + for(t1=t->type; t1!=T; t1=t1->down) + n++; + return n; +} + +static void +walkcompare(Node **np, NodeList **init) +{ + Node *n, *l, *r, *fn, *call, *a, *li, *ri, *expr; + int andor, i; + Type *t, *t1; + static Node *tempbool; + + n = *np; + + // Must be comparison of array or struct. + // Otherwise back end handles it. + t = n->left->type; + switch(t->etype) { + default: + return; + case TARRAY: + if(isslice(t)) + return; + break; + case TSTRUCT: + break; + } + + if(!islvalue(n->left) || !islvalue(n->right)) + goto hard; + + l = temp(ptrto(t)); + a = nod(OAS, l, nod(OADDR, n->left, N)); + a->right->etype = 1; // addr does not escape + typecheck(&a, Etop); + *init = list(*init, a); + + r = temp(ptrto(t)); + a = nod(OAS, r, nod(OADDR, n->right, N)); + a->right->etype = 1; // addr does not escape + typecheck(&a, Etop); + *init = list(*init, a); + + expr = N; + andor = OANDAND; + if(n->op == ONE) + andor = OOROR; + + if(t->etype == TARRAY && + t->bound <= 4 && + issimple[t->type->etype]) { + // Four or fewer elements of a basic type. + // Unroll comparisons. + for(i=0; i<t->bound; i++) { + li = nod(OINDEX, l, nodintconst(i)); + ri = nod(OINDEX, r, nodintconst(i)); + a = nod(n->op, li, ri); + if(expr == N) + expr = a; + else + expr = nod(andor, expr, a); + } + if(expr == N) + expr = nodbool(n->op == OEQ); + typecheck(&expr, Erv); + walkexpr(&expr, init); + expr->type = n->type; + *np = expr; + return; + } + + if(t->etype == TSTRUCT && countfield(t) <= 4) { + // Struct of four or fewer fields. + // Inline comparisons. + for(t1=t->type; t1; t1=t1->down) { + li = nod(OXDOT, l, newname(t1->sym)); + ri = nod(OXDOT, r, newname(t1->sym)); + a = nod(n->op, li, ri); + if(expr == N) + expr = a; + else + expr = nod(andor, expr, a); + } + if(expr == N) + expr = nodbool(n->op == OEQ); + typecheck(&expr, Erv); + walkexpr(&expr, init); + expr->type = n->type; + *np = expr; + return; + } + + // Chose not to inline, but still have addresses. + // Call equality function directly. + // The equality function requires a bool pointer for + // storing its address, because it has to be callable + // from C, and C can't access an ordinary Go return value. + // To avoid creating many temporaries, cache one per function. + if(tempbool == N || tempbool->curfn != curfn) + tempbool = temp(types[TBOOL]); + + call = nod(OCALL, eqfor(t), N); + a = nod(OADDR, tempbool, N); + a->etype = 1; // does not escape + call->list = list(call->list, a); + call->list = list(call->list, nodintconst(t->width)); + call->list = list(call->list, l); + call->list = list(call->list, r); + typecheck(&call, Etop); + walkstmt(&call); + *init = list(*init, call); + + if(n->op == OEQ) + r = tempbool; + else + r = nod(ONOT, tempbool, N); + typecheck(&r, Erv); + walkexpr(&r, init); + *np = r; + return; + +hard: + // Cannot take address of one or both of the operands. + // Instead, pass directly to runtime helper function. + // Easier on the stack than passing the address + // of temporary variables, because we are better at reusing + // the argument space than temporary variable space. + fn = syslook("equal", 1); + l = n->left; + r = n->right; + argtype(fn, n->left->type); + argtype(fn, n->left->type); + r = mkcall1(fn, n->type, init, typename(n->left->type), l, r); + if(n->op == ONE) { + r = nod(ONOT, r, N); + typecheck(&r, Erv); + } + *np = r; + return; +} diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c new file mode 100644 index 000000000..97bf233eb --- /dev/null +++ b/src/cmd/gc/y.tab.c @@ -0,0 +1,5540 @@ +/* A Bison parser, made by GNU Bison 2.5. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.5" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Copy the first part of user declarations. */ + +/* Line 268 of yacc.c */ +#line 20 "go.y" + +#include <u.h> +#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */ +#include <libc.h> +#include "go.h" + +static void fixlbrace(int); + + +/* Line 268 of yacc.c */ +#line 81 "y.tab.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + LLITERAL = 258, + LASOP = 259, + LBREAK = 260, + LCASE = 261, + LCHAN = 262, + LCOLAS = 263, + LCONST = 264, + LCONTINUE = 265, + LDDD = 266, + LDEFAULT = 267, + LDEFER = 268, + LELSE = 269, + LFALL = 270, + LFOR = 271, + LFUNC = 272, + LGO = 273, + LGOTO = 274, + LIF = 275, + LIMPORT = 276, + LINTERFACE = 277, + LMAP = 278, + LNAME = 279, + LPACKAGE = 280, + LRANGE = 281, + LRETURN = 282, + LSELECT = 283, + LSTRUCT = 284, + LSWITCH = 285, + LTYPE = 286, + LVAR = 287, + LANDAND = 288, + LANDNOT = 289, + LBODY = 290, + LCOMM = 291, + LDEC = 292, + LEQ = 293, + LGE = 294, + LGT = 295, + LIGNORE = 296, + LINC = 297, + LLE = 298, + LLSH = 299, + LLT = 300, + LNE = 301, + LOROR = 302, + LRSH = 303, + NotPackage = 304, + NotParen = 305, + PreferToRightParen = 306 + }; +#endif +/* Tokens. */ +#define LLITERAL 258 +#define LASOP 259 +#define LBREAK 260 +#define LCASE 261 +#define LCHAN 262 +#define LCOLAS 263 +#define LCONST 264 +#define LCONTINUE 265 +#define LDDD 266 +#define LDEFAULT 267 +#define LDEFER 268 +#define LELSE 269 +#define LFALL 270 +#define LFOR 271 +#define LFUNC 272 +#define LGO 273 +#define LGOTO 274 +#define LIF 275 +#define LIMPORT 276 +#define LINTERFACE 277 +#define LMAP 278 +#define LNAME 279 +#define LPACKAGE 280 +#define LRANGE 281 +#define LRETURN 282 +#define LSELECT 283 +#define LSTRUCT 284 +#define LSWITCH 285 +#define LTYPE 286 +#define LVAR 287 +#define LANDAND 288 +#define LANDNOT 289 +#define LBODY 290 +#define LCOMM 291 +#define LDEC 292 +#define LEQ 293 +#define LGE 294 +#define LGT 295 +#define LIGNORE 296 +#define LINC 297 +#define LLE 298 +#define LLSH 299 +#define LLT 300 +#define LNE 301 +#define LOROR 302 +#define LRSH 303 +#define NotPackage 304 +#define NotParen 305 +#define PreferToRightParen 306 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 293 of yacc.c */ +#line 28 "go.y" + + Node* node; + NodeList* list; + Type* type; + Sym* sym; + struct Val val; + int i; + + + +/* Line 293 of yacc.c */ +#line 230 "y.tab.c" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 343 of yacc.c */ +#line 242 "y.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 4 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 2131 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 76 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 138 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 344 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 653 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 306 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 69, 2, 2, 64, 55, 56, 2, + 59, 60, 53, 49, 75, 50, 63, 54, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 66, 62, + 2, 65, 2, 73, 74, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 71, 2, 72, 52, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 67, 51, 68, 70, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 57, 58, 61 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint16 yyprhs[] = +{ + 0, 0, 3, 8, 9, 13, 14, 18, 19, 23, + 26, 32, 36, 40, 43, 45, 49, 51, 54, 57, + 62, 63, 65, 66, 71, 72, 74, 76, 78, 80, + 83, 89, 93, 96, 102, 110, 114, 117, 123, 127, + 129, 132, 137, 141, 146, 150, 152, 155, 157, 159, + 162, 164, 168, 172, 176, 179, 182, 186, 192, 198, + 201, 202, 207, 208, 212, 213, 216, 217, 222, 227, + 232, 238, 240, 242, 245, 246, 250, 252, 256, 257, + 258, 259, 267, 268, 271, 274, 275, 276, 284, 285, + 291, 293, 297, 301, 305, 309, 313, 317, 321, 325, + 329, 333, 337, 341, 345, 349, 353, 357, 361, 365, + 369, 373, 375, 378, 381, 384, 387, 390, 393, 396, + 399, 403, 409, 416, 418, 420, 424, 430, 436, 441, + 448, 450, 455, 461, 467, 475, 477, 478, 482, 484, + 489, 491, 495, 497, 499, 501, 503, 505, 507, 509, + 510, 512, 514, 516, 518, 523, 525, 527, 529, 532, + 534, 536, 538, 540, 542, 546, 548, 550, 552, 555, + 557, 559, 561, 563, 567, 569, 571, 573, 575, 577, + 579, 581, 583, 585, 589, 594, 599, 602, 606, 612, + 614, 616, 619, 623, 629, 633, 639, 643, 647, 653, + 662, 668, 677, 683, 684, 688, 689, 691, 695, 697, + 702, 705, 706, 710, 712, 716, 718, 722, 724, 728, + 730, 734, 736, 740, 744, 747, 752, 756, 762, 768, + 770, 774, 776, 779, 781, 785, 790, 792, 795, 798, + 800, 802, 806, 807, 810, 811, 813, 815, 817, 819, + 821, 823, 825, 827, 829, 830, 835, 837, 840, 843, + 846, 849, 852, 855, 857, 861, 863, 867, 869, 873, + 875, 879, 881, 885, 887, 889, 893, 897, 898, 901, + 902, 904, 905, 907, 908, 910, 911, 913, 914, 916, + 917, 919, 920, 922, 923, 925, 926, 928, 933, 938, + 944, 951, 956, 961, 963, 965, 967, 969, 971, 973, + 975, 977, 979, 983, 988, 994, 999, 1004, 1007, 1010, + 1015, 1019, 1023, 1029, 1033, 1038, 1042, 1048, 1050, 1051, + 1053, 1057, 1059, 1061, 1064, 1066, 1068, 1074, 1075, 1078, + 1080, 1084, 1086, 1090, 1092 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int16 yyrhs[] = +{ + 77, 0, -1, 79, 78, 81, 162, -1, -1, 25, + 137, 62, -1, -1, 80, 86, 88, -1, -1, 81, + 82, 62, -1, 21, 83, -1, 21, 59, 84, 186, + 60, -1, 21, 59, 60, -1, 85, 86, 88, -1, + 85, 88, -1, 83, -1, 84, 62, 83, -1, 3, + -1, 137, 3, -1, 63, 3, -1, 25, 24, 87, + 62, -1, -1, 24, -1, -1, 89, 210, 64, 64, + -1, -1, 91, -1, 154, -1, 177, -1, 1, -1, + 32, 93, -1, 32, 59, 163, 186, 60, -1, 32, + 59, 60, -1, 92, 94, -1, 92, 59, 94, 186, + 60, -1, 92, 59, 94, 62, 164, 186, 60, -1, + 92, 59, 60, -1, 31, 97, -1, 31, 59, 165, + 186, 60, -1, 31, 59, 60, -1, 9, -1, 181, + 142, -1, 181, 142, 65, 182, -1, 181, 65, 182, + -1, 181, 142, 65, 182, -1, 181, 65, 182, -1, + 94, -1, 181, 142, -1, 181, -1, 137, -1, 96, + 142, -1, 123, -1, 123, 4, 123, -1, 182, 65, + 182, -1, 182, 8, 182, -1, 123, 42, -1, 123, + 37, -1, 6, 183, 66, -1, 6, 183, 65, 123, + 66, -1, 6, 183, 8, 123, 66, -1, 12, 66, + -1, -1, 67, 101, 179, 68, -1, -1, 99, 103, + 179, -1, -1, 104, 102, -1, -1, 35, 106, 179, + 68, -1, 182, 65, 26, 123, -1, 182, 8, 26, + 123, -1, 190, 62, 190, 62, 190, -1, 190, -1, + 107, -1, 108, 105, -1, -1, 16, 111, 109, -1, + 190, -1, 190, 62, 190, -1, -1, -1, -1, 20, + 114, 112, 115, 105, 116, 117, -1, -1, 14, 113, + -1, 14, 100, -1, -1, -1, 30, 119, 112, 120, + 35, 104, 68, -1, -1, 28, 122, 35, 104, 68, + -1, 124, -1, 123, 47, 123, -1, 123, 33, 123, + -1, 123, 38, 123, -1, 123, 46, 123, -1, 123, + 45, 123, -1, 123, 43, 123, -1, 123, 39, 123, + -1, 123, 40, 123, -1, 123, 49, 123, -1, 123, + 50, 123, -1, 123, 51, 123, -1, 123, 52, 123, + -1, 123, 53, 123, -1, 123, 54, 123, -1, 123, + 55, 123, -1, 123, 56, 123, -1, 123, 34, 123, + -1, 123, 44, 123, -1, 123, 48, 123, -1, 123, + 36, 123, -1, 130, -1, 53, 124, -1, 56, 124, + -1, 49, 124, -1, 50, 124, -1, 69, 124, -1, + 70, 124, -1, 52, 124, -1, 36, 124, -1, 130, + 59, 60, -1, 130, 59, 183, 187, 60, -1, 130, + 59, 183, 11, 187, 60, -1, 3, -1, 139, -1, + 130, 63, 137, -1, 130, 63, 59, 131, 60, -1, + 130, 63, 59, 31, 60, -1, 130, 71, 123, 72, + -1, 130, 71, 188, 66, 188, 72, -1, 125, -1, + 145, 59, 123, 60, -1, 146, 133, 127, 185, 68, + -1, 126, 67, 127, 185, 68, -1, 59, 131, 60, + 67, 127, 185, 68, -1, 161, -1, -1, 123, 66, + 129, -1, 123, -1, 67, 127, 185, 68, -1, 126, + -1, 59, 131, 60, -1, 123, -1, 143, -1, 142, + -1, 35, -1, 67, -1, 137, -1, 137, -1, -1, + 134, -1, 24, -1, 138, -1, 73, -1, 74, 3, + 63, 24, -1, 137, -1, 134, -1, 11, -1, 11, + 142, -1, 151, -1, 157, -1, 149, -1, 150, -1, + 148, -1, 59, 142, 60, -1, 151, -1, 157, -1, + 149, -1, 53, 143, -1, 157, -1, 149, -1, 150, + -1, 148, -1, 59, 142, 60, -1, 157, -1, 149, + -1, 149, -1, 151, -1, 157, -1, 149, -1, 150, + -1, 148, -1, 139, -1, 139, 63, 137, -1, 71, + 188, 72, 142, -1, 71, 11, 72, 142, -1, 7, + 144, -1, 7, 36, 142, -1, 23, 71, 142, 72, + 142, -1, 152, -1, 153, -1, 53, 142, -1, 36, + 7, 142, -1, 29, 133, 166, 186, 68, -1, 29, + 133, 68, -1, 22, 133, 167, 186, 68, -1, 22, + 133, 68, -1, 17, 155, 158, -1, 137, 59, 175, + 60, 159, -1, 59, 175, 60, 137, 59, 175, 60, + 159, -1, 196, 59, 191, 60, 206, -1, 59, 211, + 60, 137, 59, 191, 60, 206, -1, 17, 59, 175, + 60, 159, -1, -1, 67, 179, 68, -1, -1, 147, + -1, 59, 175, 60, -1, 157, -1, 160, 133, 179, + 68, -1, 160, 1, -1, -1, 162, 90, 62, -1, + 93, -1, 163, 62, 93, -1, 95, -1, 164, 62, + 95, -1, 97, -1, 165, 62, 97, -1, 168, -1, + 166, 62, 168, -1, 171, -1, 167, 62, 171, -1, + 180, 142, 194, -1, 170, 194, -1, 59, 170, 60, + 194, -1, 53, 170, 194, -1, 59, 53, 170, 60, + 194, -1, 53, 59, 170, 60, 194, -1, 24, -1, + 24, 63, 137, -1, 169, -1, 134, 172, -1, 169, + -1, 59, 169, 60, -1, 59, 175, 60, 159, -1, + 132, -1, 137, 132, -1, 137, 141, -1, 141, -1, + 173, -1, 174, 75, 173, -1, -1, 174, 187, -1, + -1, 100, -1, 91, -1, 177, -1, 1, -1, 98, + -1, 110, -1, 118, -1, 121, -1, 113, -1, -1, + 140, 66, 178, 176, -1, 15, -1, 5, 136, -1, + 10, 136, -1, 18, 125, -1, 13, 125, -1, 19, + 134, -1, 27, 189, -1, 176, -1, 179, 62, 176, + -1, 134, -1, 180, 75, 134, -1, 135, -1, 181, + 75, 135, -1, 123, -1, 182, 75, 123, -1, 131, + -1, 183, 75, 131, -1, 128, -1, 129, -1, 184, + 75, 128, -1, 184, 75, 129, -1, -1, 184, 187, + -1, -1, 62, -1, -1, 75, -1, -1, 123, -1, + -1, 182, -1, -1, 98, -1, -1, 211, -1, -1, + 212, -1, -1, 213, -1, -1, 3, -1, 21, 24, + 3, 62, -1, 32, 196, 198, 62, -1, 9, 196, + 65, 209, 62, -1, 9, 196, 198, 65, 209, 62, + -1, 31, 197, 198, 62, -1, 17, 156, 158, 62, + -1, 138, -1, 196, -1, 200, -1, 201, -1, 202, + -1, 200, -1, 202, -1, 138, -1, 24, -1, 71, + 72, 198, -1, 71, 3, 72, 198, -1, 23, 71, + 198, 72, 198, -1, 29, 67, 192, 68, -1, 22, + 67, 193, 68, -1, 53, 198, -1, 7, 199, -1, + 7, 59, 201, 60, -1, 7, 36, 198, -1, 36, + 7, 198, -1, 17, 59, 191, 60, 206, -1, 137, + 198, 194, -1, 137, 11, 198, 194, -1, 137, 198, + 194, -1, 137, 59, 191, 60, 206, -1, 198, -1, + -1, 207, -1, 59, 191, 60, -1, 198, -1, 3, + -1, 50, 3, -1, 137, -1, 208, -1, 59, 208, + 49, 208, 60, -1, -1, 210, 195, -1, 203, -1, + 211, 75, 203, -1, 204, -1, 212, 62, 204, -1, + 205, -1, 213, 62, 205, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 124, 124, 133, 140, 151, 151, 166, 167, 170, + 171, 172, 175, 208, 219, 220, 223, 230, 237, 246, + 259, 260, 267, 267, 280, 284, 285, 289, 294, 300, + 304, 308, 312, 318, 324, 330, 335, 339, 343, 349, + 355, 359, 363, 369, 373, 379, 380, 384, 390, 399, + 405, 409, 414, 426, 442, 447, 454, 474, 492, 501, + 520, 519, 531, 530, 561, 564, 571, 570, 581, 587, + 596, 607, 613, 616, 624, 623, 634, 640, 652, 656, + 661, 651, 673, 676, 680, 687, 691, 686, 709, 708, + 724, 725, 729, 733, 737, 741, 745, 749, 753, 757, + 761, 765, 769, 773, 777, 781, 785, 789, 793, 797, + 802, 808, 809, 813, 824, 828, 832, 836, 841, 845, + 855, 859, 864, 872, 876, 877, 888, 892, 896, 900, + 904, 905, 911, 918, 924, 931, 934, 941, 947, 948, + 955, 956, 974, 975, 978, 981, 985, 996, 1005, 1011, + 1014, 1017, 1024, 1025, 1031, 1040, 1048, 1060, 1065, 1071, + 1072, 1073, 1074, 1075, 1076, 1082, 1083, 1084, 1085, 1091, + 1092, 1093, 1094, 1095, 1101, 1102, 1105, 1108, 1109, 1110, + 1111, 1112, 1115, 1116, 1129, 1133, 1138, 1143, 1148, 1152, + 1153, 1156, 1162, 1169, 1175, 1182, 1188, 1199, 1210, 1239, + 1278, 1301, 1318, 1327, 1330, 1338, 1342, 1346, 1353, 1359, + 1364, 1376, 1379, 1387, 1388, 1394, 1395, 1401, 1405, 1411, + 1412, 1418, 1422, 1428, 1451, 1456, 1462, 1468, 1475, 1484, + 1493, 1508, 1514, 1519, 1523, 1530, 1543, 1544, 1550, 1556, + 1559, 1563, 1569, 1572, 1581, 1584, 1585, 1589, 1590, 1596, + 1597, 1598, 1599, 1600, 1602, 1601, 1616, 1621, 1625, 1629, + 1633, 1637, 1642, 1661, 1667, 1675, 1679, 1685, 1689, 1695, + 1699, 1705, 1709, 1718, 1722, 1726, 1730, 1736, 1739, 1747, + 1748, 1750, 1751, 1754, 1757, 1760, 1763, 1766, 1769, 1772, + 1775, 1778, 1781, 1784, 1787, 1790, 1793, 1799, 1803, 1807, + 1811, 1815, 1819, 1837, 1844, 1855, 1856, 1857, 1860, 1861, + 1864, 1868, 1878, 1882, 1886, 1890, 1894, 1898, 1902, 1908, + 1914, 1922, 1930, 1936, 1943, 1959, 1977, 1981, 1987, 1990, + 1993, 1997, 2007, 2011, 2026, 2034, 2035, 2045, 2046, 2049, + 2053, 2059, 2063, 2069, 2073 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +const char *yytname[] = +{ + "$end", "error", "$undefined", "LLITERAL", "LASOP", "LBREAK", "LCASE", + "LCHAN", "LCOLAS", "LCONST", "LCONTINUE", "LDDD", "LDEFAULT", "LDEFER", + "LELSE", "LFALL", "LFOR", "LFUNC", "LGO", "LGOTO", "LIF", "LIMPORT", + "LINTERFACE", "LMAP", "LNAME", "LPACKAGE", "LRANGE", "LRETURN", + "LSELECT", "LSTRUCT", "LSWITCH", "LTYPE", "LVAR", "LANDAND", "LANDNOT", + "LBODY", "LCOMM", "LDEC", "LEQ", "LGE", "LGT", "LIGNORE", "LINC", "LLE", + "LLSH", "LLT", "LNE", "LOROR", "LRSH", "'+'", "'-'", "'|'", "'^'", "'*'", + "'/'", "'%'", "'&'", "NotPackage", "NotParen", "'('", "')'", + "PreferToRightParen", "';'", "'.'", "'$'", "'='", "':'", "'{'", "'}'", + "'!'", "'~'", "'['", "']'", "'?'", "'@'", "','", "$accept", "file", + "package", "loadsys", "$@1", "imports", "import", "import_stmt", + "import_stmt_list", "import_here", "import_package", "import_safety", + "import_there", "$@2", "xdcl", "common_dcl", "lconst", "vardcl", + "constdcl", "constdcl1", "typedclname", "typedcl", "simple_stmt", "case", + "compound_stmt", "$@3", "caseblock", "$@4", "caseblock_list", + "loop_body", "$@5", "range_stmt", "for_header", "for_body", "for_stmt", + "$@6", "if_header", "if_stmt", "$@7", "$@8", "$@9", "else", + "switch_stmt", "$@10", "$@11", "select_stmt", "$@12", "expr", "uexpr", + "pseudocall", "pexpr_no_paren", "start_complit", "keyval", "complitexpr", + "pexpr", "expr_or_type", "name_or_type", "lbrace", "new_name", + "dcl_name", "onew_name", "sym", "hidden_importsym", "name", "labelname", + "dotdotdot", "ntype", "non_expr_type", "non_recvchantype", "convtype", + "comptype", "fnret_type", "dotname", "othertype", "ptrtype", + "recvchantype", "structtype", "interfacetype", "xfndcl", "fndcl", + "hidden_fndcl", "fntype", "fnbody", "fnres", "fnlitdcl", "fnliteral", + "xdcl_list", "vardcl_list", "constdcl_list", "typedcl_list", + "structdcl_list", "interfacedcl_list", "structdcl", "packname", "embed", + "interfacedcl", "indcl", "arg_type", "arg_type_list", + "oarg_type_list_ocomma", "stmt", "non_dcl_stmt", "$@13", "stmt_list", + "new_name_list", "dcl_name_list", "expr_list", "expr_or_type_list", + "keyval_list", "braced_keyval_list", "osemi", "ocomma", "oexpr", + "oexpr_list", "osimple_stmt", "ohidden_funarg_list", + "ohidden_structdcl_list", "ohidden_interfacedcl_list", "oliteral", + "hidden_import", "hidden_pkg_importsym", "hidden_pkgtype", "hidden_type", + "hidden_type_non_recv_chan", "hidden_type_misc", "hidden_type_recv_chan", + "hidden_type_func", "hidden_funarg", "hidden_structdcl", + "hidden_interfacedcl", "ohidden_funres", "hidden_funres", + "hidden_literal", "hidden_constant", "hidden_import_list", + "hidden_funarg_list", "hidden_structdcl_list", + "hidden_interfacedcl_list", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 43, + 45, 124, 94, 42, 47, 37, 38, 304, 305, 40, + 41, 306, 59, 46, 36, 61, 58, 123, 125, 33, + 126, 91, 93, 63, 64, 44 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 76, 77, 78, 78, 80, 79, 81, 81, 82, + 82, 82, 83, 83, 84, 84, 85, 85, 85, 86, + 87, 87, 89, 88, 90, 90, 90, 90, 90, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 92, + 93, 93, 93, 94, 94, 95, 95, 95, 96, 97, + 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, + 101, 100, 103, 102, 104, 104, 106, 105, 107, 107, + 108, 108, 108, 109, 111, 110, 112, 112, 114, 115, + 116, 113, 117, 117, 117, 119, 120, 118, 122, 121, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 124, 124, 124, 124, 124, 124, 124, 124, 124, + 125, 125, 125, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 127, 128, 129, 129, + 130, 130, 131, 131, 132, 133, 133, 134, 135, 136, + 136, 137, 137, 137, 138, 139, 140, 141, 141, 142, + 142, 142, 142, 142, 142, 143, 143, 143, 143, 144, + 144, 144, 144, 144, 145, 145, 146, 147, 147, 147, + 147, 147, 148, 148, 149, 149, 149, 149, 149, 149, + 149, 150, 151, 152, 152, 153, 153, 154, 155, 155, + 156, 156, 157, 158, 158, 159, 159, 159, 160, 161, + 161, 162, 162, 163, 163, 164, 164, 165, 165, 166, + 166, 167, 167, 168, 168, 168, 168, 168, 168, 169, + 169, 170, 171, 171, 171, 172, 173, 173, 173, 173, + 174, 174, 175, 175, 176, 176, 176, 176, 176, 177, + 177, 177, 177, 177, 178, 177, 177, 177, 177, 177, + 177, 177, 177, 179, 179, 180, 180, 181, 181, 182, + 182, 183, 183, 184, 184, 184, 184, 185, 185, 186, + 186, 187, 187, 188, 188, 189, 189, 190, 190, 191, + 191, 192, 192, 193, 193, 194, 194, 195, 195, 195, + 195, 195, 195, 196, 197, 198, 198, 198, 199, 199, + 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, + 200, 201, 202, 203, 203, 204, 205, 205, 206, 206, + 207, 207, 208, 208, 208, 209, 209, 210, 210, 211, + 211, 212, 212, 213, 213 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 4, 0, 3, 0, 3, 0, 3, 2, + 5, 3, 3, 2, 1, 3, 1, 2, 2, 4, + 0, 1, 0, 4, 0, 1, 1, 1, 1, 2, + 5, 3, 2, 5, 7, 3, 2, 5, 3, 1, + 2, 4, 3, 4, 3, 1, 2, 1, 1, 2, + 1, 3, 3, 3, 2, 2, 3, 5, 5, 2, + 0, 4, 0, 3, 0, 2, 0, 4, 4, 4, + 5, 1, 1, 2, 0, 3, 1, 3, 0, 0, + 0, 7, 0, 2, 2, 0, 0, 7, 0, 5, + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 5, 6, 1, 1, 3, 5, 5, 4, 6, + 1, 4, 5, 5, 7, 1, 0, 3, 1, 4, + 1, 3, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 4, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 3, 1, 1, 1, 2, 1, + 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 4, 4, 2, 3, 5, 1, + 1, 2, 3, 5, 3, 5, 3, 3, 5, 8, + 5, 8, 5, 0, 3, 0, 1, 3, 1, 4, + 2, 0, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 3, 2, 4, 3, 5, 5, 1, + 3, 1, 2, 1, 3, 4, 1, 2, 2, 1, + 1, 3, 0, 2, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 4, 1, 2, 2, 2, + 2, 2, 2, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 1, 1, 3, 3, 0, 2, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 4, 4, 5, + 6, 4, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 4, 5, 4, 4, 2, 2, 4, + 3, 3, 5, 3, 4, 3, 5, 1, 0, 1, + 3, 1, 1, 2, 1, 1, 5, 0, 2, 1, + 3, 1, 3, 1, 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint16 yydefact[] = +{ + 5, 0, 3, 0, 1, 0, 7, 0, 22, 151, + 153, 0, 0, 152, 211, 20, 6, 337, 0, 4, + 0, 0, 0, 21, 0, 0, 0, 16, 0, 0, + 9, 22, 0, 8, 28, 123, 149, 0, 39, 149, + 0, 256, 74, 0, 0, 0, 78, 0, 0, 285, + 88, 0, 85, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 283, 0, 25, 0, 249, 250, + 253, 251, 252, 50, 90, 130, 140, 111, 156, 155, + 124, 0, 0, 0, 176, 189, 190, 26, 208, 0, + 135, 27, 0, 19, 0, 0, 0, 0, 0, 0, + 338, 154, 11, 14, 279, 18, 22, 13, 17, 150, + 257, 147, 0, 0, 0, 0, 155, 182, 186, 172, + 170, 171, 169, 258, 130, 0, 287, 242, 0, 203, + 130, 261, 287, 145, 146, 0, 0, 269, 286, 262, + 0, 0, 287, 0, 0, 36, 48, 0, 29, 267, + 148, 0, 119, 114, 115, 118, 112, 113, 0, 0, + 142, 0, 143, 167, 165, 166, 116, 117, 0, 284, + 0, 212, 0, 32, 0, 0, 0, 0, 0, 55, + 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 136, 0, + 0, 283, 254, 0, 136, 210, 0, 0, 0, 0, + 303, 0, 0, 203, 0, 0, 304, 0, 0, 23, + 280, 0, 12, 242, 0, 0, 187, 163, 161, 162, + 159, 160, 191, 0, 0, 288, 72, 0, 75, 0, + 71, 157, 236, 155, 239, 144, 240, 281, 0, 242, + 0, 197, 79, 76, 151, 0, 196, 0, 279, 233, + 221, 0, 64, 0, 0, 194, 265, 279, 219, 231, + 295, 0, 86, 38, 217, 279, 49, 31, 213, 279, + 0, 0, 40, 0, 168, 141, 0, 0, 35, 279, + 0, 0, 51, 92, 107, 110, 93, 97, 98, 96, + 108, 95, 94, 91, 109, 99, 100, 101, 102, 103, + 104, 105, 106, 277, 120, 271, 281, 0, 125, 284, + 0, 0, 0, 277, 248, 60, 246, 245, 263, 247, + 0, 53, 52, 270, 0, 0, 0, 0, 311, 0, + 0, 0, 0, 0, 310, 0, 305, 306, 307, 0, + 339, 0, 0, 289, 0, 0, 0, 15, 10, 0, + 0, 0, 173, 183, 66, 73, 0, 0, 287, 158, + 237, 238, 282, 243, 205, 0, 0, 0, 287, 0, + 229, 0, 242, 232, 280, 0, 0, 0, 0, 295, + 0, 0, 280, 0, 296, 224, 0, 295, 0, 280, + 0, 280, 0, 42, 268, 0, 0, 0, 192, 163, + 161, 162, 160, 136, 185, 184, 280, 0, 44, 0, + 136, 138, 273, 274, 281, 0, 281, 282, 0, 0, + 0, 128, 283, 255, 131, 0, 0, 0, 209, 0, + 0, 318, 308, 309, 289, 293, 0, 291, 0, 317, + 332, 0, 0, 334, 335, 0, 0, 0, 0, 0, + 295, 0, 0, 302, 0, 290, 297, 301, 298, 205, + 164, 0, 0, 0, 0, 241, 242, 155, 206, 181, + 179, 180, 177, 178, 202, 205, 204, 80, 77, 230, + 234, 0, 222, 195, 188, 0, 0, 89, 62, 65, + 0, 226, 0, 295, 220, 193, 266, 223, 64, 218, + 37, 214, 30, 41, 0, 277, 45, 215, 279, 47, + 33, 43, 277, 0, 282, 278, 133, 282, 0, 272, + 121, 127, 126, 0, 132, 0, 264, 320, 0, 0, + 311, 0, 310, 0, 327, 343, 294, 0, 0, 0, + 341, 292, 321, 333, 0, 299, 0, 312, 0, 295, + 323, 0, 340, 328, 0, 69, 68, 287, 0, 242, + 198, 82, 205, 0, 59, 0, 295, 295, 225, 0, + 164, 0, 280, 0, 46, 0, 138, 137, 275, 276, + 122, 129, 61, 319, 328, 289, 316, 0, 0, 295, + 315, 0, 0, 313, 300, 324, 289, 289, 331, 200, + 329, 67, 70, 207, 0, 0, 81, 235, 0, 0, + 56, 0, 63, 228, 227, 87, 134, 216, 34, 139, + 322, 0, 344, 314, 325, 342, 0, 0, 0, 205, + 84, 83, 0, 0, 328, 336, 328, 330, 199, 58, + 57, 326, 201 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int16 yydefgoto[] = +{ + -1, 1, 6, 2, 3, 14, 21, 30, 104, 31, + 8, 24, 16, 17, 65, 326, 67, 148, 516, 517, + 144, 145, 68, 498, 327, 436, 499, 575, 387, 365, + 471, 236, 237, 238, 69, 126, 252, 70, 132, 377, + 571, 616, 71, 142, 398, 72, 140, 73, 74, 75, + 76, 313, 422, 423, 77, 315, 242, 135, 78, 149, + 110, 116, 13, 80, 81, 244, 245, 162, 118, 82, + 83, 478, 227, 84, 229, 230, 85, 86, 87, 129, + 213, 88, 251, 484, 89, 90, 22, 279, 518, 275, + 267, 258, 268, 269, 270, 260, 383, 246, 247, 248, + 328, 329, 321, 330, 271, 151, 92, 316, 424, 425, + 221, 373, 170, 139, 253, 464, 549, 543, 395, 100, + 211, 217, 608, 441, 346, 347, 348, 350, 550, 545, + 609, 610, 454, 455, 25, 465, 551, 546 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -551 +static const yytype_int16 yypact[] = +{ + -551, 46, 48, 121, -551, 58, -551, 135, -551, -551, + -551, 65, 72, -551, 147, 156, -551, -551, 112, -551, + 50, 134, 904, -551, 162, 463, 209, -551, 54, 237, + -551, 121, 245, -551, -551, -551, 58, 1666, -551, 58, + 288, -551, -551, 34, 288, 58, -551, 36, 184, 1467, + -551, 36, -551, 316, 462, 1467, 1467, 1467, 1467, 1467, + 1467, 1522, 1467, 1467, 965, 198, -551, 506, -551, -551, + -551, -551, -551, 796, -551, -551, 195, 1, -551, 199, + -551, 207, 216, 36, 221, -551, -551, -551, 226, 53, + -551, -551, 108, -551, 214, 110, 269, 214, 214, 233, + -551, -551, -551, -551, 238, -551, -551, -551, -551, -551, + -551, -551, 242, 1691, 1691, 1691, -551, 240, -551, -551, + -551, -551, -551, -551, 154, 1, 1467, 1658, 247, 246, + 290, -551, 1467, -551, -551, 419, 1691, 2004, 229, -551, + 272, 333, 1467, 258, 1691, -551, -551, 485, -551, -551, + -551, 656, -551, -551, -551, -551, -551, -551, 1577, 1522, + 2004, 255, -551, 10, -551, 51, -551, -551, 251, 2004, + 256, -551, 508, -551, 1632, 1467, 1467, 1467, 1467, -551, + 1467, 1467, 1467, -551, 1467, 1467, 1467, 1467, 1467, 1467, + 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467, -551, 1192, + 552, 1467, -551, 1467, -551, -551, 1134, 1467, 1467, 1467, + -551, 1203, 58, 246, 260, 332, -551, 1838, 1838, -551, + 76, 282, -551, 1658, 344, 1691, -551, -551, -551, -551, + -551, -551, -551, 293, 58, -551, -551, 328, -551, 178, + 303, 1691, -551, 1658, -551, -551, -551, 295, 308, 1658, + 1134, -551, -551, 309, 271, 364, -551, 334, 337, -551, + -551, 330, -551, 11, 66, -551, -551, 342, -551, -551, + 397, 664, -551, -551, -551, 351, -551, -551, -551, 352, + 1467, 58, 343, 1719, -551, 349, 1691, 1691, -551, 356, + 1467, 357, 2004, 2075, -551, 2028, 692, 692, 692, 692, + -551, 692, 692, 2052, -551, 593, 593, 593, 593, -551, + -551, -551, -551, 1247, -551, -551, 22, 1302, -551, 1877, + 355, 1060, 1979, 1247, -551, -551, -551, -551, -551, -551, + 86, 229, 229, 2004, 1777, 367, 361, 359, -551, 366, + 427, 1838, 52, 29, -551, 370, -551, -551, -551, 784, + -551, 118, 379, 58, 396, 400, 401, -551, -551, 404, + 1691, 409, -551, -551, -551, -551, 1357, 1412, 1467, -551, + -551, -551, 1658, -551, 1744, 414, 109, 328, 1467, 58, + 416, 423, 1658, -551, 561, 417, 1691, 44, 364, 397, + 364, 428, 451, 421, -551, -551, 58, 397, 456, 58, + 436, 58, 438, 229, -551, 1467, 1752, 1691, -551, 24, + 171, 287, 338, -551, -551, -551, 58, 439, 229, 1467, + -551, 1907, -551, -551, 425, 435, 430, 1522, 446, 448, + 453, -551, 1467, -551, -551, 443, 1134, 1060, -551, 1838, + 479, -551, -551, -551, 58, 1805, 1838, 58, 1838, -551, + -551, 514, 161, -551, -551, 460, 454, 1838, 52, 1838, + 397, 58, 58, -551, 458, 459, -551, -551, -551, 1744, + -551, 1134, 1467, 1467, 467, -551, 1658, 472, -551, -551, + -551, -551, -551, -551, -551, 1744, -551, -551, -551, -551, + -551, 477, -551, -551, -551, 1522, 474, -551, -551, -551, + 482, -551, 500, 397, -551, -551, -551, -551, -551, -551, + -551, -551, -551, 229, 501, 1247, -551, -551, 505, 1632, + -551, 229, 1247, 1247, 1247, -551, -551, -551, 503, -551, + -551, -551, -551, 511, -551, 137, -551, -551, 518, 528, + 532, 534, 535, 530, -551, -551, 537, 533, 1838, 536, + -551, 538, -551, -551, 560, -551, 1838, -551, 551, 397, + -551, 557, -551, 1830, 151, 2004, 2004, 1467, 558, 1658, + -551, 605, 1744, 125, -551, 1060, 397, 397, -551, 75, + 360, 554, 58, 563, 357, 556, 2004, -551, -551, -551, + -551, -551, -551, -551, 1830, 58, -551, 1805, 1838, 397, + -551, 58, 161, -551, -551, -551, 58, 58, -551, -551, + -551, -551, -551, -551, 570, 78, -551, -551, 1467, 1467, + -551, 1522, 569, -551, -551, -551, -551, -551, -551, -551, + -551, 576, -551, -551, -551, -551, 578, 582, 584, 1744, + -551, -551, 1931, 1955, 1830, -551, 1830, -551, -551, -551, + -551, -551, -551 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int16 yypgoto[] = +{ + -551, -551, -551, -551, -551, -551, -551, -6, -551, -551, + 608, -551, -11, -551, -551, 623, -551, -134, -25, 68, + -551, -135, -121, -551, 39, -551, -551, -551, 145, 278, + -551, -551, -551, -551, -551, -551, 515, 41, -551, -551, + -551, -551, -551, -551, -551, -551, -551, 579, 493, 45, + -551, -192, 138, -246, 192, -47, 415, 200, -20, 380, + 626, -5, 449, 346, -551, 426, 95, 509, -551, -551, + -551, -551, -33, 38, -31, -18, -551, -551, -551, -551, + -551, 43, 457, -467, -551, -551, -551, -551, -551, -551, + -551, -551, 280, -126, -227, 292, -551, 302, -551, -220, + -297, 662, -551, -248, -551, -66, 18, 194, -551, -295, + -228, -289, -191, -551, -119, -403, -551, -551, -305, -551, + -32, -551, 127, -551, 362, 250, 363, 232, 90, 98, + -550, -551, -426, 241, -551, 486, -551, -551 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -270 +static const yytype_int16 yytable[] = +{ + 12, 174, 376, 359, 119, 235, 121, 240, 274, 259, + 320, 235, 323, 278, 161, 32, 109, 79, 570, 109, + 107, 235, 103, 32, 433, 131, 554, 428, 435, 375, + 385, 111, 456, 426, 111, 380, 389, 391, 128, 393, + 111, 539, 173, 164, 630, -176, 4, 400, 146, 150, + 495, 402, -208, 27, 205, 450, 496, 27, 9, -172, + 199, 417, 150, 214, 200, 216, 218, 138, 18, -175, + 388, 133, 201, 5, 9, 120, 9, -176, 9, 27, + 122, 495, 9, -172, 501, 124, -208, 496, 133, 130, + 380, -172, 507, 127, 651, 222, 652, 427, 46, 163, + 9, 457, 451, 134, 165, 617, 174, 10, 11, 28, + -174, 452, 497, 29, 102, 257, 207, 29, -208, 390, + 134, 266, 243, 10, 11, 10, 11, 10, 11, 381, + 111, 10, 11, 618, 19, 525, 111, 528, 146, 29, + 536, 164, 150, 625, 239, 325, 7, 289, 437, 10, + 11, 228, 228, 228, 438, 560, 231, 231, 231, 15, + -260, 500, 491, 502, 450, 228, -260, 150, 20, 212, + 231, 437, 648, 208, 228, 26, 636, 486, 461, 231, + 23, 164, 228, 209, 11, 9, 366, 231, 535, 228, + 619, 620, 631, 462, 231, 318, 33, 163, 578, 437, + 621, 79, 165, 637, 638, 592, -170, 349, 226, 232, + 233, 451, 228, 437, 357, 32, -260, 231, 243, 611, + 581, 515, -260, 564, 93, 331, 332, 585, 522, 363, + -170, 261, 125, 101, 10, 11, 125, 163, -170, 276, + 105, 533, 165, 367, 243, 79, 282, 235, 108, 474, + 409, 141, 411, 209, 605, 136, 568, 235, 259, 488, + 171, 228, 198, 228, 509, -147, 231, 511, 231, 291, + 430, 623, 624, 202, -229, 203, 150, 587, 589, 228, + -175, 228, 9, 204, 231, -174, 231, 228, 11, 206, + 583, 35, 231, 215, 634, 37, -259, 219, 403, 164, + 220, 223, -259, 234, 209, 112, 249, 262, 418, 228, + 47, 48, 9, 250, 231, 285, 79, 51, 273, 353, + 361, 410, -171, 286, 228, 228, 412, 622, 287, 231, + 231, 10, 11, -229, 379, 354, 369, 453, 345, -229, + 9, 479, 358, 481, 355, 356, -171, 61, 349, 614, + 519, 360, -259, 362, -171, 163, 482, 254, -259, 64, + 165, 10, 11, 364, 257, 368, 397, 243, 374, 477, + 372, 378, 266, -169, 489, 143, 506, 243, 408, 111, + 529, 414, 415, 117, 331, 332, 263, 111, 380, 10, + 11, 111, 264, 382, 146, -173, 150, -169, 228, 384, + 394, 265, 386, 231, 392, -169, 10, 11, 405, 164, + 228, 150, 480, 399, 401, 231, 413, 483, 416, -173, + 228, 432, 419, 513, 228, 231, 444, -173, 445, 231, + 446, 79, 79, 447, 448, 458, 479, 521, 481, 349, + 541, 463, 548, 254, 228, 228, 235, 453, 612, 231, + 231, 482, 479, 453, 481, 408, 561, 349, 466, 117, + 117, 117, 467, 468, 469, 163, 79, 482, 449, 470, + 165, 243, 94, 117, 485, 254, 460, 164, 255, 379, + 95, 494, 117, 490, 96, 493, 9, 256, 503, 505, + 117, 508, 10, 11, 97, 98, 510, 117, 512, 520, + 524, 226, 514, 526, 263, 527, 530, 480, 531, 9, + 264, 534, 483, 532, 228, 340, 519, 553, 563, 231, + 117, 147, 555, 480, 10, 11, 556, 99, 483, 567, + 9, 569, 9, 163, 462, 10, 11, 572, 165, 479, + 574, 481, 576, 210, 210, 277, 210, 210, 152, 153, + 154, 155, 156, 157, 482, 166, 167, 228, 10, 11, + 577, 580, 231, 590, 243, 172, 537, 582, 288, 117, + 79, 117, 544, 547, 529, 552, 9, 150, 593, 10, + 11, 10, 11, 591, 557, 254, 559, 117, 594, 117, + 349, -151, 541, 595, -152, 117, 548, 453, 596, 597, + 601, 349, 349, 164, 600, 598, 479, 228, 481, 602, + 480, 317, 231, 604, 584, 483, 606, 117, 613, 615, + 255, 482, 626, 628, 629, 10, 11, 177, 137, 117, + 639, 437, 117, 117, 10, 11, 644, 185, 645, 106, + 160, 189, 646, 169, 647, 66, 194, 195, 196, 197, + 627, 152, 156, 579, 640, 487, 641, 272, 370, 163, + 344, 404, 588, 37, 165, 123, 344, 344, 284, 371, + 352, 37, 504, 112, 475, 599, 492, 480, 47, 48, + 9, 112, 483, 603, 91, 51, 47, 48, 9, 573, + 538, 635, 224, 51, 562, 632, 442, 443, 351, 558, + 224, 0, 0, 0, 0, 0, 117, 0, 0, 114, + 0, 0, 0, 0, 0, 225, 0, 114, 117, 0, + 117, 280, 0, 225, 544, 633, 177, 64, 117, 10, + 11, 281, 117, 0, 0, 64, 185, 10, 11, 396, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 0, + 0, 0, 117, 117, 292, 293, 294, 295, 0, 296, + 297, 298, 0, 299, 300, 301, 302, 303, 304, 305, + 306, 307, 308, 309, 310, 311, 312, 0, 160, 0, + 319, 0, 322, 344, 0, 0, 137, 137, 333, 0, + 344, 334, 0, 0, 0, 459, 0, 0, 344, 0, + 175, 335, 0, 0, -269, 0, 336, 337, 338, 0, + 0, 0, 0, 339, 0, 117, 0, 0, 0, 0, + 340, 0, 117, 0, 0, 0, 0, 0, 0, 176, + 177, 117, 178, 179, 180, 181, 182, 341, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 0, 0, 343, 0, 0, 11, 137, + 0, -269, 0, 0, 0, 117, 0, 0, 0, 137, + 0, -269, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 344, 0, + 0, 0, 421, 0, 542, 344, 160, 344, 0, 0, + 0, 0, 421, 0, -2, 34, 344, 35, 344, 36, + 0, 37, 0, 38, 39, 117, 0, 40, 117, 41, + 42, 43, 44, 45, 46, 0, 47, 48, 9, 0, + 0, 49, 50, 51, 52, 53, 54, 0, 0, 0, + 55, 0, 0, 0, 0, 137, 137, 0, 0, 0, + 0, 0, 0, 56, 57, 0, 58, 59, 0, 0, + 60, 0, 0, 61, 0, 0, -24, 0, 35, 0, + 0, 0, 37, 62, 63, 64, 168, 10, 11, 0, + 0, 0, 112, 0, 137, 117, 0, 47, 48, 9, + 0, 0, 0, 0, 51, 0, 0, 344, 137, 0, + 0, 55, 0, 0, 0, 344, 160, 0, 0, 0, + 0, 169, 344, 0, 56, 57, 0, 58, 59, 0, + 0, 60, 0, 0, 61, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 62, 63, 64, 0, 10, 11, + 0, 0, 0, 344, 0, 0, 542, 344, 0, 0, + 0, 565, 566, 0, 0, 0, 0, 0, 0, 0, + 0, 324, 0, 35, 0, 36, -244, 37, 0, 38, + 39, 0, -244, 40, 160, 41, 42, 112, 44, 45, + 46, 0, 47, 48, 9, 0, 0, 49, 50, 51, + 52, 53, 54, 344, 421, 344, 55, 0, 0, 0, + 0, 421, 586, 421, 0, 0, 0, 0, 0, 56, + 57, 0, 58, 59, 0, 0, 60, 0, 0, 61, + 0, 0, -244, 0, 0, 0, 0, 325, -244, 62, + 63, 64, 0, 10, 11, 324, 0, 35, 0, 36, + 0, 37, 0, 38, 39, 0, 0, 40, 0, 41, + 42, 112, 44, 45, 46, 0, 47, 48, 9, 0, + 0, 49, 50, 51, 52, 53, 54, 0, 0, 0, + 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 56, 57, 0, 58, 59, 0, 0, + 60, 0, 0, 61, 0, 35, -244, 642, 643, 37, + 160, 325, -244, 62, 63, 64, 0, 10, 11, 112, + 334, 0, 0, 0, 47, 48, 9, 0, 0, 0, + 335, 51, 0, 0, 0, 336, 337, 338, 158, 0, + 0, 0, 339, 0, 0, 0, 0, 0, 0, 340, + 0, 56, 57, 0, 58, 159, 0, 0, 60, 0, + 35, 61, 314, 0, 37, 0, 341, 0, 0, 0, + 0, 62, 63, 64, 112, 10, 11, 0, 342, 47, + 48, 9, 0, 0, 343, 0, 51, 11, 0, 0, + 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 56, 57, 0, 58, + 59, 0, 0, 60, 0, 35, 61, 0, 0, 37, + 0, 0, 0, 0, 420, 0, 62, 63, 64, 112, + 10, 11, 0, 0, 47, 48, 9, 0, 0, 0, + 0, 51, 0, 429, 0, 0, 0, 0, 158, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 56, 57, 0, 58, 159, 0, 0, 60, 0, + 35, 61, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 62, 63, 64, 112, 10, 11, 0, 0, 47, + 48, 9, 0, 472, 0, 0, 51, 0, 0, 0, + 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 56, 57, 0, 58, + 59, 0, 0, 60, 0, 35, 61, 0, 0, 37, + 0, 0, 0, 0, 0, 0, 62, 63, 64, 112, + 10, 11, 0, 0, 47, 48, 9, 0, 473, 0, + 0, 51, 0, 0, 0, 0, 0, 0, 55, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 56, 57, 0, 58, 59, 0, 0, 60, 0, + 35, 61, 0, 0, 37, 0, 0, 0, 0, 0, + 0, 62, 63, 64, 112, 10, 11, 0, 0, 47, + 48, 9, 0, 0, 0, 0, 51, 0, 0, 0, + 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 56, 57, 0, 58, + 59, 0, 0, 60, 0, 35, 61, 0, 0, 37, + 0, 0, 0, 0, 0, 0, 62, 63, 64, 112, + 10, 11, 0, 0, 47, 48, 9, 0, 0, 0, + 0, 51, 0, 0, 0, 0, 0, 0, 158, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 56, 57, 0, 58, 159, 0, 0, 60, 0, + 35, 61, 0, 0, 283, 0, 0, 0, 0, 0, + 0, 62, 63, 64, 112, 10, 11, 0, 0, 47, + 48, 9, 0, 0, 0, 0, 51, 0, 0, 0, + 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 56, 57, 0, 58, + 59, 0, 0, 60, 0, 0, 61, 0, 0, 37, + 0, 0, 0, 0, 0, 0, 62, 63, 64, 112, + 10, 11, 0, 0, 47, 48, 9, 0, 0, 0, + 0, 51, 0, 0, 0, 37, 0, 0, 224, 241, + 0, 0, 0, 37, 0, 112, 0, 0, 0, 0, + 47, 48, 9, 112, 0, 114, 0, 51, 47, 48, + 9, 225, 0, 0, 224, 51, 0, 290, 37, 0, + 0, 0, 113, 64, 0, 10, 11, 281, 112, 0, + 0, 114, 0, 47, 48, 9, 0, 225, 0, 114, + 51, 0, 0, 0, 0, 115, 37, 224, 0, 64, + 0, 10, 11, 0, 0, 0, 112, 64, 0, 10, + 11, 47, 48, 9, 114, 0, 0, 0, 51, 0, + 225, 37, 0, 0, 0, 406, 0, 0, 0, 283, + 0, 112, 64, 0, 10, 11, 47, 48, 9, 112, + 0, 0, 114, 51, 47, 48, 9, 0, 407, 0, + 224, 51, 0, 0, 334, 0, 0, 0, 224, 0, + 64, 0, 10, 11, 335, 0, 0, 114, 0, 336, + 337, 338, 0, 476, 0, 114, 339, 0, 0, 0, + 0, 225, 334, 439, 0, 64, 0, 10, 11, 0, + 0, 0, 335, 64, 0, 10, 11, 336, 337, 540, + 341, 0, 0, 0, 339, 0, 440, 334, 0, 0, + 0, 340, 0, 0, 0, 334, 0, 335, 343, 0, + 0, 11, 336, 337, 338, 335, 0, 0, 341, 339, + 336, 337, 338, 0, 0, 0, 340, 339, 0, 0, + 0, 0, 0, 0, 340, 0, 343, 0, 10, 11, + 0, 0, 0, 341, 0, 0, 0, 0, 0, 607, + 0, 341, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 343, 0, 0, 11, 0, 0, 0, 0, 343, + 176, 177, 11, 178, 0, 180, 181, 182, 0, 0, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 0, 0, 0, 0, 0, 0, + 176, 177, 0, 178, 0, 180, 181, 182, 0, 431, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 176, 177, 0, 178, 0, 180, + 181, 182, 0, 523, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 176, 177, + 0, 178, 0, 180, 181, 182, 0, 649, 184, 185, + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 176, 177, 0, 178, 0, 180, 181, 182, + 0, 650, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 0, 176, 177, 434, + 178, 0, 180, 181, 182, 0, 0, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 176, 177, 0, 0, 0, 180, 181, 182, 0, + 0, 184, 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 176, 177, 0, 0, 0, + 180, 181, 182, 0, 0, 184, 185, 186, 187, 0, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 177, + 0, 0, 0, 180, 181, 182, 0, 0, 184, 185, + 186, 187, 0, 189, 190, 191, 192, 193, 194, 195, + 196, 197 +}; + +#define yypact_value_is_default(yystate) \ + ((yystate) == (-551)) + +#define yytable_value_is_error(yytable_value) \ + YYID (0) + +static const yytype_int16 yycheck[] = +{ + 5, 67, 250, 223, 37, 126, 37, 126, 143, 135, + 201, 132, 204, 147, 61, 20, 36, 22, 485, 39, + 31, 142, 28, 28, 321, 45, 452, 316, 323, 249, + 258, 36, 3, 11, 39, 24, 263, 264, 43, 267, + 45, 444, 67, 61, 594, 35, 0, 275, 53, 54, + 6, 279, 1, 3, 1, 3, 12, 3, 24, 35, + 59, 289, 67, 95, 63, 97, 98, 49, 3, 59, + 59, 35, 71, 25, 24, 37, 24, 67, 24, 3, + 37, 6, 24, 59, 389, 40, 35, 12, 35, 44, + 24, 67, 397, 59, 644, 106, 646, 75, 20, 61, + 24, 72, 50, 67, 61, 572, 172, 73, 74, 59, + 59, 59, 68, 63, 60, 135, 8, 63, 67, 53, + 67, 141, 127, 73, 74, 73, 74, 73, 74, 255, + 135, 73, 74, 8, 62, 424, 141, 426, 143, 63, + 437, 159, 147, 68, 126, 67, 25, 172, 62, 73, + 74, 113, 114, 115, 68, 460, 113, 114, 115, 24, + 6, 388, 382, 390, 3, 127, 12, 172, 21, 59, + 127, 62, 639, 65, 136, 63, 602, 68, 60, 136, + 24, 199, 144, 75, 74, 24, 8, 144, 436, 151, + 65, 66, 595, 75, 151, 200, 62, 159, 503, 62, + 75, 206, 159, 606, 607, 68, 35, 212, 113, 114, + 115, 50, 174, 62, 220, 220, 62, 174, 223, 68, + 515, 413, 68, 471, 62, 207, 208, 522, 420, 234, + 59, 136, 40, 24, 73, 74, 44, 199, 67, 144, + 3, 432, 199, 65, 249, 250, 151, 368, 3, 368, + 283, 51, 283, 75, 559, 71, 476, 378, 384, 378, + 62, 223, 67, 225, 399, 66, 223, 401, 225, 174, + 317, 576, 577, 66, 3, 59, 281, 523, 524, 241, + 59, 243, 24, 83, 241, 59, 243, 249, 74, 89, + 518, 3, 249, 24, 599, 7, 6, 64, 280, 317, + 62, 59, 12, 63, 75, 17, 59, 35, 290, 271, + 22, 23, 24, 67, 271, 60, 321, 29, 60, 59, + 225, 283, 35, 72, 286, 287, 283, 575, 72, 286, + 287, 73, 74, 62, 63, 3, 241, 342, 211, 68, + 24, 374, 60, 374, 217, 218, 59, 59, 353, 569, + 416, 7, 62, 60, 67, 317, 374, 24, 68, 71, + 317, 73, 74, 35, 384, 62, 271, 372, 60, 374, + 75, 62, 392, 35, 379, 59, 396, 382, 283, 384, + 427, 286, 287, 37, 366, 367, 53, 392, 24, 73, + 74, 396, 59, 59, 399, 35, 401, 59, 360, 62, + 3, 68, 72, 360, 62, 67, 73, 74, 65, 427, + 372, 416, 374, 62, 62, 372, 67, 374, 62, 59, + 382, 66, 65, 405, 386, 382, 59, 67, 67, 386, + 71, 436, 437, 67, 7, 65, 469, 419, 469, 444, + 445, 62, 447, 24, 406, 407, 567, 452, 567, 406, + 407, 469, 485, 458, 485, 360, 461, 462, 62, 113, + 114, 115, 62, 62, 60, 427, 471, 485, 341, 60, + 427, 476, 9, 127, 60, 24, 349, 495, 59, 63, + 17, 386, 136, 60, 21, 68, 24, 68, 60, 68, + 144, 35, 73, 74, 31, 32, 60, 151, 60, 60, + 75, 406, 407, 68, 53, 75, 60, 469, 60, 24, + 59, 68, 469, 60, 476, 36, 582, 3, 60, 476, + 174, 59, 62, 485, 73, 74, 72, 64, 485, 62, + 24, 59, 24, 495, 75, 73, 74, 60, 495, 572, + 66, 572, 60, 94, 95, 60, 97, 98, 55, 56, + 57, 58, 59, 60, 572, 62, 63, 519, 73, 74, + 60, 60, 519, 60, 569, 59, 439, 62, 60, 223, + 575, 225, 445, 446, 621, 448, 24, 582, 60, 73, + 74, 73, 74, 72, 457, 24, 459, 241, 60, 243, + 595, 59, 597, 59, 59, 249, 601, 602, 68, 62, + 62, 606, 607, 621, 68, 72, 639, 569, 639, 49, + 572, 59, 569, 62, 519, 572, 59, 271, 60, 14, + 59, 639, 68, 60, 68, 73, 74, 34, 49, 283, + 60, 62, 286, 287, 73, 74, 60, 44, 60, 31, + 61, 48, 60, 64, 60, 22, 53, 54, 55, 56, + 582, 158, 159, 508, 615, 377, 615, 142, 243, 621, + 211, 281, 524, 7, 621, 39, 217, 218, 159, 243, + 213, 7, 392, 17, 372, 548, 384, 639, 22, 23, + 24, 17, 639, 556, 22, 29, 22, 23, 24, 495, + 440, 601, 36, 29, 462, 597, 334, 334, 212, 458, + 36, -1, -1, -1, -1, -1, 360, -1, -1, 53, + -1, -1, -1, -1, -1, 59, -1, 53, 372, -1, + 374, 65, -1, 59, 597, 598, 34, 71, 382, 73, + 74, 75, 386, -1, -1, 71, 44, 73, 74, 75, + 48, 49, 50, 51, 52, 53, 54, 55, 56, -1, + -1, -1, 406, 407, 175, 176, 177, 178, -1, 180, + 181, 182, -1, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, -1, 199, -1, + 201, -1, 203, 334, -1, -1, 207, 208, 209, -1, + 341, 7, -1, -1, -1, 11, -1, -1, 349, -1, + 4, 17, -1, -1, 8, -1, 22, 23, 24, -1, + -1, -1, -1, 29, -1, 469, -1, -1, -1, -1, + 36, -1, 476, -1, -1, -1, -1, -1, -1, 33, + 34, 485, 36, 37, 38, 39, 40, 53, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, -1, -1, 71, -1, -1, 74, 280, + -1, 65, -1, -1, -1, 519, -1, -1, -1, 290, + -1, 75, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 439, -1, + -1, -1, 313, -1, 445, 446, 317, 448, -1, -1, + -1, -1, 323, -1, 0, 1, 457, 3, 459, 5, + -1, 7, -1, 9, 10, 569, -1, 13, 572, 15, + 16, 17, 18, 19, 20, -1, 22, 23, 24, -1, + -1, 27, 28, 29, 30, 31, 32, -1, -1, -1, + 36, -1, -1, -1, -1, 366, 367, -1, -1, -1, + -1, -1, -1, 49, 50, -1, 52, 53, -1, -1, + 56, -1, -1, 59, -1, -1, 62, -1, 3, -1, + -1, -1, 7, 69, 70, 71, 11, 73, 74, -1, + -1, -1, 17, -1, 405, 639, -1, 22, 23, 24, + -1, -1, -1, -1, 29, -1, -1, 548, 419, -1, + -1, 36, -1, -1, -1, 556, 427, -1, -1, -1, + -1, 432, 563, -1, 49, 50, -1, 52, 53, -1, + -1, 56, -1, -1, 59, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 69, 70, 71, -1, 73, 74, + -1, -1, -1, 594, -1, -1, 597, 598, -1, -1, + -1, 472, 473, -1, -1, -1, -1, -1, -1, -1, + -1, 1, -1, 3, -1, 5, 6, 7, -1, 9, + 10, -1, 12, 13, 495, 15, 16, 17, 18, 19, + 20, -1, 22, 23, 24, -1, -1, 27, 28, 29, + 30, 31, 32, 644, 515, 646, 36, -1, -1, -1, + -1, 522, 523, 524, -1, -1, -1, -1, -1, 49, + 50, -1, 52, 53, -1, -1, 56, -1, -1, 59, + -1, -1, 62, -1, -1, -1, -1, 67, 68, 69, + 70, 71, -1, 73, 74, 1, -1, 3, -1, 5, + -1, 7, -1, 9, 10, -1, -1, 13, -1, 15, + 16, 17, 18, 19, 20, -1, 22, 23, 24, -1, + -1, 27, 28, 29, 30, 31, 32, -1, -1, -1, + 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 49, 50, -1, 52, 53, -1, -1, + 56, -1, -1, 59, -1, 3, 62, 618, 619, 7, + 621, 67, 68, 69, 70, 71, -1, 73, 74, 17, + 7, -1, -1, -1, 22, 23, 24, -1, -1, -1, + 17, 29, -1, -1, -1, 22, 23, 24, 36, -1, + -1, -1, 29, -1, -1, -1, -1, -1, -1, 36, + -1, 49, 50, -1, 52, 53, -1, -1, 56, -1, + 3, 59, 60, -1, 7, -1, 53, -1, -1, -1, + -1, 69, 70, 71, 17, 73, 74, -1, 65, 22, + 23, 24, -1, -1, 71, -1, 29, 74, -1, -1, + -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 49, 50, -1, 52, + 53, -1, -1, 56, -1, 3, 59, -1, -1, 7, + -1, -1, -1, -1, 67, -1, 69, 70, 71, 17, + 73, 74, -1, -1, 22, 23, 24, -1, -1, -1, + -1, 29, -1, 31, -1, -1, -1, -1, 36, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 49, 50, -1, 52, 53, -1, -1, 56, -1, + 3, 59, -1, -1, 7, -1, -1, -1, -1, -1, + -1, 69, 70, 71, 17, 73, 74, -1, -1, 22, + 23, 24, -1, 26, -1, -1, 29, -1, -1, -1, + -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 49, 50, -1, 52, + 53, -1, -1, 56, -1, 3, 59, -1, -1, 7, + -1, -1, -1, -1, -1, -1, 69, 70, 71, 17, + 73, 74, -1, -1, 22, 23, 24, -1, 26, -1, + -1, 29, -1, -1, -1, -1, -1, -1, 36, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 49, 50, -1, 52, 53, -1, -1, 56, -1, + 3, 59, -1, -1, 7, -1, -1, -1, -1, -1, + -1, 69, 70, 71, 17, 73, 74, -1, -1, 22, + 23, 24, -1, -1, -1, -1, 29, -1, -1, -1, + -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 49, 50, -1, 52, + 53, -1, -1, 56, -1, 3, 59, -1, -1, 7, + -1, -1, -1, -1, -1, -1, 69, 70, 71, 17, + 73, 74, -1, -1, 22, 23, 24, -1, -1, -1, + -1, 29, -1, -1, -1, -1, -1, -1, 36, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 49, 50, -1, 52, 53, -1, -1, 56, -1, + 3, 59, -1, -1, 7, -1, -1, -1, -1, -1, + -1, 69, 70, 71, 17, 73, 74, -1, -1, 22, + 23, 24, -1, -1, -1, -1, 29, -1, -1, -1, + -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 49, 50, -1, 52, + 53, -1, -1, 56, -1, -1, 59, -1, -1, 7, + -1, -1, -1, -1, -1, -1, 69, 70, 71, 17, + 73, 74, -1, -1, 22, 23, 24, -1, -1, -1, + -1, 29, -1, -1, -1, 7, -1, -1, 36, 11, + -1, -1, -1, 7, -1, 17, -1, -1, -1, -1, + 22, 23, 24, 17, -1, 53, -1, 29, 22, 23, + 24, 59, -1, -1, 36, 29, -1, 65, 7, -1, + -1, -1, 36, 71, -1, 73, 74, 75, 17, -1, + -1, 53, -1, 22, 23, 24, -1, 59, -1, 53, + 29, -1, -1, -1, -1, 59, 7, 36, -1, 71, + -1, 73, 74, -1, -1, -1, 17, 71, -1, 73, + 74, 22, 23, 24, 53, -1, -1, -1, 29, -1, + 59, 7, -1, -1, -1, 36, -1, -1, -1, 7, + -1, 17, 71, -1, 73, 74, 22, 23, 24, 17, + -1, -1, 53, 29, 22, 23, 24, -1, 59, -1, + 36, 29, -1, -1, 7, -1, -1, -1, 36, -1, + 71, -1, 73, 74, 17, -1, -1, 53, -1, 22, + 23, 24, -1, 59, -1, 53, 29, -1, -1, -1, + -1, 59, 7, 36, -1, 71, -1, 73, 74, -1, + -1, -1, 17, 71, -1, 73, 74, 22, 23, 24, + 53, -1, -1, -1, 29, -1, 59, 7, -1, -1, + -1, 36, -1, -1, -1, 7, -1, 17, 71, -1, + -1, 74, 22, 23, 24, 17, -1, -1, 53, 29, + 22, 23, 24, -1, -1, -1, 36, 29, -1, -1, + -1, -1, -1, -1, 36, -1, 71, -1, 73, 74, + -1, -1, -1, 53, -1, -1, -1, -1, -1, 59, + -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 71, -1, -1, 74, -1, -1, -1, -1, 71, + 33, 34, 74, 36, -1, 38, 39, 40, -1, -1, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, -1, -1, -1, -1, -1, -1, + 33, 34, -1, 36, -1, 38, 39, 40, -1, 72, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 33, 34, -1, 36, -1, 38, + 39, 40, -1, 66, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 33, 34, + -1, 36, -1, 38, 39, 40, -1, 66, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 33, 34, -1, 36, -1, 38, 39, 40, + -1, 66, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 54, 55, 56, -1, 33, 34, 60, + 36, -1, 38, 39, 40, -1, -1, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 33, 34, -1, -1, -1, 38, 39, 40, -1, + -1, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 33, 34, -1, -1, -1, + 38, 39, 40, -1, -1, 43, 44, 45, 46, -1, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 34, + -1, -1, -1, 38, 39, 40, -1, -1, 43, 44, + 45, 46, -1, 48, 49, 50, 51, 52, 53, 54, + 55, 56 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 77, 79, 80, 0, 25, 78, 25, 86, 24, + 73, 74, 137, 138, 81, 24, 88, 89, 3, 62, + 21, 82, 162, 24, 87, 210, 63, 3, 59, 63, + 83, 85, 137, 62, 1, 3, 5, 7, 9, 10, + 13, 15, 16, 17, 18, 19, 20, 22, 23, 27, + 28, 29, 30, 31, 32, 36, 49, 50, 52, 53, + 56, 59, 69, 70, 71, 90, 91, 92, 98, 110, + 113, 118, 121, 123, 124, 125, 126, 130, 134, 137, + 139, 140, 145, 146, 149, 152, 153, 154, 157, 160, + 161, 177, 182, 62, 9, 17, 21, 31, 32, 64, + 195, 24, 60, 83, 84, 3, 86, 88, 3, 134, + 136, 137, 17, 36, 53, 59, 137, 139, 144, 148, + 149, 150, 157, 136, 125, 130, 111, 59, 137, 155, + 125, 134, 114, 35, 67, 133, 71, 123, 182, 189, + 122, 133, 119, 59, 96, 97, 137, 59, 93, 135, + 137, 181, 124, 124, 124, 124, 124, 124, 36, 53, + 123, 131, 143, 149, 151, 157, 124, 124, 11, 123, + 188, 62, 59, 94, 181, 4, 33, 34, 36, 37, + 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 67, 59, + 63, 71, 66, 59, 133, 1, 133, 8, 65, 75, + 138, 196, 59, 156, 196, 24, 196, 197, 196, 64, + 62, 186, 88, 59, 36, 59, 142, 148, 149, 150, + 151, 157, 142, 142, 63, 98, 107, 108, 109, 182, + 190, 11, 132, 137, 141, 142, 173, 174, 175, 59, + 67, 158, 112, 190, 24, 59, 68, 134, 167, 169, + 171, 142, 35, 53, 59, 68, 134, 166, 168, 169, + 170, 180, 112, 60, 97, 165, 142, 60, 93, 163, + 65, 75, 142, 7, 143, 60, 72, 72, 60, 94, + 65, 142, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, + 123, 123, 123, 127, 60, 131, 183, 59, 137, 123, + 188, 178, 123, 127, 1, 67, 91, 100, 176, 177, + 179, 182, 182, 123, 7, 17, 22, 23, 24, 29, + 36, 53, 65, 71, 138, 198, 200, 201, 202, 137, + 203, 211, 158, 59, 3, 198, 198, 83, 60, 175, + 7, 142, 60, 137, 35, 105, 8, 65, 62, 142, + 132, 141, 75, 187, 60, 175, 179, 115, 62, 63, + 24, 169, 59, 172, 62, 186, 72, 104, 59, 170, + 53, 170, 62, 186, 3, 194, 75, 142, 120, 62, + 186, 62, 186, 182, 135, 65, 36, 59, 142, 148, + 149, 150, 157, 67, 142, 142, 62, 186, 182, 65, + 67, 123, 128, 129, 184, 185, 11, 75, 187, 31, + 131, 72, 66, 176, 60, 185, 101, 62, 68, 36, + 59, 199, 200, 202, 59, 67, 71, 67, 7, 198, + 3, 50, 59, 137, 208, 209, 3, 72, 65, 11, + 198, 60, 75, 62, 191, 211, 62, 62, 62, 60, + 60, 106, 26, 26, 190, 173, 59, 137, 147, 148, + 149, 150, 151, 157, 159, 60, 68, 105, 190, 137, + 60, 175, 171, 68, 142, 6, 12, 68, 99, 102, + 170, 194, 170, 60, 168, 68, 134, 194, 35, 97, + 60, 93, 60, 182, 142, 127, 94, 95, 164, 181, + 60, 182, 127, 66, 75, 187, 68, 75, 187, 131, + 60, 60, 60, 188, 68, 179, 176, 198, 201, 191, + 24, 137, 138, 193, 198, 205, 213, 198, 137, 192, + 204, 212, 198, 3, 208, 62, 72, 198, 209, 198, + 194, 137, 203, 60, 179, 123, 123, 62, 175, 59, + 159, 116, 60, 183, 66, 103, 60, 60, 194, 104, + 60, 185, 62, 186, 142, 185, 123, 129, 128, 129, + 60, 72, 68, 60, 60, 59, 68, 62, 72, 198, + 68, 62, 49, 198, 62, 194, 59, 59, 198, 206, + 207, 68, 190, 60, 175, 14, 117, 159, 8, 65, + 66, 75, 179, 194, 194, 68, 68, 95, 60, 68, + 206, 191, 205, 198, 194, 204, 208, 191, 191, 60, + 100, 113, 123, 123, 60, 60, 60, 60, 159, 66, + 66, 206, 206 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* This macro is provided for backward compatibility. */ + +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = 0; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - Assume YYFAIL is not used. It's too flawed to consider. See + <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html> + for details. YYERROR is fine as it does not invoke this + function. + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar, yystate; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + +/* Line 1806 of yacc.c */ +#line 128 "go.y" + { + xtop = concat(xtop, (yyvsp[(4) - (4)].list)); + } + break; + + case 3: + +/* Line 1806 of yacc.c */ +#line 134 "go.y" + { + prevlineno = lineno; + yyerror("package statement must be first"); + flusherrors(); + mkpackage("main"); + } + break; + + case 4: + +/* Line 1806 of yacc.c */ +#line 141 "go.y" + { + mkpackage((yyvsp[(2) - (3)].sym)->name); + } + break; + + case 5: + +/* Line 1806 of yacc.c */ +#line 151 "go.y" + { + importpkg = runtimepkg; + + if(debug['A']) + cannedimports("runtime.builtin", "package runtime\n\n$$\n\n"); + else + cannedimports("runtime.builtin", runtimeimport); + curio.importsafe = 1; + } + break; + + case 6: + +/* Line 1806 of yacc.c */ +#line 162 "go.y" + { + importpkg = nil; + } + break; + + case 12: + +/* Line 1806 of yacc.c */ +#line 176 "go.y" + { + Pkg *ipkg; + Sym *my; + Node *pack; + + ipkg = importpkg; + my = importmyname; + importpkg = nil; + importmyname = S; + + if(my == nil) + my = lookup(ipkg->name); + + pack = nod(OPACK, N, N); + pack->sym = my; + pack->pkg = ipkg; + pack->lineno = (yyvsp[(1) - (3)].i); + + if(my->name[0] == '.') { + importdot(ipkg, pack); + break; + } + if(my->name[0] == '_' && my->name[1] == '\0') + break; + if(my->def) { + lineno = (yyvsp[(1) - (3)].i); + redeclare(my, "as imported package name"); + } + my->def = pack; + my->lastlineno = (yyvsp[(1) - (3)].i); + my->block = 1; // at top level + } + break; + + case 13: + +/* Line 1806 of yacc.c */ +#line 209 "go.y" + { + // When an invalid import path is passed to importfile, + // it calls yyerror and then sets up a fake import with + // no package statement. This allows us to test more + // than one invalid import statement in a single file. + if(nerrors == 0) + fatal("phase error in import"); + } + break; + + case 16: + +/* Line 1806 of yacc.c */ +#line 224 "go.y" + { + // import with original name + (yyval.i) = parserline(); + importmyname = S; + importfile(&(yyvsp[(1) - (1)].val), (yyval.i)); + } + break; + + case 17: + +/* Line 1806 of yacc.c */ +#line 231 "go.y" + { + // import with given name + (yyval.i) = parserline(); + importmyname = (yyvsp[(1) - (2)].sym); + importfile(&(yyvsp[(2) - (2)].val), (yyval.i)); + } + break; + + case 18: + +/* Line 1806 of yacc.c */ +#line 238 "go.y" + { + // import into my name space + (yyval.i) = parserline(); + importmyname = lookup("."); + importfile(&(yyvsp[(2) - (2)].val), (yyval.i)); + } + break; + + case 19: + +/* Line 1806 of yacc.c */ +#line 247 "go.y" + { + if(importpkg->name == nil) { + importpkg->name = (yyvsp[(2) - (4)].sym)->name; + pkglookup((yyvsp[(2) - (4)].sym)->name, nil)->npkg++; + } else if(strcmp(importpkg->name, (yyvsp[(2) - (4)].sym)->name) != 0) + yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, (yyvsp[(2) - (4)].sym)->name, importpkg->path); + importpkg->direct = 1; + + if(safemode && !curio.importsafe) + yyerror("cannot import unsafe package \"%Z\"", importpkg->path); + } + break; + + case 21: + +/* Line 1806 of yacc.c */ +#line 261 "go.y" + { + if(strcmp((yyvsp[(1) - (1)].sym)->name, "safe") == 0) + curio.importsafe = 1; + } + break; + + case 22: + +/* Line 1806 of yacc.c */ +#line 267 "go.y" + { + defercheckwidth(); + } + break; + + case 23: + +/* Line 1806 of yacc.c */ +#line 271 "go.y" + { + resumecheckwidth(); + unimportfile(); + } + break; + + case 24: + +/* Line 1806 of yacc.c */ +#line 280 "go.y" + { + yyerror("empty top-level declaration"); + (yyval.list) = nil; + } + break; + + case 26: + +/* Line 1806 of yacc.c */ +#line 286 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 27: + +/* Line 1806 of yacc.c */ +#line 290 "go.y" + { + yyerror("non-declaration statement outside function body"); + (yyval.list) = nil; + } + break; + + case 28: + +/* Line 1806 of yacc.c */ +#line 295 "go.y" + { + (yyval.list) = nil; + } + break; + + case 29: + +/* Line 1806 of yacc.c */ +#line 301 "go.y" + { + (yyval.list) = (yyvsp[(2) - (2)].list); + } + break; + + case 30: + +/* Line 1806 of yacc.c */ +#line 305 "go.y" + { + (yyval.list) = (yyvsp[(3) - (5)].list); + } + break; + + case 31: + +/* Line 1806 of yacc.c */ +#line 309 "go.y" + { + (yyval.list) = nil; + } + break; + + case 32: + +/* Line 1806 of yacc.c */ +#line 313 "go.y" + { + (yyval.list) = (yyvsp[(2) - (2)].list); + iota = -100000; + lastconst = nil; + } + break; + + case 33: + +/* Line 1806 of yacc.c */ +#line 319 "go.y" + { + (yyval.list) = (yyvsp[(3) - (5)].list); + iota = -100000; + lastconst = nil; + } + break; + + case 34: + +/* Line 1806 of yacc.c */ +#line 325 "go.y" + { + (yyval.list) = concat((yyvsp[(3) - (7)].list), (yyvsp[(5) - (7)].list)); + iota = -100000; + lastconst = nil; + } + break; + + case 35: + +/* Line 1806 of yacc.c */ +#line 331 "go.y" + { + (yyval.list) = nil; + iota = -100000; + } + break; + + case 36: + +/* Line 1806 of yacc.c */ +#line 336 "go.y" + { + (yyval.list) = list1((yyvsp[(2) - (2)].node)); + } + break; + + case 37: + +/* Line 1806 of yacc.c */ +#line 340 "go.y" + { + (yyval.list) = (yyvsp[(3) - (5)].list); + } + break; + + case 38: + +/* Line 1806 of yacc.c */ +#line 344 "go.y" + { + (yyval.list) = nil; + } + break; + + case 39: + +/* Line 1806 of yacc.c */ +#line 350 "go.y" + { + iota = 0; + } + break; + + case 40: + +/* Line 1806 of yacc.c */ +#line 356 "go.y" + { + (yyval.list) = variter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil); + } + break; + + case 41: + +/* Line 1806 of yacc.c */ +#line 360 "go.y" + { + (yyval.list) = variter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list)); + } + break; + + case 42: + +/* Line 1806 of yacc.c */ +#line 364 "go.y" + { + (yyval.list) = variter((yyvsp[(1) - (3)].list), nil, (yyvsp[(3) - (3)].list)); + } + break; + + case 43: + +/* Line 1806 of yacc.c */ +#line 370 "go.y" + { + (yyval.list) = constiter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list)); + } + break; + + case 44: + +/* Line 1806 of yacc.c */ +#line 374 "go.y" + { + (yyval.list) = constiter((yyvsp[(1) - (3)].list), N, (yyvsp[(3) - (3)].list)); + } + break; + + case 46: + +/* Line 1806 of yacc.c */ +#line 381 "go.y" + { + (yyval.list) = constiter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil); + } + break; + + case 47: + +/* Line 1806 of yacc.c */ +#line 385 "go.y" + { + (yyval.list) = constiter((yyvsp[(1) - (1)].list), N, nil); + } + break; + + case 48: + +/* Line 1806 of yacc.c */ +#line 391 "go.y" + { + // different from dclname because the name + // becomes visible right here, not at the end + // of the declaration. + (yyval.node) = typedcl0((yyvsp[(1) - (1)].sym)); + } + break; + + case 49: + +/* Line 1806 of yacc.c */ +#line 400 "go.y" + { + (yyval.node) = typedcl1((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node), 1); + } + break; + + case 50: + +/* Line 1806 of yacc.c */ +#line 406 "go.y" + { + (yyval.node) = (yyvsp[(1) - (1)].node); + } + break; + + case 51: + +/* Line 1806 of yacc.c */ +#line 410 "go.y" + { + (yyval.node) = nod(OASOP, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + (yyval.node)->etype = (yyvsp[(2) - (3)].i); // rathole to pass opcode + } + break; + + case 52: + +/* Line 1806 of yacc.c */ +#line 415 "go.y" + { + if((yyvsp[(1) - (3)].list)->next == nil && (yyvsp[(3) - (3)].list)->next == nil) { + // simple + (yyval.node) = nod(OAS, (yyvsp[(1) - (3)].list)->n, (yyvsp[(3) - (3)].list)->n); + break; + } + // multiple + (yyval.node) = nod(OAS2, N, N); + (yyval.node)->list = (yyvsp[(1) - (3)].list); + (yyval.node)->rlist = (yyvsp[(3) - (3)].list); + } + break; + + case 53: + +/* Line 1806 of yacc.c */ +#line 427 "go.y" + { + if((yyvsp[(3) - (3)].list)->n->op == OTYPESW) { + (yyval.node) = nod(OTYPESW, N, (yyvsp[(3) - (3)].list)->n->right); + if((yyvsp[(3) - (3)].list)->next != nil) + yyerror("expr.(type) must be alone in list"); + if((yyvsp[(1) - (3)].list)->next != nil) + yyerror("argument count mismatch: %d = %d", count((yyvsp[(1) - (3)].list)), 1); + else if(((yyvsp[(1) - (3)].list)->n->op != ONAME && (yyvsp[(1) - (3)].list)->n->op != OTYPE && (yyvsp[(1) - (3)].list)->n->op != ONONAME) || isblank((yyvsp[(1) - (3)].list)->n)) + yyerror("invalid variable name %N in type switch", (yyvsp[(1) - (3)].list)->n); + else + (yyval.node)->left = dclname((yyvsp[(1) - (3)].list)->n->sym); // it's a colas, so must not re-use an oldname. + break; + } + (yyval.node) = colas((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); + } + break; + + case 54: + +/* Line 1806 of yacc.c */ +#line 443 "go.y" + { + (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1)); + (yyval.node)->etype = OADD; + } + break; + + case 55: + +/* Line 1806 of yacc.c */ +#line 448 "go.y" + { + (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1)); + (yyval.node)->etype = OSUB; + } + break; + + case 56: + +/* Line 1806 of yacc.c */ +#line 455 "go.y" + { + Node *n, *nn; + + // will be converted to OCASE + // right will point to next case + // done in casebody() + markdcl(); + (yyval.node) = nod(OXCASE, N, N); + (yyval.node)->list = (yyvsp[(2) - (3)].list); + if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { + // type switch - declare variable + nn = newname(n->sym); + declare(nn, dclcontext); + (yyval.node)->nname = nn; + + // keep track of the instances for reporting unused + nn->defn = typesw->right; + } + } + break; + + case 57: + +/* Line 1806 of yacc.c */ +#line 475 "go.y" + { + Node *n; + + // will be converted to OCASE + // right will point to next case + // done in casebody() + markdcl(); + (yyval.node) = nod(OXCASE, N, N); + if((yyvsp[(2) - (5)].list)->next == nil) + n = nod(OAS, (yyvsp[(2) - (5)].list)->n, (yyvsp[(4) - (5)].node)); + else { + n = nod(OAS2, N, N); + n->list = (yyvsp[(2) - (5)].list); + n->rlist = list1((yyvsp[(4) - (5)].node)); + } + (yyval.node)->list = list1(n); + } + break; + + case 58: + +/* Line 1806 of yacc.c */ +#line 493 "go.y" + { + // will be converted to OCASE + // right will point to next case + // done in casebody() + markdcl(); + (yyval.node) = nod(OXCASE, N, N); + (yyval.node)->list = list1(colas((yyvsp[(2) - (5)].list), list1((yyvsp[(4) - (5)].node)))); + } + break; + + case 59: + +/* Line 1806 of yacc.c */ +#line 502 "go.y" + { + Node *n, *nn; + + markdcl(); + (yyval.node) = nod(OXCASE, N, N); + if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { + // type switch - declare variable + nn = newname(n->sym); + declare(nn, dclcontext); + (yyval.node)->nname = nn; + + // keep track of the instances for reporting unused + nn->defn = typesw->right; + } + } + break; + + case 60: + +/* Line 1806 of yacc.c */ +#line 520 "go.y" + { + markdcl(); + } + break; + + case 61: + +/* Line 1806 of yacc.c */ +#line 524 "go.y" + { + (yyval.node) = liststmt((yyvsp[(3) - (4)].list)); + popdcl(); + } + break; + + case 62: + +/* Line 1806 of yacc.c */ +#line 531 "go.y" + { + // If the last token read by the lexer was consumed + // as part of the case, clear it (parser has cleared yychar). + // If the last token read by the lexer was the lookahead + // leave it alone (parser has it cached in yychar). + // This is so that the stmt_list action doesn't look at + // the case tokens if the stmt_list is empty. + yylast = yychar; + } + break; + + case 63: + +/* Line 1806 of yacc.c */ +#line 541 "go.y" + { + int last; + + // This is the only place in the language where a statement + // list is not allowed to drop the final semicolon, because + // it's the only place where a statement list is not followed + // by a closing brace. Handle the error for pedantry. + + // Find the final token of the statement list. + // yylast is lookahead; yyprev is last of stmt_list + last = yyprev; + + if(last > 0 && last != ';' && yychar != '}') + yyerror("missing statement after label"); + (yyval.node) = (yyvsp[(1) - (3)].node); + (yyval.node)->nbody = (yyvsp[(3) - (3)].list); + popdcl(); + } + break; + + case 64: + +/* Line 1806 of yacc.c */ +#line 561 "go.y" + { + (yyval.list) = nil; + } + break; + + case 65: + +/* Line 1806 of yacc.c */ +#line 565 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); + } + break; + + case 66: + +/* Line 1806 of yacc.c */ +#line 571 "go.y" + { + markdcl(); + } + break; + + case 67: + +/* Line 1806 of yacc.c */ +#line 575 "go.y" + { + (yyval.list) = (yyvsp[(3) - (4)].list); + popdcl(); + } + break; + + case 68: + +/* Line 1806 of yacc.c */ +#line 582 "go.y" + { + (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node)); + (yyval.node)->list = (yyvsp[(1) - (4)].list); + (yyval.node)->etype = 0; // := flag + } + break; + + case 69: + +/* Line 1806 of yacc.c */ +#line 588 "go.y" + { + (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node)); + (yyval.node)->list = (yyvsp[(1) - (4)].list); + (yyval.node)->colas = 1; + colasdefn((yyvsp[(1) - (4)].list), (yyval.node)); + } + break; + + case 70: + +/* Line 1806 of yacc.c */ +#line 597 "go.y" + { + // init ; test ; incr + if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0) + yyerror("cannot declare in the for-increment"); + (yyval.node) = nod(OFOR, N, N); + if((yyvsp[(1) - (5)].node) != N) + (yyval.node)->ninit = list1((yyvsp[(1) - (5)].node)); + (yyval.node)->ntest = (yyvsp[(3) - (5)].node); + (yyval.node)->nincr = (yyvsp[(5) - (5)].node); + } + break; + + case 71: + +/* Line 1806 of yacc.c */ +#line 608 "go.y" + { + // normal test + (yyval.node) = nod(OFOR, N, N); + (yyval.node)->ntest = (yyvsp[(1) - (1)].node); + } + break; + + case 73: + +/* Line 1806 of yacc.c */ +#line 617 "go.y" + { + (yyval.node) = (yyvsp[(1) - (2)].node); + (yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list)); + } + break; + + case 74: + +/* Line 1806 of yacc.c */ +#line 624 "go.y" + { + markdcl(); + } + break; + + case 75: + +/* Line 1806 of yacc.c */ +#line 628 "go.y" + { + (yyval.node) = (yyvsp[(3) - (3)].node); + popdcl(); + } + break; + + case 76: + +/* Line 1806 of yacc.c */ +#line 635 "go.y" + { + // test + (yyval.node) = nod(OIF, N, N); + (yyval.node)->ntest = (yyvsp[(1) - (1)].node); + } + break; + + case 77: + +/* Line 1806 of yacc.c */ +#line 641 "go.y" + { + // init ; test + (yyval.node) = nod(OIF, N, N); + if((yyvsp[(1) - (3)].node) != N) + (yyval.node)->ninit = list1((yyvsp[(1) - (3)].node)); + (yyval.node)->ntest = (yyvsp[(3) - (3)].node); + } + break; + + case 78: + +/* Line 1806 of yacc.c */ +#line 652 "go.y" + { + markdcl(); + } + break; + + case 79: + +/* Line 1806 of yacc.c */ +#line 656 "go.y" + { + if((yyvsp[(3) - (3)].node)->ntest == N) + yyerror("missing condition in if statement"); + } + break; + + case 80: + +/* Line 1806 of yacc.c */ +#line 661 "go.y" + { + (yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list); + } + break; + + case 81: + +/* Line 1806 of yacc.c */ +#line 665 "go.y" + { + popdcl(); + (yyval.node) = (yyvsp[(3) - (7)].node); + if((yyvsp[(7) - (7)].node) != N) + (yyval.node)->nelse = list1((yyvsp[(7) - (7)].node)); + } + break; + + case 82: + +/* Line 1806 of yacc.c */ +#line 673 "go.y" + { + (yyval.node) = N; + } + break; + + case 83: + +/* Line 1806 of yacc.c */ +#line 677 "go.y" + { + (yyval.node) = (yyvsp[(2) - (2)].node); + } + break; + + case 84: + +/* Line 1806 of yacc.c */ +#line 681 "go.y" + { + (yyval.node) = (yyvsp[(2) - (2)].node); + } + break; + + case 85: + +/* Line 1806 of yacc.c */ +#line 687 "go.y" + { + markdcl(); + } + break; + + case 86: + +/* Line 1806 of yacc.c */ +#line 691 "go.y" + { + Node *n; + n = (yyvsp[(3) - (3)].node)->ntest; + if(n != N && n->op != OTYPESW) + n = N; + typesw = nod(OXXX, typesw, n); + } + break; + + case 87: + +/* Line 1806 of yacc.c */ +#line 699 "go.y" + { + (yyval.node) = (yyvsp[(3) - (7)].node); + (yyval.node)->op = OSWITCH; + (yyval.node)->list = (yyvsp[(6) - (7)].list); + typesw = typesw->left; + popdcl(); + } + break; + + case 88: + +/* Line 1806 of yacc.c */ +#line 709 "go.y" + { + typesw = nod(OXXX, typesw, N); + } + break; + + case 89: + +/* Line 1806 of yacc.c */ +#line 713 "go.y" + { + (yyval.node) = nod(OSELECT, N, N); + (yyval.node)->lineno = typesw->lineno; + (yyval.node)->list = (yyvsp[(4) - (5)].list); + typesw = typesw->left; + } + break; + + case 91: + +/* Line 1806 of yacc.c */ +#line 726 "go.y" + { + (yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 92: + +/* Line 1806 of yacc.c */ +#line 730 "go.y" + { + (yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 93: + +/* Line 1806 of yacc.c */ +#line 734 "go.y" + { + (yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 94: + +/* Line 1806 of yacc.c */ +#line 738 "go.y" + { + (yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 95: + +/* Line 1806 of yacc.c */ +#line 742 "go.y" + { + (yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 96: + +/* Line 1806 of yacc.c */ +#line 746 "go.y" + { + (yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 97: + +/* Line 1806 of yacc.c */ +#line 750 "go.y" + { + (yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 98: + +/* Line 1806 of yacc.c */ +#line 754 "go.y" + { + (yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 99: + +/* Line 1806 of yacc.c */ +#line 758 "go.y" + { + (yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 100: + +/* Line 1806 of yacc.c */ +#line 762 "go.y" + { + (yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 101: + +/* Line 1806 of yacc.c */ +#line 766 "go.y" + { + (yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 102: + +/* Line 1806 of yacc.c */ +#line 770 "go.y" + { + (yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 103: + +/* Line 1806 of yacc.c */ +#line 774 "go.y" + { + (yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 104: + +/* Line 1806 of yacc.c */ +#line 778 "go.y" + { + (yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 105: + +/* Line 1806 of yacc.c */ +#line 782 "go.y" + { + (yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 106: + +/* Line 1806 of yacc.c */ +#line 786 "go.y" + { + (yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 107: + +/* Line 1806 of yacc.c */ +#line 790 "go.y" + { + (yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 108: + +/* Line 1806 of yacc.c */ +#line 794 "go.y" + { + (yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 109: + +/* Line 1806 of yacc.c */ +#line 798 "go.y" + { + (yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 110: + +/* Line 1806 of yacc.c */ +#line 803 "go.y" + { + (yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 112: + +/* Line 1806 of yacc.c */ +#line 810 "go.y" + { + (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); + } + break; + + case 113: + +/* Line 1806 of yacc.c */ +#line 814 "go.y" + { + if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) { + // Special case for &T{...}: turn into (*T){...}. + (yyval.node) = (yyvsp[(2) - (2)].node); + (yyval.node)->right = nod(OIND, (yyval.node)->right, N); + (yyval.node)->right->implicit = 1; + } else { + (yyval.node) = nod(OADDR, (yyvsp[(2) - (2)].node), N); + } + } + break; + + case 114: + +/* Line 1806 of yacc.c */ +#line 825 "go.y" + { + (yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N); + } + break; + + case 115: + +/* Line 1806 of yacc.c */ +#line 829 "go.y" + { + (yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N); + } + break; + + case 116: + +/* Line 1806 of yacc.c */ +#line 833 "go.y" + { + (yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N); + } + break; + + case 117: + +/* Line 1806 of yacc.c */ +#line 837 "go.y" + { + yyerror("the bitwise complement operator is ^"); + (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N); + } + break; + + case 118: + +/* Line 1806 of yacc.c */ +#line 842 "go.y" + { + (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N); + } + break; + + case 119: + +/* Line 1806 of yacc.c */ +#line 846 "go.y" + { + (yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N); + } + break; + + case 120: + +/* Line 1806 of yacc.c */ +#line 856 "go.y" + { + (yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N); + } + break; + + case 121: + +/* Line 1806 of yacc.c */ +#line 860 "go.y" + { + (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N); + (yyval.node)->list = (yyvsp[(3) - (5)].list); + } + break; + + case 122: + +/* Line 1806 of yacc.c */ +#line 865 "go.y" + { + (yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N); + (yyval.node)->list = (yyvsp[(3) - (6)].list); + (yyval.node)->isddd = 1; + } + break; + + case 123: + +/* Line 1806 of yacc.c */ +#line 873 "go.y" + { + (yyval.node) = nodlit((yyvsp[(1) - (1)].val)); + } + break; + + case 125: + +/* Line 1806 of yacc.c */ +#line 878 "go.y" + { + if((yyvsp[(1) - (3)].node)->op == OPACK) { + Sym *s; + s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg); + (yyvsp[(1) - (3)].node)->used = 1; + (yyval.node) = oldname(s); + break; + } + (yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym))); + } + break; + + case 126: + +/* Line 1806 of yacc.c */ +#line 889 "go.y" + { + (yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node)); + } + break; + + case 127: + +/* Line 1806 of yacc.c */ +#line 893 "go.y" + { + (yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node)); + } + break; + + case 128: + +/* Line 1806 of yacc.c */ +#line 897 "go.y" + { + (yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); + } + break; + + case 129: + +/* Line 1806 of yacc.c */ +#line 901 "go.y" + { + (yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node))); + } + break; + + case 131: + +/* Line 1806 of yacc.c */ +#line 906 "go.y" + { + // conversion + (yyval.node) = nod(OCALL, (yyvsp[(1) - (4)].node), N); + (yyval.node)->list = list1((yyvsp[(3) - (4)].node)); + } + break; + + case 132: + +/* Line 1806 of yacc.c */ +#line 912 "go.y" + { + (yyval.node) = (yyvsp[(3) - (5)].node); + (yyval.node)->right = (yyvsp[(1) - (5)].node); + (yyval.node)->list = (yyvsp[(4) - (5)].list); + fixlbrace((yyvsp[(2) - (5)].i)); + } + break; + + case 133: + +/* Line 1806 of yacc.c */ +#line 919 "go.y" + { + (yyval.node) = (yyvsp[(3) - (5)].node); + (yyval.node)->right = (yyvsp[(1) - (5)].node); + (yyval.node)->list = (yyvsp[(4) - (5)].list); + } + break; + + case 134: + +/* Line 1806 of yacc.c */ +#line 925 "go.y" + { + yyerror("cannot parenthesize type in composite literal"); + (yyval.node) = (yyvsp[(5) - (7)].node); + (yyval.node)->right = (yyvsp[(2) - (7)].node); + (yyval.node)->list = (yyvsp[(6) - (7)].list); + } + break; + + case 136: + +/* Line 1806 of yacc.c */ +#line 934 "go.y" + { + // composite expression. + // make node early so we get the right line number. + (yyval.node) = nod(OCOMPLIT, N, N); + } + break; + + case 137: + +/* Line 1806 of yacc.c */ +#line 942 "go.y" + { + (yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); + } + break; + + case 139: + +/* Line 1806 of yacc.c */ +#line 949 "go.y" + { + (yyval.node) = (yyvsp[(2) - (4)].node); + (yyval.node)->list = (yyvsp[(3) - (4)].list); + } + break; + + case 141: + +/* Line 1806 of yacc.c */ +#line 957 "go.y" + { + (yyval.node) = (yyvsp[(2) - (3)].node); + + // Need to know on lhs of := whether there are ( ). + // Don't bother with the OPAREN in other cases: + // it's just a waste of memory and time. + switch((yyval.node)->op) { + case ONAME: + case ONONAME: + case OPACK: + case OTYPE: + case OLITERAL: + (yyval.node) = nod(OPAREN, (yyval.node), N); + } + } + break; + + case 145: + +/* Line 1806 of yacc.c */ +#line 982 "go.y" + { + (yyval.i) = LBODY; + } + break; + + case 146: + +/* Line 1806 of yacc.c */ +#line 986 "go.y" + { + (yyval.i) = '{'; + } + break; + + case 147: + +/* Line 1806 of yacc.c */ +#line 997 "go.y" + { + if((yyvsp[(1) - (1)].sym) == S) + (yyval.node) = N; + else + (yyval.node) = newname((yyvsp[(1) - (1)].sym)); + } + break; + + case 148: + +/* Line 1806 of yacc.c */ +#line 1006 "go.y" + { + (yyval.node) = dclname((yyvsp[(1) - (1)].sym)); + } + break; + + case 149: + +/* Line 1806 of yacc.c */ +#line 1011 "go.y" + { + (yyval.node) = N; + } + break; + + case 151: + +/* Line 1806 of yacc.c */ +#line 1018 "go.y" + { + (yyval.sym) = (yyvsp[(1) - (1)].sym); + // during imports, unqualified non-exported identifiers are from builtinpkg + if(importpkg != nil && !exportname((yyvsp[(1) - (1)].sym)->name)) + (yyval.sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg); + } + break; + + case 153: + +/* Line 1806 of yacc.c */ +#line 1026 "go.y" + { + (yyval.sym) = S; + } + break; + + case 154: + +/* Line 1806 of yacc.c */ +#line 1032 "go.y" + { + if((yyvsp[(2) - (4)].val).u.sval->len == 0) + (yyval.sym) = pkglookup((yyvsp[(4) - (4)].sym)->name, importpkg); + else + (yyval.sym) = pkglookup((yyvsp[(4) - (4)].sym)->name, mkpkg((yyvsp[(2) - (4)].val).u.sval)); + } + break; + + case 155: + +/* Line 1806 of yacc.c */ +#line 1041 "go.y" + { + (yyval.node) = oldname((yyvsp[(1) - (1)].sym)); + if((yyval.node)->pack != N) + (yyval.node)->pack->used = 1; + } + break; + + case 157: + +/* Line 1806 of yacc.c */ +#line 1061 "go.y" + { + yyerror("final argument in variadic function missing type"); + (yyval.node) = nod(ODDD, typenod(typ(TINTER)), N); + } + break; + + case 158: + +/* Line 1806 of yacc.c */ +#line 1066 "go.y" + { + (yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N); + } + break; + + case 164: + +/* Line 1806 of yacc.c */ +#line 1077 "go.y" + { + (yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N); + } + break; + + case 168: + +/* Line 1806 of yacc.c */ +#line 1086 "go.y" + { + (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); + } + break; + + case 173: + +/* Line 1806 of yacc.c */ +#line 1096 "go.y" + { + (yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N); + } + break; + + case 183: + +/* Line 1806 of yacc.c */ +#line 1117 "go.y" + { + if((yyvsp[(1) - (3)].node)->op == OPACK) { + Sym *s; + s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg); + (yyvsp[(1) - (3)].node)->used = 1; + (yyval.node) = oldname(s); + break; + } + (yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym))); + } + break; + + case 184: + +/* Line 1806 of yacc.c */ +#line 1130 "go.y" + { + (yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node)); + } + break; + + case 185: + +/* Line 1806 of yacc.c */ +#line 1134 "go.y" + { + // array literal of nelem + (yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node)); + } + break; + + case 186: + +/* Line 1806 of yacc.c */ +#line 1139 "go.y" + { + (yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N); + (yyval.node)->etype = Cboth; + } + break; + + case 187: + +/* Line 1806 of yacc.c */ +#line 1144 "go.y" + { + (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N); + (yyval.node)->etype = Csend; + } + break; + + case 188: + +/* Line 1806 of yacc.c */ +#line 1149 "go.y" + { + (yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)); + } + break; + + case 191: + +/* Line 1806 of yacc.c */ +#line 1157 "go.y" + { + (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); + } + break; + + case 192: + +/* Line 1806 of yacc.c */ +#line 1163 "go.y" + { + (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N); + (yyval.node)->etype = Crecv; + } + break; + + case 193: + +/* Line 1806 of yacc.c */ +#line 1170 "go.y" + { + (yyval.node) = nod(OTSTRUCT, N, N); + (yyval.node)->list = (yyvsp[(3) - (5)].list); + fixlbrace((yyvsp[(2) - (5)].i)); + } + break; + + case 194: + +/* Line 1806 of yacc.c */ +#line 1176 "go.y" + { + (yyval.node) = nod(OTSTRUCT, N, N); + fixlbrace((yyvsp[(2) - (3)].i)); + } + break; + + case 195: + +/* Line 1806 of yacc.c */ +#line 1183 "go.y" + { + (yyval.node) = nod(OTINTER, N, N); + (yyval.node)->list = (yyvsp[(3) - (5)].list); + fixlbrace((yyvsp[(2) - (5)].i)); + } + break; + + case 196: + +/* Line 1806 of yacc.c */ +#line 1189 "go.y" + { + (yyval.node) = nod(OTINTER, N, N); + fixlbrace((yyvsp[(2) - (3)].i)); + } + break; + + case 197: + +/* Line 1806 of yacc.c */ +#line 1200 "go.y" + { + (yyval.node) = (yyvsp[(2) - (3)].node); + if((yyval.node) == N) + break; + (yyval.node)->nbody = (yyvsp[(3) - (3)].list); + (yyval.node)->endlineno = lineno; + funcbody((yyval.node)); + } + break; + + case 198: + +/* Line 1806 of yacc.c */ +#line 1211 "go.y" + { + Node *t; + + (yyval.node) = N; + (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1); + + if(strcmp((yyvsp[(1) - (5)].sym)->name, "init") == 0) { + (yyvsp[(1) - (5)].sym) = renameinit(); + if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil) + yyerror("func init must have no arguments and no return values"); + } + if(strcmp(localpkg->name, "main") == 0 && strcmp((yyvsp[(1) - (5)].sym)->name, "main") == 0) { + if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil) + yyerror("func main must have no arguments and no return values"); + } + + t = nod(OTFUNC, N, N); + t->list = (yyvsp[(3) - (5)].list); + t->rlist = (yyvsp[(5) - (5)].list); + + (yyval.node) = nod(ODCLFUNC, N, N); + (yyval.node)->nname = newname((yyvsp[(1) - (5)].sym)); + (yyval.node)->nname->defn = (yyval.node); + (yyval.node)->nname->ntype = t; // TODO: check if nname already has an ntype + declare((yyval.node)->nname, PFUNC); + + funchdr((yyval.node)); + } + break; + + case 199: + +/* Line 1806 of yacc.c */ +#line 1240 "go.y" + { + Node *rcvr, *t; + + (yyval.node) = N; + (yyvsp[(2) - (8)].list) = checkarglist((yyvsp[(2) - (8)].list), 0); + (yyvsp[(6) - (8)].list) = checkarglist((yyvsp[(6) - (8)].list), 1); + + if((yyvsp[(2) - (8)].list) == nil) { + yyerror("method has no receiver"); + break; + } + if((yyvsp[(2) - (8)].list)->next != nil) { + yyerror("method has multiple receivers"); + break; + } + rcvr = (yyvsp[(2) - (8)].list)->n; + if(rcvr->op != ODCLFIELD) { + yyerror("bad receiver in method"); + break; + } + if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN)) + yyerror("cannot parenthesize receiver type"); + + t = nod(OTFUNC, rcvr, N); + t->list = (yyvsp[(6) - (8)].list); + t->rlist = (yyvsp[(8) - (8)].list); + + (yyval.node) = nod(ODCLFUNC, N, N); + (yyval.node)->shortname = newname((yyvsp[(4) - (8)].sym)); + (yyval.node)->nname = methodname1((yyval.node)->shortname, rcvr->right); + (yyval.node)->nname->defn = (yyval.node); + (yyval.node)->nname->ntype = t; + declare((yyval.node)->nname, PFUNC); + + funchdr((yyval.node)); + } + break; + + case 200: + +/* Line 1806 of yacc.c */ +#line 1279 "go.y" + { + Sym *s; + Type *t; + + (yyval.node) = N; + + s = (yyvsp[(1) - (5)].sym); + t = functype(N, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)); + + importsym(s, ONAME); + if(s->def != N && s->def->op == ONAME) { + if(eqtype(t, s->def->type)) + break; + yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t); + } + + (yyval.node) = newname(s); + (yyval.node)->type = t; + declare((yyval.node), PFUNC); + + funchdr((yyval.node)); + } + break; + + case 201: + +/* Line 1806 of yacc.c */ +#line 1302 "go.y" + { + (yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right); + (yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list)); + + checkwidth((yyval.node)->type); + addmethod((yyvsp[(4) - (8)].sym), (yyval.node)->type, 0); + funchdr((yyval.node)); + + // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as + // (dotmeth's type)->nname->inl, and dotmeth's type has been pulled + // out by typecheck's lookdot as this $$->ttype. So by providing + // this back link here we avoid special casing there. + (yyval.node)->type->nname = (yyval.node); + } + break; + + case 202: + +/* Line 1806 of yacc.c */ +#line 1319 "go.y" + { + (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1); + (yyval.node) = nod(OTFUNC, N, N); + (yyval.node)->list = (yyvsp[(3) - (5)].list); + (yyval.node)->rlist = (yyvsp[(5) - (5)].list); + } + break; + + case 203: + +/* Line 1806 of yacc.c */ +#line 1327 "go.y" + { + (yyval.list) = nil; + } + break; + + case 204: + +/* Line 1806 of yacc.c */ +#line 1331 "go.y" + { + (yyval.list) = (yyvsp[(2) - (3)].list); + if((yyval.list) == nil) + (yyval.list) = list1(nod(OEMPTY, N, N)); + } + break; + + case 205: + +/* Line 1806 of yacc.c */ +#line 1339 "go.y" + { + (yyval.list) = nil; + } + break; + + case 206: + +/* Line 1806 of yacc.c */ +#line 1343 "go.y" + { + (yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node))); + } + break; + + case 207: + +/* Line 1806 of yacc.c */ +#line 1347 "go.y" + { + (yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0); + (yyval.list) = (yyvsp[(2) - (3)].list); + } + break; + + case 208: + +/* Line 1806 of yacc.c */ +#line 1354 "go.y" + { + closurehdr((yyvsp[(1) - (1)].node)); + } + break; + + case 209: + +/* Line 1806 of yacc.c */ +#line 1360 "go.y" + { + (yyval.node) = closurebody((yyvsp[(3) - (4)].list)); + fixlbrace((yyvsp[(2) - (4)].i)); + } + break; + + case 210: + +/* Line 1806 of yacc.c */ +#line 1365 "go.y" + { + (yyval.node) = closurebody(nil); + } + break; + + case 211: + +/* Line 1806 of yacc.c */ +#line 1376 "go.y" + { + (yyval.list) = nil; + } + break; + + case 212: + +/* Line 1806 of yacc.c */ +#line 1380 "go.y" + { + (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list)); + if(nsyntaxerrors == 0) + testdclstack(); + } + break; + + case 214: + +/* Line 1806 of yacc.c */ +#line 1389 "go.y" + { + (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); + } + break; + + case 216: + +/* Line 1806 of yacc.c */ +#line 1396 "go.y" + { + (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); + } + break; + + case 217: + +/* Line 1806 of yacc.c */ +#line 1402 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 218: + +/* Line 1806 of yacc.c */ +#line 1406 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + case 220: + +/* Line 1806 of yacc.c */ +#line 1413 "go.y" + { + (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); + } + break; + + case 221: + +/* Line 1806 of yacc.c */ +#line 1419 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 222: + +/* Line 1806 of yacc.c */ +#line 1423 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + case 223: + +/* Line 1806 of yacc.c */ +#line 1429 "go.y" + { + NodeList *l; + + Node *n; + l = (yyvsp[(1) - (3)].list); + if(l != nil && l->next == nil && l->n == nil) { + // ? symbol, during import + n = (yyvsp[(2) - (3)].node); + if(n->op == OIND) + n = n->left; + n = embedded(n->sym); + n->right = (yyvsp[(2) - (3)].node); + n->val = (yyvsp[(3) - (3)].val); + (yyval.list) = list1(n); + break; + } + + for(l=(yyvsp[(1) - (3)].list); l; l=l->next) { + l->n = nod(ODCLFIELD, l->n, (yyvsp[(2) - (3)].node)); + l->n->val = (yyvsp[(3) - (3)].val); + } + } + break; + + case 224: + +/* Line 1806 of yacc.c */ +#line 1452 "go.y" + { + (yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val); + (yyval.list) = list1((yyvsp[(1) - (2)].node)); + } + break; + + case 225: + +/* Line 1806 of yacc.c */ +#line 1457 "go.y" + { + (yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val); + (yyval.list) = list1((yyvsp[(2) - (4)].node)); + yyerror("cannot parenthesize embedded type"); + } + break; + + case 226: + +/* Line 1806 of yacc.c */ +#line 1463 "go.y" + { + (yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N); + (yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val); + (yyval.list) = list1((yyvsp[(2) - (3)].node)); + } + break; + + case 227: + +/* Line 1806 of yacc.c */ +#line 1469 "go.y" + { + (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); + (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); + (yyval.list) = list1((yyvsp[(3) - (5)].node)); + yyerror("cannot parenthesize embedded type"); + } + break; + + case 228: + +/* Line 1806 of yacc.c */ +#line 1476 "go.y" + { + (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); + (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); + (yyval.list) = list1((yyvsp[(3) - (5)].node)); + yyerror("cannot parenthesize embedded type"); + } + break; + + case 229: + +/* Line 1806 of yacc.c */ +#line 1485 "go.y" + { + Node *n; + + (yyval.sym) = (yyvsp[(1) - (1)].sym); + n = oldname((yyvsp[(1) - (1)].sym)); + if(n->pack != N) + n->pack->used = 1; + } + break; + + case 230: + +/* Line 1806 of yacc.c */ +#line 1494 "go.y" + { + Pkg *pkg; + + if((yyvsp[(1) - (3)].sym)->def == N || (yyvsp[(1) - (3)].sym)->def->op != OPACK) { + yyerror("%S is not a package", (yyvsp[(1) - (3)].sym)); + pkg = localpkg; + } else { + (yyvsp[(1) - (3)].sym)->def->used = 1; + pkg = (yyvsp[(1) - (3)].sym)->def->pkg; + } + (yyval.sym) = restrictlookup((yyvsp[(3) - (3)].sym)->name, pkg); + } + break; + + case 231: + +/* Line 1806 of yacc.c */ +#line 1509 "go.y" + { + (yyval.node) = embedded((yyvsp[(1) - (1)].sym)); + } + break; + + case 232: + +/* Line 1806 of yacc.c */ +#line 1515 "go.y" + { + (yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); + ifacedcl((yyval.node)); + } + break; + + case 233: + +/* Line 1806 of yacc.c */ +#line 1520 "go.y" + { + (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym))); + } + break; + + case 234: + +/* Line 1806 of yacc.c */ +#line 1524 "go.y" + { + (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym))); + yyerror("cannot parenthesize embedded type"); + } + break; + + case 235: + +/* Line 1806 of yacc.c */ +#line 1531 "go.y" + { + // without func keyword + (yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1); + (yyval.node) = nod(OTFUNC, fakethis(), N); + (yyval.node)->list = (yyvsp[(2) - (4)].list); + (yyval.node)->rlist = (yyvsp[(4) - (4)].list); + } + break; + + case 237: + +/* Line 1806 of yacc.c */ +#line 1545 "go.y" + { + (yyval.node) = nod(ONONAME, N, N); + (yyval.node)->sym = (yyvsp[(1) - (2)].sym); + (yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node)); + } + break; + + case 238: + +/* Line 1806 of yacc.c */ +#line 1551 "go.y" + { + (yyval.node) = nod(ONONAME, N, N); + (yyval.node)->sym = (yyvsp[(1) - (2)].sym); + (yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node)); + } + break; + + case 240: + +/* Line 1806 of yacc.c */ +#line 1560 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 241: + +/* Line 1806 of yacc.c */ +#line 1564 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + case 242: + +/* Line 1806 of yacc.c */ +#line 1569 "go.y" + { + (yyval.list) = nil; + } + break; + + case 243: + +/* Line 1806 of yacc.c */ +#line 1573 "go.y" + { + (yyval.list) = (yyvsp[(1) - (2)].list); + } + break; + + case 244: + +/* Line 1806 of yacc.c */ +#line 1581 "go.y" + { + (yyval.node) = N; + } + break; + + case 246: + +/* Line 1806 of yacc.c */ +#line 1586 "go.y" + { + (yyval.node) = liststmt((yyvsp[(1) - (1)].list)); + } + break; + + case 248: + +/* Line 1806 of yacc.c */ +#line 1591 "go.y" + { + (yyval.node) = N; + } + break; + + case 254: + +/* Line 1806 of yacc.c */ +#line 1602 "go.y" + { + (yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N); + (yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions + } + break; + + case 255: + +/* Line 1806 of yacc.c */ +#line 1607 "go.y" + { + NodeList *l; + + (yyvsp[(1) - (4)].node)->defn = (yyvsp[(4) - (4)].node); + l = list1((yyvsp[(1) - (4)].node)); + if((yyvsp[(4) - (4)].node)) + l = list(l, (yyvsp[(4) - (4)].node)); + (yyval.node) = liststmt(l); + } + break; + + case 256: + +/* Line 1806 of yacc.c */ +#line 1617 "go.y" + { + // will be converted to OFALL + (yyval.node) = nod(OXFALL, N, N); + } + break; + + case 257: + +/* Line 1806 of yacc.c */ +#line 1622 "go.y" + { + (yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N); + } + break; + + case 258: + +/* Line 1806 of yacc.c */ +#line 1626 "go.y" + { + (yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N); + } + break; + + case 259: + +/* Line 1806 of yacc.c */ +#line 1630 "go.y" + { + (yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N); + } + break; + + case 260: + +/* Line 1806 of yacc.c */ +#line 1634 "go.y" + { + (yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N); + } + break; + + case 261: + +/* Line 1806 of yacc.c */ +#line 1638 "go.y" + { + (yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N); + (yyval.node)->sym = dclstack; // context, for goto restrictions + } + break; + + case 262: + +/* Line 1806 of yacc.c */ +#line 1643 "go.y" + { + (yyval.node) = nod(ORETURN, N, N); + (yyval.node)->list = (yyvsp[(2) - (2)].list); + if((yyval.node)->list == nil && curfn != N) { + NodeList *l; + + for(l=curfn->dcl; l; l=l->next) { + if(l->n->class == PPARAM) + continue; + if(l->n->class != PPARAMOUT) + break; + if(l->n->sym->def != l->n) + yyerror("%s is shadowed during return", l->n->sym->name); + } + } + } + break; + + case 263: + +/* Line 1806 of yacc.c */ +#line 1662 "go.y" + { + (yyval.list) = nil; + if((yyvsp[(1) - (1)].node) != N) + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 264: + +/* Line 1806 of yacc.c */ +#line 1668 "go.y" + { + (yyval.list) = (yyvsp[(1) - (3)].list); + if((yyvsp[(3) - (3)].node) != N) + (yyval.list) = list((yyval.list), (yyvsp[(3) - (3)].node)); + } + break; + + case 265: + +/* Line 1806 of yacc.c */ +#line 1676 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 266: + +/* Line 1806 of yacc.c */ +#line 1680 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + case 267: + +/* Line 1806 of yacc.c */ +#line 1686 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 268: + +/* Line 1806 of yacc.c */ +#line 1690 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + case 269: + +/* Line 1806 of yacc.c */ +#line 1696 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 270: + +/* Line 1806 of yacc.c */ +#line 1700 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + case 271: + +/* Line 1806 of yacc.c */ +#line 1706 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 272: + +/* Line 1806 of yacc.c */ +#line 1710 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + case 273: + +/* Line 1806 of yacc.c */ +#line 1719 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 274: + +/* Line 1806 of yacc.c */ +#line 1723 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 275: + +/* Line 1806 of yacc.c */ +#line 1727 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + case 276: + +/* Line 1806 of yacc.c */ +#line 1731 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + case 277: + +/* Line 1806 of yacc.c */ +#line 1736 "go.y" + { + (yyval.list) = nil; + } + break; + + case 278: + +/* Line 1806 of yacc.c */ +#line 1740 "go.y" + { + (yyval.list) = (yyvsp[(1) - (2)].list); + } + break; + + case 283: + +/* Line 1806 of yacc.c */ +#line 1754 "go.y" + { + (yyval.node) = N; + } + break; + + case 285: + +/* Line 1806 of yacc.c */ +#line 1760 "go.y" + { + (yyval.list) = nil; + } + break; + + case 287: + +/* Line 1806 of yacc.c */ +#line 1766 "go.y" + { + (yyval.node) = N; + } + break; + + case 289: + +/* Line 1806 of yacc.c */ +#line 1772 "go.y" + { + (yyval.list) = nil; + } + break; + + case 291: + +/* Line 1806 of yacc.c */ +#line 1778 "go.y" + { + (yyval.list) = nil; + } + break; + + case 293: + +/* Line 1806 of yacc.c */ +#line 1784 "go.y" + { + (yyval.list) = nil; + } + break; + + case 295: + +/* Line 1806 of yacc.c */ +#line 1790 "go.y" + { + (yyval.val).ctype = CTxxx; + } + break; + + case 297: + +/* Line 1806 of yacc.c */ +#line 1800 "go.y" + { + importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval); + } + break; + + case 298: + +/* Line 1806 of yacc.c */ +#line 1804 "go.y" + { + importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type)); + } + break; + + case 299: + +/* Line 1806 of yacc.c */ +#line 1808 "go.y" + { + importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node)); + } + break; + + case 300: + +/* Line 1806 of yacc.c */ +#line 1812 "go.y" + { + importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node)); + } + break; + + case 301: + +/* Line 1806 of yacc.c */ +#line 1816 "go.y" + { + importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type)); + } + break; + + case 302: + +/* Line 1806 of yacc.c */ +#line 1820 "go.y" + { + if((yyvsp[(2) - (4)].node) == N) + break; + + (yyvsp[(2) - (4)].node)->inl = (yyvsp[(3) - (4)].list); + + funcbody((yyvsp[(2) - (4)].node)); + importlist = list(importlist, (yyvsp[(2) - (4)].node)); + + if(debug['E']) { + print("import [%Z] func %lN \n", importpkg->path, (yyvsp[(2) - (4)].node)); + if(debug['l'] > 2 && (yyvsp[(2) - (4)].node)->inl) + print("inl body:%+H\n", (yyvsp[(2) - (4)].node)->inl); + } + } + break; + + case 303: + +/* Line 1806 of yacc.c */ +#line 1838 "go.y" + { + (yyval.sym) = (yyvsp[(1) - (1)].sym); + structpkg = (yyval.sym)->pkg; + } + break; + + case 304: + +/* Line 1806 of yacc.c */ +#line 1845 "go.y" + { + (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); + importsym((yyvsp[(1) - (1)].sym), OTYPE); + } + break; + + case 310: + +/* Line 1806 of yacc.c */ +#line 1865 "go.y" + { + (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); + } + break; + + case 311: + +/* Line 1806 of yacc.c */ +#line 1869 "go.y" + { + // predefined name like uint8 + (yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg); + if((yyvsp[(1) - (1)].sym)->def == N || (yyvsp[(1) - (1)].sym)->def->op != OTYPE) { + yyerror("%s is not a type", (yyvsp[(1) - (1)].sym)->name); + (yyval.type) = T; + } else + (yyval.type) = (yyvsp[(1) - (1)].sym)->def->type; + } + break; + + case 312: + +/* Line 1806 of yacc.c */ +#line 1879 "go.y" + { + (yyval.type) = aindex(N, (yyvsp[(3) - (3)].type)); + } + break; + + case 313: + +/* Line 1806 of yacc.c */ +#line 1883 "go.y" + { + (yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type)); + } + break; + + case 314: + +/* Line 1806 of yacc.c */ +#line 1887 "go.y" + { + (yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type)); + } + break; + + case 315: + +/* Line 1806 of yacc.c */ +#line 1891 "go.y" + { + (yyval.type) = tostruct((yyvsp[(3) - (4)].list)); + } + break; + + case 316: + +/* Line 1806 of yacc.c */ +#line 1895 "go.y" + { + (yyval.type) = tointerface((yyvsp[(3) - (4)].list)); + } + break; + + case 317: + +/* Line 1806 of yacc.c */ +#line 1899 "go.y" + { + (yyval.type) = ptrto((yyvsp[(2) - (2)].type)); + } + break; + + case 318: + +/* Line 1806 of yacc.c */ +#line 1903 "go.y" + { + (yyval.type) = typ(TCHAN); + (yyval.type)->type = (yyvsp[(2) - (2)].type); + (yyval.type)->chan = Cboth; + } + break; + + case 319: + +/* Line 1806 of yacc.c */ +#line 1909 "go.y" + { + (yyval.type) = typ(TCHAN); + (yyval.type)->type = (yyvsp[(3) - (4)].type); + (yyval.type)->chan = Cboth; + } + break; + + case 320: + +/* Line 1806 of yacc.c */ +#line 1915 "go.y" + { + (yyval.type) = typ(TCHAN); + (yyval.type)->type = (yyvsp[(3) - (3)].type); + (yyval.type)->chan = Csend; + } + break; + + case 321: + +/* Line 1806 of yacc.c */ +#line 1923 "go.y" + { + (yyval.type) = typ(TCHAN); + (yyval.type)->type = (yyvsp[(3) - (3)].type); + (yyval.type)->chan = Crecv; + } + break; + + case 322: + +/* Line 1806 of yacc.c */ +#line 1931 "go.y" + { + (yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)); + } + break; + + case 323: + +/* Line 1806 of yacc.c */ +#line 1937 "go.y" + { + (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type))); + if((yyvsp[(1) - (3)].sym)) + (yyval.node)->left = newname((yyvsp[(1) - (3)].sym)); + (yyval.node)->val = (yyvsp[(3) - (3)].val); + } + break; + + case 324: + +/* Line 1806 of yacc.c */ +#line 1944 "go.y" + { + Type *t; + + t = typ(TARRAY); + t->bound = -1; + t->type = (yyvsp[(3) - (4)].type); + + (yyval.node) = nod(ODCLFIELD, N, typenod(t)); + if((yyvsp[(1) - (4)].sym)) + (yyval.node)->left = newname((yyvsp[(1) - (4)].sym)); + (yyval.node)->isddd = 1; + (yyval.node)->val = (yyvsp[(4) - (4)].val); + } + break; + + case 325: + +/* Line 1806 of yacc.c */ +#line 1960 "go.y" + { + Sym *s; + + if((yyvsp[(1) - (3)].sym) != S) { + (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (3)].sym)), typenod((yyvsp[(2) - (3)].type))); + (yyval.node)->val = (yyvsp[(3) - (3)].val); + } else { + s = (yyvsp[(2) - (3)].type)->sym; + if(s == S && isptr[(yyvsp[(2) - (3)].type)->etype]) + s = (yyvsp[(2) - (3)].type)->type->sym; + (yyval.node) = embedded(s); + (yyval.node)->right = typenod((yyvsp[(2) - (3)].type)); + (yyval.node)->val = (yyvsp[(3) - (3)].val); + } + } + break; + + case 326: + +/* Line 1806 of yacc.c */ +#line 1978 "go.y" + { + (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)))); + } + break; + + case 327: + +/* Line 1806 of yacc.c */ +#line 1982 "go.y" + { + (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))); + } + break; + + case 328: + +/* Line 1806 of yacc.c */ +#line 1987 "go.y" + { + (yyval.list) = nil; + } + break; + + case 330: + +/* Line 1806 of yacc.c */ +#line 1994 "go.y" + { + (yyval.list) = (yyvsp[(2) - (3)].list); + } + break; + + case 331: + +/* Line 1806 of yacc.c */ +#line 1998 "go.y" + { + (yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)))); + } + break; + + case 332: + +/* Line 1806 of yacc.c */ +#line 2008 "go.y" + { + (yyval.node) = nodlit((yyvsp[(1) - (1)].val)); + } + break; + + case 333: + +/* Line 1806 of yacc.c */ +#line 2012 "go.y" + { + (yyval.node) = nodlit((yyvsp[(2) - (2)].val)); + switch((yyval.node)->val.ctype){ + case CTINT: + case CTRUNE: + mpnegfix((yyval.node)->val.u.xval); + break; + case CTFLT: + mpnegflt((yyval.node)->val.u.fval); + break; + default: + yyerror("bad negated constant"); + } + } + break; + + case 334: + +/* Line 1806 of yacc.c */ +#line 2027 "go.y" + { + (yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg)); + if((yyval.node)->op != OLITERAL) + yyerror("bad constant %S", (yyval.node)->sym); + } + break; + + case 336: + +/* Line 1806 of yacc.c */ +#line 2036 "go.y" + { + if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) { + (yyval.node) = (yyvsp[(2) - (5)].node); + mpaddfixfix((yyvsp[(2) - (5)].node)->val.u.xval, (yyvsp[(4) - (5)].node)->val.u.xval, 0); + break; + } + (yyval.node) = nodcplxlit((yyvsp[(2) - (5)].node)->val, (yyvsp[(4) - (5)].node)->val); + } + break; + + case 339: + +/* Line 1806 of yacc.c */ +#line 2050 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 340: + +/* Line 1806 of yacc.c */ +#line 2054 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + case 341: + +/* Line 1806 of yacc.c */ +#line 2060 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 342: + +/* Line 1806 of yacc.c */ +#line 2064 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + case 343: + +/* Line 1806 of yacc.c */ +#line 2070 "go.y" + { + (yyval.list) = list1((yyvsp[(1) - (1)].node)); + } + break; + + case 344: + +/* Line 1806 of yacc.c */ +#line 2074 "go.y" + { + (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); + } + break; + + + +/* Line 1806 of yacc.c */ +#line 5298 "y.tab.c" + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 2067 of yacc.c */ +#line 2078 "go.y" + + +static void +fixlbrace(int lbr) +{ + // If the opening brace was an LBODY, + // set up for another one now that we're done. + // See comment in lex.c about loophack. + if(lbr == LBODY) + loophack = 1; +} + + diff --git a/src/cmd/gc/y.tab.h b/src/cmd/gc/y.tab.h new file mode 100644 index 000000000..bc6c47d6d --- /dev/null +++ b/src/cmd/gc/y.tab.h @@ -0,0 +1,171 @@ +/* A Bison parser, made by GNU Bison 2.5. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + LLITERAL = 258, + LASOP = 259, + LBREAK = 260, + LCASE = 261, + LCHAN = 262, + LCOLAS = 263, + LCONST = 264, + LCONTINUE = 265, + LDDD = 266, + LDEFAULT = 267, + LDEFER = 268, + LELSE = 269, + LFALL = 270, + LFOR = 271, + LFUNC = 272, + LGO = 273, + LGOTO = 274, + LIF = 275, + LIMPORT = 276, + LINTERFACE = 277, + LMAP = 278, + LNAME = 279, + LPACKAGE = 280, + LRANGE = 281, + LRETURN = 282, + LSELECT = 283, + LSTRUCT = 284, + LSWITCH = 285, + LTYPE = 286, + LVAR = 287, + LANDAND = 288, + LANDNOT = 289, + LBODY = 290, + LCOMM = 291, + LDEC = 292, + LEQ = 293, + LGE = 294, + LGT = 295, + LIGNORE = 296, + LINC = 297, + LLE = 298, + LLSH = 299, + LLT = 300, + LNE = 301, + LOROR = 302, + LRSH = 303, + NotPackage = 304, + NotParen = 305, + PreferToRightParen = 306 + }; +#endif +/* Tokens. */ +#define LLITERAL 258 +#define LASOP 259 +#define LBREAK 260 +#define LCASE 261 +#define LCHAN 262 +#define LCOLAS 263 +#define LCONST 264 +#define LCONTINUE 265 +#define LDDD 266 +#define LDEFAULT 267 +#define LDEFER 268 +#define LELSE 269 +#define LFALL 270 +#define LFOR 271 +#define LFUNC 272 +#define LGO 273 +#define LGOTO 274 +#define LIF 275 +#define LIMPORT 276 +#define LINTERFACE 277 +#define LMAP 278 +#define LNAME 279 +#define LPACKAGE 280 +#define LRANGE 281 +#define LRETURN 282 +#define LSELECT 283 +#define LSTRUCT 284 +#define LSWITCH 285 +#define LTYPE 286 +#define LVAR 287 +#define LANDAND 288 +#define LANDNOT 289 +#define LBODY 290 +#define LCOMM 291 +#define LDEC 292 +#define LEQ 293 +#define LGE 294 +#define LGT 295 +#define LIGNORE 296 +#define LINC 297 +#define LLE 298 +#define LLSH 299 +#define LLT 300 +#define LNE 301 +#define LOROR 302 +#define LRSH 303 +#define NotPackage 304 +#define NotParen 305 +#define PreferToRightParen 306 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 2068 of yacc.c */ +#line 28 "go.y" + + Node* node; + NodeList* list; + Type* type; + Sym* sym; + struct Val val; + int i; + + + +/* Line 2068 of yacc.c */ +#line 163 "y.tab.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +extern YYSTYPE yylval; + + diff --git a/src/cmd/gc/yerr.h b/src/cmd/gc/yerr.h new file mode 100644 index 000000000..588890d0e --- /dev/null +++ b/src/cmd/gc/yerr.h @@ -0,0 +1,73 @@ +// Copyright 2010 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. + +// Example-based syntax error messages. +// See bisonerrors, Makefile, go.y. + +static struct { + int yystate; + int yychar; + char *msg; +} yymsg[] = { + // Each line of the form % token list + // is converted by bisonerrors into the yystate and yychar caused + // by that token list. + + 221, ',', + "unexpected comma during import block", + + 377, ';', + "unexpected semicolon or newline before {", + + 398, ';', + "unexpected semicolon or newline before {", + + 237, ';', + "unexpected semicolon or newline before {", + + 474, LBODY, + "unexpected semicolon or newline before {", + + 22, '{', + "unexpected semicolon or newline before {", + + 144, ';', + "unexpected semicolon or newline in type declaration", + + 37, '}', + "unexpected } in channel type", + + 37, ')', + "unexpected ) in channel type", + + 37, ',', + "unexpected comma in channel type", + + 437, LELSE, + "unexpected semicolon or newline before else", + + 257, ',', + "name list not allowed in interface type", + + 237, LVAR, + "var declaration not allowed in for initializer", + + 65, '{', + "unexpected { at end of statement", + + 376, '{', + "unexpected { at end of statement", + + 125, ';', + "argument to go/defer must be function call", + + 425, ';', + "need trailing comma before newline in composite literal", + + 112, LNAME, + "nested func not allowed", + + 615, ';', + "else must be followed by if or statement block" +}; |