summaryrefslogtreecommitdiff
path: root/src/cmd/gc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc')
-rw-r--r--src/cmd/gc/Makefile72
-rw-r--r--src/cmd/gc/align.c12
-rwxr-xr-xsrc/cmd/gc/bisonerrors29
-rw-r--r--src/cmd/gc/bits.c10
-rw-r--r--src/cmd/gc/builtin.c118
-rw-r--r--src/cmd/gc/builtin.c.boot114
-rw-r--r--src/cmd/gc/closure.c9
-rw-r--r--src/cmd/gc/const.c123
-rw-r--r--src/cmd/gc/cplx.c7
-rw-r--r--src/cmd/gc/dcl.c567
-rw-r--r--src/cmd/gc/doc.go9
-rw-r--r--src/cmd/gc/esc.c805
-rw-r--r--src/cmd/gc/export.c345
-rw-r--r--src/cmd/gc/fmt.c1639
-rw-r--r--src/cmd/gc/gen.c171
-rw-r--r--src/cmd/gc/go.errors3
-rw-r--r--src/cmd/gc/go.h301
-rw-r--r--src/cmd/gc/go.y448
-rw-r--r--src/cmd/gc/init.c18
-rw-r--r--src/cmd/gc/inl.c842
-rw-r--r--src/cmd/gc/lex.c427
-rw-r--r--src/cmd/gc/md5.c2
-rwxr-xr-xsrc/cmd/gc/mkbuiltin22
-rw-r--r--src/cmd/gc/mkbuiltin1.c34
-rwxr-xr-xsrc/cmd/gc/mkopnames4
-rw-r--r--src/cmd/gc/mparith1.c12
-rw-r--r--src/cmd/gc/mparith2.c81
-rw-r--r--src/cmd/gc/mparith3.c12
-rw-r--r--src/cmd/gc/obj.c51
-rw-r--r--src/cmd/gc/order.c358
-rw-r--r--src/cmd/gc/pgen.c27
-rw-r--r--src/cmd/gc/print.c480
-rw-r--r--src/cmd/gc/range.c50
-rw-r--r--src/cmd/gc/reflect.c217
-rw-r--r--src/cmd/gc/runtime.go25
-rw-r--r--src/cmd/gc/select.c14
-rw-r--r--src/cmd/gc/sinit.c465
-rw-r--r--src/cmd/gc/subr.c1897
-rw-r--r--src/cmd/gc/swt.c63
-rw-r--r--src/cmd/gc/typecheck.c770
-rw-r--r--src/cmd/gc/unsafe.c25
-rw-r--r--src/cmd/gc/unsafe.go8
-rw-r--r--src/cmd/gc/walk.c812
-rw-r--r--src/cmd/gc/y.tab.c5540
-rw-r--r--src/cmd/gc/y.tab.h171
-rw-r--r--src/cmd/gc/yerr.h73
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"
+};