summaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/5g/cgen.c67
-rw-r--r--src/cmd/5g/gsubr.c25
-rw-r--r--src/cmd/5l/5.out.h1
-rw-r--r--src/cmd/5l/asm.c57
-rw-r--r--src/cmd/5l/l.h9
-rw-r--r--src/cmd/5l/obj.c24
-rw-r--r--src/cmd/6a/lex.c3
-rw-r--r--src/cmd/6c/swt.c2
-rw-r--r--src/cmd/6g/cgen.c59
-rw-r--r--src/cmd/6g/ggen.c2
-rw-r--r--src/cmd/6g/gobj.c3
-rw-r--r--src/cmd/6g/gsubr.c24
-rw-r--r--src/cmd/6g/peep.c5
-rw-r--r--src/cmd/6g/reg.c11
-rw-r--r--src/cmd/6l/6.out.h4
-rw-r--r--src/cmd/6l/asm.c172
-rw-r--r--src/cmd/6l/l.h17
-rw-r--r--src/cmd/6l/obj.c39
-rw-r--r--src/cmd/6l/optab.c20
-rw-r--r--src/cmd/6l/span.c34
-rw-r--r--src/cmd/8a/a.y24
-rw-r--r--src/cmd/8a/lex.c8
-rw-r--r--src/cmd/8a/y.tab.c1964
-rw-r--r--src/cmd/8a/y.tab.h130
-rw-r--r--src/cmd/8c/swt.c2
-rw-r--r--src/cmd/8g/cgen.c55
-rw-r--r--src/cmd/8g/gsubr.c19
-rw-r--r--src/cmd/8l/8.out.h13
-rw-r--r--src/cmd/8l/asm.c191
-rw-r--r--src/cmd/8l/l.h16
-rw-r--r--src/cmd/8l/obj.c40
-rw-r--r--src/cmd/8l/optab.c39
-rw-r--r--src/cmd/8l/pass.c50
-rw-r--r--src/cmd/8l/span.c54
-rw-r--r--src/cmd/addr2line/main.c19
-rw-r--r--src/cmd/api/goapi.go14
-rw-r--r--src/cmd/cc/cc.h1
-rw-r--r--src/cmd/cc/dpchk.c22
-rw-r--r--src/cmd/cc/funct.c2
-rw-r--r--src/cmd/cc/lexbody2
-rw-r--r--src/cmd/cgo/doc.go22
-rw-r--r--src/cmd/cgo/gcc.go108
-rw-r--r--src/cmd/cgo/main.go29
-rw-r--r--src/cmd/cgo/out.go11
-rw-r--r--src/cmd/cov/Makefile5
-rw-r--r--src/cmd/cov/doc.go36
-rw-r--r--src/cmd/cov/main.c484
-rw-r--r--src/cmd/cov/tree.c245
-rw-r--r--src/cmd/cov/tree.h47
-rw-r--r--src/cmd/dist/a.h1
-rw-r--r--src/cmd/dist/build.c67
-rw-r--r--src/cmd/dist/buildruntime.c11
-rw-r--r--src/cmd/dist/goc2c.c3
-rw-r--r--src/cmd/dist/unix.c13
-rw-r--r--src/cmd/dist/windows.c2
-rw-r--r--src/cmd/fix/netipv6zone.go11
-rw-r--r--src/cmd/fix/netipv6zone_test.go28
-rw-r--r--src/cmd/gc/align.c7
-rw-r--r--src/cmd/gc/builtin.c7
-rw-r--r--src/cmd/gc/closure.c194
-rw-r--r--src/cmd/gc/const.c36
-rw-r--r--src/cmd/gc/cplx.c8
-rw-r--r--src/cmd/gc/dcl.c56
-rw-r--r--src/cmd/gc/esc.c13
-rw-r--r--src/cmd/gc/fmt.c11
-rw-r--r--src/cmd/gc/gen.c7
-rw-r--r--src/cmd/gc/go.h26
-rw-r--r--src/cmd/gc/go.y8
-rw-r--r--src/cmd/gc/inl.c32
-rw-r--r--src/cmd/gc/lex.c11
-rwxr-xr-xsrc/cmd/gc/mkbuiltin1
-rw-r--r--src/cmd/gc/obj.c14
-rw-r--r--src/cmd/gc/pgen.c13
-rw-r--r--src/cmd/gc/racewalk.c162
-rw-r--r--src/cmd/gc/range.c6
-rw-r--r--src/cmd/gc/reflect.c46
-rw-r--r--src/cmd/gc/runtime.go6
-rw-r--r--src/cmd/gc/sinit.c8
-rw-r--r--src/cmd/gc/subr.c54
-rw-r--r--src/cmd/gc/swt.c6
-rw-r--r--src/cmd/gc/typecheck.c204
-rw-r--r--src/cmd/gc/unsafe.c42
-rw-r--r--src/cmd/gc/walk.c185
-rw-r--r--src/cmd/gc/y.tab.c594
-rw-r--r--src/cmd/go/build.go122
-rw-r--r--src/cmd/go/clean.go2
-rw-r--r--src/cmd/go/discovery.go1
-rw-r--r--src/cmd/go/doc.go66
-rw-r--r--src/cmd/go/env.go1
-rw-r--r--src/cmd/go/go11.go10
-rw-r--r--src/cmd/go/help.go8
-rw-r--r--src/cmd/go/main.go37
-rwxr-xr-xsrc/cmd/go/mkdoc.sh1
-rw-r--r--src/cmd/go/pkg.go7
-rw-r--r--src/cmd/go/run.go1
-rwxr-xr-xsrc/cmd/go/test.bash39
-rw-r--r--src/cmd/go/test.go29
-rw-r--r--src/cmd/go/testdata/errmsg/x.go3
-rw-r--r--src/cmd/go/testdata/errmsg/x1_test.go3
-rw-r--r--src/cmd/go/testdata/errmsg/x_test.go3
-rw-r--r--src/cmd/go/vcs.go2
-rw-r--r--src/cmd/go/vet.go2
-rw-r--r--src/cmd/godoc/doc.go5
-rw-r--r--src/cmd/godoc/format.go80
-rw-r--r--src/cmd/godoc/godoc.go131
-rw-r--r--src/cmd/godoc/index.go2
-rw-r--r--src/cmd/godoc/linkify.go234
-rw-r--r--src/cmd/godoc/main.go16
-rw-r--r--src/cmd/godoc/utils.go2
-rw-r--r--src/cmd/gofmt/gofmt_test.go3
-rw-r--r--src/cmd/gofmt/rewrite.go16
-rw-r--r--src/cmd/gofmt/testdata/rewrite6.golden15
-rw-r--r--src/cmd/gofmt/testdata/rewrite6.input15
-rw-r--r--src/cmd/gofmt/testdata/rewrite7.golden15
-rw-r--r--src/cmd/gofmt/testdata/rewrite7.input15
-rw-r--r--src/cmd/gofmt/testdata/rewrite8.golden10
-rw-r--r--src/cmd/gofmt/testdata/rewrite8.input10
-rw-r--r--src/cmd/ld/data.c429
-rw-r--r--src/cmd/ld/doc.go31
-rw-r--r--src/cmd/ld/dwarf.c522
-rw-r--r--src/cmd/ld/dwarf_defs.h1
-rw-r--r--src/cmd/ld/elf.c73
-rw-r--r--src/cmd/ld/elf.h7
-rw-r--r--src/cmd/ld/go.c112
-rw-r--r--src/cmd/ld/ldelf.c4
-rw-r--r--src/cmd/ld/ldmacho.c8
-rw-r--r--src/cmd/ld/ldpe.c26
-rw-r--r--src/cmd/ld/lib.c398
-rw-r--r--src/cmd/ld/lib.h65
-rw-r--r--src/cmd/ld/macho.c592
-rw-r--r--src/cmd/ld/macho.h13
-rw-r--r--src/cmd/ld/pe.c14
-rw-r--r--src/cmd/ld/symtab.c69
-rw-r--r--src/cmd/nm/nm.c6
-rw-r--r--src/cmd/prof/Makefile5
-rw-r--r--src/cmd/prof/doc.go49
-rw-r--r--src/cmd/prof/main.c910
-rw-r--r--src/cmd/vet/Makefile10
-rw-r--r--src/cmd/vet/asmdecl.go533
-rw-r--r--src/cmd/vet/assign.go44
-rw-r--r--src/cmd/vet/buildtag.go2
-rw-r--r--src/cmd/vet/deadcode.go280
-rw-r--r--src/cmd/vet/doc.go6
-rw-r--r--src/cmd/vet/main.go118
-rw-r--r--src/cmd/vet/method.go2
-rw-r--r--src/cmd/vet/print.go117
-rw-r--r--src/cmd/vet/structtag.go4
-rw-r--r--src/cmd/vet/taglit.go54
-rw-r--r--src/cmd/vet/test_asm.go24
-rw-r--r--src/cmd/vet/test_asm1.s247
-rw-r--r--src/cmd/vet/test_asm2.s251
-rw-r--r--src/cmd/vet/test_asm3.s166
-rw-r--r--src/cmd/vet/test_assign.go20
-rw-r--r--src/cmd/vet/test_buildtag_bad.go (renamed from src/cmd/vet/buildtag_bad.go)6
-rw-r--r--src/cmd/vet/test_deadcode.go2121
-rw-r--r--src/cmd/vet/test_taglit.go34
-rw-r--r--src/cmd/vet/types.go179
-rw-r--r--src/cmd/vet/typestub.go45
-rw-r--r--src/cmd/yacc/yacc.go1
159 files changed, 9586 insertions, 5041 deletions
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index 9e35f9566..1620f410a 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -679,6 +679,21 @@ agen(Node *n, Node *res)
case ODOT:
agen(nl, res);
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer. If the left node
+ // was ODOT we have already done the nil check.
+ if(nl->op != ODOT)
+ if(nl->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], N);
+ gmove(res, &n1);
+ regalloc(&n2, types[TUINT8], &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gmove(&n1, &n2);
+ regfree(&n1);
+ regfree(&n2);
+ }
if(n->xoffset != 0) {
nodconst(&n1, types[TINT32], n->xoffset);
regalloc(&n2, n1.type, N);
@@ -694,20 +709,20 @@ agen(Node *n, Node *res)
case ODOTPTR:
cgen(nl, res);
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(nl->type->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], N);
+ gmove(res, &n1);
+ regalloc(&n2, types[TUINT8], &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gmove(&n1, &n2);
+ regfree(&n1);
+ regfree(&n2);
+ }
if(n->xoffset != 0) {
- // explicit check for nil if struct is large enough
- // that we might derive too big a pointer.
- if(nl->type->type->width >= unmappedzero) {
- regalloc(&n1, types[tptr], N);
- gmove(res, &n1);
- regalloc(&n2, types[TUINT8], &n1);
- n1.op = OINDREG;
- n1.type = types[TUINT8];
- n1.xoffset = 0;
- gmove(&n1, &n2);
- regfree(&n1);
- regfree(&n2);
- }
nodconst(&n1, types[TINT32], n->xoffset);
regalloc(&n2, n1.type, N);
regalloc(&n3, types[tptr], N);
@@ -777,20 +792,18 @@ igen(Node *n, Node *a, Node *res)
regalloc(a, types[tptr], res);
cgen(n->left, a);
}
- if(n->xoffset != 0) {
- // explicit check for nil if struct is large enough
- // that we might derive too big a pointer.
- if(n->left->type->type->width >= unmappedzero) {
- regalloc(&n1, types[tptr], N);
- gmove(a, &n1);
- regalloc(&n2, types[TUINT8], &n1);
- n1.op = OINDREG;
- n1.type = types[TUINT8];
- n1.xoffset = 0;
- gmove(&n1, &n2);
- regfree(&n1);
- regfree(&n2);
- }
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(n->left->type->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], N);
+ gmove(a, &n1);
+ regalloc(&n2, types[TUINT8], &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gmove(&n1, &n2);
+ regfree(&n1);
+ regfree(&n2);
}
a->op = OINDREG;
a->xoffset = n->xoffset;
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 191c755b8..815d6fab2 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -543,6 +543,7 @@ ismem(Node *n)
case OINDREG:
case ONAME:
case OPARAM:
+ case OCLOSUREVAR:
return 1;
}
return 0;
@@ -1163,11 +1164,11 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
// Generate an instruction referencing *n
// to force segv on nil pointer dereference.
void
-checkref(Node *n)
+checkref(Node *n, int force)
{
Node m1, m2;
- if(n->type->type->width < unmappedzero)
+ if(!force && isptr[n->type->etype] && n->type->type->width < unmappedzero)
return;
regalloc(&m1, types[TUINTPTR], n);
@@ -1209,8 +1210,6 @@ checkoffset(Addr *a, int canemitcode)
void
naddr(Node *n, Addr *a, int canemitcode)
{
- Prog *p;
-
a->type = D_NONE;
a->name = D_NONE;
a->reg = NREG;
@@ -1283,16 +1282,9 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case OCLOSUREVAR:
- if(!canemitcode)
- fatal("naddr OCLOSUREVAR cannot emit code");
- p = gins(AMOVW, N, N);
- p->from.type = D_OREG;
- p->from.reg = 7;
- p->from.offset = n->xoffset;
- p->to.type = D_REG;
- p->to.reg = 1;
- a->type = D_REG;
- a->reg = 1;
+ a->type = D_OREG;
+ a->reg = 7;
+ a->offset = n->xoffset;
a->sym = S;
break;
@@ -1793,7 +1785,8 @@ sudoclean(void)
int
dotaddable(Node *n, Node *n1)
{
- int o, oary[10];
+ int o;
+ int64 oary[10];
Node *nn;
if(n->op != ODOT)
@@ -1824,7 +1817,7 @@ int
sudoaddable(int as, Node *n, Addr *a, int *w)
{
int o, i;
- int oary[10];
+ int64 oary[10];
int64 v;
Node n1, n2, n3, n4, *nn, *l, *r;
Node *reg, *reg1;
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index 4aef8a27f..97a2421b3 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -275,6 +275,7 @@ enum as
#define D_PLT1 (D_NONE+44) // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000
#define D_PLT2 (D_NONE+45) // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]!
#define D_CALL (D_NONE+46) // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy
+#define D_TLS (D_NONE+47)
/*
* this is the ranlib header
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 04f2a9c6c..a1220a38e 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -125,7 +125,7 @@ adddynrel(Sym *s, Reloc *r)
// Handle relocations found in ELF object files.
case 256 + R_ARM_PLT32:
r->type = D_CALL;
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->type == SDYNIMPORT) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
@@ -138,7 +138,7 @@ adddynrel(Sym *s, Reloc *r)
return;
case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->type != SDYNIMPORT) {
addgotsyminternal(targ);
} else {
addgotsym(targ);
@@ -149,7 +149,7 @@ adddynrel(Sym *s, Reloc *r)
return;
case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->type != SDYNIMPORT) {
addgotsyminternal(targ);
} else {
addgotsym(targ);
@@ -171,7 +171,7 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_ARM_CALL:
r->type = D_CALL;
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->type == SDYNIMPORT) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
@@ -184,7 +184,7 @@ adddynrel(Sym *s, Reloc *r)
return;
case 256 + R_ARM_ABS32:
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->type == SDYNIMPORT)
diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name);
r->type = D_ADDR;
return;
@@ -201,7 +201,7 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_ARM_PC24:
case 256 + R_ARM_JUMP24:
r->type = D_CALL;
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->type == SDYNIMPORT) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add = braddoff(r->add, targ->plt / 4);
@@ -210,7 +210,7 @@ adddynrel(Sym *s, Reloc *r)
}
// Handle references to ELF symbols from our own object files.
- if(targ->dynimpname == nil || targ->dynexport)
+ if(targ->type != SDYNIMPORT)
return;
switch(r->type) {
@@ -240,12 +240,13 @@ adddynrel(Sym *s, Reloc *r)
}
int
-elfreloc1(Reloc *r, vlong off, int32 elfsym, vlong add)
+elfreloc1(Reloc *r, vlong sectoff)
{
- USED(add); // written to obj file by ../ld/data.c's reloc
-
- LPUT(off);
+ int32 elfsym;
+
+ LPUT(sectoff);
+ elfsym = r->xsym->elfsym;
switch(r->type) {
default:
return -1;
@@ -295,6 +296,16 @@ elfsetupplt(void)
}
int
+machoreloc1(Reloc *r, vlong sectoff)
+{
+ USED(r);
+ USED(sectoff);
+
+ return -1;
+}
+
+
+int
archreloc(Reloc *r, Sym *s, vlong *val)
{
switch(r->type) {
@@ -324,15 +335,16 @@ archreloc(Reloc *r, Sym *s, vlong *val)
*val = braddoff((0xff000000U & (uint32)r->add),
(0xffffff & (uint32)
((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4)));
- return 0;
-}
-return -1;
+ return 0;
+ }
+ return -1;
}
static Reloc *
addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ)
{
-Reloc *r;
+ Reloc *r;
+
r = addrel(plt);
r->sym = got;
r->off = plt->size;
@@ -437,20 +449,13 @@ adddynsym(Sym *s)
if(s->dynid >= 0)
return;
- if(s->dynimpname == nil) {
- s->dynimpname = s->name;
- //diag("adddynsym: no dynamic name for %s", s->name);
- }
-
if(iself) {
s->dynid = nelfsym++;
d = lookup(".dynsym", 0);
/* name */
- name = s->dynimpname;
- if(name == nil)
- name = s->name;
+ name = s->extname;
adduint32(d, addstring(lookup(".dynstr", 0), name));
/* value */
@@ -464,7 +469,7 @@ adddynsym(Sym *s)
/* type */
t = STB_GLOBAL << 4;
- if(s->dynexport && (s->type&SMASK) == STEXT)
+ if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT)
t |= STT_FUNC;
else
t |= STT_OBJECT;
@@ -472,7 +477,7 @@ adddynsym(Sym *s)
adduint8(d, 0);
/* shndx */
- if(!s->dynexport && s->dynimpname != nil)
+ if(s->type == SDYNIMPORT)
adduint16(d, SHN_UNDEF);
else {
switch(s->type) {
@@ -600,7 +605,7 @@ asmb(void)
Bprint(&bso, "%5.2f dwarf\n", cputime());
dwarfemitdebugsections();
- if(isobj)
+ if(linkmode == LinkExternal)
elfemitreloc();
}
break;
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index 62dd8947f..e7794c723 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -38,6 +38,7 @@ enum
thechar = '5',
PtrSize = 4,
IntSize = 4,
+ MaxAlign = 8, // max data alignment
FuncAlign = 4 // single-instruction alignment
};
@@ -95,9 +96,12 @@ struct Reloc
{
int32 off;
uchar siz;
+ uchar done;
int16 type;
int32 add;
+ int32 xadd;
Sym* sym;
+ Sym* xsym;
};
struct Prog
@@ -133,11 +137,12 @@ struct Prog
struct Sym
{
char* name;
+ char* extname; // name used in external object files
short type;
short version;
uchar dupok;
uchar reachable;
- uchar dynexport;
+ uchar cgoexport;
uchar leaf;
int32 dynid;
int32 plt;
@@ -162,7 +167,6 @@ struct Sym
Sym* reachparent;
Sym* queue;
char* file;
- char* dynimpname;
char* dynimplib;
char* dynimpvers;
struct Section* sect;
@@ -295,7 +299,6 @@ EXTERN Auto* curhist;
EXTERN Prog* curp;
EXTERN Sym* cursym;
EXTERN Sym* datap;
-EXTERN int32 elfdatsize;
EXTERN int debug[128];
EXTERN Sym* etextp;
EXTERN char* noname;
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index 6aa7fdd69..24e6294a8 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -82,6 +82,7 @@ main(int argc, char *argv[])
INITRND = -1;
INITENTRY = 0;
LIBINITENTRY = 0;
+ linkmode = LinkInternal; // TODO: LinkAuto once everything works.
nuxiinit();
p = getgoarm();
@@ -113,25 +114,42 @@ main(int argc, char *argv[])
flagcount("a", "disassemble output", &debug['a']);
flagcount("c", "dump call graph", &debug['c']);
flagcount("d", "disable dynamic executable", &debug['d']);
+ flagstr("extld", "linker to run in external mode", &extld);
+ flagstr("extldflags", "flags for external linker", &extldflags);
flagcount("f", "ignore version mismatch", &debug['f']);
flagcount("g", "disable go package data checks", &debug['g']);
flagstr("k", "sym: set field tracking symbol", &tracksym);
+ flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
flagcount("n", "dump symbol table", &debug['n']);
flagstr("o", "outfile: set output file", &outfile);
flagcount("p", "insert profiling code", &debug['p']);
flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
flagcount("race", "enable race detector", &flag_race);
flagcount("s", "disable symbol table", &debug['s']);
+ flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
flagcount("u", "reject unsafe packages", &debug['u']);
flagcount("v", "print link trace", &debug['v']);
flagcount("w", "disable DWARF generation", &debug['w']);
flagcount("shared", "generate shared object", &flag_shared);
+ // TODO: link mode flag
flagparse(&argc, &argv, usage);
if(argc != 1)
usage();
+ // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
+ // Go was built; see ../../make.bash.
+ if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
+ linkmode = LinkInternal;
+
+ if(linkmode == LinkExternal) {
+ diag("only -linkmode=internal is supported");
+ errorexit();
+ } else if(linkmode == LinkAuto) {
+ linkmode = LinkInternal;
+ }
+
libinit();
if(HEADTYPE == -1)
@@ -268,6 +286,7 @@ main(int argc, char *argv[])
reloc();
asmb();
undef();
+ hostlink();
if(debug['c'])
print("ARM size = %d\n", armsize);
@@ -424,6 +443,7 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
ntext = 0;
eof = Boffset(f) + len;
src[0] = 0;
+ pn = estrdup(pn); // we keep it in Sym* references
newloop:
memset(h, 0, sizeof(h));
@@ -595,11 +615,15 @@ loop:
break;
case ALOCALS:
+ if(skip)
+ goto casedef;
cursym->locals = p->to.offset;
pc++;
break;
case ATYPE:
+ if(skip)
+ goto casedef;
pc++;
goto loop;
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
index d65802a20..c969e98e5 100644
--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -932,6 +932,8 @@ struct
"PCMPGTW", LTYPE3, APCMPGTW,
"PEXTRW", LTYPEX, APEXTRW,
"PINSRW", LTYPEX, APINSRW,
+ "PINSRD", LTYPEX, APINSRD,
+ "PINSRQ", LTYPEX, APINSRQ,
"PMADDWL", LTYPE3, APMADDWL,
"PMAXSW", LTYPE3, APMAXSW,
"PMAXUB", LTYPE3, APMAXUB,
@@ -949,6 +951,7 @@ struct
"PSHUFL", LTYPEX, APSHUFL,
"PSHUFLW", LTYPEX, APSHUFLW,
"PSHUFW", LTYPEX, APSHUFW,
+ "PSHUFB", LTYPEM, APSHUFB,
"PSLLO", LTYPE3, APSLLO,
"PSLLDQ", LTYPE3, APSLLO, /* syn */
"PSLLL", LTYPE3, APSLLL,
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
index 58d6d5129..541c7beaa 100644
--- a/src/cmd/6c/swt.c
+++ b/src/cmd/6c/swt.c
@@ -320,7 +320,7 @@ outcode(void)
zaddr(&b, &p->from, sf);
zaddr(&b, &p->to, st);
}
- Bflush(&b);
+ Bterm(&b);
close(f);
firstp = P;
lastp = P;
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index a51c0ca58..2eae865f3 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -568,7 +568,7 @@ agenr(Node *n, Node *a, Node *res)
Node n1, n2, n3, n4, n5, tmp, tmp2, nlen;
Prog *p1;
Type *t;
- uint32 w;
+ uint64 w;
uint64 v;
int freelen;
@@ -882,24 +882,37 @@ agen(Node *n, Node *res)
case ODOT:
agen(nl, res);
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer. If the left node
+ // was ODOT we have already done the nil check.
+ if(nl->op != ODOT)
+ if(nl->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], res);
+ gmove(res, &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n1);
+ regfree(&n1);
+ }
if(n->xoffset != 0)
ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
break;
case ODOTPTR:
cgen(nl, res);
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(nl->type->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], res);
+ gmove(res, &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n1);
+ regfree(&n1);
+ }
if(n->xoffset != 0) {
- // explicit check for nil if struct is large enough
- // that we might derive too big a pointer.
- if(nl->type->type->width >= unmappedzero) {
- regalloc(&n1, types[tptr], res);
- gmove(res, &n1);
- n1.op = OINDREG;
- n1.type = types[TUINT8];
- n1.xoffset = 0;
- gins(ATESTB, nodintconst(0), &n1);
- regfree(&n1);
- }
ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
}
break;
@@ -950,16 +963,14 @@ igen(Node *n, Node *a, Node *res)
case ODOTPTR:
cgenr(n->left, a, res);
- if(n->xoffset != 0) {
- // explicit check for nil if struct is large enough
- // that we might derive too big a pointer.
- if(n->left->type->type->width >= unmappedzero) {
- n1 = *a;
- n1.op = OINDREG;
- n1.type = types[TUINT8];
- n1.xoffset = 0;
- gins(ATESTB, nodintconst(0), &n1);
- }
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(n->left->type->type->width >= unmappedzero) {
+ n1 = *a;
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n1);
}
a->op = OINDREG;
a->xoffset += n->xoffset;
@@ -1276,12 +1287,12 @@ ret:
* or return value from function call.
* return n's offset from SP.
*/
-int32
+int64
stkof(Node *n)
{
Type *t;
Iter flist;
- int32 off;
+ int64 off;
switch(n->op) {
case OINDREG:
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 23bb5093f..5e426753c 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -942,7 +942,7 @@ cgen_bmul(int op, Node *nl, Node *nr, Node *res)
void
clearfat(Node *nl)
{
- uint32 w, c, q;
+ int64 w, c, q;
Node n1, oldn1, ax, oldax;
/* clear a fat object */
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
index 508a3548f..cdbbd5d9d 100644
--- a/src/cmd/6g/gobj.c
+++ b/src/cmd/6g/gobj.c
@@ -501,7 +501,8 @@ void
genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
{
Sym *e;
- int c, d, o, mov, add, loaded;
+ int c, d, mov, add, loaded;
+ int64 o;
Prog *p;
Type *f;
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index fc5407a1f..55864c34e 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -555,6 +555,7 @@ ismem(Node *n)
case OINDREG:
case ONAME:
case OPARAM:
+ case OCLOSUREVAR:
return 1;
case OADDR:
if(flag_largemodel)
@@ -1057,11 +1058,11 @@ gins(int as, Node *f, Node *t)
// Generate an instruction referencing *n
// to force segv on nil pointer dereference.
void
-checkref(Node *n)
+checkref(Node *n, int force)
{
Node m;
- if(n->type->type->width < unmappedzero)
+ if(!force && isptr[n->type->etype] && n->type->type->width < unmappedzero)
return;
regalloc(&m, types[TUINTPTR], n);
@@ -1098,8 +1099,6 @@ checkoffset(Addr *a, int canemitcode)
void
naddr(Node *n, Addr *a, int canemitcode)
{
- Prog *p;
-
a->scale = 0;
a->index = D_NONE;
a->type = D_NONE;
@@ -1148,6 +1147,8 @@ naddr(Node *n, Addr *a, int canemitcode)
a->type = n->val.u.reg+D_INDIR;
a->sym = n->sym;
a->offset = n->xoffset;
+ if(a->offset != (int32)a->offset)
+ yyerror("offset %lld too large for OINDREG", a->offset);
checkoffset(a, canemitcode);
break;
@@ -1163,14 +1164,9 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case OCLOSUREVAR:
- if(!canemitcode)
- fatal("naddr OCLOSUREVAR cannot emit code");
- p = gins(AMOVQ, N, N);
- p->from.type = D_DX+D_INDIR;
- p->from.offset = n->xoffset;
- p->to.type = D_BX;
- a->type = D_BX;
+ a->type = D_DX+D_INDIR;
a->sym = S;
+ a->offset = n->xoffset;
break;
case OCFUNC:
@@ -1953,9 +1949,9 @@ sudoclean(void)
int
sudoaddable(int as, Node *n, Addr *a)
{
- int o, i, w;
- int oary[10];
- int64 v;
+ int o, i;
+ int64 oary[10];
+ int64 v, w;
Node n1, n2, n3, n4, *nn, *l, *r;
Node *reg, *reg1;
Prog *p1;
diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c
index 569655786..bb24d4144 100644
--- a/src/cmd/6g/peep.c
+++ b/src/cmd/6g/peep.c
@@ -472,6 +472,7 @@ elimshortmov(Reg *r)
{
Prog *p;
+ USED(r);
for(r=firstr; r!=R; r=r->link) {
p = r->prog;
if(regtyp(&p->to)) {
@@ -555,7 +556,7 @@ elimshortmov(Reg *r)
}
}
-int
+static int
regconsttyp(Adr *a)
{
if(regtyp(a))
@@ -758,7 +759,7 @@ subprop(Reg *r0)
}
}
if(debug['P'] && debug['v'])
- print("\tran off end; return 0\n", p);
+ print("\tran off end; return 0\n");
return 0;
gotit:
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index c56d71678..ab826d431 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -182,7 +182,6 @@ regopt(Prog *firstp)
return;
}
- r1 = R;
firstr = R;
lastr = R;
@@ -783,7 +782,7 @@ brk:
Var *v;
v = var + rgp->varno;
- print("registerize %N+%d (bit=%2d et=%2E) in %R\n",
+ print("registerize %N+%lld (bit=%2d et=%2E) in %R\n",
v->node, v->offset, rgp->varno, v->etype, rgp->regno);
}
paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
@@ -948,9 +947,9 @@ doregbits(int r)
}
static int
-overlap(int32 o1, int w1, int32 o2, int w2)
+overlap(int64 o1, int w1, int64 o2, int w2)
{
- int32 t1, t2;
+ int64 t1, t2;
t1 = o1+w1;
t2 = o2+w2;
@@ -968,7 +967,7 @@ mkvar(Reg *r, Adr *a)
int i, t, n, et, z, flag;
int64 w;
uint32 regu;
- int32 o;
+ int64 o;
Bits bit;
Node *node;
@@ -1061,7 +1060,7 @@ mkvar(Reg *r, Adr *a)
v->node = node;
if(debug['R'])
- print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
+ print("bit=%2d et=%2E w=%d+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
ostats.nvar++;
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
index 805b3fc6f..237a802cd 100644
--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -654,6 +654,8 @@ enum as
APFSUB,
APFSUBR,
APINSRW,
+ APINSRD,
+ APINSRQ,
APMADDWL,
APMAXSW,
APMAXUB,
@@ -671,6 +673,7 @@ enum as
APSHUFL,
APSHUFLW,
APSHUFW,
+ APSHUFB,
APSLLO,
APSLLL,
APSLLQ,
@@ -863,6 +866,7 @@ enum
D_SIZE = D_INDIR + D_INDIR, /* 6l internal */
D_PCREL,
+ D_TLS,
T_TYPE = 1<<0,
T_INDEX = 1<<1,
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index 5fb75ba4d..8807a6ed5 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -131,7 +131,7 @@ adddynrel(Sym *s, Reloc *r)
// Handle relocations found in ELF object files.
case 256 + R_X86_64_PC32:
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->type == SDYNIMPORT)
diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
if(targ->type == 0 || targ->type == SXREF)
diag("unknown symbol %s in pcrel", targ->name);
@@ -142,7 +142,7 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_X86_64_PLT32:
r->type = D_PCREL;
r->add += 4;
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->type == SDYNIMPORT) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add += targ->plt;
@@ -150,7 +150,7 @@ adddynrel(Sym *s, Reloc *r)
return;
case 256 + R_X86_64_GOTPCREL:
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->type != SDYNIMPORT) {
// have symbol
if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
// turn MOVQ of GOT entry into LEAQ of symbol itself
@@ -161,7 +161,6 @@ adddynrel(Sym *s, Reloc *r)
}
// fall back to using GOT and hope for the best (CMOV*)
// TODO: just needs relocation, no need to put in .dynsym
- targ->dynimpname = targ->name;
}
addgotsym(targ);
r->type = D_PCREL;
@@ -171,7 +170,7 @@ adddynrel(Sym *s, Reloc *r)
return;
case 256 + R_X86_64_64:
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->type == SDYNIMPORT)
diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
r->type = D_ADDR;
return;
@@ -182,12 +181,12 @@ adddynrel(Sym *s, Reloc *r)
case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
// TODO: What is the difference between all these?
r->type = D_ADDR;
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->type == SDYNIMPORT)
diag("unexpected reloc for dynamic symbol %s", targ->name);
return;
case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->type == SDYNIMPORT) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add = targ->plt;
@@ -201,12 +200,12 @@ adddynrel(Sym *s, Reloc *r)
case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
r->type = D_PCREL;
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->type == SDYNIMPORT)
diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
return;
case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->type != SDYNIMPORT) {
// have symbol
// turn MOVQ of GOT entry into LEAQ of symbol itself
if(r->off < 2 || s->p[r->off-2] != 0x8b) {
@@ -219,7 +218,7 @@ adddynrel(Sym *s, Reloc *r)
}
// fall through
case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
- if(targ->dynimpname == nil || targ->dynexport)
+ if(targ->type != SDYNIMPORT)
diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
addgotsym(targ);
r->type = D_PCREL;
@@ -229,7 +228,7 @@ adddynrel(Sym *s, Reloc *r)
}
// Handle references to ELF symbols from our own object files.
- if(targ->dynimpname == nil || targ->dynexport)
+ if(targ->type != SDYNIMPORT)
return;
switch(r->type) {
@@ -285,10 +284,13 @@ adddynrel(Sym *s, Reloc *r)
}
int
-elfreloc1(Reloc *r, vlong off, int32 elfsym, vlong add)
+elfreloc1(Reloc *r, vlong sectoff)
{
- VPUT(off);
+ int32 elfsym;
+ VPUT(sectoff);
+
+ elfsym = r->xsym->elfsym;
switch(r->type) {
default:
return -1;
@@ -307,11 +309,74 @@ elfreloc1(Reloc *r, vlong off, int32 elfsym, vlong add)
VPUT(R_X86_64_PC32 | (uint64)elfsym<<32);
else
return -1;
- add -= r->siz;
+ break;
+
+ case D_TLS:
+ if(r->siz == 4)
+ VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
+ else
+ return -1;
+ break;
+ }
+
+ VPUT(r->xadd);
+ return 0;
+}
+
+int
+machoreloc1(Reloc *r, vlong sectoff)
+{
+ uint32 v;
+ Sym *rs;
+
+ rs = r->xsym;
+
+ if(rs->type == SHOSTOBJ) {
+ if(rs->dynid < 0) {
+ diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
+ return -1;
+ }
+ v = rs->dynid;
+ v |= 1<<27; // external relocation
+ } else {
+ v = rs->sect->extnum;
+ if(v == 0) {
+ diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type);
+ return -1;
+ }
+ }
+
+ switch(r->type) {
+ default:
+ return -1;
+ case D_ADDR:
+ v |= MACHO_X86_64_RELOC_UNSIGNED<<28;
+ break;
+ case D_PCREL:
+ v |= 1<<24; // pc-relative bit
+ v |= MACHO_X86_64_RELOC_BRANCH<<28;
+ break;
+ }
+
+ switch(r->siz) {
+ default:
+ return -1;
+ case 1:
+ v |= 0<<25;
+ break;
+ case 2:
+ v |= 1<<25;
+ break;
+ case 4:
+ v |= 2<<25;
+ break;
+ case 8:
+ v |= 3<<25;
break;
}
- VPUT(add);
+ LPUT(sectoff);
+ LPUT(v);
return 0;
}
@@ -448,29 +513,23 @@ addgotsym(Sym *s)
void
adddynsym(Sym *s)
{
- Sym *d, *str;
+ Sym *d;
int t;
char *name;
- vlong off;
if(s->dynid >= 0)
return;
- if(s->dynimpname == nil)
- diag("adddynsym: no dynamic name for %s", s->name);
-
if(iself) {
s->dynid = nelfsym++;
d = lookup(".dynsym", 0);
- name = s->dynimpname;
- if(name == nil)
- name = s->name;
+ name = s->extname;
adduint32(d, addstring(lookup(".dynstr", 0), name));
/* type */
t = STB_GLOBAL << 4;
- if(s->dynexport && (s->type&SMASK) == STEXT)
+ if(s->cgoexport && (s->type&SMASK) == STEXT)
t |= STT_FUNC;
else
t |= STT_OBJECT;
@@ -480,7 +539,7 @@ adddynsym(Sym *s)
adduint8(d, 0);
/* section where symbol is defined */
- if(!s->dynexport && s->dynimpname != nil)
+ if(s->type == SDYNIMPORT)
adduint16(d, SHN_UNDEF);
else {
switch(s->type) {
@@ -510,62 +569,15 @@ adddynsym(Sym *s)
/* size of object */
adduint64(d, s->size);
- if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) {
+ if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) {
elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
addstring(lookup(".dynstr", 0), s->dynimplib));
}
} else if(HEADTYPE == Hdarwin) {
- // Mach-o symbol nlist64
- d = lookup(".dynsym", 0);
- name = s->dynimpname;
- if(name == nil)
- name = s->name;
- if(d->size == 0 && ndynexp > 0) { // pre-allocate for dynexps
- symgrow(d, ndynexp*16);
- }
- if(s->dynid <= -100) { // pre-allocated, see cmd/ld/go.c:^sortdynexp()
- s->dynid = -s->dynid-100;
- off = s->dynid*16;
- } else {
- off = d->size;
- s->dynid = off/16;
- }
- // darwin still puts _ prefixes on all C symbols
- str = lookup(".dynstr", 0);
- setuint32(d, off, str->size);
- off += 4;
- adduint8(str, '_');
- addstring(str, name);
- if(s->type == SDYNIMPORT) {
- setuint8(d, off, 0x01); // type - N_EXT - external symbol
- off++;
- setuint8(d, off, 0); // section
- off++;
- } else {
- setuint8(d, off, 0x0f);
- off++;
- switch(s->type) {
- default:
- case STEXT:
- setuint8(d, off, 1);
- break;
- case SDATA:
- setuint8(d, off, 2);
- break;
- case SBSS:
- setuint8(d, off, 4);
- break;
- }
- off++;
- }
- setuint16(d, off, 0); // desc
- off += 2;
- if(s->type == SDYNIMPORT)
- setuint64(d, off, 0); // value
- else
- setaddr(d, off, s);
- off += 8;
- } else if(HEADTYPE != Hwindows) {
+ diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
+ } else if(HEADTYPE == Hwindows) {
+ // already taken care of
+ } else {
diag("adddynsym: unsupported binary format");
}
}
@@ -706,7 +718,7 @@ asmb(void)
dwarfemitdebugsections();
- if(isobj)
+ if(linkmode == LinkExternal)
elfemitreloc();
}
break;
@@ -729,6 +741,10 @@ asmb(void)
dwarfemitdebugsections();
break;
+ case Hdarwin:
+ if(linkmode == LinkExternal)
+ machoemitreloc();
+ break;
}
}
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index ffb8a4552..4d481c69d 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -42,6 +42,7 @@ enum
thechar = '6',
PtrSize = 8,
IntSize = 8,
+ MaxAlign = 32, // max data alignment
// Loop alignment constants:
// want to align loop entry to LoopAlign-byte boundary,
@@ -100,9 +101,12 @@ struct Reloc
{
int32 off;
uchar siz;
+ uchar done;
int32 type;
int64 add;
+ int64 xadd;
Sym* sym;
+ Sym* xsym;
};
struct Prog
@@ -140,11 +144,12 @@ struct Auto
struct Sym
{
char* name;
+ char* extname; // name used in external object files
short type;
short version;
uchar dupok;
uchar reachable;
- uchar dynexport;
+ uchar cgoexport;
uchar special;
uchar stkcheck;
uchar hide;
@@ -167,7 +172,6 @@ struct Sym
vlong size;
Sym* gotype;
char* file;
- char* dynimpname;
char* dynimplib;
char* dynimpvers;
struct Section* sect;
@@ -263,6 +267,7 @@ enum
Zo_iw,
Zm_o,
Zm_r,
+ Zm2_r,
Zm_r_xm,
Zm_r_i_xm,
Zm_r_3d,
@@ -292,10 +297,11 @@ enum
P32 = 0x32, /* 32-bit only */
Pe = 0x66, /* operand escape */
Pm = 0x0f, /* 2byte opcode escape */
- Pq = 0xff, /* both escape */
+ Pq = 0xff, /* both escapes: 66 0f */
Pb = 0xfe, /* byte operands */
- Pf2 = 0xf2, /* xmm escape 1 */
- Pf3 = 0xf3, /* xmm escape 2 */
+ Pf2 = 0xf2, /* xmm escape 1: f2 0f */
+ Pf3 = 0xf3, /* xmm escape 2: f3 0f */
+ Pq3 = 0x67, /* xmm escape 3: 66 48 0f */
Pw = 0x48, /* Rex.w */
Py = 0x80, /* defaults to 64-bit mode */
@@ -330,7 +336,6 @@ EXTERN Auto* curhist;
EXTERN Prog* curp;
EXTERN Sym* cursym;
EXTERN Sym* datap;
-EXTERN vlong elfdatsize;
EXTERN int debug[128];
EXTERN char literal[32];
EXTERN Sym* textp;
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index 10e4a9860..e98f91eeb 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -83,6 +83,7 @@ main(int argc, char *argv[])
INITRND = -1;
INITENTRY = 0;
LIBINITENTRY = 0;
+ linkmode = LinkAuto;
nuxiinit();
flagcount("1", "use alternate profiling code", &debug['1']);
@@ -106,9 +107,11 @@ main(int argc, char *argv[])
flagcount("a", "disassemble output", &debug['a']);
flagcount("c", "dump call graph", &debug['c']);
flagcount("d", "disable dynamic executable", &debug['d']);
+ flagstr("extld", "linker to run in external mode", &extld);
+ flagstr("extldflags", "flags for external linker", &extldflags);
flagcount("f", "ignore version mismatch", &debug['f']);
flagcount("g", "disable go package data checks", &debug['g']);
- flagcount("hostobj", "generate host object file", &isobj);
+ flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
flagstr("k", "sym: set field tracking symbol", &tracksym);
flagcount("n", "dump symbol table", &debug['n']);
flagstr("o", "outfile: set output file", &outfile);
@@ -116,10 +119,11 @@ main(int argc, char *argv[])
flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
flagcount("race", "enable race detector", &flag_race);
flagcount("s", "disable symbol table", &debug['s']);
+ flagcount("shared", "generate shared object", &flag_shared);
+ flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
flagcount("u", "reject unsafe packages", &debug['u']);
flagcount("v", "print link trace", &debug['v']);
flagcount("w", "disable DWARF generation", &debug['w']);
- flagcount("shared", "generate shared object", &flag_shared);
flagparse(&argc, &argv, usage);
@@ -131,13 +135,24 @@ main(int argc, char *argv[])
if(HEADTYPE == -1)
HEADTYPE = headtype(goos);
- if(isobj) {
- switch(HEADTYPE) {
- default:
- sysfatal("cannot use -hostobj with -H %s", headstr(HEADTYPE));
- case Hlinux:
- break;
- }
+ // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
+ // Go was built; see ../../make.bash.
+ if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
+ linkmode = LinkInternal;
+
+ switch(HEADTYPE) {
+ default:
+ if(linkmode == LinkAuto)
+ linkmode = LinkInternal;
+ if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0)
+ sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE));
+ break;
+ case Hdarwin:
+ case Hfreebsd:
+ case Hlinux:
+ case Hnetbsd:
+ case Hopenbsd:
+ break;
}
if(outfile == nil) {
@@ -282,6 +297,7 @@ main(int argc, char *argv[])
reloc();
asmb();
undef();
+ hostlink();
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%d symbols\n", nsymbol);
@@ -412,6 +428,7 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
ntext = 0;
eof = Boffset(f) + len;
src[0] = 0;
+ pn = estrdup(pn); // we keep it in Sym* references
newloop:
memset(h, 0, sizeof(h));
@@ -587,11 +604,15 @@ loop:
goto loop;
case ALOCALS:
+ if(skip)
+ goto casdef;
cursym->locals = p->to.offset;
pc++;
goto loop;
case ATYPE:
+ if(skip)
+ goto casdef;
pc++;
goto loop;
diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c
index a163e6faa..b0d5ca788 100644
--- a/src/cmd/6l/optab.c
+++ b/src/cmd/6l/optab.c
@@ -522,6 +522,11 @@ uchar ymshuf[] =
Ymm, Ymr, Zibm_r, 2,
0
};
+uchar ymshufb[] =
+{
+ Yxm, Yxr, Zm2_r, 2,
+ 0
+};
uchar yxshuf[] =
{
Yxm, Yxr, Zibm_r, 2,
@@ -532,6 +537,16 @@ uchar yextrw[] =
Yxr, Yrl, Zibm_r, 2,
0
};
+uchar yinsrw[] =
+{
+ Yml, Yxr, Zibm_r, 2,
+ 0
+};
+uchar yinsr[] =
+{
+ Ymm, Yxr, Zibm_r, 3,
+ 0
+};
uchar ypsdq[] =
{
Yi8, Yxr, Zibo_m, 2,
@@ -982,7 +997,9 @@ Optab optab[] =
{ APFRSQRT, ymfp, Px, 0x97 },
{ APFSUB, ymfp, Px, 0x9a },
{ APFSUBR, ymfp, Px, 0xaa },
- { APINSRW, yextrw, Pq, 0xc4,(00) },
+ { APINSRW, yinsrw, Pq, 0xc4,(00) },
+ { APINSRD, yinsr, Pq, 0x3a, 0x22, (00) },
+ { APINSRQ, yinsr, Pq3, 0x3a, 0x22, (00) },
{ APMADDWL, ymm, Py, 0xf5,Pe,0xf5 },
{ APMAXSW, yxm, Pe, 0xee },
{ APMAXUB, yxm, Pe, 0xde },
@@ -1008,6 +1025,7 @@ Optab optab[] =
{ APSHUFL, yxshuf, Pq, 0x70,(00) },
{ APSHUFLW, yxshuf, Pf2, 0x70,(00) },
{ APSHUFW, ymshuf, Pm, 0x70,(00) },
+ { APSHUFB, ymshufb,Pq, 0x38, 0x00 },
{ APSLLO, ypsdq, Pq, 0x73,(07) },
{ APSLLL, yps, Py, 0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06) },
{ APSLLQ, yps, Py, 0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06) },
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
index 283a0e349..460a34f2f 100644
--- a/src/cmd/6l/span.c
+++ b/src/cmd/6l/span.c
@@ -32,6 +32,7 @@
#include "l.h"
#include "../ld/lib.h"
+#include "../ld/elf.h"
static int rexflag;
static int asmode;
@@ -880,7 +881,30 @@ putrelv:
r = addrel(cursym);
*r = rel;
r->off = curp->pc + andptr - and;
+ } else if(iself && linkmode == LinkExternal && a->type == D_INDIR+D_FS
+ && HEADTYPE != Hopenbsd) {
+ Reloc *r;
+ Sym *s;
+
+ r = addrel(cursym);
+ r->off = curp->pc + andptr - and;
+ r->add = 0;
+ r->xadd = 0;
+ r->siz = 4;
+ r->type = D_TLS;
+ if(a->offset == tlsoffset+0)
+ s = lookup("runtime.g", 0);
+ else
+ s = lookup("runtime.m", 0);
+ s->type = STLSBSS;
+ s->reachable = 1;
+ s->size = PtrSize;
+ s->hide = 1;
+ r->sym = s;
+ r->xsym = s;
+ v = 0;
}
+
put4(v);
return;
@@ -1161,6 +1185,11 @@ found:
*andptr++ = Pe;
*andptr++ = Pm;
break;
+ case Pq3: /* 16 bit escape, Rex.w, and opcode escape */
+ *andptr++ = Pe;
+ *andptr++ = Pw;
+ *andptr++ = Pm;
+ break;
case Pf2: /* xmm opcode escape */
case Pf3:
@@ -1229,6 +1258,11 @@ found:
*andptr++ = op;
asmand(&p->from, &p->to);
break;
+ case Zm2_r:
+ *andptr++ = op;
+ *andptr++ = o->op[z+1];
+ asmand(&p->from, &p->to);
+ break;
case Zm_r_xm:
mediaop(o, op, t[3], z);
diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y
index 60707d1c9..246643427 100644
--- a/src/cmd/8a/a.y
+++ b/src/cmd/8a/a.y
@@ -54,7 +54,7 @@
%left '*' '/' '%'
%token <lval> LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
%token <lval> LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEG LTYPEXC
-%token <lval> LCONST LFP LPC LSB
+%token <lval> LTYPEX LCONST LFP LPC LSB
%token <lval> LBREG LLREG LSREG LFREG LXREG
%token <dval> LFCONST
%token <sval> LSCONST LSP
@@ -63,7 +63,7 @@
%type <con2> con2
%type <gen> mem imm imm2 reg nam rel rem rim rom omem nmem
%type <gen2> nonnon nonrel nonrem rimnon rimrem remrim
-%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
+%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 spec10
%%
prog:
| prog
@@ -117,6 +117,7 @@ inst:
| LTYPEI spec7 { outcode($1, &$2); }
| LTYPEG spec8 { outcode($1, &$2); }
| LTYPEXC spec9 { outcode($1, &$2); }
+| LTYPEX spec10 { outcode($1, &$2); }
nonnon:
{
@@ -296,6 +297,16 @@ spec9: /* CMPPS/CMPPD */
$$.to.offset = $5;
}
+spec10: /* PINSRD */
+ imm ',' rem ',' reg
+ {
+ $$.from = $3;
+ $$.to = $5;
+ if($1.type != D_CONST)
+ yyerror("illegal constant");
+ $$.to.offset = $1.offset;
+ }
+
rem:
reg
| mem
@@ -496,6 +507,15 @@ omem:
$$.scale = $8;
checkscale($$.scale);
}
+| con '(' LLREG ')' '(' LSREG '*' con ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ $$.index = $6;
+ $$.scale = $8;
+ checkscale($$.scale);
+ }
| '(' LLREG ')'
{
$$ = nullgen;
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index 770ca5a88..a7840f625 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -306,6 +306,7 @@ struct
"CMPXCHGB", LTYPE3, ACMPXCHGB,
"CMPXCHGL", LTYPE3, ACMPXCHGL,
"CMPXCHGW", LTYPE3, ACMPXCHGW,
+ "CPUID", LTYPE0, ACPUID,
"DAA", LTYPE0, ADAA,
"DAS", LTYPE0, ADAS,
"DATA", LTYPED, ADATA,
@@ -408,6 +409,7 @@ struct
"MOVB", LTYPE3, AMOVB,
"MOVL", LTYPEM, AMOVL,
"MOVW", LTYPEM, AMOVW,
+ "MOVQ", LTYPEM, AMOVQ,
"MOVBLSX", LTYPE3, AMOVBLSX,
"MOVBLZX", LTYPE3, AMOVBLZX,
"MOVBWSX", LTYPE3, AMOVBWSX,
@@ -437,6 +439,7 @@ struct
"OUTSL", LTYPE0, AOUTSL,
"OUTSW", LTYPE0, AOUTSW,
"PAUSE", LTYPEN, APAUSE,
+ "PINSRD", LTYPEX, APINSRD,
"POPAL", LTYPE0, APOPAL,
"POPAW", LTYPE0, APOPAW,
"POPFL", LTYPE0, APOPFL,
@@ -687,6 +690,7 @@ struct
"ADDPS", LTYPE3, AADDPS,
"ADDSD", LTYPE3, AADDSD,
"ADDSS", LTYPE3, AADDSS,
+ "AESENC", LTYPE3, AAESENC,
"ANDNPD", LTYPE3, AANDNPD,
"ANDNPS", LTYPE3, AANDNPS,
"ANDPD", LTYPE3, AANDPD,
@@ -755,11 +759,15 @@ struct
"ORPD", LTYPE3, AORPD,
"ORPS", LTYPE3, AORPS,
"PADDQ", LTYPE3, APADDQ,
+ "PAND", LTYPE3, APAND,
+ "PCMPEQB", LTYPE3, APCMPEQB,
"PMAXSW", LTYPE3, APMAXSW,
"PMAXUB", LTYPE3, APMAXUB,
"PMINSW", LTYPE3, APMINSW,
"PMINUB", LTYPE3, APMINUB,
+ "PMOVMSKB", LTYPE3, APMOVMSKB,
"PSADBW", LTYPE3, APSADBW,
+ "PSHUFB", LTYPE3, APSHUFB,
"PSUBB", LTYPE3, APSUBB,
"PSUBL", LTYPE3, APSUBL,
"PSUBQ", LTYPE3, APSUBQ,
diff --git a/src/cmd/8a/y.tab.c b/src/cmd/8a/y.tab.c
index 38f2de52d..6616c9139 100644
--- a/src/cmd/8a/y.tab.c
+++ b/src/cmd/8a/y.tab.c
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.6.5. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison implementation for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ 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.
-
+ the Free Software Foundation; either version 2, 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/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,7 +29,7 @@
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. */
@@ -44,7 +47,7 @@
#define YYBISON 1
/* Bison version. */
-#define YYBISON_VERSION "2.6.5"
+#define YYBISON_VERSION "2.3"
/* Skeleton name. */
#define YYSKELETON_NAME "yacc.c"
@@ -52,55 +55,11 @@
/* 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 360 of yacc.c */
-#line 31 "a.y"
-
-#include <u.h>
-#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-
-/* Line 360 of yacc.c */
-#line 75 "y.tab.c"
-
-# ifndef YY_NULL
-# if defined __cplusplus && 201103L <= __cplusplus
-# define YY_NULL nullptr
-# else
-# define YY_NULL 0
-# endif
-# endif
-
-/* Enabling verbose error messages. */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* In a future release of Bison, this section will be replaced
- by #include "y.tab.h". */
-#ifndef YY_YY_Y_TAB_H_INCLUDED
-# define YY_YY_Y_TAB_H_INCLUDED
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int yydebug;
-#endif
-
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -122,21 +81,22 @@ extern int yydebug;
LTYPEI = 270,
LTYPEG = 271,
LTYPEXC = 272,
- LCONST = 273,
- LFP = 274,
- LPC = 275,
- LSB = 276,
- LBREG = 277,
- LLREG = 278,
- LSREG = 279,
- LFREG = 280,
- LXREG = 281,
- LFCONST = 282,
- LSCONST = 283,
- LSP = 284,
- LNAME = 285,
- LLAB = 286,
- LVAR = 287
+ LTYPEX = 273,
+ LCONST = 274,
+ LFP = 275,
+ LPC = 276,
+ LSB = 277,
+ LBREG = 278,
+ LLREG = 279,
+ LSREG = 280,
+ LFREG = 281,
+ LXREG = 282,
+ LFCONST = 283,
+ LSCONST = 284,
+ LSP = 285,
+ LNAME = 286,
+ LLAB = 287,
+ LVAR = 288
};
#endif
/* Tokens. */
@@ -155,30 +115,57 @@ extern int yydebug;
#define LTYPEI 270
#define LTYPEG 271
#define LTYPEXC 272
-#define LCONST 273
-#define LFP 274
-#define LPC 275
-#define LSB 276
-#define LBREG 277
-#define LLREG 278
-#define LSREG 279
-#define LFREG 280
-#define LXREG 281
-#define LFCONST 282
-#define LSCONST 283
-#define LSP 284
-#define LNAME 285
-#define LLAB 286
-#define LVAR 287
+#define LTYPEX 273
+#define LCONST 274
+#define LFP 275
+#define LPC 276
+#define LSB 277
+#define LBREG 278
+#define LLREG 279
+#define LSREG 280
+#define LFREG 281
+#define LXREG 282
+#define LFCONST 283
+#define LSCONST 284
+#define LSP 285
+#define LNAME 286
+#define LLAB 287
+#define LVAR 288
+
+
+/* Copy the first part of user declarations. */
+#line 31 "a.y"
+
+#include <u.h>
+#include <stdio.h> /* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+
+
+/* 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 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-/* Line 376 of yacc.c */
#line 37 "a.y"
-
+{
Sym *sym;
int32 lval;
struct {
@@ -189,38 +176,22 @@ typedef union YYSTYPE
char sval[8];
Gen gen;
Gen2 gen2;
-
-
-/* Line 376 of yacc.c */
-#line 196 "y.tab.c"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+}
+/* Line 193 of yacc.c. */
+#line 182 "y.tab.c"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
-extern YYSTYPE yylval;
-
-#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 */
-#endif /* !YY_YY_Y_TAB_H_INCLUDED */
/* Copy the second part of user declarations. */
-/* Line 379 of yacc.c */
-#line 224 "y.tab.c"
+
+/* Line 216 of yacc.c. */
+#line 195 "y.tab.c"
#ifdef short
# undef short
@@ -273,36 +244,36 @@ typedef short int yytype_int16;
# if defined YYENABLE_NLS && YYENABLE_NLS
# if ENABLE_NLS
# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
# endif
# endif
# ifndef YY_
-# define YY_(Msgid) Msgid
+# define YY_(msgid) msgid
# endif
#endif
/* Suppress unused-variable warnings by "using" E. */
#if ! defined lint || defined __GNUC__
-# define YYUSE(E) ((void) (E))
+# define YYUSE(e) ((void) (e))
#else
-# define YYUSE(E) /* empty */
+# define YYUSE(e) /* empty */
#endif
/* Identity function, used to suppress warnings about constant conditions. */
#ifndef lint
-# define YYID(N) (N)
+# define YYID(n) (n)
#else
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static int
-YYID (int yyi)
+YYID (int i)
#else
static int
-YYID (yyi)
- int yyi;
+YYID (i)
+ int i;
#endif
{
- return yyi;
+ return i;
}
#endif
@@ -323,12 +294,11 @@ YYID (yyi)
# define alloca _alloca
# else
# define YYSTACK_ALLOC alloca
-# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
- /* Use EXIT_SUCCESS as a witness for stdlib.h. */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# endif
@@ -351,24 +321,24 @@ YYID (yyi)
# ifndef YYSTACK_ALLOC_MAXIMUM
# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
# endif
-# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+# if (defined __cplusplus && ! defined _STDLIB_H \
&& ! ((defined YYMALLOC || defined malloc) \
&& (defined YYFREE || defined free)))
# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# ifndef EXIT_SUCCESS
-# define EXIT_SUCCESS 0
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
# endif
# endif
# ifndef YYMALLOC
# define YYMALLOC malloc
-# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+# if ! defined malloc && ! defined _STDLIB_H && (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__ \
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
void free (void *); /* INFRINGES ON USER NAME SPACE */
# endif
@@ -384,9 +354,9 @@ void free (void *); /* INFRINGES ON USER NAME SPACE */
/* A type that is properly aligned for any stack member. */
union yyalloc
{
- yytype_int16 yyss_alloc;
- YYSTYPE yyvs_alloc;
-};
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
/* The size of the maximum gap between one aligned stack and the next. */
# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
@@ -397,19 +367,35 @@ union yyalloc
((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ YYSTACK_GAP_MAXIMUM)
-# define YYCOPY_NEEDED 1
+/* 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
/* 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) \
+# define YYSTACK_RELOCATE(Stack) \
do \
{ \
YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
- Stack = &yyptr->Stack_alloc; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
yyptr += yynewbytes / sizeof (*yyptr); \
} \
@@ -417,43 +403,23 @@ union yyalloc
#endif
-#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
-/* Copy COUNT objects from SRC to DST. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if defined __GNUC__ && 1 < __GNUC__
-# define YYCOPY(Dst, Src, Count) \
- __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
-# else
-# define YYCOPY(Dst, Src, Count) \
- do \
- { \
- YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (Dst)[yyi] = (Src)[yyi]; \
- } \
- while (YYID (0))
-# endif
-# endif
-#endif /* !YYCOPY_NEEDED */
-
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 2
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 544
+#define YYLAST 537
/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 51
+#define YYNTOKENS 52
/* YYNNTS -- Number of nonterminals. */
-#define YYNNTS 38
+#define YYNNTS 39
/* YYNRULES -- Number of rules. */
-#define YYNRULES 128
+#define YYNRULES 131
/* YYNRULES -- Number of states. */
-#define YYNSTATES 255
+#define YYNSTATES 266
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
-#define YYMAXUTOK 287
+#define YYMAXUTOK 288
#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -464,16 +430,16 @@ 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, 2, 2, 2, 49, 12, 5, 2,
- 47, 48, 10, 8, 46, 9, 2, 11, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 43, 44,
- 6, 45, 7, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 50, 12, 5, 2,
+ 48, 49, 10, 8, 47, 9, 2, 11, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 44, 45,
+ 6, 46, 7, 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, 4, 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, 3, 2, 50, 2, 2, 2,
+ 2, 2, 2, 2, 3, 2, 51, 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,
@@ -489,7 +455,7 @@ static const yytype_uint8 yytranslate[] =
2, 2, 2, 2, 2, 2, 1, 2, 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
+ 35, 36, 37, 38, 39, 40, 41, 42, 43
};
#if YYDEBUG
@@ -500,65 +466,68 @@ static const yytype_uint16 yyprhs[] =
0, 0, 3, 4, 5, 9, 10, 15, 16, 21,
23, 26, 29, 33, 37, 40, 43, 46, 49, 52,
55, 58, 61, 64, 67, 70, 73, 76, 79, 82,
- 83, 85, 89, 93, 96, 98, 101, 103, 106, 108,
- 112, 118, 122, 128, 131, 133, 136, 138, 140, 144,
- 150, 154, 160, 163, 165, 169, 173, 179, 185, 187,
- 189, 191, 193, 196, 199, 201, 203, 205, 207, 209,
- 214, 217, 220, 222, 224, 226, 228, 230, 232, 235,
- 238, 241, 244, 249, 255, 259, 262, 264, 267, 271,
- 276, 278, 280, 282, 287, 292, 299, 309, 313, 317,
- 322, 328, 337, 339, 346, 352, 360, 361, 364, 367,
- 369, 371, 373, 375, 377, 380, 383, 386, 390, 392,
- 396, 400, 404, 408, 412, 417, 422, 426, 430
+ 85, 86, 88, 92, 96, 99, 101, 104, 106, 109,
+ 111, 115, 121, 125, 131, 134, 136, 139, 141, 143,
+ 147, 153, 157, 163, 166, 168, 172, 176, 182, 188,
+ 194, 196, 198, 200, 202, 205, 208, 210, 212, 214,
+ 216, 218, 223, 226, 229, 231, 233, 235, 237, 239,
+ 241, 244, 247, 250, 253, 258, 264, 268, 271, 273,
+ 276, 280, 285, 287, 289, 291, 296, 301, 308, 318,
+ 328, 332, 336, 341, 347, 356, 358, 365, 371, 379,
+ 380, 383, 386, 388, 390, 392, 394, 396, 399, 402,
+ 405, 409, 411, 415, 419, 423, 427, 431, 436, 441,
+ 445, 449
};
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
static const yytype_int8 yyrhs[] =
{
- 52, 0, -1, -1, -1, 52, 53, 54, -1, -1,
- 41, 43, 55, 54, -1, -1, 40, 43, 56, 54,
- -1, 44, -1, 57, 44, -1, 1, 44, -1, 40,
- 45, 88, -1, 42, 45, 88, -1, 13, 58, -1,
- 14, 62, -1, 15, 61, -1, 16, 59, -1, 17,
- 60, -1, 21, 63, -1, 19, 64, -1, 22, 65,
- -1, 18, 66, -1, 20, 67, -1, 23, 68, -1,
- 24, 69, -1, 25, 70, -1, 26, 71, -1, 27,
- 72, -1, -1, 46, -1, 75, 46, 73, -1, 73,
- 46, 75, -1, 75, 46, -1, 75, -1, 46, 73,
- -1, 73, -1, 46, 76, -1, 76, -1, 78, 46,
- 76, -1, 84, 11, 87, 46, 78, -1, 81, 46,
- 79, -1, 81, 46, 87, 46, 79, -1, 46, 74,
- -1, 74, -1, 10, 84, -1, 58, -1, 62, -1,
- 75, 46, 73, -1, 75, 46, 73, 43, 33, -1,
- 75, 46, 73, -1, 75, 46, 73, 43, 34, -1,
- 75, 46, -1, 75, -1, 75, 46, 73, -1, 81,
- 46, 78, -1, 81, 46, 87, 46, 78, -1, 77,
- 46, 73, 46, 87, -1, 77, -1, 81, -1, 76,
- -1, 83, -1, 10, 77, -1, 10, 82, -1, 77,
- -1, 82, -1, 78, -1, 73, -1, 78, -1, 87,
- 47, 30, 48, -1, 40, 85, -1, 41, 85, -1,
- 32, -1, 35, -1, 33, -1, 36, -1, 39, -1,
- 34, -1, 49, 87, -1, 49, 84, -1, 49, 38,
- -1, 49, 37, -1, 49, 47, 37, 48, -1, 49,
- 47, 9, 37, 48, -1, 49, 9, 37, -1, 49,
- 80, -1, 28, -1, 9, 28, -1, 28, 9, 28,
- -1, 9, 28, 9, 28, -1, 82, -1, 83, -1,
- 87, -1, 87, 47, 33, 48, -1, 87, 47, 39,
- 48, -1, 87, 47, 33, 10, 87, 48, -1, 87,
- 47, 33, 48, 47, 33, 10, 87, 48, -1, 47,
- 33, 48, -1, 47, 39, 48, -1, 87, 47, 34,
- 48, -1, 47, 33, 10, 87, 48, -1, 47, 33,
- 48, 47, 33, 10, 87, 48, -1, 84, -1, 84,
- 47, 33, 10, 87, 48, -1, 40, 85, 47, 86,
- 48, -1, 40, 6, 7, 85, 47, 31, 48, -1,
- -1, 8, 87, -1, 9, 87, -1, 31, -1, 39,
- -1, 29, -1, 28, -1, 42, -1, 9, 87, -1,
- 8, 87, -1, 50, 87, -1, 47, 88, 48, -1,
- 87, -1, 88, 8, 88, -1, 88, 9, 88, -1,
- 88, 10, 88, -1, 88, 11, 88, -1, 88, 12,
- 88, -1, 88, 6, 6, 88, -1, 88, 7, 7,
- 88, -1, 88, 5, 88, -1, 88, 4, 88, -1,
- 88, 3, 88, -1
+ 53, 0, -1, -1, -1, 53, 54, 55, -1, -1,
+ 42, 44, 56, 55, -1, -1, 41, 44, 57, 55,
+ -1, 45, -1, 58, 45, -1, 1, 45, -1, 41,
+ 46, 90, -1, 43, 46, 90, -1, 13, 59, -1,
+ 14, 63, -1, 15, 62, -1, 16, 60, -1, 17,
+ 61, -1, 21, 64, -1, 19, 65, -1, 22, 66,
+ -1, 18, 67, -1, 20, 68, -1, 23, 69, -1,
+ 24, 70, -1, 25, 71, -1, 26, 72, -1, 27,
+ 73, -1, 28, 74, -1, -1, 47, -1, 77, 47,
+ 75, -1, 75, 47, 77, -1, 77, 47, -1, 77,
+ -1, 47, 75, -1, 75, -1, 47, 78, -1, 78,
+ -1, 80, 47, 78, -1, 86, 11, 89, 47, 80,
+ -1, 83, 47, 81, -1, 83, 47, 89, 47, 81,
+ -1, 47, 76, -1, 76, -1, 10, 86, -1, 59,
+ -1, 63, -1, 77, 47, 75, -1, 77, 47, 75,
+ 44, 34, -1, 77, 47, 75, -1, 77, 47, 75,
+ 44, 35, -1, 77, 47, -1, 77, -1, 77, 47,
+ 75, -1, 83, 47, 80, -1, 83, 47, 89, 47,
+ 80, -1, 79, 47, 75, 47, 89, -1, 80, 47,
+ 75, 47, 79, -1, 79, -1, 83, -1, 78, -1,
+ 85, -1, 10, 79, -1, 10, 84, -1, 79, -1,
+ 84, -1, 80, -1, 75, -1, 80, -1, 89, 48,
+ 31, 49, -1, 41, 87, -1, 42, 87, -1, 33,
+ -1, 36, -1, 34, -1, 37, -1, 40, -1, 35,
+ -1, 50, 89, -1, 50, 86, -1, 50, 39, -1,
+ 50, 38, -1, 50, 48, 38, 49, -1, 50, 48,
+ 9, 38, 49, -1, 50, 9, 38, -1, 50, 82,
+ -1, 29, -1, 9, 29, -1, 29, 9, 29, -1,
+ 9, 29, 9, 29, -1, 84, -1, 85, -1, 89,
+ -1, 89, 48, 34, 49, -1, 89, 48, 40, 49,
+ -1, 89, 48, 34, 10, 89, 49, -1, 89, 48,
+ 34, 49, 48, 34, 10, 89, 49, -1, 89, 48,
+ 34, 49, 48, 35, 10, 89, 49, -1, 48, 34,
+ 49, -1, 48, 40, 49, -1, 89, 48, 35, 49,
+ -1, 48, 34, 10, 89, 49, -1, 48, 34, 49,
+ 48, 34, 10, 89, 49, -1, 86, -1, 86, 48,
+ 34, 10, 89, 49, -1, 41, 87, 48, 88, 49,
+ -1, 41, 6, 7, 87, 48, 32, 49, -1, -1,
+ 8, 89, -1, 9, 89, -1, 32, -1, 40, -1,
+ 30, -1, 29, -1, 43, -1, 9, 89, -1, 8,
+ 89, -1, 51, 89, -1, 48, 90, 49, -1, 89,
+ -1, 90, 8, 90, -1, 90, 9, 90, -1, 90,
+ 10, 90, -1, 90, 11, 90, -1, 90, 12, 90,
+ -1, 90, 6, 6, 90, -1, 90, 7, 7, 90,
+ -1, 90, 5, 90, -1, 90, 4, 90, -1, 90,
+ 3, 90, -1
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
@@ -566,21 +535,22 @@ static const yytype_uint16 yyrline[] =
{
0, 68, 68, 70, 69, 77, 76, 84, 83, 89,
90, 91, 94, 99, 105, 106, 107, 108, 109, 110,
- 111, 112, 113, 114, 115, 116, 117, 118, 119, 122,
- 126, 133, 140, 147, 152, 159, 164, 171, 176, 181,
- 188, 196, 201, 209, 214, 219, 228, 229, 232, 237,
- 247, 252, 262, 267, 272, 279, 284, 292, 300, 301,
- 304, 305, 306, 310, 314, 315, 316, 319, 320, 323,
- 329, 338, 347, 352, 357, 362, 367, 372, 379, 385,
- 396, 402, 408, 414, 420, 428, 437, 442, 447, 452,
- 459, 460, 463, 469, 475, 481, 490, 499, 504, 509,
- 515, 523, 533, 537, 546, 553, 562, 565, 569, 575,
- 576, 580, 583, 584, 588, 592, 596, 600, 606, 607,
- 611, 615, 619, 623, 627, 631, 635, 639, 643
+ 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
+ 123, 127, 134, 141, 148, 153, 160, 165, 172, 177,
+ 182, 189, 197, 202, 210, 215, 220, 229, 230, 233,
+ 238, 248, 253, 263, 268, 273, 280, 285, 293, 301,
+ 311, 312, 315, 316, 317, 321, 325, 326, 327, 330,
+ 331, 334, 340, 349, 358, 363, 368, 373, 378, 383,
+ 390, 396, 407, 413, 419, 425, 431, 439, 448, 453,
+ 458, 463, 470, 471, 474, 480, 486, 492, 501, 510,
+ 519, 524, 529, 535, 543, 553, 557, 566, 573, 582,
+ 585, 589, 595, 596, 600, 603, 604, 608, 612, 616,
+ 620, 626, 627, 631, 635, 639, 643, 647, 651, 655,
+ 659, 663
};
#endif
-#if YYDEBUG || YYERROR_VERBOSE || 0
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
First, the terminals, then, starting at YYNTOKENS, nonterminals. */
static const char *const yytname[] =
@@ -588,14 +558,14 @@ static const char *const yytname[] =
"$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
"'-'", "'*'", "'/'", "'%'", "LTYPE0", "LTYPE1", "LTYPE2", "LTYPE3",
"LTYPE4", "LTYPEC", "LTYPED", "LTYPEN", "LTYPER", "LTYPET", "LTYPES",
- "LTYPEM", "LTYPEI", "LTYPEG", "LTYPEXC", "LCONST", "LFP", "LPC", "LSB",
- "LBREG", "LLREG", "LSREG", "LFREG", "LXREG", "LFCONST", "LSCONST", "LSP",
- "LNAME", "LLAB", "LVAR", "':'", "';'", "'='", "','", "'('", "')'", "'$'",
- "'~'", "$accept", "prog", "$@1", "line", "$@2", "$@3", "inst", "nonnon",
- "rimrem", "remrim", "rimnon", "nonrem", "nonrel", "spec1", "spec2",
- "spec3", "spec4", "spec5", "spec6", "spec7", "spec8", "spec9", "rem",
- "rom", "rim", "rel", "reg", "imm", "imm2", "con2", "mem", "omem", "nmem",
- "nam", "offset", "pointer", "con", "expr", YY_NULL
+ "LTYPEM", "LTYPEI", "LTYPEG", "LTYPEXC", "LTYPEX", "LCONST", "LFP",
+ "LPC", "LSB", "LBREG", "LLREG", "LSREG", "LFREG", "LXREG", "LFCONST",
+ "LSCONST", "LSP", "LNAME", "LLAB", "LVAR", "':'", "';'", "'='", "','",
+ "'('", "')'", "'$'", "'~'", "$accept", "prog", "@1", "line", "@2", "@3",
+ "inst", "nonnon", "rimrem", "remrim", "rimnon", "nonrem", "nonrel",
+ "spec1", "spec2", "spec3", "spec4", "spec5", "spec6", "spec7", "spec8",
+ "spec9", "spec10", "rem", "rom", "rim", "rel", "reg", "imm", "imm2",
+ "con2", "mem", "omem", "nmem", "nam", "offset", "pointer", "con", "expr", 0
};
#endif
@@ -608,27 +578,28 @@ static const yytype_uint16 yytoknum[] =
42, 47, 37, 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, 58, 59, 61, 44, 40, 41, 36,
- 126
+ 285, 286, 287, 288, 58, 59, 61, 44, 40, 41,
+ 36, 126
};
# endif
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const yytype_uint8 yyr1[] =
{
- 0, 51, 52, 53, 52, 55, 54, 56, 54, 54,
- 54, 54, 57, 57, 57, 57, 57, 57, 57, 57,
- 57, 57, 57, 57, 57, 57, 57, 57, 57, 58,
- 58, 59, 60, 61, 61, 62, 62, 63, 63, 63,
- 64, 65, 65, 66, 66, 66, 67, 67, 68, 68,
- 69, 69, 70, 70, 70, 71, 71, 72, 73, 73,
- 74, 74, 74, 74, 74, 74, 74, 75, 75, 76,
- 76, 76, 77, 77, 77, 77, 77, 77, 78, 78,
- 78, 78, 78, 78, 78, 79, 80, 80, 80, 80,
- 81, 81, 82, 82, 82, 82, 82, 82, 82, 82,
- 82, 82, 83, 83, 84, 84, 85, 85, 85, 86,
- 86, 86, 87, 87, 87, 87, 87, 87, 88, 88,
- 88, 88, 88, 88, 88, 88, 88, 88, 88
+ 0, 52, 53, 54, 53, 56, 55, 57, 55, 55,
+ 55, 55, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 59, 59, 60, 61, 62, 62, 63, 63, 64, 64,
+ 64, 65, 66, 66, 67, 67, 67, 68, 68, 69,
+ 69, 70, 70, 71, 71, 71, 72, 72, 73, 74,
+ 75, 75, 76, 76, 76, 76, 76, 76, 76, 77,
+ 77, 78, 78, 78, 79, 79, 79, 79, 79, 79,
+ 80, 80, 80, 80, 80, 80, 80, 81, 82, 82,
+ 82, 82, 83, 83, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 85, 85, 86, 86, 87,
+ 87, 87, 88, 88, 88, 89, 89, 89, 89, 89,
+ 89, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
@@ -636,261 +607,258 @@ static const yytype_uint8 yyr2[] =
{
0, 2, 0, 0, 3, 0, 4, 0, 4, 1,
2, 2, 3, 3, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
- 1, 3, 3, 2, 1, 2, 1, 2, 1, 3,
- 5, 3, 5, 2, 1, 2, 1, 1, 3, 5,
- 3, 5, 2, 1, 3, 3, 5, 5, 1, 1,
- 1, 1, 2, 2, 1, 1, 1, 1, 1, 4,
- 2, 2, 1, 1, 1, 1, 1, 1, 2, 2,
- 2, 2, 4, 5, 3, 2, 1, 2, 3, 4,
- 1, 1, 1, 4, 4, 6, 9, 3, 3, 4,
- 5, 8, 1, 6, 5, 7, 0, 2, 2, 1,
- 1, 1, 1, 1, 2, 2, 2, 3, 1, 3,
- 3, 3, 3, 3, 4, 4, 3, 3, 3
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 0, 1, 3, 3, 2, 1, 2, 1, 2, 1,
+ 3, 5, 3, 5, 2, 1, 2, 1, 1, 3,
+ 5, 3, 5, 2, 1, 3, 3, 5, 5, 5,
+ 1, 1, 1, 1, 2, 2, 1, 1, 1, 1,
+ 1, 4, 2, 2, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 4, 5, 3, 2, 1, 2,
+ 3, 4, 1, 1, 1, 4, 4, 6, 9, 9,
+ 3, 3, 4, 5, 8, 1, 6, 5, 7, 0,
+ 2, 2, 1, 1, 1, 1, 1, 2, 2, 2,
+ 3, 1, 3, 3, 3, 3, 3, 4, 4, 3,
+ 3, 3
};
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
- Performed when YYTABLE doesn't specify something else to do. Zero
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
- 2, 3, 1, 0, 0, 29, 0, 0, 0, 0,
- 0, 0, 29, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 9, 4, 0, 11, 30, 14, 0,
- 0, 112, 72, 74, 77, 73, 75, 76, 106, 113,
- 0, 0, 0, 15, 36, 58, 59, 90, 91, 102,
- 92, 0, 16, 67, 34, 68, 17, 0, 18, 0,
- 0, 106, 106, 0, 22, 44, 60, 64, 66, 65,
- 61, 92, 20, 0, 30, 46, 47, 23, 106, 0,
- 0, 19, 38, 0, 0, 21, 0, 24, 0, 25,
- 0, 26, 53, 27, 0, 28, 0, 7, 0, 5,
- 0, 10, 115, 114, 0, 0, 0, 0, 35, 0,
- 0, 118, 0, 116, 0, 0, 0, 81, 80, 0,
- 79, 78, 33, 0, 0, 62, 63, 45, 70, 71,
- 0, 43, 0, 0, 70, 37, 0, 0, 0, 0,
- 0, 52, 0, 0, 0, 12, 0, 13, 106, 107,
- 108, 0, 0, 97, 98, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 117, 0, 0, 0, 0,
- 84, 0, 0, 31, 32, 0, 0, 39, 0, 41,
- 0, 48, 50, 54, 55, 0, 0, 8, 6, 0,
- 111, 109, 110, 0, 0, 0, 128, 127, 126, 0,
- 0, 119, 120, 121, 122, 123, 0, 0, 93, 99,
- 94, 0, 82, 69, 0, 0, 86, 85, 0, 0,
- 0, 0, 0, 0, 104, 100, 0, 124, 125, 0,
- 0, 0, 83, 40, 87, 0, 42, 49, 51, 56,
- 57, 0, 0, 103, 95, 0, 0, 88, 105, 0,
- 0, 89, 101, 0, 96
+ 2, 3, 1, 0, 0, 30, 0, 0, 0, 0,
+ 0, 0, 30, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 4, 0, 11, 31, 14,
+ 0, 0, 115, 74, 76, 79, 75, 77, 78, 109,
+ 116, 0, 0, 0, 15, 37, 60, 61, 92, 93,
+ 105, 94, 0, 16, 69, 35, 70, 17, 0, 18,
+ 0, 0, 109, 109, 0, 22, 45, 62, 66, 68,
+ 67, 63, 94, 20, 0, 31, 47, 48, 23, 109,
+ 0, 0, 19, 39, 0, 0, 21, 0, 24, 0,
+ 25, 0, 26, 54, 27, 0, 28, 0, 29, 0,
+ 7, 0, 5, 0, 10, 118, 117, 0, 0, 0,
+ 0, 36, 0, 0, 121, 0, 119, 0, 0, 0,
+ 83, 82, 0, 81, 80, 34, 0, 0, 64, 65,
+ 46, 72, 73, 0, 44, 0, 0, 72, 38, 0,
+ 0, 0, 0, 0, 53, 0, 0, 0, 0, 12,
+ 0, 13, 109, 110, 111, 0, 0, 100, 101, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 120,
+ 0, 0, 0, 0, 86, 0, 0, 32, 33, 0,
+ 0, 40, 0, 42, 0, 49, 51, 55, 56, 0,
+ 0, 0, 8, 6, 0, 114, 112, 113, 0, 0,
+ 0, 131, 130, 129, 0, 0, 122, 123, 124, 125,
+ 126, 0, 0, 95, 102, 96, 0, 84, 71, 0,
+ 0, 88, 87, 0, 0, 0, 0, 0, 0, 0,
+ 107, 103, 0, 127, 128, 0, 0, 0, 85, 41,
+ 89, 0, 43, 50, 52, 57, 58, 59, 0, 0,
+ 106, 97, 0, 0, 0, 90, 108, 0, 0, 0,
+ 91, 104, 0, 0, 98, 99
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int16 yydefgoto[] =
{
- -1, 1, 3, 24, 146, 144, 25, 28, 56, 58,
- 52, 43, 81, 72, 85, 64, 77, 87, 89, 91,
- 93, 95, 53, 65, 54, 66, 45, 55, 179, 217,
- 46, 47, 48, 49, 107, 193, 50, 112
+ -1, 1, 3, 25, 150, 148, 26, 29, 57, 59,
+ 53, 44, 82, 73, 86, 65, 78, 88, 90, 92,
+ 94, 96, 98, 54, 66, 55, 67, 46, 56, 183,
+ 222, 47, 48, 49, 50, 110, 198, 51, 115
};
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
-#define YYPACT_NINF -96
+#define YYPACT_NINF -100
static const yytype_int16 yypact[] =
{
- -96, 34, -96, 158, -38, -30, 267, 288, 288, 338,
- 195, 20, 317, 210, 428, 288, 288, 288, 428, 68,
- -6, 2, 42, -96, -96, 45, -96, -96, -96, 449,
- 449, -96, -96, -96, -96, -96, -96, -96, 127, -96,
- 338, 388, 449, -96, -96, -96, -96, -96, -96, 46,
- 47, 382, -96, -96, 52, -96, -96, 59, -96, 62,
- 338, 127, 19, 238, -96, -96, -96, -96, -96, -96,
- -96, 63, -96, 103, 338, -96, -96, -96, 19, 403,
- 449, -96, -96, 69, 78, -96, 81, -96, 94, -96,
- 97, -96, 98, -96, 102, -96, 111, -96, 449, -96,
- 449, -96, -96, -96, 142, 449, 449, 113, -96, 23,
- 110, -96, 74, -96, 137, 58, 432, -96, -96, 439,
- -96, -96, -96, 338, 288, -96, -96, -96, 113, -96,
- 367, -96, 13, 449, -96, -96, 403, 156, 16, 338,
- 338, 338, 443, 338, 158, 523, 158, 523, 19, -96,
- -96, 11, 449, 140, -96, 449, 449, 449, 182, 194,
- 449, 449, 449, 449, 449, -96, 197, 25, 160, 161,
- -96, 475, 162, -96, -96, 163, 168, -96, 8, -96,
- 169, 173, 174, -96, -96, 175, 176, -96, -96, 177,
- -96, -96, -96, 172, 178, 192, 532, 157, 498, 449,
- 449, 64, 64, -96, -96, -96, 449, 449, 186, -96,
- -96, 191, -96, -96, 200, 215, 244, -96, 205, 222,
- 224, 200, 449, 230, -96, -96, 252, 183, 183, 216,
- 217, 234, -96, -96, 254, 240, -96, -96, -96, -96,
- -96, 221, 449, -96, -96, 271, 255, -96, -96, 236,
- 449, -96, -96, 241, -96
+ -100, 22, -100, 165, -32, -22, 265, 288, 288, 334,
+ 195, -1, 311, 212, 416, 288, 288, 288, 416, 81,
+ 7, -16, 24, -12, -100, -100, -4, -100, -100, -100,
+ 469, 469, -100, -100, -100, -100, -100, -100, -100, 39,
+ -100, 334, 387, 469, -100, -100, -100, -100, -100, -100,
+ 46, 65, 372, -100, -100, 72, -100, -100, 83, -100,
+ 86, 334, 39, 102, 242, -100, -100, -100, -100, -100,
+ -100, -100, 77, -100, 117, 334, -100, -100, -100, 102,
+ 410, 469, -100, -100, 89, 90, -100, 92, -100, 97,
+ -100, 98, -100, 100, -100, 101, -100, 105, -100, 106,
+ -100, 469, -100, 469, -100, -100, -100, 135, 469, 469,
+ 114, -100, -6, 128, -100, 71, -100, 175, 32, 218,
+ -100, -100, 425, -100, -100, -100, 334, 288, -100, -100,
+ -100, 114, -100, 357, -100, 29, 469, -100, -100, 410,
+ 181, 440, 334, 334, 334, 457, 334, 334, 165, 164,
+ 165, 164, 102, -100, -100, 6, 469, 166, -100, 469,
+ 469, 469, 207, 208, 469, 469, 469, 469, 469, -100,
+ 206, 4, 173, 174, -100, 463, 176, -100, -100, 184,
+ 187, -100, 15, -100, 193, 200, 213, -100, -100, 211,
+ 217, 220, -100, -100, 222, -100, -100, -100, 216, 219,
+ 238, 517, 525, 78, 469, 469, 95, 95, -100, -100,
+ -100, 469, 469, 232, -100, -100, 237, -100, -100, 7,
+ 252, 278, -100, 239, 254, 256, 7, 469, 81, 263,
+ -100, -100, 293, 188, 188, 255, 258, 88, -100, -100,
+ 300, 281, -100, -100, -100, -100, -100, -100, 262, 469,
+ -100, -100, 304, 305, 289, -100, -100, 277, 469, 469,
+ -100, -100, 283, 284, -100, -100
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int16 yypgoto[] =
{
- -96, -96, -96, -95, -96, -96, -96, 270, -96, -96,
- -96, 274, -96, -96, -96, -96, -96, -96, -96, -96,
- -96, -96, -2, 227, 6, -12, -1, -8, 73, -96,
- 12, 1, 5, -3, -49, -96, -10, -44
+ -100, -100, -100, -99, -100, -100, -100, 315, -100, -100,
+ -100, 318, -100, -100, -100, -100, -100, -100, -100, -100,
+ -100, -100, -100, 17, 270, 0, -7, -9, -8, 112,
+ -100, 13, 1, -3, -2, -44, -100, -10, -64
};
/* 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. */
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
#define YYTABLE_NINF -1
-static const yytype_uint8 yytable[] =
+static const yytype_uint16 yytable[] =
{
- 71, 82, 68, 84, 44, 83, 26, 59, 73, 67,
- 44, 69, 128, 129, 57, 70, 27, 215, 96, 102,
- 103, 88, 90, 92, 29, 30, 86, 105, 106, 134,
- 94, 111, 113, 152, 2, 207, 216, 97, 108, 98,
- 190, 121, 191, 175, 31, 99, 167, 168, 120, 187,
- 192, 188, 169, 71, 145, 68, 147, 127, 39, 125,
- 38, 126, 67, 80, 69, 178, 42, 135, 70, 84,
- 111, 153, 108, 208, 162, 163, 164, 155, 156, 157,
- 158, 159, 160, 161, 162, 163, 164, 100, 111, 101,
- 111, 167, 168, 114, 115, 149, 150, 169, 122, 189,
- 32, 33, 34, 35, 36, 123, 103, 37, 124, 111,
- 132, 196, 197, 198, 133, 136, 201, 202, 203, 204,
- 205, 173, 165, 176, 177, 137, 84, 138, 180, 125,
- 174, 126, 185, 104, 184, 105, 106, 181, 182, 183,
- 139, 186, 194, 140, 141, 111, 111, 111, 142, 148,
- 111, 111, 111, 111, 111, 227, 228, 143, 154, 4,
- 151, 103, 157, 158, 159, 160, 161, 162, 163, 164,
- 166, 5, 6, 7, 8, 9, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 175, 195, 199, 111,
- 111, 160, 161, 162, 163, 164, 229, 230, 20, 21,
- 22, 200, 23, 29, 30, 60, 233, 206, 209, 210,
- 212, 213, 240, 239, 214, 218, 219, 220, 29, 30,
- 224, 221, 222, 31, 223, 226, 225, 32, 33, 34,
- 35, 36, 249, 231, 37, 61, 62, 39, 31, 232,
- 253, 63, 41, 234, 51, 42, 29, 30, 130, 51,
- 78, 62, 39, 235, 178, 237, 79, 80, 238, 51,
- 42, 241, 242, 246, 243, 244, 31, 245, 247, 248,
- 32, 33, 34, 35, 36, 29, 30, 37, 61, 62,
- 39, 250, 75, 251, 252, 41, 76, 51, 42, 254,
- 131, 236, 0, 0, 0, 31, 29, 30, 0, 32,
- 33, 34, 35, 36, 0, 0, 37, 38, 0, 39,
- 0, 0, 0, 40, 41, 0, 31, 42, 0, 0,
- 32, 33, 34, 35, 36, 29, 30, 37, 38, 0,
- 39, 0, 0, 0, 0, 41, 0, 51, 42, 0,
- 0, 0, 0, 0, 0, 31, 29, 30, 0, 32,
- 33, 34, 35, 36, 0, 0, 37, 38, 0, 39,
- 0, 0, 0, 74, 41, 0, 31, 42, 0, 0,
- 32, 33, 34, 35, 36, 29, 30, 37, 38, 0,
- 39, 0, 0, 0, 0, 41, 0, 0, 42, 0,
- 29, 116, 0, 0, 0, 31, 29, 30, 0, 32,
- 33, 34, 35, 36, 0, 0, 37, 0, 0, 39,
- 31, 29, 30, 0, 41, 0, 31, 42, 0, 117,
- 118, 109, 38, 0, 39, 0, 0, 110, 0, 119,
- 39, 31, 42, 0, 0, 80, 29, 30, 42, 0,
- 29, 30, 0, 78, 62, 39, 0, 29, 171, 0,
- 80, 29, 30, 42, 0, 0, 31, 29, 30, 0,
- 31, 0, 0, 0, 0, 0, 0, 31, 38, 170,
- 39, 31, 0, 0, 39, 41, 172, 31, 42, 80,
- 0, 39, 42, 29, 30, 39, 80, 0, 0, 42,
- 80, 39, 51, 42, 0, 0, 80, 0, 0, 42,
- 0, 0, 0, 31, 158, 159, 160, 161, 162, 163,
- 164, 0, 211, 0, 0, 0, 0, 39, 0, 0,
- 0, 0, 80, 0, 0, 42, 155, 156, 157, 158,
- 159, 160, 161, 162, 163, 164, 156, 157, 158, 159,
- 160, 161, 162, 163, 164
+ 72, 68, 69, 85, 156, 84, 83, 71, 58, 74,
+ 97, 70, 99, 27, 212, 89, 91, 93, 131, 132,
+ 105, 106, 2, 45, 220, 28, 60, 87, 100, 45,
+ 101, 95, 114, 116, 103, 137, 195, 149, 196, 151,
+ 39, 104, 124, 157, 221, 107, 197, 108, 109, 192,
+ 123, 193, 128, 213, 72, 68, 69, 52, 111, 130,
+ 179, 71, 129, 171, 172, 70, 171, 172, 102, 173,
+ 85, 114, 173, 138, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 162, 163, 164, 165, 166, 167,
+ 168, 114, 111, 114, 117, 201, 202, 203, 153, 154,
+ 206, 207, 208, 209, 210, 166, 167, 168, 194, 106,
+ 108, 109, 114, 118, 33, 34, 35, 36, 37, 125,
+ 169, 38, 252, 253, 128, 135, 180, 178, 136, 85,
+ 126, 184, 181, 127, 129, 189, 139, 188, 140, 141,
+ 233, 234, 152, 177, 142, 143, 199, 144, 145, 114,
+ 114, 114, 146, 147, 114, 114, 114, 114, 114, 185,
+ 186, 187, 155, 190, 191, 106, 4, 159, 160, 161,
+ 162, 163, 164, 165, 166, 167, 168, 158, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 114, 114, 164, 165, 166, 167,
+ 168, 235, 236, 30, 31, 61, 21, 22, 23, 170,
+ 24, 239, 179, 204, 200, 205, 211, 246, 245, 247,
+ 30, 31, 214, 215, 32, 217, 30, 31, 33, 34,
+ 35, 36, 37, 218, 219, 38, 62, 63, 40, 257,
+ 223, 32, 64, 42, 224, 52, 43, 32, 262, 263,
+ 30, 31, 133, 79, 63, 40, 174, 225, 226, 80,
+ 81, 40, 52, 43, 227, 230, 81, 228, 231, 43,
+ 229, 32, 232, 30, 31, 33, 34, 35, 36, 37,
+ 237, 240, 38, 62, 63, 40, 238, 241, 243, 182,
+ 42, 244, 52, 43, 32, 248, 30, 31, 33, 34,
+ 35, 36, 37, 249, 250, 38, 39, 251, 40, 254,
+ 255, 256, 41, 42, 258, 259, 43, 32, 260, 30,
+ 31, 33, 34, 35, 36, 37, 261, 76, 38, 39,
+ 77, 40, 264, 265, 134, 242, 42, 0, 52, 43,
+ 32, 0, 30, 31, 33, 34, 35, 36, 37, 0,
+ 0, 38, 39, 0, 40, 0, 0, 0, 75, 42,
+ 0, 0, 43, 32, 0, 30, 31, 33, 34, 35,
+ 36, 37, 0, 0, 38, 39, 0, 40, 0, 0,
+ 30, 119, 42, 0, 0, 43, 32, 0, 0, 0,
+ 33, 34, 35, 36, 37, 30, 31, 38, 0, 0,
+ 40, 32, 0, 0, 0, 42, 0, 0, 43, 0,
+ 120, 121, 0, 39, 0, 40, 32, 0, 30, 31,
+ 122, 112, 0, 43, 30, 31, 0, 113, 0, 0,
+ 40, 0, 0, 30, 175, 81, 0, 0, 43, 32,
+ 0, 0, 0, 0, 0, 32, 0, 0, 30, 31,
+ 0, 79, 63, 40, 32, 0, 0, 39, 81, 40,
+ 0, 43, 0, 176, 42, 30, 31, 43, 40, 32,
+ 0, 30, 31, 81, 0, 0, 43, 30, 31, 0,
+ 0, 0, 0, 40, 0, 0, 32, 0, 81, 0,
+ 182, 43, 32, 0, 0, 0, 0, 0, 32, 0,
+ 40, 216, 0, 0, 0, 81, 40, 52, 43, 0,
+ 0, 81, 40, 0, 43, 0, 0, 81, 0, 0,
+ 43, 160, 161, 162, 163, 164, 165, 166, 167, 168,
+ 161, 162, 163, 164, 165, 166, 167, 168
};
-#define yypact_value_is_default(Yystate) \
- (!!((Yystate) == (-96)))
-
-#define yytable_value_is_error(Yytable_value) \
- YYID (0)
-
static const yytype_int16 yycheck[] =
{
- 10, 13, 10, 13, 6, 13, 44, 9, 11, 10,
- 12, 10, 61, 62, 8, 10, 46, 9, 19, 29,
- 30, 15, 16, 17, 8, 9, 14, 8, 9, 78,
- 18, 41, 42, 10, 0, 10, 28, 43, 40, 45,
- 29, 51, 31, 30, 28, 43, 33, 34, 51, 144,
- 39, 146, 39, 63, 98, 63, 100, 60, 42, 60,
- 40, 60, 63, 47, 63, 49, 50, 79, 63, 79,
- 80, 48, 74, 48, 10, 11, 12, 3, 4, 5,
- 6, 7, 8, 9, 10, 11, 12, 45, 98, 44,
- 100, 33, 34, 47, 47, 105, 106, 39, 46, 148,
- 32, 33, 34, 35, 36, 46, 116, 39, 46, 119,
- 47, 155, 156, 157, 11, 46, 160, 161, 162, 163,
- 164, 123, 48, 133, 136, 47, 136, 46, 138, 130,
- 124, 130, 142, 6, 142, 8, 9, 139, 140, 141,
- 46, 143, 152, 46, 46, 155, 156, 157, 46, 7,
- 160, 161, 162, 163, 164, 199, 200, 46, 48, 1,
- 47, 171, 5, 6, 7, 8, 9, 10, 11, 12,
- 33, 13, 14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 24, 25, 26, 27, 30, 47, 6, 199,
- 200, 8, 9, 10, 11, 12, 206, 207, 40, 41,
- 42, 7, 44, 8, 9, 10, 214, 10, 48, 48,
- 48, 48, 222, 221, 46, 46, 43, 43, 8, 9,
- 48, 46, 46, 28, 47, 33, 48, 32, 33, 34,
- 35, 36, 242, 47, 39, 40, 41, 42, 28, 48,
- 250, 46, 47, 28, 49, 50, 8, 9, 10, 49,
- 40, 41, 42, 9, 49, 33, 46, 47, 34, 49,
- 50, 31, 10, 9, 48, 48, 28, 33, 28, 48,
- 32, 33, 34, 35, 36, 8, 9, 39, 40, 41,
- 42, 10, 12, 28, 48, 47, 12, 49, 50, 48,
- 63, 218, -1, -1, -1, 28, 8, 9, -1, 32,
- 33, 34, 35, 36, -1, -1, 39, 40, -1, 42,
- -1, -1, -1, 46, 47, -1, 28, 50, -1, -1,
- 32, 33, 34, 35, 36, 8, 9, 39, 40, -1,
- 42, -1, -1, -1, -1, 47, -1, 49, 50, -1,
- -1, -1, -1, -1, -1, 28, 8, 9, -1, 32,
- 33, 34, 35, 36, -1, -1, 39, 40, -1, 42,
- -1, -1, -1, 46, 47, -1, 28, 50, -1, -1,
- 32, 33, 34, 35, 36, 8, 9, 39, 40, -1,
- 42, -1, -1, -1, -1, 47, -1, -1, 50, -1,
- 8, 9, -1, -1, -1, 28, 8, 9, -1, 32,
- 33, 34, 35, 36, -1, -1, 39, -1, -1, 42,
- 28, 8, 9, -1, 47, -1, 28, 50, -1, 37,
- 38, 33, 40, -1, 42, -1, -1, 39, -1, 47,
- 42, 28, 50, -1, -1, 47, 8, 9, 50, -1,
- 8, 9, -1, 40, 41, 42, -1, 8, 9, -1,
- 47, 8, 9, 50, -1, -1, 28, 8, 9, -1,
- 28, -1, -1, -1, -1, -1, -1, 28, 40, 37,
- 42, 28, -1, -1, 42, 47, 37, 28, 50, 47,
- -1, 42, 50, 8, 9, 42, 47, -1, -1, 50,
- 47, 42, 49, 50, -1, -1, 47, -1, -1, 50,
- -1, -1, -1, 28, 6, 7, 8, 9, 10, 11,
- 12, -1, 37, -1, -1, -1, -1, 42, -1, -1,
- -1, -1, 47, -1, -1, 50, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 4, 5, 6, 7,
- 8, 9, 10, 11, 12
+ 10, 10, 10, 13, 10, 13, 13, 10, 8, 11,
+ 19, 10, 20, 45, 10, 15, 16, 17, 62, 63,
+ 30, 31, 0, 6, 9, 47, 9, 14, 44, 12,
+ 46, 18, 42, 43, 46, 79, 30, 101, 32, 103,
+ 41, 45, 52, 49, 29, 6, 40, 8, 9, 148,
+ 52, 150, 61, 49, 64, 64, 64, 50, 41, 61,
+ 31, 64, 61, 34, 35, 64, 34, 35, 44, 40,
+ 80, 81, 40, 80, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 6, 7, 8, 9, 10, 11,
+ 12, 101, 75, 103, 48, 159, 160, 161, 108, 109,
+ 164, 165, 166, 167, 168, 10, 11, 12, 152, 119,
+ 8, 9, 122, 48, 33, 34, 35, 36, 37, 47,
+ 49, 40, 34, 35, 133, 48, 136, 127, 11, 139,
+ 47, 141, 139, 47, 133, 145, 47, 145, 48, 47,
+ 204, 205, 7, 126, 47, 47, 156, 47, 47, 159,
+ 160, 161, 47, 47, 164, 165, 166, 167, 168, 142,
+ 143, 144, 48, 146, 147, 175, 1, 3, 4, 5,
+ 6, 7, 8, 9, 10, 11, 12, 49, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 204, 205, 8, 9, 10, 11,
+ 12, 211, 212, 8, 9, 10, 41, 42, 43, 34,
+ 45, 219, 31, 6, 48, 7, 10, 227, 226, 228,
+ 8, 9, 49, 49, 29, 49, 8, 9, 33, 34,
+ 35, 36, 37, 49, 47, 40, 41, 42, 43, 249,
+ 47, 29, 47, 48, 44, 50, 51, 29, 258, 259,
+ 8, 9, 10, 41, 42, 43, 38, 44, 47, 47,
+ 48, 43, 50, 51, 47, 49, 48, 47, 49, 51,
+ 48, 29, 34, 8, 9, 33, 34, 35, 36, 37,
+ 48, 29, 40, 41, 42, 43, 49, 9, 34, 50,
+ 48, 35, 50, 51, 29, 32, 8, 9, 33, 34,
+ 35, 36, 37, 10, 49, 40, 41, 49, 43, 9,
+ 29, 49, 47, 48, 10, 10, 51, 29, 29, 8,
+ 9, 33, 34, 35, 36, 37, 49, 12, 40, 41,
+ 12, 43, 49, 49, 64, 223, 48, -1, 50, 51,
+ 29, -1, 8, 9, 33, 34, 35, 36, 37, -1,
+ -1, 40, 41, -1, 43, -1, -1, -1, 47, 48,
+ -1, -1, 51, 29, -1, 8, 9, 33, 34, 35,
+ 36, 37, -1, -1, 40, 41, -1, 43, -1, -1,
+ 8, 9, 48, -1, -1, 51, 29, -1, -1, -1,
+ 33, 34, 35, 36, 37, 8, 9, 40, -1, -1,
+ 43, 29, -1, -1, -1, 48, -1, -1, 51, -1,
+ 38, 39, -1, 41, -1, 43, 29, -1, 8, 9,
+ 48, 34, -1, 51, 8, 9, -1, 40, -1, -1,
+ 43, -1, -1, 8, 9, 48, -1, -1, 51, 29,
+ -1, -1, -1, -1, -1, 29, -1, -1, 8, 9,
+ -1, 41, 42, 43, 29, -1, -1, 41, 48, 43,
+ -1, 51, -1, 38, 48, 8, 9, 51, 43, 29,
+ -1, 8, 9, 48, -1, -1, 51, 8, 9, -1,
+ -1, -1, -1, 43, -1, -1, 29, -1, 48, -1,
+ 50, 51, 29, -1, -1, -1, -1, -1, 29, -1,
+ 43, 38, -1, -1, -1, 48, 43, 50, 51, -1,
+ -1, 48, 43, -1, 51, -1, -1, 48, -1, -1,
+ 51, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 5, 6, 7, 8, 9, 10, 11, 12
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */
static const yytype_uint8 yystos[] =
{
- 0, 52, 0, 53, 1, 13, 14, 15, 16, 17,
+ 0, 53, 0, 54, 1, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
- 40, 41, 42, 44, 54, 57, 44, 46, 58, 8,
- 9, 28, 32, 33, 34, 35, 36, 39, 40, 42,
- 46, 47, 50, 62, 73, 77, 81, 82, 83, 84,
- 87, 49, 61, 73, 75, 78, 59, 75, 60, 73,
- 10, 40, 41, 46, 66, 74, 76, 77, 78, 82,
- 83, 87, 64, 84, 46, 58, 62, 67, 40, 46,
- 47, 63, 76, 78, 87, 65, 81, 68, 75, 69,
- 75, 70, 75, 71, 81, 72, 77, 43, 45, 43,
- 45, 44, 87, 87, 6, 8, 9, 85, 73, 33,
- 39, 87, 88, 87, 47, 47, 9, 37, 38, 47,
- 84, 87, 46, 46, 46, 77, 82, 84, 85, 85,
- 10, 74, 47, 11, 85, 76, 46, 47, 46, 46,
- 46, 46, 46, 46, 56, 88, 55, 88, 7, 87,
- 87, 47, 10, 48, 48, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 48, 33, 33, 34, 39,
- 37, 9, 37, 73, 75, 30, 87, 76, 49, 79,
- 87, 73, 73, 73, 78, 87, 73, 54, 54, 85,
- 29, 31, 39, 86, 87, 47, 88, 88, 88, 6,
- 7, 88, 88, 88, 88, 88, 10, 10, 48, 48,
- 48, 37, 48, 48, 46, 9, 28, 80, 46, 43,
- 43, 46, 46, 47, 48, 48, 33, 88, 88, 87,
- 87, 47, 48, 78, 28, 9, 79, 33, 34, 78,
- 87, 31, 10, 48, 48, 33, 9, 28, 48, 87,
- 10, 28, 48, 87, 48
+ 28, 41, 42, 43, 45, 55, 58, 45, 47, 59,
+ 8, 9, 29, 33, 34, 35, 36, 37, 40, 41,
+ 43, 47, 48, 51, 63, 75, 79, 83, 84, 85,
+ 86, 89, 50, 62, 75, 77, 80, 60, 77, 61,
+ 75, 10, 41, 42, 47, 67, 76, 78, 79, 80,
+ 84, 85, 89, 65, 86, 47, 59, 63, 68, 41,
+ 47, 48, 64, 78, 80, 89, 66, 83, 69, 77,
+ 70, 77, 71, 77, 72, 83, 73, 79, 74, 80,
+ 44, 46, 44, 46, 45, 89, 89, 6, 8, 9,
+ 87, 75, 34, 40, 89, 90, 89, 48, 48, 9,
+ 38, 39, 48, 86, 89, 47, 47, 47, 79, 84,
+ 86, 87, 87, 10, 76, 48, 11, 87, 78, 47,
+ 48, 47, 47, 47, 47, 47, 47, 47, 57, 90,
+ 56, 90, 7, 89, 89, 48, 10, 49, 49, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 49,
+ 34, 34, 35, 40, 38, 9, 38, 75, 77, 31,
+ 89, 78, 50, 81, 89, 75, 75, 75, 80, 89,
+ 75, 75, 55, 55, 87, 30, 32, 40, 88, 89,
+ 48, 90, 90, 90, 6, 7, 90, 90, 90, 90,
+ 90, 10, 10, 49, 49, 49, 38, 49, 49, 47,
+ 9, 29, 82, 47, 44, 44, 47, 47, 47, 48,
+ 49, 49, 34, 90, 90, 89, 89, 48, 49, 80,
+ 29, 9, 81, 34, 35, 80, 89, 79, 32, 10,
+ 49, 49, 34, 35, 9, 29, 49, 89, 10, 10,
+ 29, 49, 89, 89, 49, 49
};
#define yyerrok (yyerrstatus = 0)
@@ -905,50 +873,78 @@ static const yytype_uint8 yystos[] =
/* 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. */
+ Once GCC version 2 has supplanted version 1, this can go. */
#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) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- YYPOPSTACK (yylen); \
- yystate = *yyssp; \
- goto yybackup; \
- } \
- else \
- { \
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
yyerror (YY_("syntax error: cannot back up")); \
YYERROR; \
} \
while (YYID (0))
-/* Error token number */
+
#define YYTERROR 1
#define YYERRCODE 256
-/* This macro is provided for backward compatibility. */
+/* 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
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
#endif
/* YYLEX -- calling `yylex' with the right arguments. */
+
#ifdef YYLEX_PARAM
# define YYLEX yylex (YYLEX_PARAM)
#else
@@ -998,8 +994,6 @@ yy_symbol_value_print (yyoutput, yytype, yyvaluep)
YYSTYPE const * const yyvaluep;
#endif
{
- FILE *yyo = yyoutput;
- YYUSE (yyo);
if (!yyvaluep)
return;
# ifdef YYPRINT
@@ -1049,20 +1043,17 @@ yy_symbol_print (yyoutput, yytype, yyvaluep)
#if (defined __STDC__ || defined __C99__FUNC__ \
|| defined __cplusplus || defined _MSC_VER)
static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
#else
static void
-yy_stack_print (yybottom, yytop)
- yytype_int16 *yybottom;
- yytype_int16 *yytop;
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
#endif
{
YYFPRINTF (stderr, "Stack now");
- for (; yybottom <= yytop; yybottom++)
- {
- int yybot = *yybottom;
- YYFPRINTF (stderr, " %d", yybot);
- }
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
YYFPRINTF (stderr, "\n");
}
@@ -1096,11 +1087,11 @@ yy_reduce_print (yyvsp, yyrule)
/* The symbols being reduced. */
for (yyi = 0; yyi < yynrhs; yyi++)
{
- YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ fprintf (stderr, " $%d = ", yyi + 1);
yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
&(yyvsp[(yyi + 1) - (yynrhs)])
);
- YYFPRINTF (stderr, "\n");
+ fprintf (stderr, "\n");
}
}
@@ -1137,6 +1128,7 @@ int yydebug;
# define YYMAXDEPTH 10000
#endif
+
#if YYERROR_VERBOSE
@@ -1239,142 +1231,115 @@ yytnamerr (char *yyres, const char *yystr)
}
# 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)
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
{
- YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
- YYSIZE_T yysize = yysize0;
- YYSIZE_T yysize1;
- enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
- /* Internationalized format string. */
- const char *yyformat = YY_NULL;
- /* 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 (YY_NULL, yytname[yyx]);
- if (! (yysize <= yysize1
- && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
- }
- }
- }
+ int yyn = yypact[yystate];
- 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_
- }
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ 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 yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
- yysize1 = yysize + yystrlen (yyformat);
- if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
- return 2;
- yysize = yysize1;
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ 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;
- }
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
- /* 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;
+ if (yyresult)
+ {
+ /* 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 = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
}
#endif /* YYERROR_VERBOSE */
+
/*-----------------------------------------------.
| Release the memory associated to this symbol. |
@@ -1406,29 +1371,37 @@ yydestruct (yymsg, yytype, yyvaluep)
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;
-
-#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END
-#endif
-#ifndef YY_INITIAL_VALUE
-# define YY_INITIAL_VALUE(Value) /* Nothing. */
-#endif
+/* The look-ahead symbol. */
+int yychar;
-/* The semantic value of the lookahead symbol. */
-YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
/* Number of syntax errors so far. */
int yynerrs;
+
/*----------.
| yyparse. |
`----------*/
@@ -1455,37 +1428,14 @@ yyparse ()
#endif
#endif
{
- int yystate;
- /* 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 through 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 yystate;
int yyn;
int yyresult;
- /* Lookahead token as an internal (translated) token number. */
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
int yytoken = 0;
- /* 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];
@@ -1493,22 +1443,54 @@ yyparse ()
YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
#endif
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
/* The number of symbols on the RHS of the reduced rule.
Keep to zero when no symbol should be popped. */
int yylen = 0;
- yyssp = yyss = yyssa;
- yyvsp = yyvs = yyvsa;
- yystacksize = YYINITDEPTH;
-
YYDPRINTF ((stderr, "Starting parse\n"));
yystate = 0;
yyerrstatus = 0;
yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
+ 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;
/*------------------------------------------------------------.
@@ -1535,6 +1517,7 @@ yyparse ()
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
@@ -1542,6 +1525,7 @@ yyparse ()
yyoverflow (YY_("memory exhausted"),
&yyss1, yysize * sizeof (*yyssp),
&yyvs1, yysize * sizeof (*yyvsp),
+
&yystacksize);
yyss = yyss1;
@@ -1564,8 +1548,9 @@ yyparse ()
(union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
if (! yyptr)
goto yyexhaustedlab;
- YYSTACK_RELOCATE (yyss_alloc, yyss);
- YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
# undef YYSTACK_RELOCATE
if (yyss1 != yyssa)
YYSTACK_FREE (yyss1);
@@ -1576,6 +1561,7 @@ yyparse ()
yyssp = yyss + yysize - 1;
yyvsp = yyvs + yysize - 1;
+
YYDPRINTF ((stderr, "Stack size increased to %lu\n",
(unsigned long int) yystacksize));
@@ -1585,9 +1571,6 @@ yyparse ()
YYDPRINTF ((stderr, "Entering state %d\n", yystate));
- if (yystate == YYFINAL)
- YYACCEPT;
-
goto yybackup;
/*-----------.
@@ -1596,16 +1579,16 @@ yyparse ()
yybackup:
/* Do appropriate processing given the current state. Read a
- lookahead token if we need one and don't already have one. */
+ look-ahead token if we need one and don't already have one. */
- /* First try to decide what to do without reference to lookahead token. */
+ /* First try to decide what to do without reference to look-ahead token. */
yyn = yypact[yystate];
- if (yypact_value_is_default (yyn))
+ if (yyn == YYPACT_NINF)
goto yydefault;
- /* Not known => get a lookahead token if don't already have one. */
+ /* Not known => get a look-ahead token if don't already have one. */
- /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
if (yychar == YYEMPTY)
{
YYDPRINTF ((stderr, "Reading a token: "));
@@ -1631,27 +1614,29 @@ yybackup:
yyn = yytable[yyn];
if (yyn <= 0)
{
- if (yytable_value_is_error (yyn))
- goto yyerrlab;
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
yyn = -yyn;
goto yyreduce;
}
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
/* Count tokens shifted since error; after three, turn off error
status. */
if (yyerrstatus)
yyerrstatus--;
- /* Shift the lookahead token. */
+ /* Shift the look-ahead token. */
YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
- /* Discard the shifted token. */
- yychar = YYEMPTY;
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
yystate = yyn;
- YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
*++yyvsp = yylval;
- YY_IGNORE_MAYBE_UNINITIALIZED_END
goto yynewstate;
@@ -1688,7 +1673,6 @@ yyreduce:
switch (yyn)
{
case 3:
-/* Line 1778 of yacc.c */
#line 70 "a.y"
{
stmtline = lineno;
@@ -1696,7 +1680,6 @@ yyreduce:
break;
case 5:
-/* Line 1778 of yacc.c */
#line 77 "a.y"
{
if((yyvsp[(1) - (2)].sym)->value != pc)
@@ -1706,7 +1689,6 @@ yyreduce:
break;
case 7:
-/* Line 1778 of yacc.c */
#line 84 "a.y"
{
(yyvsp[(1) - (2)].sym)->type = LLAB;
@@ -1715,7 +1697,6 @@ yyreduce:
break;
case 12:
-/* Line 1778 of yacc.c */
#line 95 "a.y"
{
(yyvsp[(1) - (3)].sym)->type = LVAR;
@@ -1724,7 +1705,6 @@ yyreduce:
break;
case 13:
-/* Line 1778 of yacc.c */
#line 100 "a.y"
{
if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
@@ -1734,197 +1714,175 @@ yyreduce:
break;
case 14:
-/* Line 1778 of yacc.c */
#line 105 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 15:
-/* Line 1778 of yacc.c */
#line 106 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 16:
-/* Line 1778 of yacc.c */
#line 107 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 17:
-/* Line 1778 of yacc.c */
#line 108 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 18:
-/* Line 1778 of yacc.c */
#line 109 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 19:
-/* Line 1778 of yacc.c */
#line 110 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 20:
-/* Line 1778 of yacc.c */
#line 111 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 21:
-/* Line 1778 of yacc.c */
#line 112 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 22:
-/* Line 1778 of yacc.c */
#line 113 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 23:
-/* Line 1778 of yacc.c */
#line 114 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 24:
-/* Line 1778 of yacc.c */
#line 115 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 25:
-/* Line 1778 of yacc.c */
#line 116 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 26:
-/* Line 1778 of yacc.c */
#line 117 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 27:
-/* Line 1778 of yacc.c */
#line 118 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 28:
-/* Line 1778 of yacc.c */
#line 119 "a.y"
{ outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
break;
case 29:
-/* Line 1778 of yacc.c */
-#line 122 "a.y"
+#line 120 "a.y"
+ { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].gen2)); }
+ break;
+
+ case 30:
+#line 123 "a.y"
{
(yyval.gen2).from = nullgen;
(yyval.gen2).to = nullgen;
}
break;
- case 30:
-/* Line 1778 of yacc.c */
-#line 127 "a.y"
+ case 31:
+#line 128 "a.y"
{
(yyval.gen2).from = nullgen;
(yyval.gen2).to = nullgen;
}
break;
- case 31:
-/* Line 1778 of yacc.c */
-#line 134 "a.y"
+ case 32:
+#line 135 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (3)].gen);
(yyval.gen2).to = (yyvsp[(3) - (3)].gen);
}
break;
- case 32:
-/* Line 1778 of yacc.c */
-#line 141 "a.y"
+ case 33:
+#line 142 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (3)].gen);
(yyval.gen2).to = (yyvsp[(3) - (3)].gen);
}
break;
- case 33:
-/* Line 1778 of yacc.c */
-#line 148 "a.y"
+ case 34:
+#line 149 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (2)].gen);
(yyval.gen2).to = nullgen;
}
break;
- case 34:
-/* Line 1778 of yacc.c */
-#line 153 "a.y"
+ case 35:
+#line 154 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (1)].gen);
(yyval.gen2).to = nullgen;
}
break;
- case 35:
-/* Line 1778 of yacc.c */
-#line 160 "a.y"
+ case 36:
+#line 161 "a.y"
{
(yyval.gen2).from = nullgen;
(yyval.gen2).to = (yyvsp[(2) - (2)].gen);
}
break;
- case 36:
-/* Line 1778 of yacc.c */
-#line 165 "a.y"
+ case 37:
+#line 166 "a.y"
{
(yyval.gen2).from = nullgen;
(yyval.gen2).to = (yyvsp[(1) - (1)].gen);
}
break;
- case 37:
-/* Line 1778 of yacc.c */
-#line 172 "a.y"
+ case 38:
+#line 173 "a.y"
{
(yyval.gen2).from = nullgen;
(yyval.gen2).to = (yyvsp[(2) - (2)].gen);
}
break;
- case 38:
-/* Line 1778 of yacc.c */
-#line 177 "a.y"
+ case 39:
+#line 178 "a.y"
{
(yyval.gen2).from = nullgen;
(yyval.gen2).to = (yyvsp[(1) - (1)].gen);
}
break;
- case 39:
-/* Line 1778 of yacc.c */
-#line 182 "a.y"
+ case 40:
+#line 183 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (3)].gen);
(yyval.gen2).to = (yyvsp[(3) - (3)].gen);
}
break;
- case 40:
-/* Line 1778 of yacc.c */
-#line 189 "a.y"
+ case 41:
+#line 190 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (5)].gen);
(yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
@@ -1932,18 +1890,16 @@ yyreduce:
}
break;
- case 41:
-/* Line 1778 of yacc.c */
-#line 197 "a.y"
+ case 42:
+#line 198 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (3)].gen);
(yyval.gen2).to = (yyvsp[(3) - (3)].gen);
}
break;
- case 42:
-/* Line 1778 of yacc.c */
-#line 202 "a.y"
+ case 43:
+#line 203 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (5)].gen);
(yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
@@ -1951,27 +1907,24 @@ yyreduce:
}
break;
- case 43:
-/* Line 1778 of yacc.c */
-#line 210 "a.y"
+ case 44:
+#line 211 "a.y"
{
(yyval.gen2).from = nullgen;
(yyval.gen2).to = (yyvsp[(2) - (2)].gen);
}
break;
- case 44:
-/* Line 1778 of yacc.c */
-#line 215 "a.y"
+ case 45:
+#line 216 "a.y"
{
(yyval.gen2).from = nullgen;
(yyval.gen2).to = (yyvsp[(1) - (1)].gen);
}
break;
- case 45:
-/* Line 1778 of yacc.c */
-#line 220 "a.y"
+ case 46:
+#line 221 "a.y"
{
(yyval.gen2).from = nullgen;
(yyval.gen2).to = (yyvsp[(2) - (2)].gen);
@@ -1980,18 +1933,16 @@ yyreduce:
}
break;
- case 48:
-/* Line 1778 of yacc.c */
-#line 233 "a.y"
+ case 49:
+#line 234 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (3)].gen);
(yyval.gen2).to = (yyvsp[(3) - (3)].gen);
}
break;
- case 49:
-/* Line 1778 of yacc.c */
-#line 238 "a.y"
+ case 50:
+#line 239 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (5)].gen);
(yyval.gen2).to = (yyvsp[(3) - (5)].gen);
@@ -2001,18 +1952,16 @@ yyreduce:
}
break;
- case 50:
-/* Line 1778 of yacc.c */
-#line 248 "a.y"
+ case 51:
+#line 249 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (3)].gen);
(yyval.gen2).to = (yyvsp[(3) - (3)].gen);
}
break;
- case 51:
-/* Line 1778 of yacc.c */
-#line 253 "a.y"
+ case 52:
+#line 254 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (5)].gen);
(yyval.gen2).to = (yyvsp[(3) - (5)].gen);
@@ -2022,45 +1971,40 @@ yyreduce:
}
break;
- case 52:
-/* Line 1778 of yacc.c */
-#line 263 "a.y"
+ case 53:
+#line 264 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (2)].gen);
(yyval.gen2).to = nullgen;
}
break;
- case 53:
-/* Line 1778 of yacc.c */
-#line 268 "a.y"
+ case 54:
+#line 269 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (1)].gen);
(yyval.gen2).to = nullgen;
}
break;
- case 54:
-/* Line 1778 of yacc.c */
-#line 273 "a.y"
+ case 55:
+#line 274 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (3)].gen);
(yyval.gen2).to = (yyvsp[(3) - (3)].gen);
}
break;
- case 55:
-/* Line 1778 of yacc.c */
-#line 280 "a.y"
+ case 56:
+#line 281 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (3)].gen);
(yyval.gen2).to = (yyvsp[(3) - (3)].gen);
}
break;
- case 56:
-/* Line 1778 of yacc.c */
-#line 285 "a.y"
+ case 57:
+#line 286 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (5)].gen);
(yyval.gen2).from.scale = (yyvsp[(3) - (5)].lval);
@@ -2068,9 +2012,8 @@ yyreduce:
}
break;
- case 57:
-/* Line 1778 of yacc.c */
-#line 293 "a.y"
+ case 58:
+#line 294 "a.y"
{
(yyval.gen2).from = (yyvsp[(1) - (5)].gen);
(yyval.gen2).to = (yyvsp[(3) - (5)].gen);
@@ -2078,25 +2021,33 @@ yyreduce:
}
break;
- case 62:
-/* Line 1778 of yacc.c */
-#line 307 "a.y"
+ case 59:
+#line 302 "a.y"
+ {
+ (yyval.gen2).from = (yyvsp[(3) - (5)].gen);
+ (yyval.gen2).to = (yyvsp[(5) - (5)].gen);
+ if((yyvsp[(1) - (5)].gen).type != D_CONST)
+ yyerror("illegal constant");
+ (yyval.gen2).to.offset = (yyvsp[(1) - (5)].gen).offset;
+ }
+ break;
+
+ case 64:
+#line 318 "a.y"
{
(yyval.gen) = (yyvsp[(2) - (2)].gen);
}
break;
- case 63:
-/* Line 1778 of yacc.c */
-#line 311 "a.y"
+ case 65:
+#line 322 "a.y"
{
(yyval.gen) = (yyvsp[(2) - (2)].gen);
}
break;
- case 69:
-/* Line 1778 of yacc.c */
-#line 324 "a.y"
+ case 71:
+#line 335 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_BRANCH;
@@ -2104,9 +2055,8 @@ yyreduce:
}
break;
- case 70:
-/* Line 1778 of yacc.c */
-#line 330 "a.y"
+ case 72:
+#line 341 "a.y"
{
(yyval.gen) = nullgen;
if(pass == 2)
@@ -2117,9 +2067,8 @@ yyreduce:
}
break;
- case 71:
-/* Line 1778 of yacc.c */
-#line 339 "a.y"
+ case 73:
+#line 350 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_BRANCH;
@@ -2128,63 +2077,56 @@ yyreduce:
}
break;
- case 72:
-/* Line 1778 of yacc.c */
-#line 348 "a.y"
+ case 74:
+#line 359 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 73:
-/* Line 1778 of yacc.c */
-#line 353 "a.y"
+ case 75:
+#line 364 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 74:
-/* Line 1778 of yacc.c */
-#line 358 "a.y"
+ case 76:
+#line 369 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 75:
-/* Line 1778 of yacc.c */
-#line 363 "a.y"
+ case 77:
+#line 374 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 76:
-/* Line 1778 of yacc.c */
-#line 368 "a.y"
+ case 78:
+#line 379 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_SP;
}
break;
- case 77:
-/* Line 1778 of yacc.c */
-#line 373 "a.y"
+ case 79:
+#line 384 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = (yyvsp[(1) - (1)].lval);
}
break;
- case 78:
-/* Line 1778 of yacc.c */
-#line 380 "a.y"
+ case 80:
+#line 391 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_CONST;
@@ -2192,9 +2134,8 @@ yyreduce:
}
break;
- case 79:
-/* Line 1778 of yacc.c */
-#line 386 "a.y"
+ case 81:
+#line 397 "a.y"
{
(yyval.gen) = (yyvsp[(2) - (2)].gen);
(yyval.gen).index = (yyvsp[(2) - (2)].gen).type;
@@ -2207,9 +2148,8 @@ yyreduce:
}
break;
- case 80:
-/* Line 1778 of yacc.c */
-#line 397 "a.y"
+ case 82:
+#line 408 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_SCONST;
@@ -2217,9 +2157,8 @@ yyreduce:
}
break;
- case 81:
-/* Line 1778 of yacc.c */
-#line 403 "a.y"
+ case 83:
+#line 414 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_FCONST;
@@ -2227,9 +2166,8 @@ yyreduce:
}
break;
- case 82:
-/* Line 1778 of yacc.c */
-#line 409 "a.y"
+ case 84:
+#line 420 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_FCONST;
@@ -2237,9 +2175,8 @@ yyreduce:
}
break;
- case 83:
-/* Line 1778 of yacc.c */
-#line 415 "a.y"
+ case 85:
+#line 426 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_FCONST;
@@ -2247,9 +2184,8 @@ yyreduce:
}
break;
- case 84:
-/* Line 1778 of yacc.c */
-#line 421 "a.y"
+ case 86:
+#line 432 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_FCONST;
@@ -2257,9 +2193,8 @@ yyreduce:
}
break;
- case 85:
-/* Line 1778 of yacc.c */
-#line 429 "a.y"
+ case 87:
+#line 440 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_CONST2;
@@ -2268,45 +2203,40 @@ yyreduce:
}
break;
- case 86:
-/* Line 1778 of yacc.c */
-#line 438 "a.y"
+ case 88:
+#line 449 "a.y"
{
(yyval.con2).v1 = (yyvsp[(1) - (1)].lval);
(yyval.con2).v2 = 0;
}
break;
- case 87:
-/* Line 1778 of yacc.c */
-#line 443 "a.y"
+ case 89:
+#line 454 "a.y"
{
(yyval.con2).v1 = -(yyvsp[(2) - (2)].lval);
(yyval.con2).v2 = 0;
}
break;
- case 88:
-/* Line 1778 of yacc.c */
-#line 448 "a.y"
+ case 90:
+#line 459 "a.y"
{
(yyval.con2).v1 = (yyvsp[(1) - (3)].lval);
(yyval.con2).v2 = (yyvsp[(3) - (3)].lval);
}
break;
- case 89:
-/* Line 1778 of yacc.c */
-#line 453 "a.y"
+ case 91:
+#line 464 "a.y"
{
(yyval.con2).v1 = -(yyvsp[(2) - (4)].lval);
(yyval.con2).v2 = (yyvsp[(4) - (4)].lval);
}
break;
- case 92:
-/* Line 1778 of yacc.c */
-#line 464 "a.y"
+ case 94:
+#line 475 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+D_NONE;
@@ -2314,9 +2244,8 @@ yyreduce:
}
break;
- case 93:
-/* Line 1778 of yacc.c */
-#line 470 "a.y"
+ case 95:
+#line 481 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval);
@@ -2324,9 +2253,8 @@ yyreduce:
}
break;
- case 94:
-/* Line 1778 of yacc.c */
-#line 476 "a.y"
+ case 96:
+#line 487 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+D_SP;
@@ -2334,9 +2262,8 @@ yyreduce:
}
break;
- case 95:
-/* Line 1778 of yacc.c */
-#line 482 "a.y"
+ case 97:
+#line 493 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+D_NONE;
@@ -2347,9 +2274,8 @@ yyreduce:
}
break;
- case 96:
-/* Line 1778 of yacc.c */
-#line 491 "a.y"
+ case 98:
+#line 502 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval);
@@ -2360,27 +2286,36 @@ yyreduce:
}
break;
- case 97:
-/* Line 1778 of yacc.c */
-#line 500 "a.y"
+ case 99:
+#line 511 "a.y"
+ {
+ (yyval.gen) = nullgen;
+ (yyval.gen).type = D_INDIR+(yyvsp[(3) - (9)].lval);
+ (yyval.gen).offset = (yyvsp[(1) - (9)].lval);
+ (yyval.gen).index = (yyvsp[(6) - (9)].lval);
+ (yyval.gen).scale = (yyvsp[(8) - (9)].lval);
+ checkscale((yyval.gen).scale);
+ }
+ break;
+
+ case 100:
+#line 520 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+(yyvsp[(2) - (3)].lval);
}
break;
- case 98:
-/* Line 1778 of yacc.c */
-#line 505 "a.y"
+ case 101:
+#line 525 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+D_SP;
}
break;
- case 99:
-/* Line 1778 of yacc.c */
-#line 510 "a.y"
+ case 102:
+#line 530 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+(yyvsp[(3) - (4)].lval);
@@ -2388,9 +2323,8 @@ yyreduce:
}
break;
- case 100:
-/* Line 1778 of yacc.c */
-#line 516 "a.y"
+ case 103:
+#line 536 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+D_NONE;
@@ -2400,9 +2334,8 @@ yyreduce:
}
break;
- case 101:
-/* Line 1778 of yacc.c */
-#line 524 "a.y"
+ case 104:
+#line 544 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_INDIR+(yyvsp[(2) - (8)].lval);
@@ -2412,17 +2345,15 @@ yyreduce:
}
break;
- case 102:
-/* Line 1778 of yacc.c */
-#line 534 "a.y"
+ case 105:
+#line 554 "a.y"
{
(yyval.gen) = (yyvsp[(1) - (1)].gen);
}
break;
- case 103:
-/* Line 1778 of yacc.c */
-#line 538 "a.y"
+ case 106:
+#line 558 "a.y"
{
(yyval.gen) = (yyvsp[(1) - (6)].gen);
(yyval.gen).index = (yyvsp[(3) - (6)].lval);
@@ -2431,9 +2362,8 @@ yyreduce:
}
break;
- case 104:
-/* Line 1778 of yacc.c */
-#line 547 "a.y"
+ case 107:
+#line 567 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = (yyvsp[(4) - (5)].lval);
@@ -2442,9 +2372,8 @@ yyreduce:
}
break;
- case 105:
-/* Line 1778 of yacc.c */
-#line 554 "a.y"
+ case 108:
+#line 574 "a.y"
{
(yyval.gen) = nullgen;
(yyval.gen).type = D_STATIC;
@@ -2453,174 +2382,144 @@ yyreduce:
}
break;
- case 106:
-/* Line 1778 of yacc.c */
-#line 562 "a.y"
+ case 109:
+#line 582 "a.y"
{
(yyval.lval) = 0;
}
break;
- case 107:
-/* Line 1778 of yacc.c */
-#line 566 "a.y"
+ case 110:
+#line 586 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
- case 108:
-/* Line 1778 of yacc.c */
-#line 570 "a.y"
+ case 111:
+#line 590 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
- case 110:
-/* Line 1778 of yacc.c */
-#line 577 "a.y"
+ case 113:
+#line 597 "a.y"
{
(yyval.lval) = D_AUTO;
}
break;
- case 113:
-/* Line 1778 of yacc.c */
-#line 585 "a.y"
+ case 116:
+#line 605 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
}
break;
- case 114:
-/* Line 1778 of yacc.c */
-#line 589 "a.y"
+ case 117:
+#line 609 "a.y"
{
(yyval.lval) = -(yyvsp[(2) - (2)].lval);
}
break;
- case 115:
-/* Line 1778 of yacc.c */
-#line 593 "a.y"
+ case 118:
+#line 613 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (2)].lval);
}
break;
- case 116:
-/* Line 1778 of yacc.c */
-#line 597 "a.y"
+ case 119:
+#line 617 "a.y"
{
(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
}
break;
- case 117:
-/* Line 1778 of yacc.c */
-#line 601 "a.y"
+ case 120:
+#line 621 "a.y"
{
(yyval.lval) = (yyvsp[(2) - (3)].lval);
}
break;
- case 119:
-/* Line 1778 of yacc.c */
-#line 608 "a.y"
+ case 122:
+#line 628 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
}
break;
- case 120:
-/* Line 1778 of yacc.c */
-#line 612 "a.y"
+ case 123:
+#line 632 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
}
break;
- case 121:
-/* Line 1778 of yacc.c */
-#line 616 "a.y"
+ case 124:
+#line 636 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
}
break;
- case 122:
-/* Line 1778 of yacc.c */
-#line 620 "a.y"
+ case 125:
+#line 640 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
}
break;
- case 123:
-/* Line 1778 of yacc.c */
-#line 624 "a.y"
+ case 126:
+#line 644 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
}
break;
- case 124:
-/* Line 1778 of yacc.c */
-#line 628 "a.y"
+ case 127:
+#line 648 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
}
break;
- case 125:
-/* Line 1778 of yacc.c */
-#line 632 "a.y"
+ case 128:
+#line 652 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
}
break;
- case 126:
-/* Line 1778 of yacc.c */
-#line 636 "a.y"
+ case 129:
+#line 656 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
}
break;
- case 127:
-/* Line 1778 of yacc.c */
-#line 640 "a.y"
+ case 130:
+#line 660 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
}
break;
- case 128:
-/* Line 1778 of yacc.c */
-#line 644 "a.y"
+ case 131:
+#line 664 "a.y"
{
(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
}
break;
-/* Line 1778 of yacc.c */
-#line 2611 "y.tab.c"
+/* Line 1267 of yacc.c. */
+#line 2521 "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);
@@ -2629,6 +2528,7 @@ yyreduce:
*++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. */
@@ -2648,10 +2548,6 @@ yyreduce:
| 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)
{
@@ -2659,36 +2555,37 @@ yyerrlab:
#if ! YYERROR_VERBOSE
yyerror (YY_("syntax error"));
#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
- yyssp, yytoken)
{
- char const *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;
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (yymsg);
+ }
+ else
+ {
+ yyerror (YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
}
-# undef YYSYNTAX_ERROR
#endif
}
@@ -2696,7 +2593,7 @@ yyerrlab:
if (yyerrstatus == 3)
{
- /* If just tried and failed to reuse lookahead token after an
+ /* If just tried and failed to reuse look-ahead token after an
error, discard it. */
if (yychar <= YYEOF)
@@ -2713,7 +2610,7 @@ yyerrlab:
}
}
- /* Else will try to reuse lookahead token after shifting the error
+ /* Else will try to reuse look-ahead token after shifting the error
token. */
goto yyerrlab1;
@@ -2747,7 +2644,7 @@ yyerrlab1:
for (;;)
{
yyn = yypact[yystate];
- if (!yypact_value_is_default (yyn))
+ if (yyn != YYPACT_NINF)
{
yyn += YYTERROR;
if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
@@ -2770,9 +2667,10 @@ yyerrlab1:
YY_STACK_PRINT (yyss, yyssp);
}
- YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
*++yyvsp = yylval;
- YY_IGNORE_MAYBE_UNINITIALIZED_END
/* Shift the error token. */
@@ -2796,7 +2694,7 @@ yyabortlab:
yyresult = 1;
goto yyreturn;
-#if !defined yyoverflow || YYERROR_VERBOSE
+#ifndef yyoverflow
/*-------------------------------------------------.
| yyexhaustedlab -- memory exhaustion comes here. |
`-------------------------------------------------*/
@@ -2807,14 +2705,9 @@ yyexhaustedlab:
#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);
- }
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
/* Do not reclaim the symbols of the rule which action triggered
this YYABORT or YYACCEPT. */
YYPOPSTACK (yylen);
@@ -2838,3 +2731,4 @@ yyreturn:
}
+
diff --git a/src/cmd/8a/y.tab.h b/src/cmd/8a/y.tab.h
index 621aba79f..4a84b53e4 100644
--- a/src/cmd/8a/y.tab.h
+++ b/src/cmd/8a/y.tab.h
@@ -1,21 +1,24 @@
-/* A Bison parser, made by GNU Bison 2.6.5. */
+/* A Bison parser, made by GNU Bison 2.3. */
-/* Bison interface for Yacc-like parsers in C
-
- Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
-
- This program is free software: you can redistribute it and/or modify
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ 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.
-
+ the Free Software Foundation; either version 2, 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/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
@@ -26,20 +29,10 @@
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. */
-#ifndef YY_YY_Y_TAB_H_INCLUDED
-# define YY_YY_Y_TAB_H_INCLUDED
-/* Enabling traces. */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int yydebug;
-#endif
-
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
@@ -61,21 +54,22 @@ extern int yydebug;
LTYPEI = 270,
LTYPEG = 271,
LTYPEXC = 272,
- LCONST = 273,
- LFP = 274,
- LPC = 275,
- LSB = 276,
- LBREG = 277,
- LLREG = 278,
- LSREG = 279,
- LFREG = 280,
- LXREG = 281,
- LFCONST = 282,
- LSCONST = 283,
- LSP = 284,
- LNAME = 285,
- LLAB = 286,
- LVAR = 287
+ LTYPEX = 273,
+ LCONST = 274,
+ LFP = 275,
+ LPC = 276,
+ LSB = 277,
+ LBREG = 278,
+ LLREG = 279,
+ LSREG = 280,
+ LFREG = 281,
+ LXREG = 282,
+ LFCONST = 283,
+ LSCONST = 284,
+ LSP = 285,
+ LNAME = 286,
+ LLAB = 287,
+ LVAR = 288
};
#endif
/* Tokens. */
@@ -94,30 +88,30 @@ extern int yydebug;
#define LTYPEI 270
#define LTYPEG 271
#define LTYPEXC 272
-#define LCONST 273
-#define LFP 274
-#define LPC 275
-#define LSB 276
-#define LBREG 277
-#define LLREG 278
-#define LSREG 279
-#define LFREG 280
-#define LXREG 281
-#define LFCONST 282
-#define LSCONST 283
-#define LSP 284
-#define LNAME 285
-#define LLAB 286
-#define LVAR 287
+#define LTYPEX 273
+#define LCONST 274
+#define LFP 275
+#define LPC 276
+#define LSB 277
+#define LBREG 278
+#define LLREG 279
+#define LSREG 280
+#define LFREG 281
+#define LXREG 282
+#define LFCONST 283
+#define LSCONST 284
+#define LSP 285
+#define LNAME 286
+#define LLAB 287
+#define LVAR 288
+
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-{
-/* Line 2042 of yacc.c */
#line 37 "a.y"
-
+{
Sym *sym;
int32 lval;
struct {
@@ -128,30 +122,14 @@ typedef union YYSTYPE
char sval[8];
Gen gen;
Gen2 gen2;
-
-
-/* Line 2042 of yacc.c */
-#line 135 "y.tab.h"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
+}
+/* Line 1529 of yacc.c. */
+#line 128 "y.tab.h"
+ YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE yylval;
-#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 */
-
-#endif /* !YY_YY_Y_TAB_H_INCLUDED */
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
index d331eee1a..1b8ceb0c6 100644
--- a/src/cmd/8c/swt.c
+++ b/src/cmd/8c/swt.c
@@ -324,7 +324,7 @@ outcode(void)
zaddr(&b, &p->from, sf);
zaddr(&b, &p->to, st);
}
- Bflush(&b);
+ Bterm(&b);
close(f);
firstp = P;
lastp = P;
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index 0b2f2b76e..d54db7e62 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -739,6 +739,19 @@ agen(Node *n, Node *res)
case ODOT:
agen(nl, res);
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer. If the left node
+ // was ODOT we have already done the nil check.
+ if(nl->op != ODOT)
+ if(nl->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], res);
+ gmove(res, &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n1);
+ regfree(&n1);
+ }
if(n->xoffset != 0) {
nodconst(&n1, types[tptr], n->xoffset);
gins(optoas(OADD, types[tptr]), &n1, res);
@@ -750,18 +763,18 @@ agen(Node *n, Node *res)
if(!isptr[t->etype])
fatal("agen: not ptr %N", n);
cgen(nl, res);
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(nl->type->type->width >= unmappedzero) {
+ regalloc(&n1, types[tptr], res);
+ gmove(res, &n1);
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n1);
+ regfree(&n1);
+ }
if(n->xoffset != 0) {
- // explicit check for nil if struct is large enough
- // that we might derive too big a pointer.
- if(nl->type->type->width >= unmappedzero) {
- regalloc(&n1, types[tptr], res);
- gmove(res, &n1);
- n1.op = OINDREG;
- n1.type = types[TUINT8];
- n1.xoffset = 0;
- gins(ATESTB, nodintconst(0), &n1);
- regfree(&n1);
- }
nodconst(&n1, types[tptr], n->xoffset);
gins(optoas(OADD, types[tptr]), &n1, res);
}
@@ -825,16 +838,14 @@ igen(Node *n, Node *a, Node *res)
regalloc(a, types[tptr], res);
cgen(n->left, a);
}
- if(n->xoffset != 0) {
- // explicit check for nil if struct is large enough
- // that we might derive too big a pointer.
- if(n->left->type->type->width >= unmappedzero) {
- n1 = *a;
- n1.op = OINDREG;
- n1.type = types[TUINT8];
- n1.xoffset = 0;
- gins(ATESTB, nodintconst(0), &n1);
- }
+ // explicit check for nil if struct is large enough
+ // that we might derive too big a pointer.
+ if(n->left->type->type->width >= unmappedzero) {
+ n1 = *a;
+ n1.op = OINDREG;
+ n1.type = types[TUINT8];
+ n1.xoffset = 0;
+ gins(ATESTB, nodintconst(0), &n1);
}
a->op = OINDREG;
a->xoffset += n->xoffset;
@@ -1055,7 +1066,7 @@ bgen(Node *n, int true, int likely, Prog *to)
}
if(is64(nr->type)) {
- if(!nl->addable) {
+ if(!nl->addable || isconst(nl, CTINT)) {
tempname(&n1, nl->type);
cgen(nl, &n1);
nl = &n1;
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index c4c184bb9..756bdd203 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -1150,6 +1150,7 @@ ismem(Node *n)
case OINDREG:
case ONAME:
case OPARAM:
+ case OCLOSUREVAR:
return 1;
}
return 0;
@@ -2160,11 +2161,11 @@ gins(int as, Node *f, Node *t)
// Generate an instruction referencing *n
// to force segv on nil pointer dereference.
void
-checkref(Node *n)
+checkref(Node *n, int force)
{
Node m;
- if(n->type->type->width < unmappedzero)
+ if(!force && isptr[n->type->etype] && n->type->type->width < unmappedzero)
return;
regalloc(&m, types[TUINTPTR], n);
@@ -2201,8 +2202,6 @@ checkoffset(Addr *a, int canemitcode)
void
naddr(Node *n, Addr *a, int canemitcode)
{
- Prog *p;
-
a->scale = 0;
a->index = D_NONE;
a->type = D_NONE;
@@ -2239,13 +2238,8 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case OCLOSUREVAR:
- if(!canemitcode)
- fatal("naddr OCLOSUREVAR cannot emit code");
- p = gins(AMOVL, N, N);
- p->from.type = D_DX+D_INDIR;
- p->from.offset = n->xoffset;
- p->to.type = D_BX;
- a->type = D_BX;
+ a->type = D_DX+D_INDIR;
+ a->offset = n->xoffset;
a->sym = S;
break;
@@ -2397,7 +2391,8 @@ naddr(Node *n, Addr *a, int canemitcode)
int
dotaddable(Node *n, Node *n1)
{
- int o, oary[10];
+ int o;
+ int64 oary[10];
Node *nn;
if(n->op != ODOT)
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
index 386889956..cf0bc9fee 100644
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -153,6 +153,7 @@ enum as
AMOVB,
AMOVL,
AMOVW,
+ AMOVQ,
AMOVBLSX,
AMOVBLZX,
AMOVBWSX,
@@ -397,6 +398,7 @@ enum as
ACMPXCHGW,
ACMPXCHG8B,
+ ACPUID,
ARDTSC,
AXADDB,
@@ -531,10 +533,13 @@ enum as
AORPD,
AORPS,
APADDQ,
+ APAND,
+ APCMPEQB,
APMAXSW,
APMAXUB,
APMINSW,
APMINUB,
+ APMOVMSKB,
APSADBW,
APSUBB,
APSUBL,
@@ -566,7 +571,12 @@ enum as
AUNPCKLPS,
AXORPD,
AXORPS,
-
+
+ /* SSE 3+ */
+ AAESENC,
+ APINSRD,
+ APSHUFB,
+
AUSEFIELD,
ALOCALS,
ATYPE,
@@ -646,6 +656,7 @@ enum
D_PCREL,
D_GOTOFF,
D_GOTREL,
+ D_TLS,
T_TYPE = 1<<0,
T_INDEX = 1<<1,
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index a00174c36..18591cd2f 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -128,7 +128,7 @@ adddynrel(Sym *s, Reloc *r)
// Handle relocations found in ELF object files.
case 256 + R_386_PC32:
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->type == SDYNIMPORT)
diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
if(targ->type == 0 || targ->type == SXREF)
diag("unknown symbol %s in pcrel", targ->name);
@@ -139,7 +139,7 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_386_PLT32:
r->type = D_PCREL;
r->add += 4;
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->type == SDYNIMPORT) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add += targ->plt;
@@ -147,7 +147,7 @@ adddynrel(Sym *s, Reloc *r)
return;
case 256 + R_386_GOT32:
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->type != SDYNIMPORT) {
// have symbol
// turn MOVL of GOT entry into LEAL of symbol itself
if(r->off < 2 || s->p[r->off-2] != 0x8b) {
@@ -175,19 +175,19 @@ adddynrel(Sym *s, Reloc *r)
return;
case 256 + R_386_32:
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->type == SDYNIMPORT)
diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
r->type = D_ADDR;
return;
case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
r->type = D_ADDR;
- if(targ->dynimpname != nil && !targ->dynexport)
+ if(targ->type == SDYNIMPORT)
diag("unexpected reloc for dynamic symbol %s", targ->name);
return;
case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
- if(targ->dynimpname != nil && !targ->dynexport) {
+ if(targ->type == SDYNIMPORT) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->add = targ->plt;
@@ -198,7 +198,7 @@ adddynrel(Sym *s, Reloc *r)
return;
case 512 + MACHO_FAKE_GOTPCREL:
- if(targ->dynimpname == nil || targ->dynexport) {
+ if(targ->type != SDYNIMPORT) {
// have symbol
// turn MOVL of GOT entry into LEAL of symbol itself
if(r->off < 2 || s->p[r->off-2] != 0x8b) {
@@ -217,7 +217,7 @@ adddynrel(Sym *s, Reloc *r)
}
// Handle references to ELF symbols from our own object files.
- if(targ->dynimpname == nil || targ->dynexport)
+ if(targ->type != SDYNIMPORT)
return;
switch(r->type) {
@@ -270,12 +270,13 @@ adddynrel(Sym *s, Reloc *r)
}
int
-elfreloc1(Reloc *r, vlong off, int32 elfsym, vlong add)
+elfreloc1(Reloc *r, vlong sectoff)
{
- USED(add); // written to obj file by ../ld/data.c's reloc
+ int32 elfsym;
- LPUT(off);
+ LPUT(sectoff);
+ elfsym = r->xsym->elfsym;
switch(r->type) {
default:
return -1;
@@ -293,11 +294,89 @@ elfreloc1(Reloc *r, vlong off, int32 elfsym, vlong add)
else
return -1;
break;
+
+ case D_TLS:
+ if(r->siz == 4)
+ LPUT(R_386_TLS_LE | elfsym<<8);
+ else
+ return -1;
}
return 0;
}
+int
+machoreloc1(Reloc *r, vlong sectoff)
+{
+ uint32 v;
+ Sym *rs;
+
+ rs = r->xsym;
+
+ if(rs->type == SHOSTOBJ) {
+ if(rs->dynid < 0) {
+ diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
+ return -1;
+ }
+ v = rs->dynid;
+ v |= 1<<27; // external relocation
+ } else {
+ v = rs->sect->extnum;
+ if(v == 0) {
+ diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type);
+ return -1;
+ }
+ }
+
+ switch(r->type) {
+ default:
+ return -1;
+ case D_ADDR:
+ v |= MACHO_GENERIC_RELOC_VANILLA<<28;
+ break;
+ case D_PCREL:
+ v |= 1<<24; // pc-relative bit
+ v |= MACHO_GENERIC_RELOC_VANILLA<<28;
+ break;
+ }
+
+ switch(r->siz) {
+ default:
+ return -1;
+ case 1:
+ v |= 0<<25;
+ break;
+ case 2:
+ v |= 1<<25;
+ break;
+ case 4:
+ v |= 2<<25;
+ break;
+ case 8:
+ v |= 3<<25;
+ break;
+ }
+
+ LPUT(sectoff);
+ LPUT(v);
+ return 0;
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+ USED(s);
+ switch(r->type) {
+ case D_CONST:
+ *val = r->add;
+ return 0;
+ case D_GOTOFF:
+ *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
+ return 0;
+ }
+ return -1;
+}
+
void
elfsetupplt(void)
{
@@ -326,21 +405,6 @@ elfsetupplt(void)
}
}
-int
-archreloc(Reloc *r, Sym *s, vlong *val)
-{
- USED(s);
- switch(r->type) {
- case D_CONST:
- *val = r->add;
- return 0;
- case D_GOTOFF:
- *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
- return 0;
- }
- return -1;
-}
-
static void
addpltsym(Sym *s)
{
@@ -428,26 +492,20 @@ addgotsym(Sym *s)
void
adddynsym(Sym *s)
{
- Sym *d, *str;
+ Sym *d;
int t;
char *name;
- vlong off;
if(s->dynid >= 0)
return;
- if(s->dynimpname == nil)
- diag("adddynsym: no dynamic name for %s", s->name);
-
if(iself) {
s->dynid = nelfsym++;
d = lookup(".dynsym", 0);
/* name */
- name = s->dynimpname;
- if(name == nil)
- name = s->name;
+ name = s->extname;
adduint32(d, addstring(lookup(".dynstr", 0), name));
/* value */
@@ -461,7 +519,7 @@ adddynsym(Sym *s)
/* type */
t = STB_GLOBAL << 4;
- if(s->dynexport && (s->type&SMASK) == STEXT)
+ if(s->cgoexport && (s->type&SMASK) == STEXT)
t |= STT_FUNC;
else
t |= STT_OBJECT;
@@ -469,7 +527,7 @@ adddynsym(Sym *s)
adduint8(d, 0);
/* shndx */
- if(!s->dynexport && s->dynimpname != nil)
+ if(s->type == SDYNIMPORT)
adduint16(d, SHN_UNDEF);
else {
switch(s->type) {
@@ -490,57 +548,10 @@ adddynsym(Sym *s)
adduint16(d, t);
}
} else if(HEADTYPE == Hdarwin) {
- // Mach-O symbol nlist32
- d = lookup(".dynsym", 0);
- name = s->dynimpname;
- if(name == nil)
- name = s->name;
- if(d->size == 0 && ndynexp > 0) { // pre-allocate for dynexps
- symgrow(d, ndynexp*12);
- }
- if(s->dynid <= -100) { // pre-allocated, see cmd/ld/go.c:^sortdynexp()
- s->dynid = -s->dynid-100;
- off = s->dynid*12;
- } else {
- off = d->size;
- s->dynid = off/12;
- }
- // darwin still puts _ prefixes on all C symbols
- str = lookup(".dynstr", 0);
- setuint32(d, off, str->size);
- off += 4;
- adduint8(str, '_');
- addstring(str, name);
- if(s->type == SDYNIMPORT) {
- setuint8(d, off, 0x01); // type - N_EXT - external symbol
- off++;
- setuint8(d, off, 0); // section
- off++;
- } else {
- setuint8(d, off, 0x0f);
- off++;
- switch(s->type) {
- default:
- case STEXT:
- setuint8(d, off, 1);
- break;
- case SDATA:
- setuint8(d, off, 2);
- break;
- case SBSS:
- setuint8(d, off, 4);
- break;
- }
- off++;
- }
- setuint16(d, off, 0); // desc
- off += 2;
- if(s->type == SDYNIMPORT)
- setuint32(d, off, 0); // value
- else
- setaddr(d, off, s);
- off += 4;
- } else if(HEADTYPE != Hwindows) {
+ diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
+ } else if(HEADTYPE == Hwindows) {
+ // already taken care of
+ } else {
diag("adddynsym: unsupported binary format");
}
}
@@ -666,7 +677,7 @@ asmb(void)
Bprint(&bso, "%5.2f dwarf\n", cputime());
dwarfemitdebugsections();
- if(isobj)
+ if(linkmode == LinkExternal)
elfemitreloc();
}
break;
@@ -688,6 +699,10 @@ asmb(void)
Bprint(&bso, "%5.2f dwarf\n", cputime());
dwarfemitdebugsections();
break;
+ case Hdarwin:
+ if(linkmode == LinkExternal)
+ machoemitreloc();
+ break;
}
}
if(debug['v'])
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index f88f058e3..ce12d59ba 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -42,6 +42,7 @@ enum
thechar = '8',
PtrSize = 4,
IntSize = 4,
+ MaxAlign = 32, // max data alignment
FuncAlign = 16
};
@@ -83,9 +84,12 @@ struct Reloc
{
int32 off;
uchar siz;
+ uchar done;
int32 type;
int32 add;
+ int32 xadd;
Sym* sym;
+ Sym* xsym;
};
struct Prog
@@ -122,11 +126,12 @@ struct Auto
struct Sym
{
char* name;
+ char* extname; // name used in external object files
short type;
short version;
uchar dupok;
uchar reachable;
- uchar dynexport;
+ uchar cgoexport;
uchar special;
uchar stkcheck;
uchar hide;
@@ -149,7 +154,6 @@ struct Sym
Sym* reachparent;
Sym* queue;
char* file;
- char* dynimpname;
char* dynimplib;
char* dynimpvers;
struct Section* sect;
@@ -172,7 +176,7 @@ struct Optab
short as;
uchar* ytab;
uchar prefix;
- uchar op[10];
+ uchar op[12];
};
enum
@@ -217,6 +221,7 @@ enum
Zxxx = 0,
Zlit,
+ Zlitm_r,
Z_rp,
Zbr,
Zcall,
@@ -233,6 +238,7 @@ enum
Zloop,
Zm_o,
Zm_r,
+ Zm2_r,
Zm_r_xm,
Zm_r_i_xm,
Zaut_r,
@@ -249,6 +255,7 @@ enum
Zib_rr,
Zil_rr,
Zclr,
+ Zibm_r, /* mmx1,mmx2/mem64,imm8 */
Zbyte,
Zmov,
Zmax,
@@ -279,14 +286,12 @@ EXTERN int32 INITTEXT;
EXTERN int32 INITDAT;
EXTERN char* INITENTRY; /* entry point */
EXTERN char* LIBINITENTRY; /* shared library entry point */
-EXTERN int32 casepc;
EXTERN char* pcstr;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
EXTERN Sym* cursym;
EXTERN Sym* datap;
-EXTERN int32 elfdatsize;
EXTERN int debug[128];
EXTERN char literal[32];
EXTERN Sym* etextp;
@@ -312,7 +317,6 @@ EXTERN int dtype;
EXTERN int tlsoffset;
EXTERN Sym* adrgotype; // type symbol on last Adr read
EXTERN Sym* fromgotype; // type symbol on last p->from read
-EXTERN int elftextsh;
extern Optab optab[];
extern char* anames[];
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index dcb8390b9..c819b9936 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -90,6 +90,7 @@ main(int argc, char *argv[])
INITRND = -1;
INITENTRY = 0;
LIBINITENTRY = 0;
+ linkmode = LinkAuto;
nuxiinit();
flagcount("1", "use alternate profiling code", &debug['1']);
@@ -112,9 +113,11 @@ main(int argc, char *argv[])
flagcount("a", "disassemble output", &debug['a']);
flagcount("c", "dump call graph", &debug['c']);
flagcount("d", "disable dynamic executable", &debug['d']);
+ flagstr("extld", "linker to run in external mode", &extld);
+ flagstr("extldflags", "flags for external linker", &extldflags);
flagcount("f", "ignore version mismatch", &debug['f']);
flagcount("g", "disable go package data checks", &debug['g']);
- flagcount("hostobj", "generate host object file", &isobj);
+ flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
flagstr("k", "sym: set field tracking symbol", &tracksym);
flagstr("o", "outfile: set output file", &outfile);
flagcount("p", "insert profiling code", &debug['p']);
@@ -122,9 +125,11 @@ main(int argc, char *argv[])
flagcount("race", "enable race detector", &flag_race);
flagcount("s", "disable symbol table", &debug['s']);
flagcount("n", "dump symbol table", &debug['n']);
+ flagstr("tmpdir", "leave temporary files in this directory", &tmpdir);
flagcount("u", "reject unsafe packages", &debug['u']);
flagcount("v", "print link trace", &debug['v']);
flagcount("w", "disable DWARF generation", &debug['w']);
+ // TODO: link mode flag
flagparse(&argc, &argv, usage);
@@ -136,13 +141,24 @@ main(int argc, char *argv[])
if(HEADTYPE == -1)
HEADTYPE = headtype(goos);
- if(isobj) {
- switch(HEADTYPE) {
- default:
- sysfatal("cannot use -hostobj with -H %s", headstr(HEADTYPE));
- case Hlinux:
- break;
- }
+ // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
+ // Go was built; see ../../make.bash.
+ if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
+ linkmode = LinkInternal;
+
+ switch(HEADTYPE) {
+ default:
+ if(linkmode == LinkAuto)
+ linkmode = LinkInternal;
+ if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0)
+ sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE));
+ break;
+ case Hdarwin:
+ case Hfreebsd:
+ case Hlinux:
+ case Hnetbsd:
+ case Hopenbsd:
+ break;
}
if(outfile == nil) {
@@ -308,6 +324,8 @@ main(int argc, char *argv[])
reloc();
asmb();
undef();
+ hostlink();
+
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%d symbols\n", nsymbol);
@@ -431,7 +449,7 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
ntext = 0;
eof = Boffset(f) + len;
src[0] = 0;
-
+ pn = estrdup(pn); // we keep it in Sym* references
newloop:
memset(h, 0, sizeof(h));
@@ -596,11 +614,15 @@ loop:
goto loop;
case ALOCALS:
+ if(skip)
+ goto casdef;
cursym->locals = p->to.offset;
pc++;
goto loop;
case ATYPE:
+ if(skip)
+ goto casdef;
pc++;
goto loop;
diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c
index 79d7b39f0..1d9d2f55f 100644
--- a/src/cmd/8l/optab.c
+++ b/src/cmd/8l/optab.c
@@ -150,9 +150,16 @@ uchar ymovl[] =
// Yi0, Yml, Zibo_m, 2, // shorter but slower AND $0,dst
Yi32, Yrl, Zil_rp, 1,
Yi32, Yml, Zilo_m, 2,
+ Yml, Yxr, Zm_r_xm, 2, // XMM MOVD (32 bit)
+ Yxr, Yml, Zr_m_xm, 2, // XMM MOVD (32 bit)
Yiauto, Yrl, Zaut_r, 2,
0
};
+uchar ymovq[] =
+{
+ Yml, Yxr, Zm_r_xm, 2,
+ 0
+};
uchar ym_rl[] =
{
Ym, Yrl, Zm_r, 1,
@@ -357,6 +364,12 @@ uchar ysvrs[] =
Ym, Ynone, Zm_o, 2,
0
};
+uchar ymskb[] =
+{
+ Yxr, Yrl, Zm_r_xm, 2,
+ Ymr, Yrl, Zm_r_xm, 1,
+ 0
+};
uchar yxm[] =
{
Yxm, Yxr, Zm_r_xm, 1,
@@ -435,6 +448,21 @@ uchar yprefetch[] =
Ym, Ynone, Zm_o, 2,
0,
};
+uchar yaes[] =
+{
+ Yxm, Yxr, Zlitm_r, 2,
+ 0
+};
+uchar yinsrd[] =
+{
+ Yml, Yxr, Zibm_r, 2,
+ 0
+};
+uchar ymshufb[] =
+{
+ Yxm, Yxr, Zm2_r, 2,
+ 0
+};
Optab optab[] =
/* as, ytab, andproto, opcode */
@@ -552,8 +580,9 @@ Optab optab[] =
{ ALSLL, yml_rl, Pm, 0x03 },
{ ALSLW, yml_rl, Pq, 0x03 },
{ AMOVB, ymovb, Pb, 0x88,0x8a,0xb0,0xc6,(00) },
- { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
+ { AMOVL, ymovl, Px, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),Pe,0x6e,Pe,0x7e },
{ AMOVW, ymovl, Pe, 0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00) },
+ { AMOVQ, ymovq, Pf3, 0x7e },
{ AMOVBLSX, ymb_rl, Pm, 0xbe },
{ AMOVBLZX, ymb_rl, Pm, 0xb6 },
{ AMOVBWSX, ymb_rl, Pq, 0xbe },
@@ -793,6 +822,7 @@ Optab optab[] =
{ ACMPXCHGW, yrl_ml, Pm, 0xb1 },
{ ACMPXCHG8B, yscond, Pm, 0xc7,(01) },
+ { ACPUID, ynone, Pm, 0xa2 },
{ ARDTSC, ynone, Pm, 0x31 },
{ AXADDB, yrb_mb, Pb, 0x0f,0xc0 },
@@ -925,10 +955,13 @@ Optab optab[] =
{ AORPD, yxm, Pq, 0x56 },
{ AORPS, yxm, Pm, 0x56 },
{ APADDQ, yxm, Pe, 0xd4 },
+ { APAND, yxm, Pe, 0xdb },
+ { APCMPEQB, yxmq, Pe ,0x74 },
{ APMAXSW, yxm, Pe, 0xee },
{ APMAXUB, yxm, Pe, 0xde },
{ APMINSW, yxm, Pe, 0xea },
{ APMINUB, yxm, Pe, 0xda },
+ { APMOVMSKB, ymskb, Px, Pe,0xd7,0xd7 },
{ APSADBW, yxm, Pq, 0xf6 },
{ APSUBB, yxm, Pe, 0xf8 },
{ APSUBL, yxm, Pe, 0xfa },
@@ -961,6 +994,10 @@ Optab optab[] =
{ AXORPD, yxm, Pe, 0x57 },
{ AXORPS, yxm, Pm, 0x57 },
+ { AAESENC, yaes, Pq, 0x38,0xdc,(0) },
+ { APINSRD, yinsrd, Pq, 0x3a, 0x22, (00) },
+ { APSHUFB, ymshufb,Pq, 0x38, 0x00 },
+
{ AUSEFIELD, ynop, Px, 0,0 },
{ ALOCALS },
{ ATYPE },
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
index 14dd3e0dc..4871761ff 100644
--- a/src/cmd/8l/pass.c
+++ b/src/cmd/8l/pass.c
@@ -296,16 +296,23 @@ patch(void)
// MOVL 0(GS), reg
// and then off(reg) instead of saying off(GS) directly
// when the offset is negative.
+ // In external mode we just produce a reloc.
if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
&& p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->from = p->from;
- q->from.type = D_INDIR + p->to.type;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0;
+ if(linkmode != LinkExternal) {
+ q = appendp(p);
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->to = p->to;
+ q->as = p->as;
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0;
+ } else {
+ // Add signals to relocate.
+ p->from.index = D_GS;
+ p->from.scale = 1;
+ }
}
}
if(HEADTYPE == Hplan9x32) {
@@ -450,16 +457,25 @@ dostkoff(void)
break;
case Hlinux:
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = 0;
- p->to.type = D_CX;
+ if(linkmode != LinkExternal) {
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0;
+ p->to.type = D_CX;
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
+ p = appendp(p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = tlsoffset + 0;
+ p->to.type = D_CX;
+ } else {
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = tlsoffset + 0;
+ p->to.type = D_CX;
+ p->from.index = D_GS;
+ p->from.scale = 1;
+ }
break;
case Hplan9x32:
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c
index b828d8645..980186b16 100644
--- a/src/cmd/8l/span.c
+++ b/src/cmd/8l/span.c
@@ -32,6 +32,7 @@
#include "l.h"
#include "../ld/lib.h"
+#include "../ld/elf.h"
static int32 vaddr(Adr*, Reloc*);
@@ -559,6 +560,14 @@ vaddr(Adr *a, Reloc *r)
return v;
}
+static int
+istls(Adr *a)
+{
+ if(HEADTYPE == Hlinux)
+ return a->index == D_GS;
+ return a->type == D_INDIR+D_GS;
+}
+
void
asmand(Adr *a, int r)
{
@@ -569,7 +578,7 @@ asmand(Adr *a, int r)
v = a->offset;
t = a->type;
rel.siz = 0;
- if(a->index != D_NONE) {
+ if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) {
if(t < D_INDIR || t >= 2*D_INDIR) {
switch(t) {
default:
@@ -658,7 +667,7 @@ asmand(Adr *a, int r)
*andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
- if(v >= -128 && v < 128 && rel.siz == 0) {
+ if(v >= -128 && v < 128 && rel.siz == 0 && a->index != D_FS && a->index != D_GS) {
andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
andptr[1] = v;
andptr += 2;
@@ -680,7 +689,29 @@ putrelv:
r = addrel(cursym);
*r = rel;
r->off = curp->pc + andptr - and;
+ } else if(iself && linkmode == LinkExternal && istls(a) && HEADTYPE != Hopenbsd) {
+ Reloc *r;
+ Sym *s;
+
+ r = addrel(cursym);
+ r->off = curp->pc + andptr - and;
+ r->add = 0;
+ r->xadd = 0;
+ r->siz = 4;
+ r->type = D_TLS;
+ if(a->offset == tlsoffset+0)
+ s = lookup("runtime.g", 0);
+ else
+ s = lookup("runtime.m", 0);
+ s->type = STLSBSS;
+ s->reachable = 1;
+ s->hide = 1;
+ s->size = PtrSize;
+ r->sym = s;
+ r->xsym = s;
+ v = 0;
}
+
put4(v);
return;
@@ -1003,11 +1034,23 @@ found:
*andptr++ = op;
break;
+ case Zlitm_r:
+ for(; op = o->op[z]; z++)
+ *andptr++ = op;
+ asmand(&p->from, reg[p->to.type]);
+ break;
+
case Zm_r:
*andptr++ = op;
asmand(&p->from, reg[p->to.type]);
break;
+ case Zm2_r:
+ *andptr++ = op;
+ *andptr++ = o->op[z+1];
+ asmand(&p->from, reg[p->to.type]);
+ break;
+
case Zm_r_xm:
mediaop(o, op, t[3], z);
asmand(&p->from, reg[p->to.type]);
@@ -1019,6 +1062,13 @@ found:
*andptr++ = p->to.offset;
break;
+ case Zibm_r:
+ while ((op = o->op[z++]) != 0)
+ *andptr++ = op;
+ asmand(&p->from, reg[p->to.type]);
+ *andptr++ = p->to.offset;
+ break;
+
case Zaut_r:
*andptr++ = 0x8d; /* leal */
if(p->from.type != D_ADDR)
diff --git a/src/cmd/addr2line/main.c b/src/cmd/addr2line/main.c
index 6b2fe5dfe..9faadc27b 100644
--- a/src/cmd/addr2line/main.c
+++ b/src/cmd/addr2line/main.c
@@ -12,12 +12,18 @@
#include <mach.h>
void
+printusage(int fd)
+{
+ fprint(fd, "usage: addr2line binary\n");
+ fprint(fd, "reads addresses from standard input and writes two lines for each:\n");
+ fprint(fd, "\tfunction name\n");
+ fprint(fd, "\tfile:line\n");
+}
+
+void
usage(void)
{
- fprint(2, "usage: addr2line binary\n");
- fprint(2, "reads addresses from standard input and writes two lines for each:\n");
- fprint(2, "\tfunction name\n");
- fprint(2, "\tfile:line\n");
+ printusage(2);
exits("usage");
}
@@ -32,6 +38,11 @@ main(int argc, char **argv)
Biobuf bin, bout;
char file[1024];
+ if(argc > 1 && strcmp(argv[1], "--help") == 0) {
+ printusage(1);
+ exits(0);
+ }
+
ARGBEGIN{
default:
usage();
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 0d76b0cdb..ff75f00e3 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -38,9 +38,7 @@ import (
// Flags
var (
- // TODO(bradfitz): once Go 1.1 comes out, allow the -c flag to take a comma-separated
- // list of files, rather than just one.
- checkFile = flag.String("c", "", "optional filename to check API against")
+ checkFile = flag.String("c", "", "optional comma-separated filename(s) to check API against")
allowNew = flag.Bool("allow_new", true, "allow API additions")
exceptFile = flag.String("except", "", "optional filename of packages that are allowed to change without triggering a failure in the tool")
nextFile = flag.String("next", "", "optional filename of tentative upcoming API features for the next release. This file can be lazily maintained. It only affects the delta warnings from the -c file printed on success.")
@@ -138,9 +136,7 @@ func main() {
}
for _, pkg := range pkgs {
- if strings.HasPrefix(pkg, "cmd/") ||
- strings.HasPrefix(pkg, "exp/") ||
- strings.HasPrefix(pkg, "old/") {
+ if strings.HasPrefix(pkg, "cmd/") {
continue
}
if fi, err := os.Stat(filepath.Join(w.root, pkg)); err != nil || !fi.IsDir() {
@@ -188,7 +184,10 @@ func main() {
return
}
- required := fileFeatures(*checkFile)
+ var required []string
+ for _, file := range strings.Split(*checkFile, ",") {
+ required = append(required, fileFeatures(file)...)
+ }
optional := fileFeatures(*nextFile)
exception := fileFeatures(*exceptFile)
fail = !compareAPI(bw, features, required, optional, exception)
@@ -725,7 +724,6 @@ func (w *Walker) varValueType(vi interface{}) (string, error) {
default:
return "", fmt.Errorf("unknown const value type %T", vi)
}
- panic("unreachable")
}
// resolveName finds a top-level node named name and returns the node
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
index 866aeb0ab..c8de94120 100644
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -800,6 +800,7 @@ int machcap(Node*);
#pragma varargck type "Q" int32
#pragma varargck type "O" int
#pragma varargck type "O" uint
+#pragma varargck type "S" ushort*
#pragma varargck type "T" Type*
#pragma varargck type "U" char*
#pragma varargck type "|" int
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
index 2f038f520..34163ff92 100644
--- a/src/cmd/cc/dpchk.c
+++ b/src/cmd/cc/dpchk.c
@@ -692,22 +692,24 @@ pragcgo(char *verb)
goto out;
}
- if(strcmp(verb, "cgo_export") == 0 || strcmp(verb, "dynexport") == 0) {
+ if(strcmp(verb, "dynexport") == 0)
+ verb = "cgo_export_dynamic";
+ if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) {
local = getimpsym();
if(local == nil)
goto err2;
if(!more()) {
- fmtprint(&pragcgobuf, "cgo_export %q\n", local->name);
+ fmtprint(&pragcgobuf, "%s %q\n", verb, local->name);
goto out;
}
remote = getimpsym();
if(remote == nil)
goto err2;
- fmtprint(&pragcgobuf, "cgo_export %q %q\n", local->name, remote->name);
+ fmtprint(&pragcgobuf, "%s %q %q\n", verb, local->name, remote->name);
goto out;
err2:
- yyerror("usage: #pragma cgo_export local [remote]");
+ yyerror("usage: #pragma %s local [remote]", verb);
goto out;
}
@@ -749,6 +751,18 @@ pragcgo(char *verb)
goto out;
}
+ if(strcmp(verb, "cgo_ldflag") == 0) {
+ p = getquoted();
+ if(p == nil)
+ goto err5;
+ fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p);
+ goto out;
+
+ err5:
+ yyerror("usage: #pragma cgo_ldflag \"arg\"");
+ goto out;
+ }
+
out:
while(getnsc() != '\n')
;
diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c
index 057151987..7921277b4 100644
--- a/src/cmd/cc/funct.c
+++ b/src/cmd/cc/funct.c
@@ -269,7 +269,7 @@ dclfunct(Type *t, Sym *s)
goto bad;
f = alloc(sizeof(*f));
- for(o=0; o<sizeof(f->sym); o++)
+ for(o=0; o<nelem(f->sym); o++)
f->sym[o] = S;
t->funct = f;
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
index 5fa980267..f4a69739c 100644
--- a/src/cmd/cc/lexbody
+++ b/src/cmd/cc/lexbody
@@ -263,7 +263,7 @@ lookup(void)
for(s = hash[h]; s != S; s = s->link) {
if(s->name[0] != c)
continue;
- if(memcmp(s->name, symb, l) == 0)
+ if(strcmp(s->name, symb) == 0)
return s;
}
s = alloc(sizeof(*s));
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 955b7c495..a1b02d4be 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -70,7 +70,7 @@ assignment context to retrieve both the return value (if any) and the
C errno variable as an error (use _ to skip the result value if the
function returns void). For example:
- n, err := C.atoi("abc")
+ n, err := C.sqrt(-1)
_, err := C.voidFunc()
In C, a function argument written as a fixed size array
@@ -463,7 +463,7 @@ The directives are:
#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5
#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
- A side effect of the cgo_dynamic_import directive with a
+ A side effect of the cgo_import_dynamic directive with a
library is to make the final binary depend on that dynamic
library. To get the dependency without importing any specific
symbols, use _ for local and remote.
@@ -472,7 +472,7 @@ The directives are:
#pragma cgo_import_dynamic _ _ "libc.so.6"
For compatibility with current versions of SWIG,
- #pragma dynimport is an alias for #pragma cgo_dynamic_import.
+ #pragma dynimport is an alias for #pragma cgo_import_dynamic.
#pragma cgo_dynamic_linker "<path>"
@@ -484,16 +484,16 @@ The directives are:
Example:
#pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
-#pragma cgo_export <local> <remote>
+#pragma cgo_export_dynamic <local> <remote>
- In both internal and external linking modes, put the Go symbol
+ In internal linking mode, put the Go symbol
named <local> into the program's exported symbol table as
<remote>, so that C code can refer to it by that name. This
mechanism makes it possible for C code to call back into Go or
to share Go's data.
For compatibility with current versions of SWIG,
- #pragma dynexport is an alias for #pragma cgo_export.
+ #pragma dynexport is an alias for #pragma cgo_export_dynamic.
#pragma cgo_import_static <local>
@@ -505,6 +505,14 @@ The directives are:
Example:
#pragma cgo_import_static puts_wrapper
+#pragma cgo_export_static <local> <remote>
+
+ In external linking mode, put the Go symbol
+ named <local> into the program's exported symbol table as
+ <remote>, so that C code can refer to it by that name. This
+ mechanism makes it possible for C code to call back into Go or
+ to share Go's data.
+
#pragma cgo_ldflag "<arg>"
In external linking mode, invoke the host linker (usually gcc)
@@ -565,7 +573,7 @@ The directives in the 6c-compiled file are used according to the kind
of final link used.
In internal mode, 6l itself processes all the host object files, in
-particular foo.cgo2.o. To do so, it uses the cgo_dynamic_import and
+particular foo.cgo2.o. To do so, it uses the cgo_import_dynamic and
cgo_dynamic_linker directives to learn that the otherwise undefined
reference to sin in foo.cgo2.o should be rewritten to refer to the
symbol sin with version GLIBC_2.2.5 from the dynamic library
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 4b0a521a8..bc7a6472f 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -66,71 +66,16 @@ func cname(s string) string {
return s
}
-// ParseFlags extracts #cgo CFLAGS and LDFLAGS options from the file
-// preamble. Multiple occurrences are concatenated with a separating space,
-// even across files.
-func (p *Package) ParseFlags(f *File, srcfile string) {
+// DiscardCgoDirectives processes the import C preamble, and discards
+// all #cgo CFLAGS and LDFLAGS directives, so they don't make their
+// way into _cgo_export.h.
+func (f *File) DiscardCgoDirectives() {
linesIn := strings.Split(f.Preamble, "\n")
linesOut := make([]string, 0, len(linesIn))
-
-NextLine:
for _, line := range linesIn {
l := strings.TrimSpace(line)
if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) {
linesOut = append(linesOut, line)
- continue
- }
-
- l = strings.TrimSpace(l[4:])
- fields := strings.SplitN(l, ":", 2)
- if len(fields) != 2 {
- fatalf("%s: bad #cgo line: %s", srcfile, line)
- }
-
- var k string
- kf := strings.Fields(fields[0])
- switch len(kf) {
- case 1:
- k = kf[0]
- case 2:
- k = kf[1]
- switch kf[0] {
- case goos:
- case goarch:
- case goos + "/" + goarch:
- default:
- continue NextLine
- }
- default:
- fatalf("%s: bad #cgo option: %s", srcfile, fields[0])
- }
-
- args, err := splitQuoted(fields[1])
- if err != nil {
- fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
- }
- for _, arg := range args {
- if !safeName(arg) {
- fatalf("%s: #cgo option %s is unsafe: %s", srcfile, k, arg)
- }
- }
-
- switch k {
-
- case "CFLAGS", "LDFLAGS":
- p.addToFlag(k, args)
-
- case "pkg-config":
- cflags, ldflags, err := pkgConfig(args)
- if err != nil {
- fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
- }
- p.addToFlag("CFLAGS", cflags)
- p.addToFlag("LDFLAGS", ldflags)
-
- default:
- fatalf("%s: unsupported #cgo option %s", srcfile, k)
-
}
}
f.Preamble = strings.Join(linesOut, "\n")
@@ -139,47 +84,13 @@ NextLine:
// addToFlag appends args to flag. All flags are later written out onto the
// _cgo_flags file for the build system to use.
func (p *Package) addToFlag(flag string, args []string) {
- if oldv, ok := p.CgoFlags[flag]; ok {
- p.CgoFlags[flag] = oldv + " " + strings.Join(args, " ")
- } else {
- p.CgoFlags[flag] = strings.Join(args, " ")
- }
+ p.CgoFlags[flag] = append(p.CgoFlags[flag], args...)
if flag == "CFLAGS" {
// We'll also need these when preprocessing for dwarf information.
p.GccOptions = append(p.GccOptions, args...)
}
}
-// pkgConfig runs pkg-config and extracts --libs and --cflags information
-// for packages.
-func pkgConfig(packages []string) (cflags, ldflags []string, err error) {
- for _, name := range packages {
- if len(name) == 0 || name[0] == '-' {
- return nil, nil, errors.New(fmt.Sprintf("invalid name: %q", name))
- }
- }
-
- args := append([]string{"pkg-config", "--cflags"}, packages...)
- stdout, stderr, ok := run(nil, args)
- if !ok {
- os.Stderr.Write(stderr)
- return nil, nil, errors.New("pkg-config failed")
- }
- cflags, err = splitQuoted(string(stdout))
- if err != nil {
- return
- }
-
- args = append([]string{"pkg-config", "--libs"}, packages...)
- stdout, stderr, ok = run(nil, args)
- if !ok {
- os.Stderr.Write(stderr)
- return nil, nil, errors.New("pkg-config failed")
- }
- ldflags, err = splitQuoted(string(stdout))
- return
-}
-
// splitQuoted splits the string s around each instance of one or more consecutive
// white space characters while taking into account quotes and escaping, and
// returns an array of substrings of s or an empty list if s contains only white space.
@@ -898,6 +809,15 @@ func (p *Package) gccDefines(stdin []byte) string {
func (p *Package) gccErrors(stdin []byte) string {
// TODO(rsc): require failure
args := p.gccCmd()
+
+ // GCC 4.8.0 has a bug: it sometimes does not apply
+ // -Wunused-value to values that are macros defined in system
+ // headers. See issue 5118. Adding -Wsystem-headers avoids
+ // that problem. This will produce additional errors, but it
+ // doesn't matter because we will ignore all errors that are
+ // not marked for the cgo-test file.
+ args = append(args, "-Wsystem-headers")
+
if *debugGcc {
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
os.Stderr.Write(stdin)
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 7adc795de..9bd326e1d 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -33,7 +33,7 @@ type Package struct {
PtrSize int64
IntSize int64
GccOptions []string
- CgoFlags map[string]string // #cgo flags (CFLAGS, LDFLAGS)
+ CgoFlags map[string][]string // #cgo flags (CFLAGS, LDFLAGS)
Written map[string]bool
Name map[string]*Name // accumulated Name from Files
ExpFunc []*ExpFunc // accumulated ExpFunc from Files
@@ -208,6 +208,15 @@ func main() {
p := newPackage(args[:i])
+ // Record CGO_LDFLAGS from the environment for external linking.
+ if ldflags := os.Getenv("CGO_LDFLAGS"); ldflags != "" {
+ args, err := splitQuoted(ldflags)
+ if err != nil {
+ fatalf("bad CGO_LDFLAGS: %q (%s)", ldflags, err)
+ }
+ p.addToFlag("LDFLAGS", args)
+ }
+
// Need a unique prefix for the global C symbols that
// we use to coordinate between gcc and ourselves.
// We already put _cgo_ at the beginning, so the main
@@ -226,10 +235,9 @@ func main() {
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
- // Parse flags for all files before translating due to CFLAGS.
f := new(File)
f.ReadGo(input)
- p.ParseFlags(f, input)
+ f.DiscardCgoDirectives()
fs[i] = f
}
@@ -282,11 +290,6 @@ func main() {
// newPackage returns a new Package that will invoke
// gcc with the additional arguments specified in args.
func newPackage(args []string) *Package {
- // Copy the gcc options to a new slice so the list
- // can grow without overwriting the slice that args is in.
- gccOptions := make([]string, len(args))
- copy(gccOptions, args)
-
goarch = runtime.GOARCH
if s := os.Getenv("GOARCH"); s != "" {
goarch = s
@@ -309,12 +312,12 @@ func newPackage(args []string) *Package {
os.Setenv("LC_ALL", "C")
p := &Package{
- PtrSize: ptrSize,
- IntSize: intSize,
- GccOptions: gccOptions,
- CgoFlags: make(map[string]string),
- Written: make(map[string]bool),
+ PtrSize: ptrSize,
+ IntSize: intSize,
+ CgoFlags: make(map[string][]string),
+ Written: make(map[string]bool),
}
+ p.addToFlag("CFLAGS", args)
return p
}
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index a126cf17f..ee1d89142 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -31,7 +31,12 @@ func (p *Package) writeDefs() {
fflg := creat(*objDir + "_cgo_flags")
for k, v := range p.CgoFlags {
- fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v)
+ fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " "))
+ if k == "LDFLAGS" {
+ for _, arg := range v {
+ fmt.Fprintf(fc, "#pragma cgo_ldflag %q\n", arg)
+ }
+ }
}
fflg.Close()
@@ -100,6 +105,7 @@ func (p *Package) writeDefs() {
fmt.Fprintf(fm, "extern char %s[];\n", n.C)
fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
+ fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", n.C)
fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
cVars[n.C] = true
@@ -651,8 +657,9 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
if fn.Recv != nil {
goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
}
- fmt.Fprintf(fc, "#pragma cgo_export %s\n", goname)
+ fmt.Fprintf(fc, "#pragma cgo_export_dynamic %s\n", goname)
fmt.Fprintf(fc, "extern void ·%s();\n\n", goname)
+ fmt.Fprintf(fc, "#pragma cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g
fmt.Fprintf(fc, "void\n")
fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
diff --git a/src/cmd/cov/Makefile b/src/cmd/cov/Makefile
deleted file mode 100644
index 3f528d751..000000000
--- a/src/cmd/cov/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# 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.dist
diff --git a/src/cmd/cov/doc.go b/src/cmd/cov/doc.go
deleted file mode 100644
index ab5d1220a..000000000
--- a/src/cmd/cov/doc.go
+++ /dev/null
@@ -1,36 +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.
-
-// +build ignore
-
-/*
-
-Cov is a rudimentary code coverage tool.
-
-Usage:
- go tool cov [-lsv] [-g substring] [-m minlines] [6.out args]
-
-Given a command to run, it runs the command while tracking which
-sections of code have been executed. When the command finishes,
-cov prints the line numbers of sections of code in the binary that
-were not executed. With no arguments it assumes the command "6.out".
-
-
-The options are:
-
- -l
- print full path names instead of paths relative to the current directory
- -s
- show the source code that didn't execute, in addition to the line numbers.
- -v
- print debugging information during the run.
- -g substring
- restrict the coverage analysis to functions or files whose names contain substring
- -m minlines
- only report uncovered sections of code larger than minlines lines
-
-The program is the same for all architectures: 386, amd64, and arm.
-
-*/
-package main
diff --git a/src/cmd/cov/main.c b/src/cmd/cov/main.c
deleted file mode 100644
index 33ef49e17..000000000
--- a/src/cmd/cov/main.c
+++ /dev/null
@@ -1,484 +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.
-
-/*
- * code coverage
- */
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include "tree.h"
-
-#include <ureg_amd64.h>
-#include <mach.h>
-typedef struct Ureg Ureg;
-
-void
-usage(void)
-{
- fprint(2, "usage: cov [-lsv] [-g substring] [-m minlines] [6.out args...]\n");
- fprint(2, "-g specifies pattern of interesting functions or files\n");
- exits("usage");
-}
-
-typedef struct Range Range;
-struct Range
-{
- uvlong pc;
- uvlong epc;
-};
-
-int chatty;
-int fd;
-int longnames;
-int pid;
-int doshowsrc;
-Map *mem;
-Map *text;
-Fhdr fhdr;
-char *substring;
-char cwd[1000];
-int ncwd;
-int minlines = -1000;
-
-Tree breakpoints; // code ranges not run
-
-/*
- * comparison for Range structures
- * they are "equal" if they overlap, so
- * that a search for [pc, pc+1) finds the
- * Range containing pc.
- */
-int
-rangecmp(void *va, void *vb)
-{
- Range *a = va, *b = vb;
- if(a->epc <= b->pc)
- return 1;
- if(b->epc <= a->pc)
- return -1;
- return 0;
-}
-
-/*
- * remember that we ran the section of code [pc, epc).
- */
-void
-ran(uvlong pc, uvlong epc)
-{
- Range key;
- Range *r;
- uvlong oldepc;
-
- if(chatty)
- print("run %#llux-%#llux\n", pc, epc);
-
- key.pc = pc;
- key.epc = pc+1;
- r = treeget(&breakpoints, &key);
- if(r == nil)
- sysfatal("unchecked breakpoint at %#llux+%d", pc, (int)(epc-pc));
-
- // Might be that the tail of the sequence
- // was run already, so r->epc is before the end.
- // Adjust len.
- if(epc > r->epc)
- epc = r->epc;
-
- if(r->pc == pc) {
- r->pc = epc;
- } else {
- // Chop r to before pc;
- // add new entry for after if needed.
- // Changing r->epc does not affect r's position in the tree.
- oldepc = r->epc;
- r->epc = pc;
- if(epc < oldepc) {
- Range *n;
- n = malloc(sizeof *n);
- if(n == nil)
- sysfatal("out of memory");
- n->pc = epc;
- n->epc = oldepc;
- treeput(&breakpoints, n, n);
- }
- }
-}
-
-void
-showsrc(char *file, int line1, int line2)
-{
- Biobuf *b;
- char *p;
- int n, stop;
-
- if((b = Bopen(file, OREAD)) == nil) {
- print("\topen %s: %r\n", file);
- return;
- }
-
- for(n=1; n<line1 && (p = Brdstr(b, '\n', 1)) != nil; n++)
- free(p);
-
- // print up to five lines (this one and 4 more).
- // if there are more than five lines, print 4 and "..."
- stop = n+4;
- if(stop > line2)
- stop = line2;
- if(stop < line2)
- stop--;
- for(; n<=stop && (p = Brdstr(b, '\n', 1)) != nil; n++) {
- print(" %d %s\n", n, p);
- free(p);
- }
- if(n < line2)
- print(" ...\n");
- Bterm(b);
-}
-
-/*
- * if s is in the current directory or below,
- * return the relative path.
- */
-char*
-shortname(char *s)
-{
- if(!longnames && strlen(s) > ncwd && memcmp(s, cwd, ncwd) == 0 && s[ncwd] == '/')
- return s+ncwd+1;
- return s;
-}
-
-/*
- * we've decided that [pc, epc) did not run.
- * do something about it.
- */
-void
-missing(uvlong pc, uvlong epc)
-{
- char file[1000];
- int line1, line2;
- char buf[100];
- Symbol s;
- char *p;
- uvlong uv;
-
- if(!findsym(pc, CTEXT, &s) || !fileline(file, sizeof file, pc)) {
- notfound:
- print("%#llux-%#llux\n", pc, epc);
- return;
- }
- p = strrchr(file, ':');
- *p++ = 0;
- line1 = atoi(p);
- for(uv=pc; uv<epc; ) {
- if(!fileline(file, sizeof file, epc-2))
- goto notfound;
- uv += machdata->instsize(text, uv);
- }
- p = strrchr(file, ':');
- *p++ = 0;
- line2 = atoi(p);
-
- if(line2+1-line2 < minlines)
- return;
-
- if(pc == s.value) {
- // never entered function
- print("%s:%d %s never called (%#llux-%#llux)\n", shortname(file), line1, s.name, pc, epc);
- return;
- }
- if(pc <= s.value+13) {
- // probably stub for stack growth.
- // check whether last instruction is call to morestack.
- // the -5 below is the length of
- // CALL sys.morestack.
- buf[0] = 0;
- machdata->das(text, epc-5, 0, buf, sizeof buf);
- if(strstr(buf, "morestack"))
- return;
- }
-
- if(epc - pc == 5) {
- // check for CALL sys.panicindex
- buf[0] = 0;
- machdata->das(text, pc, 0, buf, sizeof buf);
- if(strstr(buf, "panicindex"))
- return;
- }
-
- if(epc - pc == 2 || epc -pc == 3) {
- // check for XORL inside shift.
- // (on x86 have to implement large left or unsigned right shift with explicit zeroing).
- // f+90 0x00002c9f CMPL CX,$20
- // f+93 0x00002ca2 JCS f+97(SB)
- // f+95 0x00002ca4 XORL AX,AX <<<
- // f+97 0x00002ca6 SHLL CL,AX
- // f+99 0x00002ca8 MOVL $1,CX
- //
- // f+c8 0x00002cd7 CMPL CX,$40
- // f+cb 0x00002cda JCS f+d0(SB)
- // f+cd 0x00002cdc XORQ AX,AX <<<
- // f+d0 0x00002cdf SHLQ CL,AX
- // f+d3 0x00002ce2 MOVQ $1,CX
- buf[0] = 0;
- machdata->das(text, pc, 0, buf, sizeof buf);
- if(strncmp(buf, "XOR", 3) == 0) {
- machdata->das(text, epc, 0, buf, sizeof buf);
- if(strncmp(buf, "SHL", 3) == 0 || strncmp(buf, "SHR", 3) == 0)
- return;
- }
- }
-
- if(epc - pc == 3) {
- // check for SAR inside shift.
- // (on x86 have to implement large signed right shift as >>31).
- // f+36 0x00016216 CMPL CX,$20
- // f+39 0x00016219 JCS f+3e(SB)
- // f+3b 0x0001621b SARL $1f,AX <<<
- // f+3e 0x0001621e SARL CL,AX
- // f+40 0x00016220 XORL CX,CX
- // f+42 0x00016222 CMPL CX,AX
- buf[0] = 0;
- machdata->das(text, pc, 0, buf, sizeof buf);
- if(strncmp(buf, "SAR", 3) == 0) {
- machdata->das(text, epc, 0, buf, sizeof buf);
- if(strncmp(buf, "SAR", 3) == 0)
- return;
- }
- }
-
- // show first instruction to make clear where we were.
- machdata->das(text, pc, 0, buf, sizeof buf);
-
- if(line1 != line2)
- print("%s:%d,%d %#llux-%#llux %s\n",
- shortname(file), line1, line2, pc, epc, buf);
- else
- print("%s:%d %#llux-%#llux %s\n",
- shortname(file), line1, pc, epc, buf);
- if(doshowsrc)
- showsrc(file, line1, line2);
-}
-
-/*
- * walk the tree, calling missing for each non-empty
- * section of missing code.
- */
-void
-walktree(TreeNode *t)
-{
- Range *n;
-
- if(t == nil)
- return;
- walktree(t->left);
- n = t->key;
- if(n->pc < n->epc)
- missing(n->pc, n->epc);
- walktree(t->right);
-}
-
-/*
- * set a breakpoint all over [pc, epc)
- * and remember that we did.
- */
-void
-breakpoint(uvlong pc, uvlong epc)
-{
- Range *r;
-
- r = malloc(sizeof *r);
- if(r == nil)
- sysfatal("out of memory");
- r->pc = pc;
- r->epc = epc;
- treeput(&breakpoints, r, r);
-
- for(; pc < epc; pc+=machdata->bpsize)
- put1(mem, pc, machdata->bpinst, machdata->bpsize);
-}
-
-/*
- * install breakpoints over all text symbols
- * that match the pattern.
- */
-void
-cover(void)
-{
- Symbol s;
- char *lastfn;
- uvlong lastpc;
- int i;
- char buf[200];
-
- lastfn = nil;
- lastpc = 0;
- for(i=0; textsym(&s, i); i++) {
- switch(s.type) {
- case 'T':
- case 't':
- if(lastpc != 0) {
- breakpoint(lastpc, s.value);
- lastpc = 0;
- }
- // Ignore second entry for a given name;
- // that's the debugging blob.
- if(lastfn && strcmp(s.name, lastfn) == 0)
- break;
- lastfn = s.name;
- buf[0] = 0;
- fileline(buf, sizeof buf, s.value);
- if(substring == nil || strstr(buf, substring) || strstr(s.name, substring))
- lastpc = s.value;
- }
- }
-}
-
-uvlong
-rgetzero(Map *map, char *reg)
-{
- USED(map);
- USED(reg);
-
- return 0;
-}
-
-/*
- * remove the breakpoints at pc and successive instructions,
- * up to and including the first jump or other control flow transfer.
- */
-void
-uncover(uvlong pc)
-{
- uchar buf[1000];
- int n, n1, n2;
- uvlong foll[2];
-
- // Double-check that we stopped at a breakpoint.
- if(get1(mem, pc, buf, machdata->bpsize) < 0)
- sysfatal("read mem inst at %#llux: %r", pc);
- if(memcmp(buf, machdata->bpinst, machdata->bpsize) != 0)
- sysfatal("stopped at %#llux; not at breakpoint %d", pc, machdata->bpsize);
-
- // Figure out how many bytes of straight-line code
- // there are in the text starting at pc.
- n = 0;
- while(n < sizeof buf) {
- n1 = machdata->instsize(text, pc+n);
- if(n+n1 > sizeof buf)
- break;
- n2 = machdata->foll(text, pc+n, rgetzero, foll);
- n += n1;
- if(n2 != 1 || foll[0] != pc+n)
- break;
- }
-
- // Record that this section of code ran.
- ran(pc, pc+n);
-
- // Put original instructions back.
- if(get1(text, pc, buf, n) < 0)
- sysfatal("get1: %r");
- if(put1(mem, pc, buf, n) < 0)
- sysfatal("put1: %r");
-}
-
-int
-startprocess(char **argv)
-{
- int pid;
-
- if((pid = fork()) < 0)
- sysfatal("fork: %r");
- if(pid == 0) {
- pid = getpid();
- if(ctlproc(pid, "hang") < 0)
- sysfatal("ctlproc hang: %r");
- exec(argv[0], argv);
- sysfatal("exec %s: %r", argv[0]);
- }
- if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0)
- sysfatal("attach %d %s: %r", pid, argv[0]);
- return pid;
-}
-
-int
-go(void)
-{
- uvlong pc;
- char buf[100];
- int n;
-
- for(n = 0;; n++) {
- ctlproc(pid, "startstop");
- if(get8(mem, offsetof(Ureg, ip), &pc) < 0) {
- rerrstr(buf, sizeof buf);
- if(strstr(buf, "exited") || strstr(buf, "No such process"))
- return n;
- sysfatal("cannot read pc: %r");
- }
- pc--;
- if(put8(mem, offsetof(Ureg, ip), pc) < 0)
- sysfatal("cannot write pc: %r");
- uncover(pc);
- }
-}
-
-void
-main(int argc, char **argv)
-{
- int n;
-
- ARGBEGIN{
- case 'g':
- substring = EARGF(usage());
- break;
- case 'l':
- longnames++;
- break;
- case 'n':
- minlines = atoi(EARGF(usage()));
- break;
- case 's':
- doshowsrc = 1;
- break;
- case 'v':
- chatty++;
- break;
- default:
- usage();
- }ARGEND
-
- getwd(cwd, sizeof cwd);
- ncwd = strlen(cwd);
-
- if(argc == 0) {
- *--argv = "6.out";
- }
- fd = open(argv[0], OREAD);
- if(fd < 0)
- sysfatal("open %s: %r", argv[0]);
- if(crackhdr(fd, &fhdr) <= 0)
- sysfatal("crackhdr: %r");
- machbytype(fhdr.type);
- if(syminit(fd, &fhdr) <= 0)
- sysfatal("syminit: %r");
- text = loadmap(nil, fd, &fhdr);
- if(text == nil)
- sysfatal("loadmap: %r");
- pid = startprocess(argv);
- mem = attachproc(pid, &fhdr);
- if(mem == nil)
- sysfatal("attachproc: %r");
- breakpoints.cmp = rangecmp;
- cover();
- n = go();
- walktree(breakpoints.root);
- if(chatty)
- print("%d breakpoints\n", n);
- detachproc(mem);
- exits(0);
-}
-
diff --git a/src/cmd/cov/tree.c b/src/cmd/cov/tree.c
deleted file mode 100644
index 366a47efd..000000000
--- a/src/cmd/cov/tree.c
+++ /dev/null
@@ -1,245 +0,0 @@
-// Renamed from Map to Tree to avoid conflict with libmach.
-
-/*
-Copyright (c) 2003-2007 Russ Cox, Tom Bergan, Austin Clements,
- Massachusetts Institute of Technology
-Portions Copyright (c) 2009 The Go Authors. All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-// Mutable map structure, but still based on
-// Okasaki, Red Black Trees in a Functional Setting, JFP 1999,
-// which is a lot easier than the traditional red-black
-// and plenty fast enough for me. (Also I could copy
-// and edit fmap.c.)
-
-#include <u.h>
-#include <libc.h>
-#include "tree.h"
-
-enum
-{
- Red = 0,
- Black = 1
-};
-
-
-// Red-black trees are binary trees with this property:
-// 1. No red node has a red parent.
-// 2. Every path from the root to a leaf contains the
-// same number of black nodes.
-
-static TreeNode*
-rwTreeNode(TreeNode *p, int color, TreeNode *left, void *key, void *value, TreeNode *right)
-{
- if(p == nil)
- p = malloc(sizeof *p);
- if(p == nil)
- sysfatal("out of memory");
- p->color = color;
- p->left = left;
- p->key = key;
- p->value = value;
- p->right = right;
- return p;
-}
-
-static TreeNode*
-balance(TreeNode *m0)
-{
- void *xk, *xv, *yk, *yv, *zk, *zv;
- TreeNode *a, *b, *c, *d;
- TreeNode *m1, *m2;
- int color;
- TreeNode *left, *right;
- void *key, *value;
-
- color = m0->color;
- left = m0->left;
- key = m0->key;
- value = m0->value;
- right = m0->right;
-
- // Okasaki notation: (T is mkTreeNode, B is Black, R is Red, x, y, z are key-value.
- //
- // balance B (T R (T R a x b) y c) z d
- // balance B (T R a x (T R b y c)) z d
- // balance B a x (T R (T R b y c) z d)
- // balance B a x (T R b y (T R c z d))
- //
- // = T R (T B a x b) y (T B c z d)
-
- if(color == Black){
- if(left && left->color == Red){
- if(left->left && left->left->color == Red){
- a = left->left->left;
- xk = left->left->key;
- xv = left->left->value;
- b = left->left->right;
- yk = left->key;
- yv = left->value;
- c = left->right;
- zk = key;
- zv = value;
- d = right;
- m1 = left;
- m2 = left->left;
- goto hard;
- }else if(left->right && left->right->color == Red){
- a = left->left;
- xk = left->key;
- xv = left->value;
- b = left->right->left;
- yk = left->right->key;
- yv = left->right->value;
- c = left->right->right;
- zk = key;
- zv = value;
- d = right;
- m1 = left;
- m2 = left->right;
- goto hard;
- }
- }else if(right && right->color == Red){
- if(right->left && right->left->color == Red){
- a = left;
- xk = key;
- xv = value;
- b = right->left->left;
- yk = right->left->key;
- yv = right->left->value;
- c = right->left->right;
- zk = right->key;
- zv = right->value;
- d = right->right;
- m1 = right;
- m2 = right->left;
- goto hard;
- }else if(right->right && right->right->color == Red){
- a = left;
- xk = key;
- xv = value;
- b = right->left;
- yk = right->key;
- yv = right->value;
- c = right->right->left;
- zk = right->right->key;
- zv = right->right->value;
- d = right->right->right;
- m1 = right;
- m2 = right->right;
- goto hard;
- }
- }
- }
- return rwTreeNode(m0, color, left, key, value, right);
-
-hard:
- return rwTreeNode(m0, Red, rwTreeNode(m1, Black, a, xk, xv, b),
- yk, yv, rwTreeNode(m2, Black, c, zk, zv, d));
-}
-
-static TreeNode*
-ins0(TreeNode *p, void *k, void *v, TreeNode *rw)
-{
- if(p == nil)
- return rwTreeNode(rw, Red, nil, k, v, nil);
- if(p->key == k){
- if(rw)
- return rwTreeNode(rw, p->color, p->left, k, v, p->right);
- p->value = v;
- return p;
- }
- if(p->key < k)
- p->left = ins0(p->left, k, v, rw);
- else
- p->right = ins0(p->right, k, v, rw);
- return balance(p);
-}
-
-static TreeNode*
-ins1(Tree *m, TreeNode *p, void *k, void *v, TreeNode *rw)
-{
- int i;
-
- if(p == nil)
- return rwTreeNode(rw, Red, nil, k, v, nil);
- i = m->cmp(p->key, k);
- if(i == 0){
- if(rw)
- return rwTreeNode(rw, p->color, p->left, k, v, p->right);
- p->value = v;
- return p;
- }
- if(i < 0)
- p->left = ins1(m, p->left, k, v, rw);
- else
- p->right = ins1(m, p->right, k, v, rw);
- return balance(p);
-}
-
-void
-treeputelem(Tree *m, void *key, void *val, TreeNode *rw)
-{
- if(m->cmp)
- m->root = ins1(m, m->root, key, val, rw);
- else
- m->root = ins0(m->root, key, val, rw);
-}
-
-void
-treeput(Tree *m, void *key, void *val)
-{
- treeputelem(m, key, val, nil);
-}
-
-void*
-treeget(Tree *m, void *key)
-{
- int i;
- TreeNode *p;
-
- p = m->root;
- if(m->cmp){
- for(;;){
- if(p == nil)
- return nil;
- i = m->cmp(p->key, key);
- if(i < 0)
- p = p->left;
- else if(i > 0)
- p = p->right;
- else
- return p->value;
- }
- }else{
- for(;;){
- if(p == nil)
- return nil;
- if(p->key == key)
- return p->value;
- if(p->key < key)
- p = p->left;
- else
- p = p->right;
- }
- }
-}
diff --git a/src/cmd/cov/tree.h b/src/cmd/cov/tree.h
deleted file mode 100644
index a716d83ad..000000000
--- a/src/cmd/cov/tree.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Renamed from Map to Tree to avoid conflict with libmach.
-
-/*
-Copyright (c) 2003-2007 Russ Cox, Tom Bergan, Austin Clements,
- Massachusetts Institute of Technology
-Portions Copyright (c) 2009 The Go Authors. All rights reserved.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-typedef struct Tree Tree;
-typedef struct TreeNode TreeNode;
-struct Tree
-{
- int (*cmp)(void*, void*);
- TreeNode *root;
-};
-
-struct TreeNode
-{
- int color;
- TreeNode *left;
- void *key;
- void *value;
- TreeNode *right;
-};
-
-void *treeget(Tree*, void*);
-void treeput(Tree*, void*, void*);
-void treeputelem(Tree*, void*, void*, TreeNode*);
diff --git a/src/cmd/dist/a.h b/src/cmd/dist/a.h
index fcd81cc51..73c126476 100644
--- a/src/cmd/dist/a.h
+++ b/src/cmd/dist/a.h
@@ -72,6 +72,7 @@ extern char *gohostos;
extern char *goos;
extern char *goroot;
extern char *goroot_final;
+extern char *goextlinkenabled;
extern char *goversion;
extern char *workdir;
extern char *tooldir;
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
index dda45ca62..169e5cadd 100644
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -20,6 +20,7 @@ char *goarm;
char *go386;
char *goroot = GOROOT_FINAL;
char *goroot_final = GOROOT_FINAL;
+char *goextlinkenabled = "";
char *workdir;
char *tooldir;
char *gochar;
@@ -139,6 +140,13 @@ init(void)
bprintf(&b, "%c", gochars[i]);
gochar = btake(&b);
+ xgetenv(&b, "GO_EXTLINK_ENABLED");
+ if(b.len > 0) {
+ goextlinkenabled = btake(&b);
+ if(!streq(goextlinkenabled, "0") && !streq(goextlinkenabled, "1"))
+ fatal("unknown $GO_EXTLINK_ENABLED %s", goextlinkenabled);
+ }
+
xsetenv("GOROOT", goroot);
xsetenv("GOARCH", goarch);
xsetenv("GOOS", goos);
@@ -313,7 +321,6 @@ static char *unreleased[] = {
"src/cmd/cov",
"src/cmd/prof",
"src/pkg/old",
- "src/pkg/exp",
};
// setup sets up the tree for the initial build.
@@ -615,6 +622,10 @@ install(char *dir)
// clang is too smart about unused command-line arguments
vadd(&gccargs, "-Qunused-arguments");
}
+ if(streq(gohostos, "darwin")) {
+ // golang.org/issue/5261
+ vadd(&gccargs, "-mmacosx-version-min=10.6");
+ }
}
islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc");
@@ -795,6 +806,9 @@ install(char *dir)
bpathf(&b1, "%s/arch_%s.h", bstr(&path), goarch), 0);
copy(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir),
bpathf(&b1, "%s/defs_%s_%s.h", bstr(&path), goos, goarch), 0);
+ p = bpathf(&b1, "%s/signal_%s_%s.h", bstr(&path), goos, goarch);
+ if(isfile(p))
+ copy(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0);
copy(bpathf(&b, "%s/os_GOOS.h", workdir),
bpathf(&b1, "%s/os_%s.h", bstr(&path), goos), 0);
copy(bpathf(&b, "%s/signals_GOOS.h", workdir),
@@ -920,6 +934,8 @@ install(char *dir)
vadd(&compile, bprintf(&b, "GOARM=\"%s\"", goarm));
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GO386=\"%s\"", go386));
+ vadd(&compile, "-D");
+ vadd(&compile, bprintf(&b, "GO_EXTLINK_ENABLED=\"%s\"", goextlinkenabled));
}
// gc/lex.c records the GOEXPERIMENT setting used during the build.
@@ -940,6 +956,8 @@ install(char *dir)
}
vadd(&compile, "-I");
vadd(&compile, workdir);
+ vadd(&compile, "-I");
+ vadd(&compile, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
vadd(&compile, "-D");
vadd(&compile, bprintf(&b, "GOOS_%s", goos));
vadd(&compile, "-D");
@@ -1045,7 +1063,16 @@ out:
static bool
matchfield(char *f)
{
- return streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap");
+ char *p;
+ bool res;
+
+ p = xstrrchr(f, ',');
+ if(p == nil)
+ return streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap") || streq(f, "go1.1");
+ *p = 0;
+ res = matchfield(f) && matchfield(p+1);
+ *p = ',';
+ return res;
}
// shouldbuild reports whether we should build this file.
@@ -1071,7 +1098,8 @@ shouldbuild(char *file, char *dir)
name = lastelem(file);
if(streq(name, "goos.c") || streq(name, "flag.c"))
return 1;
- return 0;
+ if(!contains(name, "plan9"))
+ return 0;
}
if(streq(dir, "libbio"))
return 0;
@@ -1574,7 +1602,7 @@ cmdclean(int argc, char **argv)
void
cmdbanner(int argc, char **argv)
{
- char *pathsep;
+ char *pathsep, *pid, *ns;
Buf b, b1, search, path;
ARGBEGIN{
@@ -1598,15 +1626,28 @@ cmdbanner(int argc, char **argv)
xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot);
xprintf("Installed commands in %s\n", gobin);
- // Check that gobin appears in $PATH.
- xgetenv(&b, "PATH");
- pathsep = ":";
- if(streq(gohostos, "windows"))
- pathsep = ";";
- bprintf(&b1, "%s%s%s", pathsep, bstr(&b), pathsep);
- bprintf(&search, "%s%s%s", pathsep, gobin, pathsep);
- if(xstrstr(bstr(&b1), bstr(&search)) == nil)
- xprintf("*** You need to add %s to your PATH.\n", gobin);
+ if(streq(gohostos, "plan9")) {
+ // Check that gobin is bound before /bin.
+ readfile(&b, "#c/pid");
+ bsubst(&b, " ", "");
+ pid = btake(&b);
+ bprintf(&b, "/proc/%s/ns", pid);
+ ns = btake(&b);
+ readfile(&b, ns);
+ bprintf(&search, "bind -b %s /bin\n", gobin);
+ if(xstrstr(bstr(&b), bstr(&search)) == nil)
+ xprintf("*** You need to bind %s before /bin.\n", gobin);
+ } else {
+ // Check that gobin appears in $PATH.
+ xgetenv(&b, "PATH");
+ pathsep = ":";
+ if(streq(gohostos, "windows"))
+ pathsep = ";";
+ bprintf(&b1, "%s%s%s", pathsep, bstr(&b), pathsep);
+ bprintf(&search, "%s%s%s", pathsep, gobin, pathsep);
+ if(xstrstr(bstr(&b1), bstr(&search)) == nil)
+ xprintf("*** You need to add %s to your PATH.\n", gobin);
+ }
if(streq(gohostos, "darwin")) {
if(isfile(bpathf(&path, "%s/cov", tooldir)))
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
index f46f72d4b..ee867566f 100644
--- a/src/cmd/dist/buildruntime.c
+++ b/src/cmd/dist/buildruntime.c
@@ -133,12 +133,17 @@ static struct {
"// which is where these macros come into play.\n"
"// get_tls sets up the temporary and then g and r use it.\n"
"//\n"
- "// The final wrinkle is that get_tls needs to read from %gs:0,\n"
+ "// Another wrinkle is that get_tls needs to read from %gs:0,\n"
"// but in 8l input it's called 8(GS), because 8l is going to\n"
"// subtract 8 from all the offsets, as described above.\n"
+ "//\n"
+ "// The final wrinkle is that when generating an ELF .o file for\n"
+ "// external linking mode, we need to be able to relocate the\n"
+ "// -8(r) and -4(r) instructions. Tag them with an extra (GS*1)\n"
+ "// that is ignored by the linker except for that identification.\n"
"#define get_tls(r) MOVL 8(GS), r\n"
- "#define g(r) -8(r)\n"
- "#define m(r) -4(r)\n"
+ "#define g(r) -8(r)(GS*1)\n"
+ "#define m(r) -4(r)(GS*1)\n"
},
{"386", "",
"#define get_tls(r)\n"
diff --git a/src/cmd/dist/goc2c.c b/src/cmd/dist/goc2c.c
index a103bce8d..f58460397 100644
--- a/src/cmd/dist/goc2c.c
+++ b/src/cmd/dist/goc2c.c
@@ -66,7 +66,7 @@ static int gcc;
/* File and line number */
static const char *file;
-static unsigned int lineno = 1;
+static unsigned int lineno;
/* List of names and types. */
struct params {
@@ -754,6 +754,7 @@ goc2c(char *goc, char *c)
input = bstr(&in);
output = &out;
+ lineno = 1;
process_file();
writefile(&out, c, 0);
diff --git a/src/cmd/dist/unix.c b/src/cmd/dist/unix.c
index e4e2dcc9f..f2ea48974 100644
--- a/src/cmd/dist/unix.c
+++ b/src/cmd/dist/unix.c
@@ -698,6 +698,19 @@ main(int argc, char **argv)
if(strcmp(gohostarch, "arm") == 0)
maxnbg = 1;
+ // The OS X 10.6 linker does not support external
+ // linking mode; see
+ // https://code.google.com/p/go/issues/detail?id=5130 .
+ // The mapping from the uname release field to the OS X
+ // version number is complicated, but basically 10 or under is
+ // OS X 10.6 or earlier.
+ if(strcmp(gohostos, "darwin") == 0) {
+ if(uname(&u) < 0)
+ fatal("uname: %s", strerror(errno));
+ if(u.release[1] == '.' || hasprefix(u.release, "10"))
+ goextlinkenabled = "0";
+ }
+
init();
xmain(argc, argv);
bfree(&b);
diff --git a/src/cmd/dist/windows.c b/src/cmd/dist/windows.c
index 7bcda4508..ba23a7ae8 100644
--- a/src/cmd/dist/windows.c
+++ b/src/cmd/dist/windows.c
@@ -271,6 +271,8 @@ static void bgwait1(void);
static void
genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
{
+ // Another copy of this logic is in ../../lib9/run_windows.c.
+ // If there's a bug here, fix the logic there too.
int i, j, nslash;
Buf cmd;
char *q;
diff --git a/src/cmd/fix/netipv6zone.go b/src/cmd/fix/netipv6zone.go
index 587b9ffec..fe973a211 100644
--- a/src/cmd/fix/netipv6zone.go
+++ b/src/cmd/fix/netipv6zone.go
@@ -14,7 +14,7 @@ var netipv6zoneFix = fix{
"netipv6zone",
"2012-11-26",
netipv6zone,
- `Adapt element key to IPNet, IPAddr, UDPAddr or TCPAddr composite literals.
+ `Adapt element key to IPAddr, UDPAddr or TCPAddr composite literals.
https://codereview.appspot.com/6849045/
`,
@@ -39,7 +39,7 @@ func netipv6zone(f *ast.File) bool {
return
}
switch ss := se.Sel.String(); ss {
- case "IPNet", "IPAddr", "UDPAddr", "TCPAddr":
+ case "IPAddr", "UDPAddr", "TCPAddr":
for i, e := range cl.Elts {
if _, ok := e.(*ast.KeyValueExpr); ok {
break
@@ -51,11 +51,8 @@ func netipv6zone(f *ast.File) bool {
Value: e,
}
case 1:
- if ss == "IPNet" {
- cl.Elts[i] = &ast.KeyValueExpr{
- Key: ast.NewIdent("Mask"),
- Value: e,
- }
+ if e.(*ast.BasicLit).Value == "0" {
+ cl.Elts = append(cl.Elts[:i], cl.Elts[i+1:]...)
} else {
cl.Elts[i] = &ast.KeyValueExpr{
Key: ast.NewIdent("Port"),
diff --git a/src/cmd/fix/netipv6zone_test.go b/src/cmd/fix/netipv6zone_test.go
index 229daa386..0fab00531 100644
--- a/src/cmd/fix/netipv6zone_test.go
+++ b/src/cmd/fix/netipv6zone_test.go
@@ -15,36 +15,24 @@ var netipv6zoneTests = []testCase{
import "net"
-var a = []struct {
- *net.IPNet
-}{
- &net.IPNet{net.ParseIP("2001:DB8::"), net.IPMask(net.ParseIP("ffff:ffff:ffff::"))},
-}
-
func f() net.Addr {
- b := net.IPNet{net.IPv4(127, 0, 0, 1), net.IPv4Mask(255, 0, 0, 0)}
- c := &net.IPAddr{ip1}
+ a := &net.IPAddr{ip1}
sub(&net.UDPAddr{ip2, 12345})
- d := &net.TCPAddr{IP: ip3, Port: 54321}
- return &net.TCPAddr{ip4}, nil
+ c := &net.TCPAddr{IP: ip3, Port: 54321}
+ d := &net.TCPAddr{ip4, 0}
+ return &net.TCPAddr{ip5}, nil
}
`,
Out: `package main
import "net"
-var a = []struct {
- *net.IPNet
-}{
- &net.IPNet{IP: net.ParseIP("2001:DB8::"), Mask: net.IPMask(net.ParseIP("ffff:ffff:ffff::"))},
-}
-
func f() net.Addr {
- b := net.IPNet{IP: net.IPv4(127, 0, 0, 1), Mask: net.IPv4Mask(255, 0, 0, 0)}
- c := &net.IPAddr{IP: ip1}
+ a := &net.IPAddr{IP: ip1}
sub(&net.UDPAddr{IP: ip2, Port: 12345})
- d := &net.TCPAddr{IP: ip3, Port: 54321}
- return &net.TCPAddr{IP: ip4}, nil
+ c := &net.TCPAddr{IP: ip3, Port: 54321}
+ d := &net.TCPAddr{IP: ip4}
+ return &net.TCPAddr{IP: ip5}, nil
}
`,
},
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index be9f552f6..80c65387b 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -46,7 +46,8 @@ static vlong
widstruct(Type *errtype, Type *t, vlong o, int flag)
{
Type *f;
- int32 w, maxalign;
+ int64 w;
+ int32 maxalign;
maxalign = flag;
if(maxalign < 1)
@@ -643,7 +644,7 @@ argsize(Type *t)
{
Iter save;
Type *fp;
- int w, x;
+ int64 w, x;
w = 0;
@@ -664,5 +665,7 @@ argsize(Type *t)
}
w = (w+widthptr-1) & ~(widthptr-1);
+ if((int)w != w)
+ fatal("argsize too big");
return w;
}
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
index 7de448d1e..9053dfe10 100644
--- a/src/cmd/gc/builtin.c
+++ b/src/cmd/gc/builtin.c
@@ -1,3 +1,4 @@
+// AUTO-GENERATED by mkbuiltin; DO NOT EDIT
char *runtimeimport =
"package runtime\n"
"import runtime \"runtime\"\n"
@@ -63,7 +64,13 @@ char *runtimeimport =
"func @\"\".equal (@\"\".typ·2 *byte, @\"\".x1·3 any, @\"\".x2·4 any) (@\"\".ret·1 bool)\n"
"func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64) (@\"\".hmap·1 map[any]any)\n"
"func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 any)\n"
+ "func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
+ "func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
+ "func @\"\".mapaccess1_faststr (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
"func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 any, @\"\".pres·2 bool)\n"
+ "func @\"\".mapaccess2_fast32 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
+ "func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
+ "func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
"func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 any, @\"\".val·4 any)\n"
"func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n"
"func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 any)\n"
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
index 4e029ef83..d81c5281d 100644
--- a/src/cmd/gc/closure.c
+++ b/src/cmd/gc/closure.c
@@ -60,6 +60,7 @@ closurebody(NodeList *body)
func = curfn;
func->nbody = body;
+ func->endlineno = lineno;
funcbody(func);
// closure-specific variables are hanging off the
@@ -75,7 +76,7 @@ closurebody(NodeList *body)
return func;
}
-static Node* makeclosure(Node *func, int nowrap);
+static Node* makeclosure(Node *func);
void
typecheckclosure(Node *func, int top)
@@ -124,17 +125,17 @@ typecheckclosure(Node *func, int top)
}
// Create top-level function
- xtop = list(xtop, makeclosure(func, func->cvars==nil || (top&Ecall)));
+ xtop = list(xtop, makeclosure(func));
}
static Node*
-makeclosure(Node *func, int nowrap)
+makeclosure(Node *func)
{
Node *xtype, *v, *addr, *xfunc, *cv;
NodeList *l, *body;
static int closgen;
char *p;
- int offset;
+ vlong offset;
/*
* wrap body in external function
@@ -154,6 +155,7 @@ makeclosure(Node *func, int nowrap)
declare(xfunc->nname, PFUNC);
xfunc->nname->funcdepth = func->funcdepth;
xfunc->funcdepth = func->funcdepth;
+ xfunc->endlineno = func->endlineno;
// declare variables holding addresses taken from closure
// and initialize in entry prologue.
@@ -255,26 +257,174 @@ walkclosure(Node *func, NodeList **init)
return clos;
}
-// Special case for closures that get called in place.
-// Optimize runtime.closure(X, __func__xxxx_, .... ) away
-// to __func__xxxx_(Y ....).
-// On entry, expect n->op == OCALL, n->left->op == OCLOSURE.
+static Node *makepartialcall(Node*, Type*, Node*);
+
void
-walkcallclosure(Node *n, NodeList **init)
+typecheckpartialcall(Node *fn, Node *sym)
+{
+ switch(fn->op) {
+ case ODOTINTER:
+ case ODOTMETH:
+ break;
+ default:
+ fatal("invalid typecheckpartialcall");
+ }
+
+ // Create top-level function.
+ fn->nname = makepartialcall(fn, fn->type, sym);
+ fn->right = sym;
+ fn->op = OCALLPART;
+ fn->type = fn->nname->type;
+}
+
+static Node*
+makepartialcall(Node *fn, Type *t0, Node *meth)
+{
+ Node *ptr, *n, *fld, *call, *xtype, *xfunc, *cv;
+ Type *rcvrtype, *basetype, *t;
+ NodeList *body, *l, *callargs, *retargs;
+ char *p;
+ Sym *sym;
+ int i, ddd;
+
+ // TODO: names are not right
+ rcvrtype = fn->left->type;
+ if(exportname(meth->sym->name))
+ p = smprint("%-hT.%s·fm", rcvrtype, meth->sym->name);
+ else
+ p = smprint("%-hT.(%-S)·fm", rcvrtype, meth->sym);
+ basetype = rcvrtype;
+ if(isptr[rcvrtype->etype])
+ basetype = basetype->type;
+ if(basetype->sym == S)
+ fatal("missing base type for %T", rcvrtype);
+
+ sym = pkglookup(p, basetype->sym->pkg);
+ free(p);
+ if(sym->flags & SymUniq)
+ return sym->def;
+ sym->flags |= SymUniq;
+
+ xtype = nod(OTFUNC, N, N);
+ i = 0;
+ l = nil;
+ callargs = nil;
+ ddd = 0;
+ xfunc = nod(ODCLFUNC, N, N);
+ for(t = getinargx(t0)->type; t; t = t->down) {
+ snprint(namebuf, sizeof namebuf, "a%d", i++);
+ n = newname(lookup(namebuf));
+ n->class = PPARAM;
+ xfunc->dcl = list(xfunc->dcl, n);
+ callargs = list(callargs, n);
+ fld = nod(ODCLFIELD, n, typenod(t->type));
+ if(t->isddd) {
+ fld->isddd = 1;
+ ddd = 1;
+ }
+ l = list(l, fld);
+ }
+ xtype->list = l;
+ i = 0;
+ l = nil;
+ retargs = nil;
+ for(t = getoutargx(t0)->type; t; t = t->down) {
+ snprint(namebuf, sizeof namebuf, "r%d", i++);
+ n = newname(lookup(namebuf));
+ n->class = PPARAMOUT;
+ xfunc->dcl = list(xfunc->dcl, n);
+ retargs = list(retargs, n);
+ l = list(l, nod(ODCLFIELD, n, typenod(t->type)));
+ }
+ xtype->rlist = l;
+
+ xfunc->dupok = 1;
+ xfunc->nname = newname(sym);
+ xfunc->nname->sym->flags |= SymExported; // disable export
+ xfunc->nname->ntype = xtype;
+ xfunc->nname->defn = xfunc;
+ declare(xfunc->nname, PFUNC);
+
+ // Declare and initialize variable holding receiver.
+ body = nil;
+ cv = nod(OCLOSUREVAR, N, N);
+ cv->xoffset = widthptr;
+ cv->type = rcvrtype;
+ ptr = nod(ONAME, N, N);
+ ptr->sym = lookup("rcvr");
+ ptr->class = PAUTO;
+ ptr->addable = 1;
+ ptr->ullman = 1;
+ ptr->used = 1;
+ ptr->curfn = xfunc;
+ xfunc->dcl = list(xfunc->dcl, ptr);
+ if(isptr[rcvrtype->etype] || isinter(rcvrtype)) {
+ ptr->ntype = typenod(rcvrtype);
+ body = list(body, nod(OAS, ptr, cv));
+ } else {
+ ptr->ntype = typenod(ptrto(rcvrtype));
+ body = list(body, nod(OAS, ptr, nod(OADDR, cv, N)));
+ }
+
+ call = nod(OCALL, nod(OXDOT, ptr, meth), N);
+ call->list = callargs;
+ call->isddd = ddd;
+ if(t0->outtuple == 0) {
+ body = list(body, call);
+ } else {
+ n = nod(OAS2, N, N);
+ n->list = retargs;
+ n->rlist = list1(call);
+ body = list(body, n);
+ n = nod(ORETURN, N, N);
+ body = list(body, n);
+ }
+
+ xfunc->nbody = body;
+
+ typecheck(&xfunc, Etop);
+ sym->def = xfunc;
+ xtop = list(xtop, xfunc);
+
+ return xfunc;
+}
+
+Node*
+walkpartialcall(Node *n, NodeList **init)
{
- USED(init);
- if (n->op != OCALLFUNC || n->left->op != OCLOSURE) {
- dump("walkcallclosure", n);
- fatal("abuse of walkcallclosure");
+ Node *clos, *typ;
+
+ // Create closure in the form of a composite literal.
+ // For x.M with receiver (x) type T, the generated code looks like:
+ //
+ // clos = &struct{F uintptr; R T}{M.T·f, x}
+ //
+ // Like walkclosure above.
+
+ if(isinter(n->left->type)) {
+ n->left = cheapexpr(n->left, init);
+ checknotnil(n->left, init);
}
- // New arg list for n. First the closure-args
- // and then the original parameter list.
- n->list = concat(n->left->enter, n->list);
- n->left = n->left->closure->nname;
- dowidth(n->left->type);
- n->type = getoutargx(n->left->type);
- // for a single valued function, pull the field type out of the struct
- if (n->type && n->type->type && !n->type->type->down)
- n->type = n->type->type->type;
+ typ = nod(OTSTRUCT, N, N);
+ typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
+ typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup("R")), typenod(n->left->type)));
+
+ clos = nod(OCOMPLIT, N, nod(OIND, typ, N));
+ clos->esc = n->esc;
+ clos->right->implicit = 1;
+ clos->list = list1(nod(OCFUNC, n->nname->nname, N));
+ clos->list = list(clos->list, n->left);
+
+ // Force type conversion from *struct to the func type.
+ clos = nod(OCONVNOP, clos, N);
+ clos->type = n->type;
+
+ typecheck(&clos, Erv);
+ // typecheck will insert a PTRLIT node under CONVNOP,
+ // tag it with escape analysis result.
+ clos->left->esc = n->esc;
+ walkexpr(&clos, init);
+
+ return clos;
}
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index 4f1ff6778..e9d99df18 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -119,6 +119,27 @@ convlit1(Node **np, Type *t, int explicit)
}
n->type = t;
return;
+ case OCOMPLEX:
+ if(n->type->etype == TIDEAL) {
+ switch(t->etype) {
+ default:
+ // If trying to convert to non-complex type,
+ // leave as complex128 and let typechecker complain.
+ t = types[TCOMPLEX128];
+ //fallthrough
+ case TCOMPLEX128:
+ n->type = t;
+ convlit(&n->left, types[TFLOAT64]);
+ convlit(&n->right, types[TFLOAT64]);
+ break;
+ case TCOMPLEX64:
+ n->type = t;
+ convlit(&n->left, types[TFLOAT32]);
+ convlit(&n->right, types[TFLOAT32]);
+ break;
+ }
+ }
+ return;
}
// avoided repeated calculations, errors
@@ -1068,6 +1089,11 @@ idealkind(Node *n)
return k1;
else
return k2;
+ case OREAL:
+ case OIMAG:
+ return CTFLT;
+ case OCOMPLEX:
+ return CTCPLX;
case OADDSTR:
return CTSTR;
case OANDAND:
@@ -1110,7 +1136,6 @@ defaultlit(Node **np, Type *t)
lno = setlineno(n);
ctype = idealkind(n);
- t1 = T;
switch(ctype) {
default:
if(t != T) {
@@ -1185,6 +1210,7 @@ void
defaultlit2(Node **lp, Node **rp, int force)
{
Node *l, *r;
+ int lkind, rkind;
l = *lp;
r = *rp;
@@ -1204,18 +1230,20 @@ defaultlit2(Node **lp, Node **rp, int force)
convlit(lp, types[TBOOL]);
convlit(rp, types[TBOOL]);
}
- if(isconst(l, CTCPLX) || isconst(r, CTCPLX)) {
+ lkind = idealkind(l);
+ rkind = idealkind(r);
+ if(lkind == CTCPLX || rkind == CTCPLX) {
convlit(lp, types[TCOMPLEX128]);
convlit(rp, types[TCOMPLEX128]);
return;
}
- if(isconst(l, CTFLT) || isconst(r, CTFLT)) {
+ if(lkind == CTFLT || rkind == CTFLT) {
convlit(lp, types[TFLOAT64]);
convlit(rp, types[TFLOAT64]);
return;
}
- if(isconst(l, CTRUNE) || isconst(r, CTRUNE)) {
+ if(lkind == CTRUNE || rkind == CTRUNE) {
convlit(lp, runetype);
convlit(rp, runetype);
return;
diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c
index e0127fc59..c9bab7a76 100644
--- a/src/cmd/gc/cplx.c
+++ b/src/cmd/gc/cplx.c
@@ -36,7 +36,7 @@ void
complexmove(Node *f, Node *t)
{
int ft, tt;
- Node n1, n2, n3, n4;
+ Node n1, n2, n3, n4, tmp;
if(debug['g']) {
dump("\ncomplexmove-f", f);
@@ -62,9 +62,9 @@ complexmove(Node *f, Node *t)
// make f addable.
// also use temporary if possible stack overlap.
if(!f->addable || overlap(f, t)) {
- tempname(&n1, f->type);
- complexmove(f, &n1);
- f = &n1;
+ tempname(&tmp, f->type);
+ complexmove(f, &tmp);
+ f = &tmp;
}
subnode(&n1, &n2, f);
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index aa2489d9a..d3759efde 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -225,8 +225,12 @@ declare(Node *n, int ctxt)
if(ctxt == PAUTO)
n->xoffset = 0;
- if(s->block == block)
- redeclare(s, "in this block");
+ if(s->block == block) {
+ // functype will print errors about duplicate function arguments.
+ // Don't repeat the error here.
+ if(ctxt != PPARAM && ctxt != PPARAMOUT)
+ redeclare(s, "in this block");
+ }
s->block = block;
s->lastlineno = parserline();
@@ -824,22 +828,24 @@ structfield(Node *n)
return f;
}
+static uint32 uniqgen;
+
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;
- }
+ for( ; t; t=t->down) {
+ if(t->sym && t->nname && !isblank(t->nname)) {
+ if(t->sym->uniqgen == uniqgen) {
+ lineno = t->nname->lineno;
+ yyerror("duplicate %s %s", what, t->sym->name);
+ } else
+ t->sym->uniqgen = uniqgen;
+ }
+ }
lineno = lno;
}
@@ -865,6 +871,7 @@ tostruct(NodeList *l)
if(f->broke)
t->broke = 1;
+ uniqgen++;
checkdupfields(t->type, "field");
if (!t->broke)
@@ -897,7 +904,6 @@ tofunargs(NodeList *l)
if(f->broke)
t->broke = 1;
- checkdupfields(t->type, "argument");
return t;
}
@@ -1004,6 +1010,7 @@ tointerface(NodeList *l)
if(f->broke)
t->broke = 1;
+ uniqgen++;
checkdupfields(t->type, "method");
t = sortinter(t);
checkwidth(t);
@@ -1187,6 +1194,11 @@ functype(Node *this, NodeList *in, NodeList *out)
t->type->down = tofunargs(out);
t->type->down->down = tofunargs(in);
+ uniqgen++;
+ checkdupfields(t->type->type, "argument");
+ checkdupfields(t->type->down->type, "argument");
+ checkdupfields(t->type->down->down->type, "argument");
+
if (t->type->broke || t->type->down->broke || t->type->down->down->broke)
t->broke = 1;
@@ -1327,6 +1339,8 @@ addmethod(Sym *sf, Type *t, int local, int nointerface)
f = methtype(pa, 1);
if(f == T) {
t = pa;
+ if(t == T) // rely on typecheck having complained before
+ return;
if(t != T) {
if(isptr[t->etype]) {
if(t->sym != S) {
@@ -1335,10 +1349,8 @@ addmethod(Sym *sf, Type *t, int local, int nointerface)
}
t = t->type;
}
- }
- if(t->broke) // rely on typecheck having complained before
- return;
- if(t != T) {
+ if(t->broke) // rely on typecheck having complained before
+ return;
if(t->sym == S) {
yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t);
return;
@@ -1368,6 +1380,12 @@ addmethod(Sym *sf, Type *t, int local, int nointerface)
}
}
+ if(local && !pa->local) {
+ // defining method on non-local type.
+ yyerror("cannot define new methods on non-local type %T", pa);
+ return;
+ }
+
n = nod(ODCLFIELD, newname(sf), N);
n->type = t;
@@ -1383,12 +1401,6 @@ addmethod(Sym *sf, Type *t, int local, int nointerface)
return;
}
- if(local && !pa->local) {
- // defining method on non-local type.
- yyerror("cannot define new methods on non-local type %T", pa);
- return;
- }
-
f = structfield(n);
f->nointerface = nointerface;
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
index 46c06d10e..df273e392 100644
--- a/src/cmd/gc/esc.c
+++ b/src/cmd/gc/esc.c
@@ -596,6 +596,14 @@ esc(EscState *e, Node *n)
// Contents make it to memory, lose track.
escassign(e, &e->theSink, n->left);
break;
+
+ case OCALLPART:
+ n->esc = EscNone; // until proven otherwise
+ e->noesc = list(e->noesc, n);
+ n->escloopdepth = e->loopdepth;
+ // Contents make it to memory, lose track.
+ escassign(e, &e->theSink, n->left);
+ break;
case OMAPLIT:
n->esc = EscNone; // until proven otherwise
@@ -667,6 +675,7 @@ escassign(EscState *e, Node *dst, Node *src)
case OCONVNOP:
case OMAPLIT:
case OSTRUCTLIT:
+ case OCALLPART:
break;
case ONAME:
@@ -713,6 +722,7 @@ escassign(EscState *e, Node *dst, Node *src)
case OMAKESLICE:
case ONEW:
case OCLOSURE:
+ case OCALLPART:
escflows(e, dst, src);
break;
@@ -1033,7 +1043,7 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
switch(src->op) {
case ONAME:
- if(src->class == PPARAM && leaks && src->esc != EscHeap) {
+ if(src->class == PPARAM && (leaks || dst->escloopdepth < 0) && src->esc != EscHeap) {
src->esc = EscScope;
if(debug['m'])
warnl(src->lineno, "leaking param: %hN", src);
@@ -1073,6 +1083,7 @@ escwalk(EscState *e, int level, Node *dst, Node *src)
case OMAPLIT:
case ONEW:
case OCLOSURE:
+ case OCALLPART:
if(leaks) {
src->esc = EscHeap;
if(debug['m'])
diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
index ab81e6c88..35f01a5c2 100644
--- a/src/cmd/gc/fmt.c
+++ b/src/cmd/gc/fmt.c
@@ -168,7 +168,7 @@ Lconv(Fmt *fp)
lno = a[i].incl->line - 1; // now print out start of this file
}
if(n == 0)
- fmtprint(fp, "<epoch>");
+ fmtprint(fp, "<unknown line number>");
return 0;
}
@@ -443,6 +443,9 @@ Zconv(Fmt *fp)
fmtrune(fp, '\\');
fmtrune(fp, r);
break;
+ case 0xFEFF: // BOM, basically disallowed in source code
+ fmtstrcpy(fp, "\\uFEFF");
+ break;
}
}
return 0;
@@ -630,7 +633,7 @@ typefmt(Fmt *fp, Type *t)
case TARRAY:
if(t->bound >= 0)
- return fmtprint(fp, "[%d]%T", (int)t->bound, t->type);
+ return fmtprint(fp, "[%lld]%T", t->bound, t->type);
if(t->bound == -100)
return fmtprint(fp, "[...]%T", t->type);
return fmtprint(fp, "[]%T", t->type);
@@ -1022,6 +1025,7 @@ static int opprec[] = {
[ODOTTYPE] = 8,
[ODOT] = 8,
[OXDOT] = 8,
+ [OCALLPART] = 8,
[OPLUS] = 7,
[ONOT] = 7,
@@ -1269,9 +1273,10 @@ exprfmt(Fmt *f, Node *n, int prec)
case ODOTPTR:
case ODOTINTER:
case ODOTMETH:
+ case OCALLPART:
exprfmt(f, n->left, nprec);
if(n->right == N || n->right->sym == S)
- fmtstrcpy(f, ".<nil>");
+ return fmtstrcpy(f, ".<nil>");
return fmtprint(f, ".%hhS", n->right->sym);
case ODOTTYPE:
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index 5f03d9476..955ec2c5b 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -491,6 +491,9 @@ gen(Node *n)
case ORETURN:
cgen_ret(n);
break;
+
+ case OCHECKNOTNIL:
+ checkref(n->left, 1);
}
ret:
@@ -807,7 +810,7 @@ cgen_slice(Node *n, Node *res)
if(n->op == OSLICEARR) {
if(!isptr[n->left->type->etype])
fatal("slicearr is supposed to work on pointer: %+N\n", n);
- checkref(n->left);
+ checkref(n->left, 0);
}
if(isnil(n->left)) {
@@ -833,7 +836,7 @@ cgen_slice(Node *n, Node *res)
* <0 is pointer to next field (+1)
*/
int
-dotoffset(Node *n, int *oary, Node **nn)
+dotoffset(Node *n, int64 *oary, Node **nn)
{
int i;
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index f86c152f2..48bcf0233 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -155,10 +155,10 @@ struct Type
Type* orig; // original type (type literal or predefined type)
int lineno;
- // TFUNCT
- uchar thistuple;
- uchar outtuple;
- uchar intuple;
+ // TFUNC
+ int thistuple;
+ int outtuple;
+ int intuple;
uchar outnamed;
Type* method;
@@ -252,9 +252,7 @@ struct Node
uchar embedded; // ODCLFIELD embedded type
uchar colas; // OAS resulting from :=
uchar diag; // already printed error about this
- uchar esc; // EscXXX
uchar noescape; // func arguments do not escape
- uchar funcdepth;
uchar builtin; // built-in name, like len or close
uchar walkdef;
uchar typecheck;
@@ -268,6 +266,9 @@ struct Node
uchar addrtaken; // address taken, even if not moved to heap
uchar dupok; // duplicate definitions ok (for func)
schar likely; // likeliness of if statement
+ uchar hasbreak; // has break statement
+ uint esc; // EscXXX
+ int funcdepth;
// most nodes
Type* type;
@@ -368,6 +369,7 @@ struct Sym
uchar sym; // huffman encoding in object file
Sym* link;
int32 npkg; // number of imported packages with this name
+ uint32 uniqgen;
// saved and restored by dcopy
Pkg* pkg;
@@ -392,6 +394,7 @@ struct Pkg
uchar imported; // export data of this package was parsed
char exported; // import line written in export data
char direct; // imported directly
+ char safe; // whether the package is marked as safe
};
typedef struct Iter Iter;
@@ -450,6 +453,7 @@ enum
OCALLFUNC, // f()
OCALLMETH, // t.Method()
OCALLINTER, // err.Error()
+ OCALLPART, // t.Method (without ())
OCAP, // cap
OCLOSE, // close
OCLOSURE, // f = func() { etc }
@@ -562,6 +566,7 @@ enum
OITAB, // itable word of an interface value.
OCLOSUREVAR, // variable reference at beginning of closure function
OCFUNC, // reference to c function pointer (not go func value)
+ OCHECKNOTNIL, // emit code to ensure pointer/interface not nil
// arch-specific registers
OREGISTER, // a register, such as AX.
@@ -987,7 +992,8 @@ Node* closurebody(NodeList *body);
void closurehdr(Node *ntype);
void typecheckclosure(Node *func, int top);
Node* walkclosure(Node *func, NodeList **init);
-void walkcallclosure(Node *n, NodeList **init);
+void typecheckpartialcall(Node*, Node*);
+Node* walkpartialcall(Node*, NodeList**);
/*
* const.c
@@ -1097,7 +1103,7 @@ void cgen_eface(Node* n, Node* res);
void cgen_slice(Node* n, Node* res);
void clearlabels(void);
void checklabels(void);
-int dotoffset(Node *n, int *oary, Node **nn);
+int dotoffset(Node *n, int64 *oary, Node **nn);
void gen(Node *n);
void genlist(NodeList *l);
Node* sysfunc(char *name);
@@ -1363,6 +1369,7 @@ Node* typecheck(Node **np, int top);
void typechecklist(NodeList *l, int top);
Node* typecheckdef(Node *n);
void copytype(Node *n, Type *t);
+void checkreturn(Node*);
void queuemethod(Node *n);
/*
@@ -1416,7 +1423,8 @@ EXTERN Node* nodfp;
int anyregalloc(void);
void betypeinit(void);
void bgen(Node *n, int true, int likely, Prog *to);
-void checkref(Node*);
+void checkref(Node *n, int force);
+void checknotnil(Node*, NodeList**);
void cgen(Node*, Node*);
void cgen_asop(Node *n);
void cgen_call(Node *n, int proc);
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 794961e8e..29cd37008 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -251,7 +251,8 @@ import_package:
} else if(strcmp(importpkg->name, $2->name) != 0)
yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, $2->name, importpkg->path);
importpkg->direct = 1;
-
+ importpkg->safe = curio.importsafe;
+
if(safemode && !curio.importsafe)
yyerror("cannot import unsafe package \"%Z\"", importpkg->path);
}
@@ -536,7 +537,10 @@ compound_stmt:
}
stmt_list '}'
{
- $$ = liststmt($3);
+ if($3 == nil)
+ $$ = nod(OEMPTY, N, N);
+ else
+ $$ = liststmt($3);
popdcl();
}
diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c
index 1cc13a304..f77b51d70 100644
--- a/src/cmd/gc/inl.c
+++ b/src/cmd/gc/inl.c
@@ -188,6 +188,7 @@ ishairy(Node *n, int *budget)
break;
case OCLOSURE:
+ case OCALLPART:
case ORANGE:
case OFOR:
case OSELECT:
@@ -357,7 +358,7 @@ inlnode(Node **np)
}
case OCLOSURE:
- // TODO do them here (or earlier) instead of in walkcallclosure,
+ // TODO do them here (or earlier),
// so escape analysis can avoid more heapmoves.
return;
}
@@ -565,24 +566,31 @@ mkinlcall1(Node **np, Node *fn, int isddd)
inlretvars = nil;
i = 0;
// Make temp names to use instead of the originals
- for(ll = dcl; ll; ll=ll->next)
+ for(ll = dcl; ll; ll=ll->next) {
+ if(ll->n->class == PPARAMOUT) // return values handled below.
+ continue;
if(ll->n->op == ONAME) {
ll->n->inlvar = inlvar(ll->n);
// Typecheck because inlvar is not necessarily a function parameter.
typecheck(&ll->n->inlvar, Erv);
if ((ll->n->class&~PHEAP) != PAUTO)
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) {
+ // temporaries for return values.
+ for(t = getoutargx(fn->type)->type; t; t = t->down) {
+ if(t != T && t->nname != N && !isblank(t->nname)) {
+ m = inlvar(t->nname);
+ typecheck(&m, Erv);
+ t->nname->inlvar = m;
+ } else {
+ // anonymous return values, synthesize names for use in assignment that replaces return
m = retvar(t, i++);
- ninit = list(ninit, nod(ODCL, m, N));
- inlretvars = list(inlretvars, m);
}
+ ninit = list(ninit, nod(ODCL, m, N));
+ inlretvars = list(inlretvars, m);
+ }
// assign receiver.
if(fn->type->thistuple && n->left->op == ODOTMETH) {
@@ -790,6 +798,12 @@ inlvar(Node *var)
n->class = PAUTO;
n->used = 1;
n->curfn = curfn; // the calling function, not the called one
+
+ // esc pass wont run if we're inlining into a iface wrapper
+ // luckily, we can steal the results from the target func
+ if(var->esc == EscHeap)
+ addrescapes(n);
+
curfn->dcl = list(curfn->dcl, n);
return n;
}
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 68ae6864d..b7f71d553 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -376,6 +376,7 @@ main(int argc, char *argv[])
curfn = l->n;
saveerrors();
typechecklist(l->n->nbody, Etop);
+ checkreturn(l->n);
if(nerrors != 0)
l->n->nbody = nil; // type errors; do not compile
}
@@ -601,7 +602,7 @@ void
importfile(Val *f, int line)
{
Biobuf *imp;
- char *file, *p, *q;
+ char *file, *p, *q, *tag;
int32 c;
int len;
Strlit *path;
@@ -609,8 +610,6 @@ importfile(Val *f, int line)
USED(line);
- // TODO(rsc): don't bother reloading imports more than once?
-
if(f->ctype != CTSTR) {
yyerror("import statement not a string");
fakeimport();
@@ -685,7 +684,11 @@ importfile(Val *f, int line)
// to the lexer to avoid parsing export data twice.
if(importpkg->imported) {
file = strdup(namebuf);
- p = smprint("package %s\n$$\n", importpkg->name);
+ tag = "";
+ if(importpkg->safe) {
+ tag = "safe";
+ }
+ p = smprint("package %s %s\n$$\n", importpkg->name, tag);
cannedimports(file, p);
return;
}
diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin
index 2f76e6f06..1dab1c9a0 100755
--- a/src/cmd/gc/mkbuiltin
+++ b/src/cmd/gc/mkbuiltin
@@ -19,6 +19,7 @@ fi
GC=${GOCHAR}g
gcc -o mkbuiltin1 mkbuiltin1.c
rm -f _builtin.c
+echo "// AUTO-GENERATED by mkbuiltin; DO NOT EDIT" >>_builtin.c
for i in runtime unsafe
do
go tool $GC -A $i.go
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index b87d35b7b..e4bcd1170 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -16,6 +16,8 @@ static void dumpglobls(void);
void
dumpobj(void)
{
+ NodeList *externs, *tmp;
+
bout = Bopen(outfile, OWRITE);
if(bout == nil) {
flusherrors();
@@ -31,8 +33,20 @@ dumpobj(void)
outhist(bout);
+ externs = nil;
+ if(externdcl != nil)
+ externs = externdcl->end;
+
dumpglobls();
dumptypestructs();
+
+ // Dump extra globals.
+ tmp = externdcl;
+ if(externs != nil)
+ externdcl = externs->next;
+ dumpglobls();
+ externdcl = tmp;
+
dumpdata();
dumpfuncs();
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
index df8903baf..82d8186b0 100644
--- a/src/cmd/gc/pgen.c
+++ b/src/cmd/gc/pgen.c
@@ -177,8 +177,13 @@ cmpstackvar(Node *a, Node *b)
{
if (a->class != b->class)
return (a->class == PAUTO) ? 1 : -1;
- if (a->class != PAUTO)
- return a->xoffset - b->xoffset;
+ if (a->class != PAUTO) {
+ if (a->xoffset < b->xoffset)
+ return -1;
+ if (a->xoffset > b->xoffset)
+ return 1;
+ return 0;
+ }
if ((a->used == 0) != (b->used == 0))
return b->used - a->used;
return b->type->align - a->type->align;
@@ -240,6 +245,10 @@ allocauto(Prog* ptxt)
stksize = rnd(stksize, n->type->align);
if(thechar == '5')
stksize = rnd(stksize, widthptr);
+ if(stksize >= (1ULL<<31)) {
+ setlineno(curfn);
+ yyerror("stack frame too large (>2GB)");
+ }
n->stkdelta = -stksize - n->xoffset;
}
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
index bae98ec1b..5d4f62e76 100644
--- a/src/cmd/gc/racewalk.c
+++ b/src/cmd/gc/racewalk.c
@@ -26,6 +26,7 @@ static Node* uintptraddr(Node *n);
static Node* basenod(Node *n);
static void foreach(Node *n, void(*f)(Node*, void*), void *c);
static void hascallspred(Node *n, void *c);
+static void appendinit(Node **np, NodeList *init);
static Node* detachexpr(Node *n, NodeList **init);
// Do not instrument the following packages at all,
@@ -132,14 +133,13 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
case OASOP:
case OAS:
case OAS2:
- case OAS2DOTTYPE:
case OAS2RECV:
case OAS2FUNC:
case OAS2MAPR:
racewalknode(&n->left, init, 1, 0);
racewalknode(&n->right, init, 0, 0);
goto ret;
-
+
case OCFUNC:
// can't matter
goto ret;
@@ -185,17 +185,12 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
racewalknode(&n->left, init, 0, 0);
goto ret;
- case OSWITCH:
- if(n->ntest->op == OTYPESW)
- // TODO(dvyukov): the expression can contain calls or reads.
- return;
- goto ret;
-
case ONOT:
case OMINUS:
case OPLUS:
case OREAL:
case OIMAG:
+ case OCOM:
racewalknode(&n->left, init, wr, 0);
goto ret;
@@ -222,29 +217,24 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
case OCAP:
racewalknode(&n->left, init, 0, 0);
if(istype(n->left->type, TMAP)) {
- // crashes on len(m[0]) or len(f())
- SET(n1);
- USED(n1);
- /*
- n1 = nod(OADDR, n->left, N);
- n1 = conv(n1, types[TUNSAFEPTR]);
- n1 = conv(n1, ptrto(ptrto(types[TINT8])));
- n1 = nod(OIND, n1, N);
+ n1 = nod(OCONVNOP, n->left, N);
+ n1->type = ptrto(types[TUINT8]);
n1 = nod(OIND, n1, N);
typecheck(&n1, Erv);
callinstr(&n1, init, 0, skip);
- */
}
goto ret;
case OLSH:
case ORSH:
+ case OLROT:
case OAND:
case OANDNOT:
case OOR:
case OXOR:
case OSUB:
case OMUL:
+ case OHMUL:
case OEQ:
case ONE:
case OLT:
@@ -260,9 +250,13 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
case OANDAND:
case OOROR:
racewalknode(&n->left, init, wr, 0);
- // It requires more complex tree transformation,
- // because we don't know whether it will be executed or not.
- //racewalknode(&n->right, init, wr, 0);
+ // walk has ensured the node has moved to a location where
+ // side effects are safe.
+ // n->right may not be executed,
+ // so instrumentation goes to n->right->ninit, not init.
+ l = nil;
+ racewalknode(&n->right, &l, wr, 0);
+ appendinit(&n->right, l);
goto ret;
case ONAME:
@@ -279,7 +273,6 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
case ODIV:
case OMOD:
- // TODO(dvyukov): add a test for this
racewalknode(&n->left, init, wr, 0);
racewalknode(&n->right, init, wr, 0);
goto ret;
@@ -313,6 +306,14 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
racewalknode(&n->right, init, 0, 0);
goto ret;
+ case OITAB:
+ racewalknode(&n->left, init, 0, 0);
+ goto ret;
+
+ case OTYPESW:
+ racewalknode(&n->right, init, 0, 0);
+ goto ret;
+
// should not appear in AST by now
case OSEND:
case ORECV:
@@ -324,67 +325,69 @@ racewalknode(Node **np, NodeList **init, int wr, int skip)
case OPANIC:
case ORECOVER:
case OCONVIFACE:
+ case OCMPIFACE:
+ case OMAKECHAN:
+ case OMAKEMAP:
+ case OMAKESLICE:
+ case OCALL:
+ case OCOPY:
+ case OAPPEND:
+ case ORUNESTR:
+ case OARRAYBYTESTR:
+ case OARRAYRUNESTR:
+ case OSTRARRAYBYTE:
+ case OSTRARRAYRUNE:
+ case OINDEXMAP: // lowered to call
+ case OCMPSTR:
+ case OADDSTR:
+ case ODOTTYPE:
+ case ODOTTYPE2:
+ case OAS2DOTTYPE:
+ case OCALLPART: // lowered to PTRLIT
+ case OCLOSURE: // lowered to PTRLIT
+ case ORANGE: // lowered to ordinary for loop
+ case OARRAYLIT: // lowered to assignments
+ case OMAPLIT:
+ case OSTRUCTLIT:
yyerror("racewalk: %O must be lowered by now", n->op);
goto ret;
+ // impossible nodes: only appear in backend.
+ case ORROTC:
+ case OEXTEND:
+ yyerror("racewalk: %O cannot exist now", n->op);
+ goto ret;
+
// just do generic traversal
case OFOR:
case OIF:
case OCALLMETH:
case ORETURN:
+ case OSWITCH:
case OSELECT:
case OEMPTY:
+ case OBREAK:
+ case OCONTINUE:
+ case OFALL:
+ case OGOTO:
+ case OLABEL:
goto ret;
// does not require instrumentation
- case OINDEXMAP: // implemented in runtime
case OPRINT: // don't bother instrumenting it
case OPRINTN: // don't bother instrumenting it
+ case OCHECKNOTNIL: // always followed by a read.
case OPARAM: // it appears only in fn->exit to copy heap params back
- goto ret;
-
- // unimplemented
- case OCMPSTR:
- case OADDSTR:
- case OSLICESTR:
- case OAPPEND:
- case OCOPY:
- case OMAKECHAN:
- case OMAKEMAP:
- case OMAKESLICE:
- case ORUNESTR:
- case OARRAYBYTESTR:
- case OARRAYRUNESTR:
- case OSTRARRAYBYTE:
- case OSTRARRAYRUNE:
- case OCMPIFACE:
- case OARRAYLIT:
- case OMAPLIT:
- case OSTRUCTLIT:
- case OCLOSURE:
- case ODOTTYPE:
- case ODOTTYPE2:
- case OCALL:
- case OBREAK:
- case ODCL:
- case OCONTINUE:
- case OFALL:
- case OGOTO:
- case OLABEL:
+ case OCLOSUREVAR:// immutable pointer to captured variable
+ case ODOTMETH: // either part of CALLMETH or CALLPART (lowered to PTRLIT)
+ case OINDREG: // at this stage, only n(SP) nodes from nodarg
+ case ODCL: // declarations (without value) cannot be races
case ODCLCONST:
case ODCLTYPE:
- case OLITERAL:
- case ORANGE:
case OTYPE:
case ONONAME:
- case OINDREG:
- case OCOM:
- case ODOTMETH:
- case OITAB:
- case OEXTEND:
- case OHMUL:
- case OLROT:
- case ORROTC:
+ case OLITERAL:
+ case OSLICESTR: // always preceded by bounds checking, avoid double instrumentation.
goto ret;
}
@@ -400,7 +403,6 @@ ret:
racewalklist(n->nbody, nil);
racewalklist(n->nelse, nil);
racewalklist(n->rlist, nil);
-
*np = n;
}
@@ -442,6 +444,7 @@ callinstr(Node **np, NodeList **init, int wr, int skip)
if(isartificial(n))
return 0;
if(t->etype == TSTRUCT) {
+ // TODO: instrument arrays similarly.
// PARAMs w/o PHEAP are not interesting.
if(n->class == PPARAM || n->class == PPARAMOUT)
return 0;
@@ -478,7 +481,7 @@ callinstr(Node **np, NodeList **init, int wr, int skip)
// that has got a pointer inside. Whether it points to
// the heap or not is impossible to know at compile time
if((class&PHEAP) || class == PPARAMREF || class == PEXTERN
- || b->type->etype == TARRAY || b->op == ODOTPTR || b->op == OIND || b->op == OXDOT) {
+ || b->op == OINDEX || b->op == ODOTPTR || b->op == OIND || b->op == OXDOT) {
hascalls = 0;
foreach(n, hascallspred, &hascalls);
if(hascalls) {
@@ -504,6 +507,8 @@ uintptraddr(Node *n)
return r;
}
+// basenod returns the simplest child node of n pointing to the same
+// memory area.
static Node*
basenod(Node *n)
{
@@ -512,7 +517,7 @@ basenod(Node *n)
n = n->left;
continue;
}
- if(n->op == OINDEX) {
+ if(n->op == OINDEX && isfixedarray(n->type)) {
n = n->left;
continue;
}
@@ -577,3 +582,30 @@ hascallspred(Node *n, void *c)
(*(int*)c)++;
}
}
+
+// appendinit is like addinit in subr.c
+// but appends rather than prepends.
+static void
+appendinit(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(n->ninit, init);
+ n->ullman = UINF;
+}
+
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
index 50c4617c0..8af45b9d2 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -181,9 +181,9 @@ walkrange(Node *n)
case TMAP:
th = typ(TARRAY);
th->type = ptrto(types[TUINT8]);
- // see ../../pkg/runtime/hashmap.h:/hash_iter
- // Size in words.
- th->bound = 5 + 4*3 + 4*4/widthptr;
+ // see ../../pkg/runtime/hashmap.c:/hash_iter
+ // Size of hash_iter in # of pointers.
+ th->bound = 11;
hit = temp(th);
fn = syslook("mapiterinit", 1);
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index b8eb79938..fc182b03e 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -1026,13 +1026,29 @@ dalgsym(Type *t)
}
static int
+gcinline(Type *t) {
+ switch(t->etype) {
+ case TARRAY:
+ if(t->bound == 1)
+ return 1;
+ if(t->width <= 4*widthptr)
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+static int
dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size)
{
Type *t1;
- vlong o, off2, fieldoffset;
+ vlong o, off2, fieldoffset, i;
if(t->align > 0 && (*off % t->align) != 0)
fatal("dgcsym1: invalid initial alignment, %T", t);
+
+ if(t->width == BADWIDTH)
+ dowidth(t);
switch(t->etype) {
case TINT8:
@@ -1056,6 +1072,7 @@ dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size)
case TPTR32:
case TPTR64:
+ // NOTE: Any changes here need to be made to reflect.PtrTo as well.
if(*off % widthptr != 0)
fatal("dgcsym1: invalid alignment, %T", t);
if(!haspointers(t->type) || t->type->etype == TUINT8) {
@@ -1069,7 +1086,6 @@ dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size)
*off += t->width;
break;
- case TCHAN:
case TUNSAFEPTR:
case TFUNC:
if(*off % widthptr != 0)
@@ -1079,8 +1095,20 @@ dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size)
*off += t->width;
break;
+ // struct Hchan*
+ case TCHAN:
+ // NOTE: Any changes here need to be made to reflect.ChanOf as well.
+ if(*off % widthptr != 0)
+ fatal("dgcsym1: invalid alignment, %T", t);
+ ot = duintptr(s, ot, GC_CHAN_PTR);
+ ot = duintptr(s, ot, *off);
+ ot = dsymptr(s, ot, dtypesym(t), 0);
+ *off += t->width;
+ break;
+
// struct Hmap*
case TMAP:
+ // NOTE: Any changes here need to be made to reflect.MapOf as well.
if(*off % widthptr != 0)
fatal("dgcsym1: invalid alignment, %T", t);
ot = duintptr(s, ot, GC_MAP_PTR);
@@ -1116,7 +1144,10 @@ dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size)
case TARRAY:
if(t->bound < -1)
fatal("dgcsym1: invalid bound, %T", t);
+ if(t->type->width == BADWIDTH)
+ dowidth(t->type);
if(isslice(t)) {
+ // NOTE: Any changes here need to be made to reflect.SliceOf as well.
// struct { byte* array; uint32 len; uint32 cap; }
if(*off % widthptr != 0)
fatal("dgcsym1: invalid alignment, %T", t);
@@ -1130,10 +1161,14 @@ dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size)
}
*off += t->width;
} else {
+ // NOTE: Any changes here need to be made to reflect.ArrayOf as well,
+ // at least once ArrayOf's gc info is implemented and ArrayOf is exported.
+ // struct { byte* array; uint32 len; uint32 cap; }
if(t->bound < 1 || !haspointers(t->type)) {
*off += t->width;
- } else if(t->bound == 1) {
- ot = dgcsym1(s, ot, t->type, off, stack_size); // recursive call of dgcsym1
+ } else if(gcinline(t)) {
+ for(i=0; i<t->bound; i++)
+ ot = dgcsym1(s, ot, t->type, off, stack_size); // recursive call of dgcsym1
} else {
if(stack_size < GC_STACK_CAPACITY) {
ot = duintptr(s, ot, GC_ARRAY_START); // a stack push during GC
@@ -1184,6 +1219,9 @@ dgcsym(Type *t)
return s;
s->flags |= SymGcgen;
+ if(t->width == BADWIDTH)
+ dowidth(t);
+
ot = 0;
off = 0;
ot = duintptr(s, ot, t->width);
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index c49d05c5c..2139a95d9 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -89,7 +89,13 @@ 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)
+func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapaccess1_faststr(mapType *byte, hmap map[any]any, key any) (val *any)
func mapaccess2(mapType *byte, hmap map[any]any, key any) (val any, pres bool)
+func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
+func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
+func mapaccess2_faststr(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 mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
func mapdelete(mapType *byte, hmap map[any]any, key any)
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 353fc00ce..f8c61828c 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -801,7 +801,8 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init)
{
Node *r, *a;
NodeList *l;
- int nerr, b;
+ int nerr;
+ int64 b;
Type *t, *tk, *tv, *t1;
Node *vstat, *index, *value;
Sym *syma, *symb;
@@ -1142,7 +1143,10 @@ stataddr(Node *nam, Node *n)
l = getlit(n->right);
if(l < 0)
break;
- nam->xoffset += l*n->type->width;
+ // Check for overflow.
+ if(n->type->width != 0 && MAXWIDTH/n->type->width <= l)
+ break;
+ nam->xoffset += l*n->type->width;
nam->type = n->type;
return 1;
}
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index c53eaf285..20a15bc71 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -548,6 +548,12 @@ algtype1(Type *t, Type **bad)
*bad = T;
switch(t->etype) {
+ case TANY:
+ case TFORW:
+ // will be defined later.
+ *bad = t;
+ return -1;
+
case TINT8:
case TUINT8:
case TINT16:
@@ -665,11 +671,14 @@ Type*
maptype(Type *key, Type *val)
{
Type *t;
+ Type *bad;
+ int atype;
if(key != nil) {
- switch(key->etype) {
+ atype = algtype1(key, &bad);
+ switch(bad == T ? key->etype : bad->etype) {
default:
- if(algtype1(key, nil) == ANOEQ)
+ if(atype == ANOEQ)
yyerror("invalid map key type %T", key);
break;
case TANY:
@@ -714,6 +723,12 @@ methcmp(const void *va, const void *vb)
a = *(Type**)va;
b = *(Type**)vb;
+ if(a->sym == S && b->sym == S)
+ return 0;
+ if(a->sym == S)
+ return -1;
+ if(b->sym == S)
+ return 1;
i = strcmp(a->sym->name, b->sym->name);
if(i != 0)
return i;
@@ -824,7 +839,7 @@ Type*
aindex(Node *b, Type *t)
{
Type *r;
- int bound;
+ int64 bound;
bound = -1; // open bound
typecheck(&b, Erv);
@@ -1393,7 +1408,7 @@ assignconv(Node *n, Type *t, char *context)
Node *r, *old;
char *why;
- if(n == N || n->type == T)
+ if(n == N || n->type == T || n->type->broke)
return n;
old = n;
@@ -1759,6 +1774,13 @@ ullmancalc(Node *n)
case OCALLINTER:
ul = UINF;
goto out;
+ case OANDAND:
+ case OOROR:
+ // hard with race detector
+ if(flag_race) {
+ ul = UINF;
+ goto out;
+ }
}
ul = 1;
if(n->left != N)
@@ -1772,6 +1794,8 @@ ullmancalc(Node *n)
ul = ur;
out:
+ if(ul > 200)
+ ul = 200; // clamp to uchar with room to grow
n->ullman = ul;
}
@@ -2096,7 +2120,7 @@ localexpr(Node *n, Type *t, NodeList **init)
void
setmaxarg(Type *t)
{
- int32 w;
+ int64 w;
dowidth(t);
w = t->argwid;
@@ -2565,6 +2589,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
fn->dupok = 1;
typecheck(&fn, Etop);
typechecklist(fn->nbody, Etop);
+ inlcalls(fn);
curfn = nil;
funccompile(fn, 0);
}
@@ -3273,11 +3298,14 @@ liststmt(NodeList *l)
int
count(NodeList *l)
{
- int n;
+ vlong n;
n = 0;
for(; l; l=l->next)
n++;
+ if((int)n != n) { // Overflow.
+ yyerror("too many elements in list");
+ }
return n;
}
@@ -3722,3 +3750,17 @@ isbadimport(Strlit *path)
}
return 0;
}
+
+void
+checknotnil(Node *x, NodeList **init)
+{
+ Node *n;
+
+ if(isinter(x->type)) {
+ x = nod(OITAB, x, N);
+ typecheck(&x, Erv);
+ }
+ n = nod(OCHECKNOTNIL, x, N);
+ n->typecheck = 1;
+ *init = list(*init, n);
+}
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
index a497b8622..3ad5f02a5 100644
--- a/src/cmd/gc/swt.c
+++ b/src/cmd/gc/swt.c
@@ -322,6 +322,10 @@ casebody(Node *sw, Node *typeswvar)
setlineno(last);
yyerror("cannot fallthrough in type switch");
}
+ if(l->next == nil) {
+ setlineno(last);
+ yyerror("cannot fallthrough final case in switch");
+ }
last->op = OFALL;
} else
stat = list(stat, br);
@@ -354,6 +358,8 @@ mkcaselist(Node *sw, int arg)
c = c1;
ord++;
+ if((uint16)ord != ord)
+ fatal("too many cases in switch");
c->ordinal = ord;
c->node = n;
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index fbab85d03..40eecd337 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -276,6 +276,29 @@ callrecvlist(NodeList *l)
return 0;
}
+// indexlit implements typechecking of untyped values as
+// array/slice indexes. It is equivalent to defaultlit
+// except for constants of numerical kind, which are acceptable
+// whenever they can be represented by a value of type int.
+static void
+indexlit(Node **np)
+{
+ Node *n;
+
+ n = *np;
+ if(n == N || !isideal(n->type))
+ return;
+ switch(consttype(n)) {
+ case CTINT:
+ case CTRUNE:
+ case CTFLT:
+ case CTCPLX:
+ defaultlit(np, types[TINT]);
+ break;
+ }
+ defaultlit(np, T);
+}
+
static void
typecheck1(Node **np, int top)
{
@@ -732,6 +755,7 @@ reswitch:
yyerror("rhs of . must be a name"); // impossible
goto error;
}
+ r = n->right;
if(n->left->op == OTYPE) {
if(!looktypedot(n, t, 0)) {
@@ -775,7 +799,12 @@ reswitch:
switch(n->op) {
case ODOTINTER:
case ODOTMETH:
- ok |= Ecall;
+ if(top&Ecall)
+ ok |= Ecall;
+ else {
+ typecheckpartialcall(n, r);
+ ok |= Erv;
+ }
break;
default:
ok |= Erv;
@@ -839,7 +868,7 @@ reswitch:
case TSTRING:
case TARRAY:
- defaultlit(&n->right, T);
+ indexlit(&n->right);
if(t->etype == TSTRING)
n->type = types[TUINT8];
else
@@ -855,8 +884,8 @@ reswitch:
yyerror("non-integer %s index %N", why, n->right);
break;
}
- if(n->right->op == OLITERAL) {
- if(mpgetfix(n->right->val.u.xval) < 0)
+ if(isconst(n->right, CTINT)) {
+ if(mpgetfix(n->right->val.u.xval) < 0)
yyerror("invalid %s index %N (index must be non-negative)", why, n->right);
else if(isfixedarray(t) && t->bound > 0 && mpgetfix(n->right->val.u.xval) >= t->bound)
yyerror("invalid array index %N (out of bounds for %d-element array)", n->right, t->bound);
@@ -932,8 +961,8 @@ reswitch:
typecheck(&n->right->left, Erv);
typecheck(&n->right->right, Erv);
defaultlit(&n->left, T);
- defaultlit(&n->right->left, T);
- defaultlit(&n->right->right, T);
+ indexlit(&n->right->left);
+ indexlit(&n->right->right);
l = n->left;
if(isfixedarray(l->type)) {
if(!islvalue(n->left)) {
@@ -1180,16 +1209,18 @@ reswitch:
if(l->type == T || r->type == T)
goto error;
defaultlit2(&l, &r, 0);
+ if(l->type == T || r->type == T)
+ goto error;
n->left = l;
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);
+ if(!eqtype(l->type, r->type)) {
+ yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
goto error;
}
switch(l->type->etype) {
default:
- goto badcmplx;
+ yyerror("invalid operation: %N (arguments have type %T, expected floating-point)", n, l->type, r->type);
+ goto error;
case TIDEAL:
t = types[TIDEAL];
break;
@@ -1692,10 +1723,6 @@ ret:
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);
- goto error;
- }
// TODO(rsc): simplify
if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
yyerror("%N used as value", n);
@@ -2323,7 +2350,8 @@ pushtype(Node *n, Type *t)
static void
typecheckcomplit(Node **np)
{
- int bad, i, len, nerr;
+ int bad, i, nerr;
+ int64 len;
Node *l, *n, *norig, *r, **hash;
NodeList *ll;
Type *t, *f;
@@ -2558,6 +2586,7 @@ islvalue(Node *n)
// fall through
case OIND:
case ODOTPTR:
+ case OCLOSUREVAR:
return 1;
case ODOT:
return islvalue(n->left);
@@ -3144,3 +3173,148 @@ checkmake(Type *t, char *arg, Node *n)
}
return 0;
}
+
+static void markbreaklist(NodeList*, Node*);
+
+static void
+markbreak(Node *n, Node *implicit)
+{
+ Label *lab;
+
+ if(n == N)
+ return;
+
+ switch(n->op) {
+ case OBREAK:
+ if(n->left == N) {
+ if(implicit)
+ implicit->hasbreak = 1;
+ } else {
+ lab = n->left->sym->label;
+ if(lab != L)
+ lab->def->hasbreak = 1;
+ }
+ break;
+
+ case OFOR:
+ case OSWITCH:
+ case OTYPESW:
+ case OSELECT:
+ case ORANGE:
+ implicit = n;
+ // fall through
+
+ default:
+ markbreak(n->left, implicit);
+ markbreak(n->right, implicit);
+ markbreak(n->ntest, implicit);
+ markbreak(n->nincr, implicit);
+ markbreaklist(n->ninit, implicit);
+ markbreaklist(n->nbody, implicit);
+ markbreaklist(n->nelse, implicit);
+ markbreaklist(n->list, implicit);
+ markbreaklist(n->rlist, implicit);
+ break;
+ }
+}
+
+static void
+markbreaklist(NodeList *l, Node *implicit)
+{
+ Node *n;
+ Label *lab;
+
+ for(; l; l=l->next) {
+ n = l->n;
+ if(n->op == OLABEL && l->next && n->defn == l->next->n) {
+ switch(n->defn->op) {
+ case OFOR:
+ case OSWITCH:
+ case OTYPESW:
+ case OSELECT:
+ case ORANGE:
+ lab = mal(sizeof *lab);
+ lab->def = n->defn;
+ n->left->sym->label = lab;
+ markbreak(n->defn, n->defn);
+ n->left->sym->label = L;
+ l = l->next;
+ continue;
+ }
+ }
+ markbreak(n, implicit);
+ }
+}
+
+static int
+isterminating(NodeList *l, int top)
+{
+ int def;
+ Node *n;
+
+ if(l == nil)
+ return 0;
+ if(top) {
+ while(l->next && l->n->op != OLABEL)
+ l = l->next;
+ markbreaklist(l, nil);
+ }
+ while(l->next)
+ l = l->next;
+ n = l->n;
+
+ if(n == N)
+ return 0;
+
+ switch(n->op) {
+ // NOTE: OLABEL is treated as a separate statement,
+ // not a separate prefix, so skipping to the last statement
+ // in the block handles the labeled statement case by
+ // skipping over the label. No case OLABEL here.
+
+ case OBLOCK:
+ return isterminating(n->list, 0);
+
+ case OGOTO:
+ case ORETURN:
+ case OPANIC:
+ case OXFALL:
+ return 1;
+
+ case OFOR:
+ if(n->ntest != N)
+ return 0;
+ if(n->hasbreak)
+ return 0;
+ return 1;
+
+ case OIF:
+ return isterminating(n->nbody, 0) && isterminating(n->nelse, 0);
+
+ case OSWITCH:
+ case OTYPESW:
+ case OSELECT:
+ if(n->hasbreak)
+ return 0;
+ def = 0;
+ for(l=n->list; l; l=l->next) {
+ if(!isterminating(l->n->nbody, 0))
+ return 0;
+ if(l->n->list == nil) // default
+ def = 1;
+ }
+ if(n->op != OSELECT && !def)
+ return 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+checkreturn(Node *fn)
+{
+ if(fn->type->outtuple && fn->nbody != nil)
+ if(!isterminating(fn->nbody, 1))
+ yyerrorl(fn->endlineno, "missing return at end of function");
+}
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
index 95200ad41..ff08c0eef 100644
--- a/src/cmd/gc/unsafe.c
+++ b/src/cmd/gc/unsafe.c
@@ -16,10 +16,10 @@
Node*
unsafenmagic(Node *nn)
{
- Node *r, *n;
+ Node *r, *n, *base, *r1;
Sym *s;
Type *t, *tr;
- long v;
+ vlong v;
Val val;
Node *fn;
NodeList *args;
@@ -49,11 +49,43 @@ unsafenmagic(Node *nn)
goto yes;
}
if(strcmp(s->name, "Offsetof") == 0) {
- typecheck(&r, Erv);
- if(r->op != ODOT && r->op != ODOTPTR)
+ // must be a selector.
+ if(r->op != OXDOT)
goto bad;
+ // Remember base of selector to find it back after dot insertion.
+ // Since r->left may be mutated by typechecking, check it explicitly
+ // first to track it correctly.
+ typecheck(&r->left, Erv);
+ base = r->left;
typecheck(&r, Erv);
- v = r->xoffset;
+ switch(r->op) {
+ case ODOT:
+ case ODOTPTR:
+ break;
+ case OCALLPART:
+ yyerror("invalid expression %N: argument is a method value", nn);
+ v = 0;
+ goto ret;
+ default:
+ goto bad;
+ }
+ v = 0;
+ // add offsets for inserted dots.
+ for(r1=r; r1->left!=base; r1=r1->left) {
+ switch(r1->op) {
+ case ODOT:
+ v += r1->xoffset;
+ break;
+ case ODOTPTR:
+ yyerror("invalid expression %N: selector implies indirection of embedded %N", nn, r1->left);
+ goto ret;
+ default:
+ dump("unsafenmagic", r);
+ fatal("impossible %#O node after dot insertion", r1->op);
+ goto bad;
+ }
+ }
+ v += r1->xoffset;
goto yes;
}
if(strcmp(s->name, "Alignof") == 0) {
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index de2105ed3..d9c6341b4 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -29,40 +29,6 @@ static void walkdiv(Node**, NodeList**);
static int bounded(Node*, int64);
static Mpint mpzero;
-// can this code branch reach the end
-// without an unconditional RETURN
-// this is hard, so it is conservative
-static int
-walkret(NodeList *l)
-{
- Node *n;
-
-loop:
- while(l && l->next)
- l = l->next;
- if(l == nil)
- return 1;
-
- // at this point, we have the last
- // statement of the function
- n = l->n;
- switch(n->op) {
- case OBLOCK:
- l = n->list;
- goto loop;
-
- case OGOTO:
- case ORETURN:
- case OPANIC:
- return 0;
- break;
- }
-
- // all other statements
- // will flow to the end
- return 1;
-}
-
void
walk(Node *fn)
{
@@ -76,9 +42,6 @@ walk(Node *fn)
snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym);
dumplist(s, curfn->nbody);
}
- if(curfn->type->outtuple)
- if(walkret(curfn->nbody))
- yyerror("function ends without a return statement");
lno = lineno;
@@ -221,6 +184,7 @@ walkstmt(Node **np)
case OLABEL:
case ODCLCONST:
case ODCLTYPE:
+ case OCHECKNOTNIL:
break;
case OBLOCK:
@@ -433,13 +397,28 @@ walkexpr(Node **np, NodeList **init)
case OIMAG:
case ODOTMETH:
case ODOTINTER:
+ walkexpr(&n->left, init);
+ goto ret;
+
case OIND:
+ if(n->left->type->type->width == 0) {
+ n->left = cheapexpr(n->left, init);
+ checknotnil(n->left, init);
+ }
walkexpr(&n->left, init);
goto ret;
case ODOT:
+ usefield(n);
+ walkexpr(&n->left, init);
+ goto ret;
+
case ODOTPTR:
usefield(n);
+ if(n->op == ODOTPTR && n->left->type->type->width == 0) {
+ n->left = cheapexpr(n->left, init);
+ checknotnil(n->left, init);
+ }
walkexpr(&n->left, init);
goto ret;
@@ -561,13 +540,6 @@ walkexpr(Node **np, NodeList **init)
if(n->list && n->list->n->op == OAS)
goto ret;
- /*
- if(n->left->op == OCLOSURE) {
- walkcallclosure(n, init);
- t = n->left->type;
- }
- */
-
walkexpr(&n->left, init);
walkexprlist(n->list, init);
@@ -673,8 +645,48 @@ walkexpr(Node **np, NodeList **init)
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r->left, init);
- fn = mapfn("mapaccess2", r->left->type);
- r = mkcall1(fn, getoutargx(fn->type), init, typename(r->left->type), r->left, r->right);
+ t = r->left->type;
+ p = nil;
+ if(t->type->width <= 128) { // Check ../../pkg/runtime/hashmap.c:MAXVALUESIZE before changing.
+ switch(simsimtype(t->down)) {
+ case TINT32:
+ case TUINT32:
+ p = "mapaccess2_fast32";
+ break;
+ case TINT64:
+ case TUINT64:
+ p = "mapaccess2_fast64";
+ break;
+ case TSTRING:
+ p = "mapaccess2_faststr";
+ break;
+ }
+ }
+ if(p != nil) {
+ // from:
+ // a,b = m[i]
+ // to:
+ // var,b = mapaccess2_fast*(t, m, i)
+ // a = *var
+ a = n->list->n;
+ var = temp(ptrto(t->type));
+ var->typecheck = 1;
+
+ fn = mapfn(p, t);
+ r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, r->right);
+ n->rlist = list1(r);
+ n->op = OAS2FUNC;
+ n->list->n = var;
+ walkexpr(&n, init);
+ *init = list(*init, n);
+
+ n = nod(OAS, a, nod(OIND, var, N));
+ typecheck(&n, Etop);
+ walkexpr(&n, init);
+ goto ret;
+ }
+ fn = mapfn("mapaccess2", t);
+ r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, r->right);
n->rlist = list1(r);
n->op = OAS2FUNC;
goto as2func;
@@ -1041,7 +1053,33 @@ walkexpr(Node **np, NodeList **init)
goto ret;
t = n->left->type;
- n = mkcall1(mapfn("mapaccess1", t), t->type, init, typename(t), n->left, n->right);
+ p = nil;
+ if(t->type->width <= 128) { // Check ../../pkg/runtime/hashmap.c:MAXVALUESIZE before changing.
+ switch(simsimtype(t->down)) {
+ case TINT32:
+ case TUINT32:
+ p = "mapaccess1_fast32";
+ break;
+ case TINT64:
+ case TUINT64:
+ p = "mapaccess1_fast64";
+ break;
+ case TSTRING:
+ p = "mapaccess1_faststr";
+ break;
+ }
+ }
+ if(p != nil) {
+ // use fast version. The fast versions return a pointer to the value - we need
+ // to dereference it to get the result.
+ n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, n->right);
+ n = nod(OIND, n, N);
+ n->type = t->type;
+ n->typecheck = 1;
+ } else {
+ // no fast version for this key
+ n = mkcall1(mapfn("mapaccess1", t), t->type, init, typename(t), n->left, n->right);
+ }
goto ret;
case ORECV:
@@ -1292,6 +1330,10 @@ walkexpr(Node **np, NodeList **init)
case OCLOSURE:
n = walkclosure(n, init);
goto ret;
+
+ case OCALLPART:
+ n = walkpartialcall(n, init);
+ goto ret;
}
fatal("missing switch %O", n->op);
@@ -2814,11 +2856,19 @@ walkcompare(Node **np, NodeList **init)
typecheck(&call, Etop);
walkstmt(&call);
*init = list(*init, call);
-
- if(n->op == OEQ)
- r = tempbool;
- else
- r = nod(ONOT, tempbool, N);
+
+ // tempbool cannot be used directly as multiple comparison
+ // expressions may exist in the same statement. Create another
+ // temporary to hold the value (its address is not taken so it can
+ // be optimized away).
+ r = temp(types[TBOOL]);
+ a = nod(OAS, r, tempbool);
+ typecheck(&a, Etop);
+ walkstmt(&a);
+ *init = list(*init, a);
+
+ if(n->op != OEQ)
+ r = nod(ONOT, r, N);
typecheck(&r, Erv);
walkexpr(&r, init);
*np = r;
@@ -2847,14 +2897,29 @@ hard:
static int
samecheap(Node *a, Node *b)
{
- if(a == N || b == N || a->op != b->op)
- return 0;
-
- switch(a->op) {
- case ONAME:
- return a == b;
- // TODO: Could do more here, but maybe this is enough.
- // It's all cheapexpr does.
+ Node *ar, *br;
+ while(a != N && b != N && a->op == b->op) {
+ switch(a->op) {
+ default:
+ return 0;
+ case ONAME:
+ return a == b;
+ case ODOT:
+ case ODOTPTR:
+ ar = a->right;
+ br = b->right;
+ if(ar->op != ONAME || br->op != ONAME || ar->sym != br->sym)
+ return 0;
+ break;
+ case OINDEX:
+ ar = a->right;
+ br = b->right;
+ if(!isconst(ar, CTINT) || !isconst(br, CTINT) || mpcmpfixfix(ar->val.u.xval, br->val.u.xval) != 0)
+ return 0;
+ break;
+ }
+ a = a->left;
+ b = b->left;
}
return 0;
}
diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c
index 75175455e..21c67e805 100644
--- a/src/cmd/gc/y.tab.c
+++ b/src/cmd/gc/y.tab.c
@@ -658,39 +658,39 @@ 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, 423, 428, 440, 456, 461, 468, 488, 506, 515,
- 534, 533, 545, 544, 575, 578, 585, 584, 595, 601,
- 610, 621, 627, 630, 638, 637, 648, 654, 666, 670,
- 675, 665, 696, 695, 708, 711, 717, 720, 732, 736,
- 731, 754, 753, 769, 770, 774, 778, 782, 786, 790,
- 794, 798, 802, 806, 810, 814, 818, 822, 826, 830,
- 834, 838, 842, 847, 853, 854, 858, 869, 873, 877,
- 881, 886, 890, 900, 904, 909, 917, 921, 922, 933,
- 937, 941, 945, 949, 950, 956, 963, 969, 976, 979,
- 986, 992, 1009, 1016, 1017, 1024, 1025, 1044, 1045, 1048,
- 1051, 1055, 1066, 1075, 1081, 1084, 1087, 1094, 1095, 1101,
- 1116, 1124, 1136, 1141, 1147, 1148, 1149, 1150, 1151, 1152,
- 1158, 1159, 1160, 1161, 1167, 1168, 1169, 1170, 1171, 1177,
- 1178, 1181, 1184, 1185, 1186, 1187, 1188, 1191, 1192, 1205,
- 1209, 1214, 1219, 1224, 1228, 1229, 1232, 1238, 1245, 1251,
- 1258, 1264, 1275, 1289, 1318, 1358, 1383, 1401, 1410, 1413,
- 1421, 1425, 1429, 1436, 1442, 1447, 1459, 1462, 1472, 1473,
- 1479, 1480, 1486, 1490, 1496, 1497, 1503, 1507, 1513, 1536,
- 1541, 1547, 1553, 1560, 1569, 1578, 1593, 1599, 1604, 1608,
- 1615, 1628, 1629, 1635, 1641, 1644, 1648, 1654, 1657, 1666,
- 1669, 1670, 1674, 1675, 1681, 1682, 1683, 1684, 1685, 1687,
- 1686, 1701, 1706, 1710, 1714, 1718, 1722, 1727, 1746, 1752,
- 1760, 1764, 1770, 1774, 1780, 1784, 1790, 1794, 1803, 1807,
- 1811, 1815, 1821, 1824, 1832, 1833, 1835, 1836, 1839, 1842,
- 1845, 1848, 1851, 1854, 1857, 1860, 1863, 1866, 1869, 1872,
- 1875, 1878, 1884, 1888, 1892, 1896, 1900, 1904, 1924, 1931,
- 1942, 1943, 1944, 1947, 1948, 1951, 1955, 1965, 1969, 1973,
- 1977, 1981, 1985, 1989, 1995, 2001, 2009, 2017, 2023, 2030,
- 2046, 2064, 2068, 2074, 2077, 2080, 2084, 2094, 2098, 2113,
- 2121, 2122, 2134, 2135, 2138, 2142, 2148, 2152, 2158, 2162
+ 260, 261, 268, 268, 281, 285, 286, 290, 295, 301,
+ 305, 309, 313, 319, 325, 331, 336, 340, 344, 350,
+ 356, 360, 364, 370, 374, 380, 381, 385, 391, 400,
+ 406, 424, 429, 441, 457, 462, 469, 489, 507, 516,
+ 535, 534, 549, 548, 579, 582, 589, 588, 599, 605,
+ 614, 625, 631, 634, 642, 641, 652, 658, 670, 674,
+ 679, 669, 700, 699, 712, 715, 721, 724, 736, 740,
+ 735, 758, 757, 773, 774, 778, 782, 786, 790, 794,
+ 798, 802, 806, 810, 814, 818, 822, 826, 830, 834,
+ 838, 842, 846, 851, 857, 858, 862, 873, 877, 881,
+ 885, 890, 894, 904, 908, 913, 921, 925, 926, 937,
+ 941, 945, 949, 953, 954, 960, 967, 973, 980, 983,
+ 990, 996, 1013, 1020, 1021, 1028, 1029, 1048, 1049, 1052,
+ 1055, 1059, 1070, 1079, 1085, 1088, 1091, 1098, 1099, 1105,
+ 1120, 1128, 1140, 1145, 1151, 1152, 1153, 1154, 1155, 1156,
+ 1162, 1163, 1164, 1165, 1171, 1172, 1173, 1174, 1175, 1181,
+ 1182, 1185, 1188, 1189, 1190, 1191, 1192, 1195, 1196, 1209,
+ 1213, 1218, 1223, 1228, 1232, 1233, 1236, 1242, 1249, 1255,
+ 1262, 1268, 1279, 1293, 1322, 1362, 1387, 1405, 1414, 1417,
+ 1425, 1429, 1433, 1440, 1446, 1451, 1463, 1466, 1476, 1477,
+ 1483, 1484, 1490, 1494, 1500, 1501, 1507, 1511, 1517, 1540,
+ 1545, 1551, 1557, 1564, 1573, 1582, 1597, 1603, 1608, 1612,
+ 1619, 1632, 1633, 1639, 1645, 1648, 1652, 1658, 1661, 1670,
+ 1673, 1674, 1678, 1679, 1685, 1686, 1687, 1688, 1689, 1691,
+ 1690, 1705, 1710, 1714, 1718, 1722, 1726, 1731, 1750, 1756,
+ 1764, 1768, 1774, 1778, 1784, 1788, 1794, 1798, 1807, 1811,
+ 1815, 1819, 1825, 1828, 1836, 1837, 1839, 1840, 1843, 1846,
+ 1849, 1852, 1855, 1858, 1861, 1864, 1867, 1870, 1873, 1876,
+ 1879, 1882, 1888, 1892, 1896, 1900, 1904, 1908, 1928, 1935,
+ 1946, 1947, 1948, 1951, 1952, 1955, 1959, 1969, 1973, 1977,
+ 1981, 1985, 1989, 1993, 1999, 2005, 2013, 2021, 2027, 2034,
+ 2050, 2068, 2072, 2078, 2081, 2084, 2088, 2098, 2102, 2117,
+ 2125, 2126, 2138, 2139, 2142, 2146, 2152, 2156, 2162, 2166
};
#endif
@@ -2494,14 +2494,15 @@ yyreduce:
} 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;
-
+ importpkg->safe = curio.importsafe;
+
if(safemode && !curio.importsafe)
yyerror("cannot import unsafe package \"%Z\"", importpkg->path);
}
break;
case 21:
-#line 261 "go.y"
+#line 262 "go.y"
{
if(strcmp((yyvsp[(1) - (1)].sym)->name, "safe") == 0)
curio.importsafe = 1;
@@ -2509,14 +2510,14 @@ yyreduce:
break;
case 22:
-#line 267 "go.y"
+#line 268 "go.y"
{
defercheckwidth();
}
break;
case 23:
-#line 271 "go.y"
+#line 272 "go.y"
{
resumecheckwidth();
unimportfile();
@@ -2524,7 +2525,7 @@ yyreduce:
break;
case 24:
-#line 280 "go.y"
+#line 281 "go.y"
{
yyerror("empty top-level declaration");
(yyval.list) = nil;
@@ -2532,14 +2533,14 @@ yyreduce:
break;
case 26:
-#line 286 "go.y"
+#line 287 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 27:
-#line 290 "go.y"
+#line 291 "go.y"
{
yyerror("non-declaration statement outside function body");
(yyval.list) = nil;
@@ -2547,35 +2548,35 @@ yyreduce:
break;
case 28:
-#line 295 "go.y"
+#line 296 "go.y"
{
(yyval.list) = nil;
}
break;
case 29:
-#line 301 "go.y"
+#line 302 "go.y"
{
(yyval.list) = (yyvsp[(2) - (2)].list);
}
break;
case 30:
-#line 305 "go.y"
+#line 306 "go.y"
{
(yyval.list) = (yyvsp[(3) - (5)].list);
}
break;
case 31:
-#line 309 "go.y"
+#line 310 "go.y"
{
(yyval.list) = nil;
}
break;
case 32:
-#line 313 "go.y"
+#line 314 "go.y"
{
(yyval.list) = (yyvsp[(2) - (2)].list);
iota = -100000;
@@ -2584,7 +2585,7 @@ yyreduce:
break;
case 33:
-#line 319 "go.y"
+#line 320 "go.y"
{
(yyval.list) = (yyvsp[(3) - (5)].list);
iota = -100000;
@@ -2593,7 +2594,7 @@ yyreduce:
break;
case 34:
-#line 325 "go.y"
+#line 326 "go.y"
{
(yyval.list) = concat((yyvsp[(3) - (7)].list), (yyvsp[(5) - (7)].list));
iota = -100000;
@@ -2602,7 +2603,7 @@ yyreduce:
break;
case 35:
-#line 331 "go.y"
+#line 332 "go.y"
{
(yyval.list) = nil;
iota = -100000;
@@ -2610,84 +2611,84 @@ yyreduce:
break;
case 36:
-#line 336 "go.y"
+#line 337 "go.y"
{
(yyval.list) = list1((yyvsp[(2) - (2)].node));
}
break;
case 37:
-#line 340 "go.y"
+#line 341 "go.y"
{
(yyval.list) = (yyvsp[(3) - (5)].list);
}
break;
case 38:
-#line 344 "go.y"
+#line 345 "go.y"
{
(yyval.list) = nil;
}
break;
case 39:
-#line 350 "go.y"
+#line 351 "go.y"
{
iota = 0;
}
break;
case 40:
-#line 356 "go.y"
+#line 357 "go.y"
{
(yyval.list) = variter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
}
break;
case 41:
-#line 360 "go.y"
+#line 361 "go.y"
{
(yyval.list) = variter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
}
break;
case 42:
-#line 364 "go.y"
+#line 365 "go.y"
{
(yyval.list) = variter((yyvsp[(1) - (3)].list), nil, (yyvsp[(3) - (3)].list));
}
break;
case 43:
-#line 370 "go.y"
+#line 371 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
}
break;
case 44:
-#line 374 "go.y"
+#line 375 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (3)].list), N, (yyvsp[(3) - (3)].list));
}
break;
case 46:
-#line 381 "go.y"
+#line 382 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
}
break;
case 47:
-#line 385 "go.y"
+#line 386 "go.y"
{
(yyval.list) = constiter((yyvsp[(1) - (1)].list), N, nil);
}
break;
case 48:
-#line 391 "go.y"
+#line 392 "go.y"
{
// different from dclname because the name
// becomes visible right here, not at the end
@@ -2697,14 +2698,14 @@ yyreduce:
break;
case 49:
-#line 400 "go.y"
+#line 401 "go.y"
{
(yyval.node) = typedcl1((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node), 1);
}
break;
case 50:
-#line 406 "go.y"
+#line 407 "go.y"
{
(yyval.node) = (yyvsp[(1) - (1)].node);
@@ -2725,7 +2726,7 @@ yyreduce:
break;
case 51:
-#line 424 "go.y"
+#line 425 "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
@@ -2733,7 +2734,7 @@ yyreduce:
break;
case 52:
-#line 429 "go.y"
+#line 430 "go.y"
{
if((yyvsp[(1) - (3)].list)->next == nil && (yyvsp[(3) - (3)].list)->next == nil) {
// simple
@@ -2748,7 +2749,7 @@ yyreduce:
break;
case 53:
-#line 441 "go.y"
+#line 442 "go.y"
{
if((yyvsp[(3) - (3)].list)->n->op == OTYPESW) {
(yyval.node) = nod(OTYPESW, N, (yyvsp[(3) - (3)].list)->n->right);
@@ -2767,7 +2768,7 @@ yyreduce:
break;
case 54:
-#line 457 "go.y"
+#line 458 "go.y"
{
(yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
(yyval.node)->etype = OADD;
@@ -2775,7 +2776,7 @@ yyreduce:
break;
case 55:
-#line 462 "go.y"
+#line 463 "go.y"
{
(yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
(yyval.node)->etype = OSUB;
@@ -2783,7 +2784,7 @@ yyreduce:
break;
case 56:
-#line 469 "go.y"
+#line 470 "go.y"
{
Node *n, *nn;
@@ -2806,7 +2807,7 @@ yyreduce:
break;
case 57:
-#line 489 "go.y"
+#line 490 "go.y"
{
Node *n;
@@ -2827,7 +2828,7 @@ yyreduce:
break;
case 58:
-#line 507 "go.y"
+#line 508 "go.y"
{
// will be converted to OCASE
// right will point to next case
@@ -2839,7 +2840,7 @@ yyreduce:
break;
case 59:
-#line 516 "go.y"
+#line 517 "go.y"
{
Node *n, *nn;
@@ -2858,22 +2859,25 @@ yyreduce:
break;
case 60:
-#line 534 "go.y"
+#line 535 "go.y"
{
markdcl();
}
break;
case 61:
-#line 538 "go.y"
+#line 539 "go.y"
{
- (yyval.node) = liststmt((yyvsp[(3) - (4)].list));
+ if((yyvsp[(3) - (4)].list) == nil)
+ (yyval.node) = nod(OEMPTY, N, N);
+ else
+ (yyval.node) = liststmt((yyvsp[(3) - (4)].list));
popdcl();
}
break;
case 62:
-#line 545 "go.y"
+#line 549 "go.y"
{
// If the last token read by the lexer was consumed
// as part of the case, clear it (parser has cleared yychar).
@@ -2886,7 +2890,7 @@ yyreduce:
break;
case 63:
-#line 555 "go.y"
+#line 559 "go.y"
{
int last;
@@ -2908,28 +2912,28 @@ yyreduce:
break;
case 64:
-#line 575 "go.y"
+#line 579 "go.y"
{
(yyval.list) = nil;
}
break;
case 65:
-#line 579 "go.y"
+#line 583 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node));
}
break;
case 66:
-#line 585 "go.y"
+#line 589 "go.y"
{
markdcl();
}
break;
case 67:
-#line 589 "go.y"
+#line 593 "go.y"
{
(yyval.list) = (yyvsp[(3) - (4)].list);
popdcl();
@@ -2937,7 +2941,7 @@ yyreduce:
break;
case 68:
-#line 596 "go.y"
+#line 600 "go.y"
{
(yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
(yyval.node)->list = (yyvsp[(1) - (4)].list);
@@ -2946,7 +2950,7 @@ yyreduce:
break;
case 69:
-#line 602 "go.y"
+#line 606 "go.y"
{
(yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
(yyval.node)->list = (yyvsp[(1) - (4)].list);
@@ -2956,7 +2960,7 @@ yyreduce:
break;
case 70:
-#line 611 "go.y"
+#line 615 "go.y"
{
// init ; test ; incr
if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0)
@@ -2970,7 +2974,7 @@ yyreduce:
break;
case 71:
-#line 622 "go.y"
+#line 626 "go.y"
{
// normal test
(yyval.node) = nod(OFOR, N, N);
@@ -2979,7 +2983,7 @@ yyreduce:
break;
case 73:
-#line 631 "go.y"
+#line 635 "go.y"
{
(yyval.node) = (yyvsp[(1) - (2)].node);
(yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list));
@@ -2987,14 +2991,14 @@ yyreduce:
break;
case 74:
-#line 638 "go.y"
+#line 642 "go.y"
{
markdcl();
}
break;
case 75:
-#line 642 "go.y"
+#line 646 "go.y"
{
(yyval.node) = (yyvsp[(3) - (3)].node);
popdcl();
@@ -3002,7 +3006,7 @@ yyreduce:
break;
case 76:
-#line 649 "go.y"
+#line 653 "go.y"
{
// test
(yyval.node) = nod(OIF, N, N);
@@ -3011,7 +3015,7 @@ yyreduce:
break;
case 77:
-#line 655 "go.y"
+#line 659 "go.y"
{
// init ; test
(yyval.node) = nod(OIF, N, N);
@@ -3022,14 +3026,14 @@ yyreduce:
break;
case 78:
-#line 666 "go.y"
+#line 670 "go.y"
{
markdcl();
}
break;
case 79:
-#line 670 "go.y"
+#line 674 "go.y"
{
if((yyvsp[(3) - (3)].node)->ntest == N)
yyerror("missing condition in if statement");
@@ -3037,14 +3041,14 @@ yyreduce:
break;
case 80:
-#line 675 "go.y"
+#line 679 "go.y"
{
(yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list);
}
break;
case 81:
-#line 679 "go.y"
+#line 683 "go.y"
{
Node *n;
NodeList *nn;
@@ -3062,14 +3066,14 @@ yyreduce:
break;
case 82:
-#line 696 "go.y"
+#line 700 "go.y"
{
markdcl();
}
break;
case 83:
-#line 700 "go.y"
+#line 704 "go.y"
{
if((yyvsp[(4) - (5)].node)->ntest == N)
yyerror("missing condition in if statement");
@@ -3079,28 +3083,28 @@ yyreduce:
break;
case 84:
-#line 708 "go.y"
+#line 712 "go.y"
{
(yyval.list) = nil;
}
break;
case 85:
-#line 712 "go.y"
+#line 716 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list));
}
break;
case 86:
-#line 717 "go.y"
+#line 721 "go.y"
{
(yyval.list) = nil;
}
break;
case 87:
-#line 721 "go.y"
+#line 725 "go.y"
{
NodeList *node;
@@ -3112,14 +3116,14 @@ yyreduce:
break;
case 88:
-#line 732 "go.y"
+#line 736 "go.y"
{
markdcl();
}
break;
case 89:
-#line 736 "go.y"
+#line 740 "go.y"
{
Node *n;
n = (yyvsp[(3) - (3)].node)->ntest;
@@ -3130,7 +3134,7 @@ yyreduce:
break;
case 90:
-#line 744 "go.y"
+#line 748 "go.y"
{
(yyval.node) = (yyvsp[(3) - (7)].node);
(yyval.node)->op = OSWITCH;
@@ -3141,14 +3145,14 @@ yyreduce:
break;
case 91:
-#line 754 "go.y"
+#line 758 "go.y"
{
typesw = nod(OXXX, typesw, N);
}
break;
case 92:
-#line 758 "go.y"
+#line 762 "go.y"
{
(yyval.node) = nod(OSELECT, N, N);
(yyval.node)->lineno = typesw->lineno;
@@ -3158,154 +3162,154 @@ yyreduce:
break;
case 94:
-#line 771 "go.y"
+#line 775 "go.y"
{
(yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 95:
-#line 775 "go.y"
+#line 779 "go.y"
{
(yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 96:
-#line 779 "go.y"
+#line 783 "go.y"
{
(yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 97:
-#line 783 "go.y"
+#line 787 "go.y"
{
(yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 98:
-#line 787 "go.y"
+#line 791 "go.y"
{
(yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 99:
-#line 791 "go.y"
+#line 795 "go.y"
{
(yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 100:
-#line 795 "go.y"
+#line 799 "go.y"
{
(yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 101:
-#line 799 "go.y"
+#line 803 "go.y"
{
(yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 102:
-#line 803 "go.y"
+#line 807 "go.y"
{
(yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 103:
-#line 807 "go.y"
+#line 811 "go.y"
{
(yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 104:
-#line 811 "go.y"
+#line 815 "go.y"
{
(yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 105:
-#line 815 "go.y"
+#line 819 "go.y"
{
(yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 106:
-#line 819 "go.y"
+#line 823 "go.y"
{
(yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 107:
-#line 823 "go.y"
+#line 827 "go.y"
{
(yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 108:
-#line 827 "go.y"
+#line 831 "go.y"
{
(yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 109:
-#line 831 "go.y"
+#line 835 "go.y"
{
(yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 110:
-#line 835 "go.y"
+#line 839 "go.y"
{
(yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 111:
-#line 839 "go.y"
+#line 843 "go.y"
{
(yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 112:
-#line 843 "go.y"
+#line 847 "go.y"
{
(yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 113:
-#line 848 "go.y"
+#line 852 "go.y"
{
(yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 115:
-#line 855 "go.y"
+#line 859 "go.y"
{
(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
}
break;
case 116:
-#line 859 "go.y"
+#line 863 "go.y"
{
if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) {
// Special case for &T{...}: turn into (*T){...}.
@@ -3319,28 +3323,28 @@ yyreduce:
break;
case 117:
-#line 870 "go.y"
+#line 874 "go.y"
{
(yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N);
}
break;
case 118:
-#line 874 "go.y"
+#line 878 "go.y"
{
(yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N);
}
break;
case 119:
-#line 878 "go.y"
+#line 882 "go.y"
{
(yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N);
}
break;
case 120:
-#line 882 "go.y"
+#line 886 "go.y"
{
yyerror("the bitwise complement operator is ^");
(yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
@@ -3348,28 +3352,28 @@ yyreduce:
break;
case 121:
-#line 887 "go.y"
+#line 891 "go.y"
{
(yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
}
break;
case 122:
-#line 891 "go.y"
+#line 895 "go.y"
{
(yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N);
}
break;
case 123:
-#line 901 "go.y"
+#line 905 "go.y"
{
(yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N);
}
break;
case 124:
-#line 905 "go.y"
+#line 909 "go.y"
{
(yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
(yyval.node)->list = (yyvsp[(3) - (5)].list);
@@ -3377,7 +3381,7 @@ yyreduce:
break;
case 125:
-#line 910 "go.y"
+#line 914 "go.y"
{
(yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N);
(yyval.node)->list = (yyvsp[(3) - (6)].list);
@@ -3386,14 +3390,14 @@ yyreduce:
break;
case 126:
-#line 918 "go.y"
+#line 922 "go.y"
{
(yyval.node) = nodlit((yyvsp[(1) - (1)].val));
}
break;
case 128:
-#line 923 "go.y"
+#line 927 "go.y"
{
if((yyvsp[(1) - (3)].node)->op == OPACK) {
Sym *s;
@@ -3407,35 +3411,35 @@ yyreduce:
break;
case 129:
-#line 934 "go.y"
+#line 938 "go.y"
{
(yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node));
}
break;
case 130:
-#line 938 "go.y"
+#line 942 "go.y"
{
(yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node));
}
break;
case 131:
-#line 942 "go.y"
+#line 946 "go.y"
{
(yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
}
break;
case 132:
-#line 946 "go.y"
+#line 950 "go.y"
{
(yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node)));
}
break;
case 134:
-#line 951 "go.y"
+#line 955 "go.y"
{
// conversion
(yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
@@ -3444,7 +3448,7 @@ yyreduce:
break;
case 135:
-#line 957 "go.y"
+#line 961 "go.y"
{
(yyval.node) = (yyvsp[(3) - (5)].node);
(yyval.node)->right = (yyvsp[(1) - (5)].node);
@@ -3454,7 +3458,7 @@ yyreduce:
break;
case 136:
-#line 964 "go.y"
+#line 968 "go.y"
{
(yyval.node) = (yyvsp[(3) - (5)].node);
(yyval.node)->right = (yyvsp[(1) - (5)].node);
@@ -3463,7 +3467,7 @@ yyreduce:
break;
case 137:
-#line 970 "go.y"
+#line 974 "go.y"
{
yyerror("cannot parenthesize type in composite literal");
(yyval.node) = (yyvsp[(5) - (7)].node);
@@ -3473,7 +3477,7 @@ yyreduce:
break;
case 139:
-#line 979 "go.y"
+#line 983 "go.y"
{
// composite expression.
// make node early so we get the right line number.
@@ -3482,14 +3486,14 @@ yyreduce:
break;
case 140:
-#line 987 "go.y"
+#line 991 "go.y"
{
(yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
}
break;
case 141:
-#line 993 "go.y"
+#line 997 "go.y"
{
// These nodes do not carry line numbers.
// Since a composite literal commonly spans several lines,
@@ -3509,7 +3513,7 @@ yyreduce:
break;
case 142:
-#line 1010 "go.y"
+#line 1014 "go.y"
{
(yyval.node) = (yyvsp[(2) - (4)].node);
(yyval.node)->list = (yyvsp[(3) - (4)].list);
@@ -3517,7 +3521,7 @@ yyreduce:
break;
case 144:
-#line 1018 "go.y"
+#line 1022 "go.y"
{
(yyval.node) = (yyvsp[(2) - (4)].node);
(yyval.node)->list = (yyvsp[(3) - (4)].list);
@@ -3525,7 +3529,7 @@ yyreduce:
break;
case 146:
-#line 1026 "go.y"
+#line 1030 "go.y"
{
(yyval.node) = (yyvsp[(2) - (3)].node);
@@ -3545,21 +3549,21 @@ yyreduce:
break;
case 150:
-#line 1052 "go.y"
+#line 1056 "go.y"
{
(yyval.i) = LBODY;
}
break;
case 151:
-#line 1056 "go.y"
+#line 1060 "go.y"
{
(yyval.i) = '{';
}
break;
case 152:
-#line 1067 "go.y"
+#line 1071 "go.y"
{
if((yyvsp[(1) - (1)].sym) == S)
(yyval.node) = N;
@@ -3569,21 +3573,21 @@ yyreduce:
break;
case 153:
-#line 1076 "go.y"
+#line 1080 "go.y"
{
(yyval.node) = dclname((yyvsp[(1) - (1)].sym));
}
break;
case 154:
-#line 1081 "go.y"
+#line 1085 "go.y"
{
(yyval.node) = N;
}
break;
case 156:
-#line 1088 "go.y"
+#line 1092 "go.y"
{
(yyval.sym) = (yyvsp[(1) - (1)].sym);
// during imports, unqualified non-exported identifiers are from builtinpkg
@@ -3593,14 +3597,14 @@ yyreduce:
break;
case 158:
-#line 1096 "go.y"
+#line 1100 "go.y"
{
(yyval.sym) = S;
}
break;
case 159:
-#line 1102 "go.y"
+#line 1106 "go.y"
{
Pkg *p;
@@ -3616,7 +3620,7 @@ yyreduce:
break;
case 160:
-#line 1117 "go.y"
+#line 1121 "go.y"
{
(yyval.node) = oldname((yyvsp[(1) - (1)].sym));
if((yyval.node)->pack != N)
@@ -3625,7 +3629,7 @@ yyreduce:
break;
case 162:
-#line 1137 "go.y"
+#line 1141 "go.y"
{
yyerror("final argument in variadic function missing type");
(yyval.node) = nod(ODDD, typenod(typ(TINTER)), N);
@@ -3633,35 +3637,35 @@ yyreduce:
break;
case 163:
-#line 1142 "go.y"
+#line 1146 "go.y"
{
(yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N);
}
break;
case 169:
-#line 1153 "go.y"
+#line 1157 "go.y"
{
(yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N);
}
break;
case 173:
-#line 1162 "go.y"
+#line 1166 "go.y"
{
(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
}
break;
case 178:
-#line 1172 "go.y"
+#line 1176 "go.y"
{
(yyval.node) = nod(OTPAREN, (yyvsp[(2) - (3)].node), N);
}
break;
case 188:
-#line 1193 "go.y"
+#line 1197 "go.y"
{
if((yyvsp[(1) - (3)].node)->op == OPACK) {
Sym *s;
@@ -3675,14 +3679,14 @@ yyreduce:
break;
case 189:
-#line 1206 "go.y"
+#line 1210 "go.y"
{
(yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node));
}
break;
case 190:
-#line 1210 "go.y"
+#line 1214 "go.y"
{
// array literal of nelem
(yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node));
@@ -3690,7 +3694,7 @@ yyreduce:
break;
case 191:
-#line 1215 "go.y"
+#line 1219 "go.y"
{
(yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N);
(yyval.node)->etype = Cboth;
@@ -3698,7 +3702,7 @@ yyreduce:
break;
case 192:
-#line 1220 "go.y"
+#line 1224 "go.y"
{
(yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
(yyval.node)->etype = Csend;
@@ -3706,21 +3710,21 @@ yyreduce:
break;
case 193:
-#line 1225 "go.y"
+#line 1229 "go.y"
{
(yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
}
break;
case 196:
-#line 1233 "go.y"
+#line 1237 "go.y"
{
(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
}
break;
case 197:
-#line 1239 "go.y"
+#line 1243 "go.y"
{
(yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
(yyval.node)->etype = Crecv;
@@ -3728,7 +3732,7 @@ yyreduce:
break;
case 198:
-#line 1246 "go.y"
+#line 1250 "go.y"
{
(yyval.node) = nod(OTSTRUCT, N, N);
(yyval.node)->list = (yyvsp[(3) - (5)].list);
@@ -3737,7 +3741,7 @@ yyreduce:
break;
case 199:
-#line 1252 "go.y"
+#line 1256 "go.y"
{
(yyval.node) = nod(OTSTRUCT, N, N);
fixlbrace((yyvsp[(2) - (3)].i));
@@ -3745,7 +3749,7 @@ yyreduce:
break;
case 200:
-#line 1259 "go.y"
+#line 1263 "go.y"
{
(yyval.node) = nod(OTINTER, N, N);
(yyval.node)->list = (yyvsp[(3) - (5)].list);
@@ -3754,7 +3758,7 @@ yyreduce:
break;
case 201:
-#line 1265 "go.y"
+#line 1269 "go.y"
{
(yyval.node) = nod(OTINTER, N, N);
fixlbrace((yyvsp[(2) - (3)].i));
@@ -3762,7 +3766,7 @@ yyreduce:
break;
case 202:
-#line 1276 "go.y"
+#line 1280 "go.y"
{
(yyval.node) = (yyvsp[(2) - (3)].node);
if((yyval.node) == N)
@@ -3777,7 +3781,7 @@ yyreduce:
break;
case 203:
-#line 1290 "go.y"
+#line 1294 "go.y"
{
Node *t;
@@ -3809,7 +3813,7 @@ yyreduce:
break;
case 204:
-#line 1319 "go.y"
+#line 1323 "go.y"
{
Node *rcvr, *t;
@@ -3850,7 +3854,7 @@ yyreduce:
break;
case 205:
-#line 1359 "go.y"
+#line 1363 "go.y"
{
Sym *s;
Type *t;
@@ -3878,7 +3882,7 @@ yyreduce:
break;
case 206:
-#line 1384 "go.y"
+#line 1388 "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));
@@ -3897,7 +3901,7 @@ yyreduce:
break;
case 207:
-#line 1402 "go.y"
+#line 1406 "go.y"
{
(yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
(yyval.node) = nod(OTFUNC, N, N);
@@ -3907,14 +3911,14 @@ yyreduce:
break;
case 208:
-#line 1410 "go.y"
+#line 1414 "go.y"
{
(yyval.list) = nil;
}
break;
case 209:
-#line 1414 "go.y"
+#line 1418 "go.y"
{
(yyval.list) = (yyvsp[(2) - (3)].list);
if((yyval.list) == nil)
@@ -3923,21 +3927,21 @@ yyreduce:
break;
case 210:
-#line 1422 "go.y"
+#line 1426 "go.y"
{
(yyval.list) = nil;
}
break;
case 211:
-#line 1426 "go.y"
+#line 1430 "go.y"
{
(yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node)));
}
break;
case 212:
-#line 1430 "go.y"
+#line 1434 "go.y"
{
(yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0);
(yyval.list) = (yyvsp[(2) - (3)].list);
@@ -3945,14 +3949,14 @@ yyreduce:
break;
case 213:
-#line 1437 "go.y"
+#line 1441 "go.y"
{
closurehdr((yyvsp[(1) - (1)].node));
}
break;
case 214:
-#line 1443 "go.y"
+#line 1447 "go.y"
{
(yyval.node) = closurebody((yyvsp[(3) - (4)].list));
fixlbrace((yyvsp[(2) - (4)].i));
@@ -3960,21 +3964,21 @@ yyreduce:
break;
case 215:
-#line 1448 "go.y"
+#line 1452 "go.y"
{
(yyval.node) = closurebody(nil);
}
break;
case 216:
-#line 1459 "go.y"
+#line 1463 "go.y"
{
(yyval.list) = nil;
}
break;
case 217:
-#line 1463 "go.y"
+#line 1467 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list));
if(nsyntaxerrors == 0)
@@ -3985,56 +3989,56 @@ yyreduce:
break;
case 219:
-#line 1474 "go.y"
+#line 1478 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
}
break;
case 221:
-#line 1481 "go.y"
+#line 1485 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
}
break;
case 222:
-#line 1487 "go.y"
+#line 1491 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 223:
-#line 1491 "go.y"
+#line 1495 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 225:
-#line 1498 "go.y"
+#line 1502 "go.y"
{
(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
}
break;
case 226:
-#line 1504 "go.y"
+#line 1508 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 227:
-#line 1508 "go.y"
+#line 1512 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 228:
-#line 1514 "go.y"
+#line 1518 "go.y"
{
NodeList *l;
@@ -4060,7 +4064,7 @@ yyreduce:
break;
case 229:
-#line 1537 "go.y"
+#line 1541 "go.y"
{
(yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val);
(yyval.list) = list1((yyvsp[(1) - (2)].node));
@@ -4068,7 +4072,7 @@ yyreduce:
break;
case 230:
-#line 1542 "go.y"
+#line 1546 "go.y"
{
(yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val);
(yyval.list) = list1((yyvsp[(2) - (4)].node));
@@ -4077,7 +4081,7 @@ yyreduce:
break;
case 231:
-#line 1548 "go.y"
+#line 1552 "go.y"
{
(yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N);
(yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val);
@@ -4086,7 +4090,7 @@ yyreduce:
break;
case 232:
-#line 1554 "go.y"
+#line 1558 "go.y"
{
(yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
(yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
@@ -4096,7 +4100,7 @@ yyreduce:
break;
case 233:
-#line 1561 "go.y"
+#line 1565 "go.y"
{
(yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
(yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
@@ -4106,7 +4110,7 @@ yyreduce:
break;
case 234:
-#line 1570 "go.y"
+#line 1574 "go.y"
{
Node *n;
@@ -4118,7 +4122,7 @@ yyreduce:
break;
case 235:
-#line 1579 "go.y"
+#line 1583 "go.y"
{
Pkg *pkg;
@@ -4134,14 +4138,14 @@ yyreduce:
break;
case 236:
-#line 1594 "go.y"
+#line 1598 "go.y"
{
(yyval.node) = embedded((yyvsp[(1) - (1)].sym));
}
break;
case 237:
-#line 1600 "go.y"
+#line 1604 "go.y"
{
(yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
ifacedcl((yyval.node));
@@ -4149,14 +4153,14 @@ yyreduce:
break;
case 238:
-#line 1605 "go.y"
+#line 1609 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym)));
}
break;
case 239:
-#line 1609 "go.y"
+#line 1613 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym)));
yyerror("cannot parenthesize embedded type");
@@ -4164,7 +4168,7 @@ yyreduce:
break;
case 240:
-#line 1616 "go.y"
+#line 1620 "go.y"
{
// without func keyword
(yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1);
@@ -4175,7 +4179,7 @@ yyreduce:
break;
case 242:
-#line 1630 "go.y"
+#line 1634 "go.y"
{
(yyval.node) = nod(ONONAME, N, N);
(yyval.node)->sym = (yyvsp[(1) - (2)].sym);
@@ -4184,7 +4188,7 @@ yyreduce:
break;
case 243:
-#line 1636 "go.y"
+#line 1640 "go.y"
{
(yyval.node) = nod(ONONAME, N, N);
(yyval.node)->sym = (yyvsp[(1) - (2)].sym);
@@ -4193,56 +4197,56 @@ yyreduce:
break;
case 245:
-#line 1645 "go.y"
+#line 1649 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 246:
-#line 1649 "go.y"
+#line 1653 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 247:
-#line 1654 "go.y"
+#line 1658 "go.y"
{
(yyval.list) = nil;
}
break;
case 248:
-#line 1658 "go.y"
+#line 1662 "go.y"
{
(yyval.list) = (yyvsp[(1) - (2)].list);
}
break;
case 249:
-#line 1666 "go.y"
+#line 1670 "go.y"
{
(yyval.node) = N;
}
break;
case 251:
-#line 1671 "go.y"
+#line 1675 "go.y"
{
(yyval.node) = liststmt((yyvsp[(1) - (1)].list));
}
break;
case 253:
-#line 1676 "go.y"
+#line 1680 "go.y"
{
(yyval.node) = N;
}
break;
case 259:
-#line 1687 "go.y"
+#line 1691 "go.y"
{
(yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N);
(yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions
@@ -4250,7 +4254,7 @@ yyreduce:
break;
case 260:
-#line 1692 "go.y"
+#line 1696 "go.y"
{
NodeList *l;
@@ -4263,7 +4267,7 @@ yyreduce:
break;
case 261:
-#line 1702 "go.y"
+#line 1706 "go.y"
{
// will be converted to OFALL
(yyval.node) = nod(OXFALL, N, N);
@@ -4271,35 +4275,35 @@ yyreduce:
break;
case 262:
-#line 1707 "go.y"
+#line 1711 "go.y"
{
(yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N);
}
break;
case 263:
-#line 1711 "go.y"
+#line 1715 "go.y"
{
(yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N);
}
break;
case 264:
-#line 1715 "go.y"
+#line 1719 "go.y"
{
(yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N);
}
break;
case 265:
-#line 1719 "go.y"
+#line 1723 "go.y"
{
(yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N);
}
break;
case 266:
-#line 1723 "go.y"
+#line 1727 "go.y"
{
(yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N);
(yyval.node)->sym = dclstack; // context, for goto restrictions
@@ -4307,7 +4311,7 @@ yyreduce:
break;
case 267:
-#line 1728 "go.y"
+#line 1732 "go.y"
{
(yyval.node) = nod(ORETURN, N, N);
(yyval.node)->list = (yyvsp[(2) - (2)].list);
@@ -4327,7 +4331,7 @@ yyreduce:
break;
case 268:
-#line 1747 "go.y"
+#line 1751 "go.y"
{
(yyval.list) = nil;
if((yyvsp[(1) - (1)].node) != N)
@@ -4336,7 +4340,7 @@ yyreduce:
break;
case 269:
-#line 1753 "go.y"
+#line 1757 "go.y"
{
(yyval.list) = (yyvsp[(1) - (3)].list);
if((yyvsp[(3) - (3)].node) != N)
@@ -4345,189 +4349,189 @@ yyreduce:
break;
case 270:
-#line 1761 "go.y"
+#line 1765 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 271:
-#line 1765 "go.y"
+#line 1769 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 272:
-#line 1771 "go.y"
+#line 1775 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 273:
-#line 1775 "go.y"
+#line 1779 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 274:
-#line 1781 "go.y"
+#line 1785 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 275:
-#line 1785 "go.y"
+#line 1789 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 276:
-#line 1791 "go.y"
+#line 1795 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 277:
-#line 1795 "go.y"
+#line 1799 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 278:
-#line 1804 "go.y"
+#line 1808 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 279:
-#line 1808 "go.y"
+#line 1812 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 280:
-#line 1812 "go.y"
+#line 1816 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 281:
-#line 1816 "go.y"
+#line 1820 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 282:
-#line 1821 "go.y"
+#line 1825 "go.y"
{
(yyval.list) = nil;
}
break;
case 283:
-#line 1825 "go.y"
+#line 1829 "go.y"
{
(yyval.list) = (yyvsp[(1) - (2)].list);
}
break;
case 288:
-#line 1839 "go.y"
+#line 1843 "go.y"
{
(yyval.node) = N;
}
break;
case 290:
-#line 1845 "go.y"
+#line 1849 "go.y"
{
(yyval.list) = nil;
}
break;
case 292:
-#line 1851 "go.y"
+#line 1855 "go.y"
{
(yyval.node) = N;
}
break;
case 294:
-#line 1857 "go.y"
+#line 1861 "go.y"
{
(yyval.list) = nil;
}
break;
case 296:
-#line 1863 "go.y"
+#line 1867 "go.y"
{
(yyval.list) = nil;
}
break;
case 298:
-#line 1869 "go.y"
+#line 1873 "go.y"
{
(yyval.list) = nil;
}
break;
case 300:
-#line 1875 "go.y"
+#line 1879 "go.y"
{
(yyval.val).ctype = CTxxx;
}
break;
case 302:
-#line 1885 "go.y"
+#line 1889 "go.y"
{
importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval);
}
break;
case 303:
-#line 1889 "go.y"
+#line 1893 "go.y"
{
importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type));
}
break;
case 304:
-#line 1893 "go.y"
+#line 1897 "go.y"
{
importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node));
}
break;
case 305:
-#line 1897 "go.y"
+#line 1901 "go.y"
{
importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node));
}
break;
case 306:
-#line 1901 "go.y"
+#line 1905 "go.y"
{
importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type));
}
break;
case 307:
-#line 1905 "go.y"
+#line 1909 "go.y"
{
if((yyvsp[(2) - (4)].node) == N) {
dclcontext = PEXTERN; // since we skip the funcbody below
@@ -4548,7 +4552,7 @@ yyreduce:
break;
case 308:
-#line 1925 "go.y"
+#line 1929 "go.y"
{
(yyval.sym) = (yyvsp[(1) - (1)].sym);
structpkg = (yyval.sym)->pkg;
@@ -4556,7 +4560,7 @@ yyreduce:
break;
case 309:
-#line 1932 "go.y"
+#line 1936 "go.y"
{
(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
importsym((yyvsp[(1) - (1)].sym), OTYPE);
@@ -4564,14 +4568,14 @@ yyreduce:
break;
case 315:
-#line 1952 "go.y"
+#line 1956 "go.y"
{
(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
}
break;
case 316:
-#line 1956 "go.y"
+#line 1960 "go.y"
{
// predefined name like uint8
(yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
@@ -4584,49 +4588,49 @@ yyreduce:
break;
case 317:
-#line 1966 "go.y"
+#line 1970 "go.y"
{
(yyval.type) = aindex(N, (yyvsp[(3) - (3)].type));
}
break;
case 318:
-#line 1970 "go.y"
+#line 1974 "go.y"
{
(yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type));
}
break;
case 319:
-#line 1974 "go.y"
+#line 1978 "go.y"
{
(yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type));
}
break;
case 320:
-#line 1978 "go.y"
+#line 1982 "go.y"
{
(yyval.type) = tostruct((yyvsp[(3) - (4)].list));
}
break;
case 321:
-#line 1982 "go.y"
+#line 1986 "go.y"
{
(yyval.type) = tointerface((yyvsp[(3) - (4)].list));
}
break;
case 322:
-#line 1986 "go.y"
+#line 1990 "go.y"
{
(yyval.type) = ptrto((yyvsp[(2) - (2)].type));
}
break;
case 323:
-#line 1990 "go.y"
+#line 1994 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(2) - (2)].type);
@@ -4635,7 +4639,7 @@ yyreduce:
break;
case 324:
-#line 1996 "go.y"
+#line 2000 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (4)].type);
@@ -4644,7 +4648,7 @@ yyreduce:
break;
case 325:
-#line 2002 "go.y"
+#line 2006 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (3)].type);
@@ -4653,7 +4657,7 @@ yyreduce:
break;
case 326:
-#line 2010 "go.y"
+#line 2014 "go.y"
{
(yyval.type) = typ(TCHAN);
(yyval.type)->type = (yyvsp[(3) - (3)].type);
@@ -4662,14 +4666,14 @@ yyreduce:
break;
case 327:
-#line 2018 "go.y"
+#line 2022 "go.y"
{
(yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
}
break;
case 328:
-#line 2024 "go.y"
+#line 2028 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type)));
if((yyvsp[(1) - (3)].sym))
@@ -4679,7 +4683,7 @@ yyreduce:
break;
case 329:
-#line 2031 "go.y"
+#line 2035 "go.y"
{
Type *t;
@@ -4696,7 +4700,7 @@ yyreduce:
break;
case 330:
-#line 2047 "go.y"
+#line 2051 "go.y"
{
Sym *s;
@@ -4715,49 +4719,49 @@ yyreduce:
break;
case 331:
-#line 2065 "go.y"
+#line 2069 "go.y"
{
(yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list))));
}
break;
case 332:
-#line 2069 "go.y"
+#line 2073 "go.y"
{
(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)));
}
break;
case 333:
-#line 2074 "go.y"
+#line 2078 "go.y"
{
(yyval.list) = nil;
}
break;
case 335:
-#line 2081 "go.y"
+#line 2085 "go.y"
{
(yyval.list) = (yyvsp[(2) - (3)].list);
}
break;
case 336:
-#line 2085 "go.y"
+#line 2089 "go.y"
{
(yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))));
}
break;
case 337:
-#line 2095 "go.y"
+#line 2099 "go.y"
{
(yyval.node) = nodlit((yyvsp[(1) - (1)].val));
}
break;
case 338:
-#line 2099 "go.y"
+#line 2103 "go.y"
{
(yyval.node) = nodlit((yyvsp[(2) - (2)].val));
switch((yyval.node)->val.ctype){
@@ -4775,7 +4779,7 @@ yyreduce:
break;
case 339:
-#line 2114 "go.y"
+#line 2118 "go.y"
{
(yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg));
if((yyval.node)->op != OLITERAL)
@@ -4784,7 +4788,7 @@ yyreduce:
break;
case 341:
-#line 2123 "go.y"
+#line 2127 "go.y"
{
if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) {
(yyval.node) = (yyvsp[(2) - (5)].node);
@@ -4798,42 +4802,42 @@ yyreduce:
break;
case 344:
-#line 2139 "go.y"
+#line 2143 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 345:
-#line 2143 "go.y"
+#line 2147 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 346:
-#line 2149 "go.y"
+#line 2153 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 347:
-#line 2153 "go.y"
+#line 2157 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
break;
case 348:
-#line 2159 "go.y"
+#line 2163 "go.y"
{
(yyval.list) = list1((yyvsp[(1) - (1)].node));
}
break;
case 349:
-#line 2163 "go.y"
+#line 2167 "go.y"
{
(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
}
@@ -4841,7 +4845,7 @@ yyreduce:
/* Line 1267 of yacc.c. */
-#line 4846 "y.tab.c"
+#line 4850 "y.tab.c"
default: break;
}
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -5055,7 +5059,7 @@ yyreturn:
}
-#line 2167 "go.y"
+#line 2171 "go.y"
static void
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 38fc43ef1..025b258bf 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -20,6 +20,7 @@ import (
"path/filepath"
"regexp"
"runtime"
+ "strconv"
"strings"
"sync"
"time"
@@ -40,9 +41,13 @@ build writes the resulting executable to output.
Otherwise build compiles the packages but discards the results,
serving only as a check that the packages can be built.
-The -o flag specifies the output file name. If not specified, the
-name is packagename.a (for a non-main package) or the base
-name of the first source file (for a main package).
+The -o flag specifies the output file name. If not specified, the
+output file name depends on the arguments and derives from the name
+of the package, such as p.a for package p, unless p is 'main'. If
+the package is main and file names are provided, the file name
+derives from the first file name mentioned, such as f1 for 'go build
+f1.go f2.go'; with no files provided ('go build'), the output file
+name is the base name of the containing directory.
The build flags are shared by the build, install, run, and test commands:
@@ -53,6 +58,9 @@ The build flags are shared by the build, install, run, and test commands:
-p n
the number of builds that can be run in parallel.
The default is the number of CPUs available.
+ -race
+ enable data race detection.
+ Supported only on linux/amd64, darwin/amd64 and windows/amd64.
-v
print the names of packages as they are compiled.
-work
@@ -60,20 +68,22 @@ The build flags are shared by the build, install, run, and test commands:
do not delete it when exiting.
-x
print the commands.
- -race
- enable data race detection.
- Supported only on linux/amd64, darwin/amd64 and windows/amd64.
-ccflags 'arg list'
- arguments to pass on each 5c, 6c, or 8c compiler invocation
+ arguments to pass on each 5c, 6c, or 8c compiler invocation.
-compiler name
- name of compiler to use, as in runtime.Compiler (gccgo or gc)
+ name of compiler to use, as in runtime.Compiler (gccgo or gc).
-gccgoflags 'arg list'
- arguments to pass on each gccgo compiler/linker invocation
+ arguments to pass on each gccgo compiler/linker invocation.
-gcflags 'arg list'
- arguments to pass on each 5g, 6g, or 8g compiler invocation
+ arguments to pass on each 5g, 6g, or 8g compiler invocation.
+ -installsuffix suffix
+ a suffix to use in the name of the package installation directory,
+ in order to keep output separate from default builds.
+ If using the -race flag, the install suffix is automatically set to race
+ or, if set explicitly, has _race appended to it.
-ldflags 'flag list'
- arguments to pass on each 5l, 6l, or 8l linker invocation
+ arguments to pass on each 5l, 6l, or 8l linker invocation.
-tags 'tag list'
a list of build tags to consider satisfied during the build.
See the documentation for the go/build package for
@@ -153,6 +163,7 @@ func addBuildFlags(cmd *Command) {
cmd.Flag.BoolVar(&buildA, "a", false, "")
cmd.Flag.BoolVar(&buildN, "n", false, "")
cmd.Flag.IntVar(&buildP, "p", buildP, "")
+ cmd.Flag.StringVar(&buildContext.InstallSuffix, "installsuffix", "", "")
cmd.Flag.BoolVar(&buildV, "v", false, "")
cmd.Flag.BoolVar(&buildX, "x", false, "")
cmd.Flag.BoolVar(&buildWork, "work", false, "")
@@ -391,7 +402,9 @@ var (
func (b *builder) init() {
var err error
- b.print = fmt.Print
+ b.print = func(a ...interface{}) (int, error) {
+ return fmt.Fprint(os.Stderr, a...)
+ }
b.actionCache = make(map[cacheKey]*action)
b.mkdirCache = make(map[string]bool)
@@ -1188,8 +1201,8 @@ var cgoLine = regexp.MustCompile(`\[[^\[\]]+\.cgo1\.go:[0-9]+\]`)
// run runs the command given by cmdline in the directory dir.
// If the command fails, run prints information about the failure
// and returns a non-nil error.
-func (b *builder) run(dir string, desc string, cmdargs ...interface{}) error {
- out, err := b.runOut(dir, desc, cmdargs...)
+func (b *builder) run(dir string, desc string, env []string, cmdargs ...interface{}) error {
+ out, err := b.runOut(dir, desc, env, cmdargs...)
if len(out) > 0 {
if desc == "" {
desc = b.fmtcmd(dir, "%s", strings.Join(stringList(cmdargs...), " "))
@@ -1221,10 +1234,10 @@ func (b *builder) processOutput(out []byte) string {
// runOut runs the command given by cmdline in the directory dir.
// It returns the command output and any errors that occurred.
-func (b *builder) runOut(dir string, desc string, cmdargs ...interface{}) ([]byte, error) {
+func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
cmdline := stringList(cmdargs...)
if buildN || buildX {
- b.showcmd(dir, "%s", strings.Join(cmdline, " "))
+ b.showcmd(dir, "%s", joinUnambiguously(cmdline))
if buildN {
return nil, nil
}
@@ -1237,7 +1250,7 @@ func (b *builder) runOut(dir string, desc string, cmdargs ...interface{}) ([]byt
cmd.Stdout = &buf
cmd.Stderr = &buf
cmd.Dir = dir
- cmd.Env = envForDir(cmd.Dir)
+ cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir))
err := cmd.Run()
// cmd.Run will fail on Unix if some other process has the binary
@@ -1289,7 +1302,25 @@ func (b *builder) runOut(dir string, desc string, cmdargs ...interface{}) ([]byt
return buf.Bytes(), err
}
- panic("unreachable")
+}
+
+// joinUnambiguously prints the slice, quoting where necessary to make the
+// output unambiguous.
+// TODO: See issue 5279. The printing of commands needs a complete redo.
+func joinUnambiguously(a []string) string {
+ var buf bytes.Buffer
+ for i, s := range a {
+ if i > 0 {
+ buf.WriteByte(' ')
+ }
+ q := strconv.Quote(s)
+ if s == "" || strings.Contains(s, " ") || len(q) > len(s)+2 {
+ buf.WriteString(q)
+ } else {
+ buf.WriteString(s)
+ }
+ }
+ return buf.String()
}
// mkdir makes the named directory.
@@ -1439,13 +1470,13 @@ func (gcToolchain) gc(b *builder, p *Package, obj string, importArgs []string, g
args = append(args, mkAbs(p.Dir, f))
}
- output, err = b.runOut(p.Dir, p.ImportPath, args)
+ output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
return ofile, output, err
}
func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
sfile = mkAbs(p.Dir, sfile)
- return b.run(p.Dir, p.ImportPath, tool(archChar+"a"), "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
+ return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-I", obj, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
}
func (gcToolchain) pkgpath(basedir string, p *Package) string {
@@ -1458,7 +1489,7 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
}
- return b.run(p.Dir, p.ImportPath, tool("pack"), "grcP", b.work, mkAbs(objDir, afile), absOfiles)
+ return b.run(p.Dir, p.ImportPath, nil, tool("pack"), "grcP", b.work, mkAbs(objDir, afile), absOfiles)
}
func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
@@ -1477,14 +1508,14 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
swigDirs[sd] = true
}
}
- return b.run(".", p.ImportPath, tool(archChar+"l"), "-o", out, importArgs, swigArg, buildLdflags, mainpkg)
+ return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, swigArg, buildLdflags, mainpkg)
}
func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
cfile = mkAbs(p.Dir, cfile)
args := stringList(tool(archChar+"c"), "-F", "-V", "-w", "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
- return b.run(p.Dir, p.ImportPath, args)
+ return b.run(p.Dir, p.ImportPath, nil, args)
}
// The Gccgo toolchain.
@@ -1516,7 +1547,7 @@ func (gccgoToolchain) gc(b *builder, p *Package, obj string, importArgs []string
args = append(args, mkAbs(p.Dir, f))
}
- output, err = b.runOut(p.Dir, p.ImportPath, args)
+ output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
return ofile, output, err
}
@@ -1527,7 +1558,7 @@ func (gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) erro
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
}
defs = append(defs, b.gccArchArgs()...)
- return b.run(p.Dir, p.ImportPath, "gccgo", "-I", obj, "-o", ofile, defs, sfile)
+ return b.run(p.Dir, p.ImportPath, nil, "gccgo", "-I", obj, "-o", ofile, defs, sfile)
}
func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
@@ -1542,7 +1573,7 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
for _, f := range ofiles {
absOfiles = append(absOfiles, mkAbs(objDir, f))
}
- return b.run(p.Dir, p.ImportPath, "ar", "cru", mkAbs(objDir, afile), absOfiles)
+ return b.run(p.Dir, p.ImportPath, nil, "ar", "cru", mkAbs(objDir, afile), absOfiles)
}
func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
@@ -1584,7 +1615,7 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
if usesCgo && goos == "linux" {
ldflags = append(ldflags, "-Wl,-E")
}
- return b.run(".", p.ImportPath, "gccgo", "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
+ return b.run(".", p.ImportPath, nil, "gccgo", "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
}
func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
@@ -1596,7 +1627,7 @@ func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) er
defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
}
// TODO: Support using clang here (during gccgo build)?
- return b.run(p.Dir, p.ImportPath, "gcc", "-Wall", "-g",
+ return b.run(p.Dir, p.ImportPath, nil, "gcc", "-Wall", "-g",
"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
}
@@ -1632,11 +1663,11 @@ func (b *builder) libgcc(p *Package) (string, error) {
// print function to capture the command-line. This
// let's us assign it to $LIBGCC and produce a valid
// buildscript for cgo packages.
- b.print = func(a ...interface{}) (n int, err error) {
+ b.print = func(a ...interface{}) (int, error) {
return fmt.Fprint(&buf, a...)
}
}
- f, err := b.runOut(p.Dir, p.ImportPath, gccCmd, "-print-libgcc-file-name")
+ f, err := b.runOut(p.Dir, p.ImportPath, nil, gccCmd, "-print-libgcc-file-name")
if err != nil {
return "", fmt.Errorf("gcc -print-libgcc-file-name: %v (%s)", err, f)
}
@@ -1659,12 +1690,12 @@ func (b *builder) libgcc(p *Package) (string, error) {
// gcc runs the gcc C compiler to create an object from a single C file.
func (b *builder) gcc(p *Package, out string, flags []string, cfile string) error {
cfile = mkAbs(p.Dir, cfile)
- return b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), flags, "-o", out, "-c", cfile)
+ return b.run(p.Dir, p.ImportPath, nil, b.gccCmd(p.Dir), flags, "-o", out, "-c", cfile)
}
// gccld runs the gcc linker to create an executable from a set of object files
func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error {
- return b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), "-o", out, obj, flags)
+ return b.run(p.Dir, p.ImportPath, nil, b.gccCmd(p.Dir), "-o", out, obj, flags)
}
// gccCmd returns a gcc command line prefix
@@ -1745,7 +1776,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
cgoLDFLAGS := stringList(envList("CGO_LDFLAGS"), p.CgoLDFLAGS)
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
- out, err := b.runOut(p.Dir, p.ImportPath, "pkg-config", "--cflags", pkgs)
+ out, err := b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--cflags", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
@@ -1754,7 +1785,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
if len(out) > 0 {
cgoCFLAGS = append(cgoCFLAGS, strings.Fields(string(out))...)
}
- out, err = b.runOut(p.Dir, p.ImportPath, "pkg-config", "--libs", pkgs)
+ out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
if err != nil {
b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
@@ -1791,6 +1822,16 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
cgoflags = append(cgoflags, "-import_syscall=false")
}
+ // Update $CGO_LDFLAGS with p.CgoLDFLAGS.
+ var cgoenv []string
+ if len(cgoLDFLAGS) > 0 {
+ flags := make([]string, len(cgoLDFLAGS))
+ for i, f := range cgoLDFLAGS {
+ flags[i] = strconv.Quote(f)
+ }
+ cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
+ }
+
if _, ok := buildToolchain.(gccgoToolchain); ok {
cgoflags = append(cgoflags, "-gccgo")
if pkgpath := gccgoPkgpath(p); pkgpath != "" {
@@ -1798,7 +1839,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
}
objExt = "o"
}
- if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, cgoflags, "--", cgoCFLAGS, p.CgoFiles); err != nil {
+ if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCFLAGS, p.CgoFiles); err != nil {
return nil, nil, err
}
outGo = append(outGo, gofiles...)
@@ -1883,7 +1924,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,
if p.Standard && p.ImportPath == "runtime/cgo" {
cgoflags = append(cgoflags, "-dynlinker") // record path to dynamic linker
}
- if err := b.run(p.Dir, p.ImportPath, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC, cgoflags); err != nil {
+ if err := b.run(p.Dir, p.ImportPath, nil, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC, cgoflags); err != nil {
return nil, nil, err
}
@@ -2006,7 +2047,7 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
args = append(args, "-c++")
}
- if out, err := b.runOut(p.Dir, p.ImportPath, "swig", args, file); err != nil {
+ if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil {
if len(out) > 0 {
if bytes.Contains(out, []byte("Unrecognized option -intgosize")) {
return "", "", errors.New("must have SWIG version >= 2.0.9\n")
@@ -2044,7 +2085,7 @@ func (b *builder) swigOne(p *Package, file, obj string, cxx bool, intgosize stri
cxxlib = []string{"-lstdc++"}
}
ldflags := stringList(osldflags[goos], cxxlib)
- b.run(p.Dir, p.ImportPath, b.gccCmd(p.Dir), "-o", soname, gccObj, ldflags)
+ b.run(p.Dir, p.ImportPath, nil, b.gccCmd(p.Dir), "-o", soname, gccObj, ldflags)
return obj + goFile, cObj, nil
}
@@ -2083,6 +2124,9 @@ func raceInit() {
buildGcflags = append(buildGcflags, "-race")
buildLdflags = append(buildLdflags, "-race")
buildCcflags = append(buildCcflags, "-D", "RACE")
- buildContext.InstallTag = "race"
+ if buildContext.InstallSuffix != "" {
+ buildContext.InstallSuffix += "_"
+ }
+ buildContext.InstallSuffix += "race"
buildContext.BuildTags = append(buildContext.BuildTags, "race")
}
diff --git a/src/cmd/go/clean.go b/src/cmd/go/clean.go
index ba600d3bb..8345c9af1 100644
--- a/src/cmd/go/clean.go
+++ b/src/cmd/go/clean.go
@@ -106,6 +106,8 @@ func clean(p *Package) {
if cleaned[p] {
return
}
+ cleaned[p] = true
+
if p.Dir == "" {
errorf("can't load package: %v", p.Error)
return
diff --git a/src/cmd/go/discovery.go b/src/cmd/go/discovery.go
index d9f930867..047834050 100644
--- a/src/cmd/go/discovery.go
+++ b/src/cmd/go/discovery.go
@@ -48,7 +48,6 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport) {
})
}
}
- return
}
// attrValue returns the attribute value for the case-insensitive key
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index 0297b7602..df82ab45b 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
+// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
+
/*
Go is a tool for managing Go source code.
@@ -56,9 +59,13 @@ build writes the resulting executable to output.
Otherwise build compiles the packages but discards the results,
serving only as a check that the packages can be built.
-The -o flag specifies the output file name. If not specified, the
-name is packagename.a (for a non-main package) or the base
-name of the first source file (for a main package).
+The -o flag specifies the output file name. If not specified, the
+output file name depends on the arguments and derives from the name
+of the package, such as p.a for package p, unless p is 'main'. If
+the package is main and file names are provided, the file name
+derives from the first file name mentioned, such as f1 for 'go build
+f1.go f2.go'; with no files provided ('go build'), the output file
+name is the base name of the containing directory.
The build flags are shared by the build, install, run, and test commands:
@@ -69,6 +76,9 @@ The build flags are shared by the build, install, run, and test commands:
-p n
the number of builds that can be run in parallel.
The default is the number of CPUs available.
+ -race
+ enable data race detection.
+ Supported only on linux/amd64, darwin/amd64 and windows/amd64.
-v
print the names of packages as they are compiled.
-work
@@ -76,20 +86,22 @@ The build flags are shared by the build, install, run, and test commands:
do not delete it when exiting.
-x
print the commands.
- -race
- enable data race detection.
- Supported only on linux/amd64, darwin/amd64 and windows/amd64.
-ccflags 'arg list'
- arguments to pass on each 5c, 6c, or 8c compiler invocation
+ arguments to pass on each 5c, 6c, or 8c compiler invocation.
-compiler name
- name of compiler to use, as in runtime.Compiler (gccgo or gc)
+ name of compiler to use, as in runtime.Compiler (gccgo or gc).
-gccgoflags 'arg list'
- arguments to pass on each gccgo compiler/linker invocation
+ arguments to pass on each gccgo compiler/linker invocation.
-gcflags 'arg list'
- arguments to pass on each 5g, 6g, or 8g compiler invocation
+ arguments to pass on each 5g, 6g, or 8g compiler invocation.
+ -installsuffix suffix
+ a suffix to use in the name of the package installation directory,
+ in order to keep output separate from default builds.
+ If using the -race flag, the install suffix is automatically set to race
+ or, if set explicitly, has _race appended to it.
-ldflags 'flag list'
- arguments to pass on each 5l, 6l, or 8l linker invocation
+ arguments to pass on each 5l, 6l, or 8l linker invocation.
-tags 'tag list'
a list of build tags to consider satisfied during the build.
See the documentation for the go/build package for
@@ -358,6 +370,7 @@ Usage:
go run [build flags] gofiles... [arguments...]
Run compiles and runs the main package comprising the named Go source files.
+If no files are named, it compiles and runs all non-test Go source files.
For more about build flags, see 'go help build'.
@@ -385,6 +398,9 @@ the file pattern "*_test.go". These additional files can contain test functions
benchmark functions, and example functions. See 'go help testfunc' for more.
Each listed package causes the execution of a separate test binary.
+Test files that declare a package with the suffix "_test" will be compiled as a
+separate package, and then linked and run with the main test binary.
+
By default, go test needs no arguments. It compiles and tests the package
with source in the current directory, including tests, and runs the tests.
@@ -394,6 +410,7 @@ non-test installation.
In addition to the build flags, the flags handled by 'go test' itself are:
-c Compile the test binary to pkg.test but do not run it.
+ (Where pkg is the last element of the package's import path.)
-i
Install packages that are dependencies of the test.
@@ -569,7 +586,7 @@ a revision control system.
A few common code hosting sites have special syntax:
- BitBucket (Mercurial)
+ Bitbucket (Git, Mercurial)
import "bitbucket.org/user/project"
import "bitbucket.org/user/project/sub/directory"
@@ -679,6 +696,11 @@ Description of testing flags
The 'go test' command takes both flags that apply to 'go test' itself
and flags that apply to the resulting test binary.
+Several of the flags control profiling and write an execution profile
+suitable for "go tool pprof"; run "go tool pprof help" for more
+information. The --alloc_space, --alloc_objects, and --show_bytes
+options of pprof control how the information is presented.
+
The following flags are recognized by the 'go test' command and
control the execution of any test:
@@ -691,17 +713,18 @@ control the execution of any test:
Print memory allocation statistics for benchmarks.
-benchtime t
- Run enough iterations of each benchmark to take t, specified
- as a time.Duration (for example, -benchtime 1h30s).
- The default is 1 second (1s).
+ Run enough iterations of each benchmark to take t, specified
+ as a time.Duration (for example, -benchtime 1h30s).
+ The default is 1 second (1s).
-blockprofile block.out
Write a goroutine blocking profile to the specified file
when all tests are complete.
-blockprofilerate n
- Control the detail provided in goroutine blocking profiles by setting
- runtime.BlockProfileRate to n. See 'godoc runtime BlockProfileRate'.
+ Control the detail provided in goroutine blocking profiles by
+ calling runtime.SetBlockProfileRate with n.
+ See 'godoc runtime SetBlockProfileRate'.
The profiler aims to sample, on average, one blocking event every
n nanoseconds the program spends blocked. By default,
if -test.blockprofile is set without this flag, all blocking events
@@ -716,8 +739,8 @@ control the execution of any test:
Write a CPU profile to the specified file before exiting.
-memprofile mem.out
- Write a memory profile to the specified file when all tests
- are complete.
+ Write a memory profile to the specified file after all tests
+ have passed.
-memprofilerate n
Enable more precise (and expensive) memory profiles by setting
@@ -743,10 +766,11 @@ control the execution of any test:
exhaustive tests.
-timeout t
- If a test runs longer than t, panic.
+ If a test runs longer than t, panic.
-v
- Verbose output: log all tests as they are run.
+ Verbose output: log all tests as they are run. Also print all
+ text from Log and Logf calls even if the test succeeds.
The test binary, called pkg.test where pkg is the name of the
directory containing the package sources, can be invoked directly
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
index 6cab37b48..00e03e9bd 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -42,6 +42,7 @@ func mkEnv() []envVar {
{"GOHOSTOS", runtime.GOOS},
{"GOOS", goos},
{"GOPATH", os.Getenv("GOPATH")},
+ {"GORACE", os.Getenv("GORACE")},
{"GOROOT", goroot},
{"GOTOOLDIR", toolDir},
}
diff --git a/src/cmd/go/go11.go b/src/cmd/go/go11.go
new file mode 100644
index 000000000..8a434dfed
--- /dev/null
+++ b/src/cmd/go/go11.go
@@ -0,0 +1,10 @@
+// Copyright 2013 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.
+
+// +build go1.1
+
+package main
+
+// Test that go1.1 tag above is included in builds. main.go refers to this definition.
+const go11tag = true
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index 6d2bd7dbb..c70a25fdd 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -20,13 +20,13 @@ denotes the package in that directory.
Otherwise, the import path P denotes the package found in
the directory DIR/src/P for some DIR listed in the GOPATH
-environment variable (see 'go help gopath').
+environment variable (see 'go help gopath').
If no import paths are given, the action applies to the
package in the current directory.
The special import path "all" expands to all package directories
-found in all the GOPATH trees. For example, 'go list all'
+found in all the GOPATH trees. For example, 'go list all'
lists all the packages on the local system.
The special import path "std" is like all but expands to just the
@@ -68,7 +68,7 @@ a revision control system.
A few common code hosting sites have special syntax:
- BitBucket (Mercurial)
+ Bitbucket (Git, Mercurial)
import "bitbucket.org/user/project"
import "bitbucket.org/user/project/sub/directory"
@@ -232,7 +232,7 @@ Here's an example directory layout:
bar.a (installed package object)
Go searches each directory listed in GOPATH to find source code,
-but new packages are always downloaded into the first directory
+but new packages are always downloaded into the first directory
in the list.
`,
}
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index bf1dad40f..3180dbeed 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -108,6 +108,7 @@ func setExitStatus(n int) {
}
func main() {
+ _ = go11tag
flag.Usage = usage
flag.Parse()
log.SetFlags(0)
@@ -129,8 +130,11 @@ func main() {
fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
} else {
for _, p := range filepath.SplitList(gopath) {
- if strings.Contains(p, "~") && runtime.GOOS != "windows" {
- fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot contain shell metacharacter '~': %q\n", p)
+ // Note: using HasPrefix instead of Contains because a ~ can appear
+ // in the middle of directory elements, such as /tmp/git-1.8.2~rc3
+ // or C:\PROGRA~1. Only ~ as a path prefix has meaning to the shell.
+ if strings.HasPrefix(p, "~") {
+ fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p)
os.Exit(2)
}
if build.IsLocalImport(p) {
@@ -189,6 +193,9 @@ var documentationTemplate = `// Copyright 2011 The Go Authors. All rights reser
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
+// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
+
/*
{{range .}}{{if .Short}}{{.Short | capitalize}}
@@ -386,16 +393,26 @@ func runOut(dir string, cmdargs ...interface{}) []byte {
// child will be faster.
func envForDir(dir string) []string {
env := os.Environ()
- for i, kv := range env {
- if strings.HasPrefix(kv, "PWD=") {
- env[i] = "PWD=" + dir
- return env
- }
- }
// Internally we only use rooted paths, so dir is rooted.
// Even if dir is not rooted, no harm done.
- env = append(env, "PWD="+dir)
- return env
+ return mergeEnvLists([]string{"PWD=" + dir}, env)
+}
+
+// mergeEnvLists merges the two environment lists such that
+// variables with the same name in "in" replace those in "out".
+func mergeEnvLists(in, out []string) []string {
+NextVar:
+ for _, inkv := range in {
+ k := strings.SplitAfterN(inkv, "=", 2)[0]
+ for i, outkv := range out {
+ if strings.HasPrefix(outkv, k) {
+ out[i] = inkv
+ continue NextVar
+ }
+ }
+ out = append(out, inkv)
+ }
+ return out
}
// matchPattern(pattern)(name) reports whether
diff --git a/src/cmd/go/mkdoc.sh b/src/cmd/go/mkdoc.sh
index 7768baeb6..12fd7ba3e 100755
--- a/src/cmd/go/mkdoc.sh
+++ b/src/cmd/go/mkdoc.sh
@@ -3,6 +3,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
+go install # So the next line will produce updated documentation.
go help documentation > doc.go
gofmt -w doc.go
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 7fc61fd86..b33d800bf 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -72,6 +72,7 @@ type Package struct {
imports []*Package
deps []*Package
gofiles []string // GoFiles+CgoFiles+TestGoFiles+XTestGoFiles files, absolute paths
+ sfiles []string
allgofiles []string // gofiles + IgnoredGoFiles, absolute paths
target string // installed file for this package (may be executable)
fake bool // synthesized package
@@ -366,6 +367,12 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
}
sort.Strings(p.gofiles)
+ p.sfiles = stringList(p.SFiles)
+ for i := range p.sfiles {
+ p.sfiles[i] = filepath.Join(p.Dir, p.sfiles[i])
+ }
+ sort.Strings(p.sfiles)
+
p.allgofiles = stringList(p.IgnoredGoFiles)
for i := range p.allgofiles {
p.allgofiles[i] = filepath.Join(p.Dir, p.allgofiles[i])
diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go
index b50569363..91bdc1be2 100644
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -16,6 +16,7 @@ var cmdRun = &Command{
Short: "compile and run Go program",
Long: `
Run compiles and runs the main package comprising the named Go source files.
+If no files are named, it compiles and runs all non-test Go source files.
For more about build flags, see 'go help build'.
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index 460061a11..e2264a46e 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -11,18 +11,19 @@ ok=true
unset GOPATH
unset GOBIN
-# Test that error messages have file:line information
-# at beginning of line.
-for i in testdata/errmsg/*.go
-do
- # TODO: |cat should not be necessary here but is.
- ./testgo test $i 2>&1 | cat >err.out || true
- if ! grep -q "^$i:" err.out; then
- echo "$i: missing file:line in error message"
- cat err.out
- ok=false
- fi
-done
+# Test that error messages have file:line information at beginning of
+# the line. Also test issue 4917: that the error is on stderr.
+d=$(mktemp -d -t testgoXXX)
+fn=$d/err.go
+echo "package main" > $fn
+echo 'import "bar"' >> $fn
+./testgo run $fn 2>$d/err.out || true
+if ! grep -q "^$fn:" $d/err.out; then
+ echo "missing file:line in error message"
+ cat $d/err.out
+ ok=false
+fi
+rm -r $d
# Test local (./) imports.
testlocal() {
@@ -51,7 +52,7 @@ testlocal() {
ok=false
fi
- rm -f err.out hello.out hello
+ rm -f hello.out hello
# Test that go install x.go fails.
if ./testgo install "testdata/$local/easy.go" >/dev/null 2>&1; then
@@ -183,7 +184,7 @@ fi
# issue 4186. go get cannot be used to download packages to $GOROOT
# Test that without GOPATH set, go get should fail
-d=$(mktemp -d -t testgo)
+d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src/pkg
if GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with $GOPATH unset'
@@ -191,7 +192,7 @@ if GOPATH= GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch
fi
rm -rf $d
# Test that with GOPATH=$GOROOT, go get should fail
-d=$(mktemp -d -t testgo)
+d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src/pkg
if GOPATH=$d GOROOT=$d ./testgo get -d code.google.com/p/go.codereview/cmd/hgpatch ; then
echo 'go get code.google.com/p/go.codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'
@@ -200,7 +201,7 @@ fi
rm -rf $d
# issue 3941: args with spaces
-d=$(mktemp -d -t testgo)
+d=$(mktemp -d -t testgoXXX)
cat >$d/main.go<<EOF
package main
var extern string
@@ -226,7 +227,7 @@ rm -f strings.prof strings.test
# issue 4568. test that symlinks don't screw things up too badly.
old=$(pwd)
-d=$(mktemp -d -t testgo)
+d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src
(
ln -s $d $d/src/dir1
@@ -247,7 +248,7 @@ fi
rm -rf $d
# issue 4515.
-d=$(mktemp -d -t testgo)
+d=$(mktemp -d -t testgoXXX)
mkdir -p $d/src/example/a $d/src/example/b $d/bin
cat >$d/src/example/a/main.go <<EOF
package main
@@ -280,7 +281,7 @@ unset GOPATH
rm -rf $d
# issue 4773. case-insensitive collisions
-d=$(mktemp -d -t testgo)
+d=$(mktemp -d -t testgoXXX)
export GOPATH=$d
mkdir -p $d/src/example/a $d/src/example/b
cat >$d/src/example/a/a.go <<EOF
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index 3132ab210..b1db16f77 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -50,6 +50,9 @@ the file pattern "*_test.go". These additional files can contain test functions
benchmark functions, and example functions. See 'go help testfunc' for more.
Each listed package causes the execution of a separate test binary.
+Test files that declare a package with the suffix "_test" will be compiled as a
+separate package, and then linked and run with the main test binary.
+
By default, go test needs no arguments. It compiles and tests the package
with source in the current directory, including tests, and runs the tests.
@@ -59,6 +62,7 @@ non-test installation.
In addition to the build flags, the flags handled by 'go test' itself are:
-c Compile the test binary to pkg.test but do not run it.
+ (Where pkg is the last element of the package's import path.)
-i
Install packages that are dependencies of the test.
@@ -81,6 +85,11 @@ var helpTestflag = &Command{
The 'go test' command takes both flags that apply to 'go test' itself
and flags that apply to the resulting test binary.
+Several of the flags control profiling and write an execution profile
+suitable for "go tool pprof"; run "go tool pprof help" for more
+information. The --alloc_space, --alloc_objects, and --show_bytes
+options of pprof control how the information is presented.
+
The following flags are recognized by the 'go test' command and
control the execution of any test:
@@ -93,17 +102,18 @@ control the execution of any test:
Print memory allocation statistics for benchmarks.
-benchtime t
- Run enough iterations of each benchmark to take t, specified
- as a time.Duration (for example, -benchtime 1h30s).
- The default is 1 second (1s).
+ Run enough iterations of each benchmark to take t, specified
+ as a time.Duration (for example, -benchtime 1h30s).
+ The default is 1 second (1s).
-blockprofile block.out
Write a goroutine blocking profile to the specified file
when all tests are complete.
-blockprofilerate n
- Control the detail provided in goroutine blocking profiles by setting
- runtime.BlockProfileRate to n. See 'godoc runtime BlockProfileRate'.
+ Control the detail provided in goroutine blocking profiles by
+ calling runtime.SetBlockProfileRate with n.
+ See 'godoc runtime SetBlockProfileRate'.
The profiler aims to sample, on average, one blocking event every
n nanoseconds the program spends blocked. By default,
if -test.blockprofile is set without this flag, all blocking events
@@ -118,8 +128,8 @@ control the execution of any test:
Write a CPU profile to the specified file before exiting.
-memprofile mem.out
- Write a memory profile to the specified file when all tests
- are complete.
+ Write a memory profile to the specified file after all tests
+ have passed.
-memprofilerate n
Enable more precise (and expensive) memory profiles by setting
@@ -145,10 +155,11 @@ control the execution of any test:
exhaustive tests.
-timeout t
- If a test runs longer than t, panic.
+ If a test runs longer than t, panic.
-v
- Verbose output: log all tests as they are run.
+ Verbose output: log all tests as they are run. Also print all
+ text from Log and Logf calls even if the test succeeds.
The test binary, called pkg.test where pkg is the name of the
directory containing the package sources, can be invoked directly
diff --git a/src/cmd/go/testdata/errmsg/x.go b/src/cmd/go/testdata/errmsg/x.go
deleted file mode 100644
index 60f5b6e98..000000000
--- a/src/cmd/go/testdata/errmsg/x.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package foo
-
-import "bar"
diff --git a/src/cmd/go/testdata/errmsg/x1_test.go b/src/cmd/go/testdata/errmsg/x1_test.go
deleted file mode 100644
index eb1a6798c..000000000
--- a/src/cmd/go/testdata/errmsg/x1_test.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package foo_test
-
-import "bar"
diff --git a/src/cmd/go/testdata/errmsg/x_test.go b/src/cmd/go/testdata/errmsg/x_test.go
deleted file mode 100644
index 60f5b6e98..000000000
--- a/src/cmd/go/testdata/errmsg/x_test.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package foo
-
-import "bar"
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index b99579441..39881a6dc 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -641,7 +641,7 @@ func oldGoogleCode(match map[string]string) error {
}
// bitbucketVCS determines the version control system for a
-// BitBucket repository, by using the BitBucket API.
+// Bitbucket repository, by using the Bitbucket API.
func bitbucketVCS(match map[string]string) error {
if err := noVCSSuffix(match); err != nil {
return err
diff --git a/src/cmd/go/vet.go b/src/cmd/go/vet.go
index eb0b89cca..503e16362 100644
--- a/src/cmd/go/vet.go
+++ b/src/cmd/go/vet.go
@@ -32,6 +32,6 @@ func runVet(cmd *Command, args []string) {
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
- run(tool("vet"), relPaths(pkg.gofiles))
+ run(tool("vet"), relPaths(stringList(pkg.gofiles, pkg.sfiles)))
}
}
diff --git a/src/cmd/godoc/doc.go b/src/cmd/godoc/doc.go
index ddb6d2687..1fa57a8b3 100644
--- a/src/cmd/godoc/doc.go
+++ b/src/cmd/godoc/doc.go
@@ -61,12 +61,17 @@ The flags are:
to the indexer (the indexer will never finish), a value of 1.0
means that index creation is running at full throttle (other
goroutines may get no time while the index is built)
+ -links=true:
+ link identifiers to their declarations
-write_index=false
write index to a file; the file name must be specified with
-index_files
-maxresults=10000
maximum number of full text search results shown
(no full text index is built if maxresults <= 0)
+ -notes="BUG"
+ regular expression matching note markers to show
+ (e.g., "BUG|TODO", ".*")
-html
print HTML in command-line mode
-goroot=$GOROOT
diff --git a/src/cmd/godoc/format.go b/src/cmd/godoc/format.go
index 122ddc7d6..59a89c5bf 100644
--- a/src/cmd/godoc/format.go
+++ b/src/cmd/godoc/format.go
@@ -23,15 +23,21 @@ import (
// ----------------------------------------------------------------------------
// Implementation of FormatSelections
-// A Selection is a function returning offset pairs []int{a, b}
-// describing consecutive non-overlapping text segments [a, b).
-// If there are no more segments, a Selection must return nil.
+// A Segment describes a text segment [start, end).
+// The zero value of a Segment is a ready-to-use empty segment.
//
-// TODO It's more efficient to return a pair (a, b int) instead
-// of creating lots of slices. Need to determine how to
-// indicate the end of a Selection.
+type Segment struct {
+ start, end int
+}
+
+func (seg *Segment) isEmpty() bool { return seg.start >= seg.end }
+
+// A Selection is an "iterator" function returning a text segment.
+// Repeated calls to a selection return consecutive, non-overlapping,
+// non-empty segments, followed by an infinite sequence of empty
+// segments. The first empty segment marks the end of the selection.
//
-type Selection func() []int
+type Selection func() Segment
// A LinkWriter writes some start or end "tag" to w for the text offset offs.
// It is called by FormatSelections at the start or end of each link segment.
@@ -141,17 +147,17 @@ func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection,
//
type merger struct {
selections []Selection
- segments [][]int // segments[i] is the next segment of selections[i]
+ segments []Segment // segments[i] is the next segment of selections[i]
}
const infinity int = 2e9
func newMerger(selections []Selection) *merger {
- segments := make([][]int, len(selections))
+ segments := make([]Segment, len(selections))
for i, sel := range selections {
- segments[i] = []int{infinity, infinity}
+ segments[i] = Segment{infinity, infinity}
if sel != nil {
- if seg := sel(); seg != nil {
+ if seg := sel(); !seg.isEmpty() {
segments[i] = seg
}
}
@@ -170,12 +176,12 @@ func (m *merger) next() (index, offs int, start bool) {
index = -1
for i, seg := range m.segments {
switch {
- case seg[0] < offs:
- offs = seg[0]
+ case seg.start < offs:
+ offs = seg.start
index = i
start = true
- case seg[1] < offs:
- offs = seg[1]
+ case seg.end < offs:
+ offs = seg.end
index = i
start = false
}
@@ -188,18 +194,17 @@ func (m *merger) next() (index, offs int, start bool) {
// either way it is ok to consume the start offset: set it
// to infinity so it won't be considered in the following
// next call
- m.segments[index][0] = infinity
+ m.segments[index].start = infinity
if start {
return
}
// end offset found - consume it
- m.segments[index][1] = infinity
+ m.segments[index].end = infinity
// advance to the next segment for that selection
seg := m.selections[index]()
- if seg == nil {
- return
+ if !seg.isEmpty() {
+ m.segments[index] = seg
}
- m.segments[index] = seg
return
}
@@ -209,7 +214,7 @@ func (m *merger) next() (index, offs int, start bool) {
// lineSelection returns the line segments for text as a Selection.
func lineSelection(text []byte) Selection {
i, j := 0, 0
- return func() (seg []int) {
+ return func() (seg Segment) {
// find next newline, if any
for j < len(text) {
j++
@@ -219,30 +224,30 @@ func lineSelection(text []byte) Selection {
}
if i < j {
// text[i:j] constitutes a line
- seg = []int{i, j}
+ seg = Segment{i, j}
i = j
}
return
}
}
-// commentSelection returns the sequence of consecutive comments
-// in the Go src text as a Selection.
+// tokenSelection returns, as a selection, the sequence of
+// consecutive occurrences of token sel in the Go src text.
//
-func commentSelection(src []byte) Selection {
+func tokenSelection(src []byte, sel token.Token) Selection {
var s scanner.Scanner
fset := token.NewFileSet()
file := fset.AddFile("", fset.Base(), len(src))
s.Init(file, src, nil, scanner.ScanComments)
- return func() (seg []int) {
+ return func() (seg Segment) {
for {
pos, tok, lit := s.Scan()
if tok == token.EOF {
break
}
offs := file.Offset(pos)
- if tok == token.COMMENT {
- seg = []int{offs, offs + len(lit)}
+ if tok == sel {
+ seg = Segment{offs, offs + len(lit)}
break
}
}
@@ -251,13 +256,20 @@ func commentSelection(src []byte) Selection {
}
// makeSelection is a helper function to make a Selection from a slice of pairs.
+// Pairs describing empty segments are ignored.
+//
func makeSelection(matches [][]int) Selection {
- return func() (seg []int) {
- if len(matches) > 0 {
- seg = matches[0]
- matches = matches[1:]
+ i := 0
+ return func() Segment {
+ for i < len(matches) {
+ m := matches[i]
+ i++
+ if m[0] < m[1] {
+ // non-empty segment
+ return Segment{m[0], m[1]}
+ }
}
- return
+ return Segment{}
}
}
@@ -338,7 +350,7 @@ func selectionTag(w io.Writer, text []byte, selections int) {
func FormatText(w io.Writer, text []byte, line int, goSource bool, pattern string, selection Selection) {
var comments, highlights Selection
if goSource {
- comments = commentSelection(text)
+ comments = tokenSelection(text, token.COMMENT)
}
if pattern != "" {
highlights = regexpSelection(text, pattern)
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index 872b0dc1e..26b0b97e1 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -66,6 +66,7 @@ var (
templateDir = flag.String("templates", "", "directory containing alternate template files")
showPlayground = flag.Bool("play", false, "enable playground in web interface")
showExamples = flag.Bool("ex", false, "show examples in command line mode")
+ declLinks = flag.Bool("links", true, "link identifiers to their declarations")
// search index
indexEnabled = flag.Bool("index", false, "enable search index")
@@ -84,15 +85,11 @@ var (
cmdHandler docServer
pkgHandler docServer
- // which code 'Notes' to show
- notes = flag.String("notes", "BUG", "comma separated list of Note markers as per pkg:go/doc")
- // list of 'Notes' to show
- notesToShow []string
+ // source code notes
+ notes = flag.String("notes", "BUG", "regular expression matching note markers to show")
)
func initHandlers() {
- notesToShow = strings.Split(*notes, ",")
-
fileServer = http.FileServer(&httpFS{fs})
cmdHandler = docServer{"/cmd/", "/src/cmd"}
pkgHandler = docServer{"/pkg/", "/src/pkg"}
@@ -276,17 +273,23 @@ func infoSnippet_htmlFunc(info SpotInfo) string {
return `<span class="alert">no snippet text available</span>`
}
-func nodeFunc(node interface{}, fset *token.FileSet) string {
+func nodeFunc(info *PageInfo, node interface{}) string {
var buf bytes.Buffer
- writeNode(&buf, fset, node)
+ writeNode(&buf, info.FSet, node)
return buf.String()
}
-func node_htmlFunc(node interface{}, fset *token.FileSet) string {
+func node_htmlFunc(info *PageInfo, node interface{}, linkify bool) string {
var buf1 bytes.Buffer
- writeNode(&buf1, fset, node)
+ writeNode(&buf1, info.FSet, node)
+
var buf2 bytes.Buffer
- FormatText(&buf2, buf1.Bytes(), -1, true, "", nil)
+ if n, _ := node.(ast.Node); n != nil && linkify && *declLinks {
+ LinkifyText(&buf2, buf1.Bytes(), n)
+ } else {
+ FormatText(&buf2, buf1.Bytes(), -1, true, "", nil)
+ }
+
return buf2.String()
}
@@ -337,14 +340,14 @@ func stripExampleSuffix(name string) string {
return name
}
-func example_textFunc(funcName string, examples []*doc.Example, fset *token.FileSet, indent string) string {
+func example_textFunc(info *PageInfo, funcName, indent string) string {
if !*showExamples {
return ""
}
var buf bytes.Buffer
first := true
- for _, eg := range examples {
+ for _, eg := range info.Examples {
name := stripExampleSuffix(eg.Name)
if name != funcName {
continue
@@ -358,7 +361,7 @@ func example_textFunc(funcName string, examples []*doc.Example, fset *token.File
// print code
cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments}
var buf1 bytes.Buffer
- writeNode(&buf1, fset, cnode)
+ writeNode(&buf1, info.FSet, cnode)
code := buf1.String()
// Additional formatting if this is a function body.
if n := len(code); n >= 2 && code[0] == '{' && code[n-1] == '}' {
@@ -378,9 +381,9 @@ func example_textFunc(funcName string, examples []*doc.Example, fset *token.File
return buf.String()
}
-func example_htmlFunc(funcName string, examples []*doc.Example, fset *token.FileSet) string {
+func example_htmlFunc(info *PageInfo, funcName string) string {
var buf bytes.Buffer
- for _, eg := range examples {
+ for _, eg := range info.Examples {
name := stripExampleSuffix(eg.Name)
if name != funcName {
@@ -389,7 +392,7 @@ func example_htmlFunc(funcName string, examples []*doc.Example, fset *token.File
// print code
cnode := &printer.CommentedNode{Node: eg.Code, Comments: eg.Comments}
- code := node_htmlFunc(cnode, fset)
+ code := node_htmlFunc(info, cnode, true)
out := eg.Output
wholeFile := true
@@ -411,7 +414,7 @@ func example_htmlFunc(funcName string, examples []*doc.Example, fset *token.File
play := ""
if eg.Play != nil && *showPlayground {
var buf bytes.Buffer
- if err := format.Node(&buf, fset, eg.Play); err != nil {
+ if err := format.Node(&buf, info.FSet, eg.Play); err != nil {
log.Print(err)
} else {
play = buf.String()
@@ -476,19 +479,33 @@ func pkgLinkFunc(path string) string {
return pkgHandler.pattern[1:] + relpath // remove trailing '/' for relative URL
}
-func posLink_urlFunc(node ast.Node, fset *token.FileSet) string {
+// n must be an ast.Node or a *doc.Note
+func posLink_urlFunc(info *PageInfo, n interface{}) string {
+ var pos, end token.Pos
+
+ switch n := n.(type) {
+ case ast.Node:
+ pos = n.Pos()
+ end = n.End()
+ case *doc.Note:
+ pos = n.Pos
+ end = n.End
+ default:
+ panic(fmt.Sprintf("wrong type for posLink_url template formatter: %T", n))
+ }
+
var relpath string
var line int
- var low, high int // selection
+ var low, high int // selection offset range
- if p := node.Pos(); p.IsValid() {
- pos := fset.Position(p)
- relpath = pos.Filename
- line = pos.Line
- low = pos.Offset
+ if pos.IsValid() {
+ p := info.FSet.Position(pos)
+ relpath = p.Filename
+ line = p.Line
+ low = p.Offset
}
- if p := node.End(); p.IsValid() {
- high = fset.Position(p).Offset
+ if end.IsValid() {
+ high = info.FSet.Position(end).Offset
}
var buf bytes.Buffer
@@ -525,7 +542,7 @@ var fmap = template.FuncMap{
"filename": filenameFunc,
"repeat": strings.Repeat,
- // accss to FileInfos (directory listings)
+ // access to FileInfos (directory listings)
"fileInfoName": fileInfoNameFunc,
"fileInfoTime": fileInfoTimeFunc,
@@ -911,12 +928,12 @@ type PageInfo struct {
Err error // error or nil
// package info
- FSet *token.FileSet // nil if no package documentation
- PDoc *doc.Package // nil if no package documentation
- Examples []*doc.Example // nil if no example code
- Notes map[string][]string // nil if no package Notes
- PAst *ast.File // nil if no AST with package exports
- IsMain bool // true for package main
+ FSet *token.FileSet // nil if no package documentation
+ PDoc *doc.Package // nil if no package documentation
+ Examples []*doc.Example // nil if no example code
+ Notes map[string][]*doc.Note // nil if no package Notes
+ PAst *ast.File // nil if no AST with package exports
+ IsMain bool // true for package main
// directory info
Dirs *DirList // nil if no directory information
@@ -1024,6 +1041,23 @@ func collectExamples(pkg *ast.Package, testfiles map[string]*ast.File) []*doc.Ex
return examples
}
+// poorMansImporter returns a (dummy) package object named
+// by the last path component of the provided package path
+// (as is the convention for packages). This is sufficient
+// to resolve package identifiers without doing an actual
+// import. It never returns an error.
+//
+func poorMansImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
+ pkg := imports[path]
+ if pkg == nil {
+ // note that strings.LastIndex returns -1 if there is no "/"
+ pkg = ast.NewObj(ast.Pkg, path[strings.LastIndex(path, "/")+1:])
+ pkg.Data = ast.NewScope(nil) // required by ast.NewPackage for dot-import
+ imports[path] = pkg
+ }
+ return pkg, nil
+}
+
// getPageInfo returns the PageInfo for a package directory abspath. If the
// parameter genAST is set, an AST containing only the package exports is
// computed (PageInfo.PAst), otherwise package documentation (PageInfo.Doc)
@@ -1032,8 +1066,8 @@ func collectExamples(pkg *ast.Package, testfiles map[string]*ast.File) []*doc.Ex
// directories, PageInfo.Dirs is nil. If an error occurred, PageInfo.Err is
// set to the respective error but the error is not logged.
//
-func (h *docServer) getPageInfo(abspath, relpath string, mode PageInfoMode) (info PageInfo) {
- info.Dirname = abspath
+func (h *docServer) getPageInfo(abspath, relpath string, mode PageInfoMode) *PageInfo {
+ info := &PageInfo{Dirname: abspath}
// Restrict to the package files that would be used when building
// the package on this system. This makes sure that if there are
@@ -1050,7 +1084,7 @@ func (h *docServer) getPageInfo(abspath, relpath string, mode PageInfoMode) (inf
// continue if there are no Go source files; we still want the directory info
if _, nogo := err.(*build.NoGoError); err != nil && !nogo {
info.Err = err
- return
+ return info
}
// collect package files
@@ -1073,9 +1107,11 @@ func (h *docServer) getPageInfo(abspath, relpath string, mode PageInfoMode) (inf
files, err := parseFiles(fset, abspath, pkgfiles)
if err != nil {
info.Err = err
- return
+ return info
}
- pkg := &ast.Package{Name: pkgname, Files: files}
+
+ // ignore any errors - they are due to unresolved identifiers
+ pkg, _ := ast.NewPackage(fset, files, poorMansImporter, nil)
// extract package documentation
info.FSet = fset
@@ -1100,10 +1136,15 @@ func (h *docServer) getPageInfo(abspath, relpath string, mode PageInfoMode) (inf
// collect any notes that we want to show
if info.PDoc.Notes != nil {
- info.Notes = make(map[string][]string)
- for _, m := range notesToShow {
- if n := info.PDoc.Notes[m]; n != nil {
- info.Notes[m] = n
+ // could regexp.Compile only once per godoc, but probably not worth it
+ if rx, err := regexp.Compile(*notes); err == nil {
+ for m, n := range info.PDoc.Notes {
+ if rx.MatchString(m) {
+ if info.Notes == nil {
+ info.Notes = make(map[string][]*doc.Note)
+ }
+ info.Notes[m] = n
+ }
}
}
}
@@ -1142,7 +1183,7 @@ func (h *docServer) getPageInfo(abspath, relpath string, mode PageInfoMode) (inf
info.DirTime = timestamp
info.DirFlat = mode&flatDir != 0
- return
+ return info
}
func (h *docServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -1474,6 +1515,8 @@ func readIndex(filenames string) error {
matches, err := filepath.Glob(filenames)
if err != nil {
return err
+ } else if matches == nil {
+ return fmt.Errorf("no index files match %q", filenames)
}
sort.Strings(matches) // make sure files are in the right order
files := make([]io.Reader, 0, len(matches))
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
index 91c56461a..8198fca0d 100644
--- a/src/cmd/godoc/index.go
+++ b/src/cmd/godoc/index.go
@@ -651,8 +651,6 @@ func (x *Indexer) addFile(filename string, goFile bool) (file *token.File, ast *
// makes sure that the important files are included and massively reduces the
// number of files to index. The advantage over a blacklist is that unexpected
// (non-blacklisted) files won't suddenly explode the index.
-//
-// TODO(gri): We may want to make this list customizable, perhaps via a flag.
// Files are whitelisted if they have a file name or extension
// present as key in whitelisted.
diff --git a/src/cmd/godoc/linkify.go b/src/cmd/godoc/linkify.go
new file mode 100644
index 000000000..5b4862419
--- /dev/null
+++ b/src/cmd/godoc/linkify.go
@@ -0,0 +1,234 @@
+// Copyright 2013 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.
+
+// This file implements LinkifyText which introduces
+// links for identifiers pointing to their declarations.
+// The approach does not cover all cases because godoc
+// doesn't have complete type information, but it's
+// reasonably good for browsing.
+
+package main
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "io"
+ "strconv"
+)
+
+// LinkifyText HTML-escapes source text and writes it to w.
+// Identifiers that are in a "use" position (i.e., that are
+// not being declared), are wrapped with HTML links pointing
+// to the respective declaration, if possible. Comments are
+// formatted the same way as with FormatText.
+//
+func LinkifyText(w io.Writer, text []byte, n ast.Node) {
+ links := linksFor(n)
+
+ i := 0 // links index
+ prev := "" // prev HTML tag
+ linkWriter := func(w io.Writer, _ int, start bool) {
+ // end tag
+ if !start {
+ if prev != "" {
+ fmt.Fprintf(w, `</%s>`, prev)
+ prev = ""
+ }
+ return
+ }
+
+ // start tag
+ prev = ""
+ if i < len(links) {
+ switch info := links[i]; {
+ case info.path != "" && info.name == "":
+ // package path
+ fmt.Fprintf(w, `<a href="/pkg/%s/">`, info.path)
+ prev = "a"
+ case info.path != "" && info.name != "":
+ // qualified identifier
+ fmt.Fprintf(w, `<a href="/pkg/%s/#%s">`, info.path, info.name)
+ prev = "a"
+ case info.path == "" && info.name != "":
+ // local identifier
+ if info.mode == identVal {
+ fmt.Fprintf(w, `<span id="%s">`, info.name)
+ prev = "span"
+ } else {
+ fmt.Fprintf(w, `<a href="#%s">`, info.name)
+ prev = "a"
+ }
+ }
+ i++
+ }
+ }
+
+ idents := tokenSelection(text, token.IDENT)
+ comments := tokenSelection(text, token.COMMENT)
+ FormatSelections(w, text, linkWriter, idents, selectionTag, comments)
+}
+
+// A link describes the (HTML) link information for an identifier.
+// The zero value of a link represents "no link".
+//
+type link struct {
+ mode identMode
+ path, name string // package path, identifier name
+}
+
+// linksFor returns the list of links for the identifiers used
+// by node in the same order as they appear in the source.
+//
+func linksFor(node ast.Node) (list []link) {
+ modes := identModesFor(node)
+
+ // NOTE: We are expecting ast.Inspect to call the
+ // callback function in source text order.
+ ast.Inspect(node, func(node ast.Node) bool {
+ switch n := node.(type) {
+ case *ast.Ident:
+ m := modes[n]
+ info := link{mode: m}
+ switch m {
+ case identUse:
+ if n.Obj == nil && predeclared[n.Name] {
+ info.path = builtinPkgPath
+ }
+ info.name = n.Name
+ case identDef:
+ // any declaration expect const or var - empty link
+ case identVal:
+ // const or var declaration
+ info.name = n.Name
+ }
+ list = append(list, info)
+ return false
+ case *ast.SelectorExpr:
+ // Detect qualified identifiers of the form pkg.ident.
+ // If anything fails we return true and collect individual
+ // identifiers instead.
+ if x, _ := n.X.(*ast.Ident); x != nil {
+ // x must be a package for a qualified identifier
+ if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg {
+ if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil {
+ // spec.Path.Value is the import path
+ if path, err := strconv.Unquote(spec.Path.Value); err == nil {
+ // Register two links, one for the package
+ // and one for the qualified identifier.
+ info := link{path: path}
+ list = append(list, info)
+ info.name = n.Sel.Name
+ list = append(list, info)
+ return false
+ }
+ }
+ }
+ }
+ }
+ return true
+ })
+
+ return
+}
+
+// The identMode describes how an identifier is "used" at its source location.
+type identMode int
+
+const (
+ identUse identMode = iota // identifier is used (must be zero value for identMode)
+ identDef // identifier is defined
+ identVal // identifier is defined in a const or var declaration
+)
+
+// identModesFor returns a map providing the identMode for each identifier used by node.
+func identModesFor(node ast.Node) map[*ast.Ident]identMode {
+ m := make(map[*ast.Ident]identMode)
+
+ ast.Inspect(node, func(node ast.Node) bool {
+ switch n := node.(type) {
+ case *ast.Field:
+ for _, n := range n.Names {
+ m[n] = identDef
+ }
+ case *ast.ImportSpec:
+ if name := n.Name; name != nil {
+ m[name] = identDef
+ }
+ case *ast.ValueSpec:
+ for _, n := range n.Names {
+ m[n] = identVal
+ }
+ case *ast.TypeSpec:
+ m[n.Name] = identDef
+ case *ast.FuncDecl:
+ m[n.Name] = identDef
+ case *ast.AssignStmt:
+ // Short variable declarations only show up if we apply
+ // this code to all source code (as opposed to exported
+ // declarations only).
+ if n.Tok == token.DEFINE {
+ // Some of the lhs variables may be re-declared,
+ // so technically they are not defs. We don't
+ // care for now.
+ for _, x := range n.Lhs {
+ // Each lhs expression should be an
+ // ident, but we are conservative and check.
+ if n, _ := x.(*ast.Ident); n != nil {
+ m[n] = identVal
+ }
+ }
+ }
+ }
+ return true
+ })
+
+ return m
+}
+
+// The predeclared map represents the set of all predeclared identifiers.
+// TODO(gri) This information is also encoded in similar maps in go/doc,
+// but not exported. Consider exporting an accessor and using
+// it instead.
+var predeclared = map[string]bool{
+ "bool": true,
+ "byte": true,
+ "complex64": true,
+ "complex128": true,
+ "error": true,
+ "float32": true,
+ "float64": true,
+ "int": true,
+ "int8": true,
+ "int16": true,
+ "int32": true,
+ "int64": true,
+ "rune": true,
+ "string": true,
+ "uint": true,
+ "uint8": true,
+ "uint16": true,
+ "uint32": true,
+ "uint64": true,
+ "uintptr": true,
+ "true": true,
+ "false": true,
+ "iota": true,
+ "nil": true,
+ "append": true,
+ "cap": true,
+ "close": true,
+ "complex": true,
+ "copy": true,
+ "delete": true,
+ "imag": true,
+ "len": true,
+ "make": true,
+ "new": true,
+ "panic": true,
+ "print": true,
+ "println": true,
+ "real": true,
+ "recover": true,
+}
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
index 134410090..81e739d20 100644
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -374,26 +374,26 @@ func main() {
}
// first, try as package unless forced as command
- var info PageInfo
+ var info *PageInfo
if !forceCmd {
info = pkgHandler.getPageInfo(abspath, relpath, mode)
}
// second, try as command unless the path is absolute
// (the go command invokes godoc w/ absolute paths; don't override)
- var cinfo PageInfo
+ var cinfo *PageInfo
if !filepath.IsAbs(path) {
abspath = pathpkg.Join(cmdHandler.fsRoot, path)
cinfo = cmdHandler.getPageInfo(abspath, relpath, mode)
}
// determine what to use
- if info.IsEmpty() {
- if !cinfo.IsEmpty() {
+ if info == nil || info.IsEmpty() {
+ if cinfo != nil && !cinfo.IsEmpty() {
// only cinfo exists - switch to cinfo
info = cinfo
}
- } else if !cinfo.IsEmpty() {
+ } else if cinfo != nil && !cinfo.IsEmpty() {
// both info and cinfo exist - use cinfo if info
// contains only subdirectory information
if info.PAst == nil && info.PDoc == nil {
@@ -403,15 +403,19 @@ func main() {
}
}
+ if info == nil {
+ log.Fatalf("%s: no such directory or package", flag.Arg(0))
+ }
if info.Err != nil {
log.Fatalf("%v", info.Err)
}
+
if info.PDoc != nil && info.PDoc.ImportPath == target {
// Replace virtual /target with actual argument from command line.
info.PDoc.ImportPath = flag.Arg(0)
}
- // If we have more than one argument, use the remaining arguments for filtering
+ // If we have more than one argument, use the remaining arguments for filtering.
if flag.NArg() > 1 {
args := flag.Args()[1:]
rx := makeRx(args)
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
index 7def015c8..0cdb7ff7a 100644
--- a/src/cmd/godoc/utils.go
+++ b/src/cmd/godoc/utils.go
@@ -56,8 +56,6 @@ func isText(s []byte) bool {
return true
}
-// TODO(gri): Should have a mapping from extension to handler, eventually.
-
// textExt[x] is true if the extension x indicates a text file, and false otherwise.
var textExt = map[string]bool{
".css": false, // must be served raw
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
index 202d0a50c..75a322a6c 100644
--- a/src/cmd/gofmt/gofmt_test.go
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -82,6 +82,9 @@ var tests = []struct {
{"testdata/rewrite3.input", "-r=x->x"},
{"testdata/rewrite4.input", "-r=(x)->x"},
{"testdata/rewrite5.input", "-r=x+x->2*x"},
+ {"testdata/rewrite6.input", "-r=fun(x)->Fun(x)"},
+ {"testdata/rewrite7.input", "-r=fun(x...)->Fun(x)"},
+ {"testdata/rewrite8.input", "-r=interface{}->int"},
{"testdata/stdin*.input", "-stdin"},
{"testdata/comments.input", ""},
{"testdata/import.input", ""},
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index dfabb6198..66d2331a5 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -35,10 +35,10 @@ func initRewrite() {
// It might make sense to expand this to allow statement patterns,
// but there are problems with preserving formatting and also
// with what a wildcard for a statement looks like.
-func parseExpr(s string, what string) ast.Expr {
+func parseExpr(s, what string) ast.Expr {
x, err := parser.ParseExpr(s)
if err != nil {
- fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
+ fmt.Fprintf(os.Stderr, "parsing %s %s at %s\n", what, s, err)
os.Exit(2)
}
return x
@@ -107,6 +107,7 @@ var (
identType = reflect.TypeOf((*ast.Ident)(nil))
objectPtrType = reflect.TypeOf((*ast.Object)(nil))
positionType = reflect.TypeOf(token.NoPos)
+ callExprType = reflect.TypeOf((*ast.CallExpr)(nil))
scopePtrType = reflect.TypeOf((*ast.Scope)(nil))
)
@@ -192,8 +193,17 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
v := val.Interface().(*ast.Ident)
return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
case objectPtrType, positionType:
- // object pointers and token positions don't need to match
+ // object pointers and token positions always match
return true
+ case callExprType:
+ // For calls, the Ellipsis fields (token.Position) must
+ // match since that is how f(x) and f(x...) are different.
+ // Check them here but fall through for the remaining fields.
+ p := pattern.Interface().(*ast.CallExpr)
+ v := val.Interface().(*ast.CallExpr)
+ if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() {
+ return false
+ }
}
p := reflect.Indirect(pattern)
diff --git a/src/cmd/gofmt/testdata/rewrite6.golden b/src/cmd/gofmt/testdata/rewrite6.golden
new file mode 100644
index 000000000..e565dbdd9
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite6.golden
@@ -0,0 +1,15 @@
+// Copyright 2013 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.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ Fun(x) // -r='fun(x)->Fun(x)' should rewrite this to Fun(x)
+ fun(x...) // -r='fun(x)->Fun(x)' should not rewrite this
+}
diff --git a/src/cmd/gofmt/testdata/rewrite6.input b/src/cmd/gofmt/testdata/rewrite6.input
new file mode 100644
index 000000000..8c088b3e8
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite6.input
@@ -0,0 +1,15 @@
+// Copyright 2013 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.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ fun(x) // -r='fun(x)->Fun(x)' should rewrite this to Fun(x)
+ fun(x...) // -r='fun(x)->Fun(x)' should not rewrite this
+}
diff --git a/src/cmd/gofmt/testdata/rewrite7.golden b/src/cmd/gofmt/testdata/rewrite7.golden
new file mode 100644
index 000000000..29babad9f
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite7.golden
@@ -0,0 +1,15 @@
+// Copyright 2013 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.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ fun(x) // -r='fun(x...)->Fun(x)' should not rewrite this
+ Fun(x) // -r='fun(x...)->Fun(x)' should rewrite this to Fun(x)
+}
diff --git a/src/cmd/gofmt/testdata/rewrite7.input b/src/cmd/gofmt/testdata/rewrite7.input
new file mode 100644
index 000000000..073e2a3e6
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite7.input
@@ -0,0 +1,15 @@
+// Copyright 2013 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.
+
+// Rewriting of calls must take the ... (ellipsis)
+// attribute for the last argument into account.
+
+package p
+
+func fun(x []int) {}
+
+func g(x []int) {
+ fun(x) // -r='fun(x...)->Fun(x)' should not rewrite this
+ fun(x...) // -r='fun(x...)->Fun(x)' should rewrite this to Fun(x)
+}
diff --git a/src/cmd/gofmt/testdata/rewrite8.golden b/src/cmd/gofmt/testdata/rewrite8.golden
new file mode 100644
index 000000000..cfc452b03
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite8.golden
@@ -0,0 +1,10 @@
+// Copyright 2013 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.
+
+// Check that literal type expression rewrites are accepted.
+// Was issue 4406.
+
+package p
+
+type T int
diff --git a/src/cmd/gofmt/testdata/rewrite8.input b/src/cmd/gofmt/testdata/rewrite8.input
new file mode 100644
index 000000000..235efa91c
--- /dev/null
+++ b/src/cmd/gofmt/testdata/rewrite8.input
@@ -0,0 +1,10 @@
+// Copyright 2013 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.
+
+// Check that literal type expression rewrites are accepted.
+// Was issue 4406.
+
+package p
+
+type T interface{}
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 6c6b1be43..23fc23e5f 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -33,11 +33,12 @@
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
+#include "../ld/macho.h"
#include "../ld/pe.h"
#include "../../pkg/runtime/mgc0.h"
void dynreloc(void);
-static vlong addaddrplus4(Sym *s, Sym *t, int32 add);
+static vlong addaddrplus4(Sym *s, Sym *t, vlong add);
/*
* divide-and-conquer list-link
@@ -135,11 +136,7 @@ addrel(Sym *s)
s->maxr = 4;
else
s->maxr <<= 1;
- s->r = realloc(s->r, s->maxr*sizeof s->r[0]);
- if(s->r == 0) {
- diag("out of memory");
- errorexit();
- }
+ s->r = erealloc(s->r, s->maxr*sizeof s->r[0]);
memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
}
return &s->r[s->nr++];
@@ -158,6 +155,7 @@ relocsym(Sym *s)
cursym = s;
memset(&p, 0, sizeof p);
for(r=s->r; r<s->r+s->nr; r++) {
+ r->done = 1;
off = r->off;
siz = r->siz;
if(off < 0 || off+siz > s->np) {
@@ -174,41 +172,88 @@ relocsym(Sym *s)
if(r->sym != S && r->sym->type == SDYNIMPORT)
diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type);
- if(r->sym != S && !r->sym->reachable)
+ if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable)
diag("unreachable sym in relocation: %s %s", s->name, r->sym->name);
switch(r->type) {
default:
o = 0;
- if(isobj || archreloc(r, s, &o) < 0)
+ if(linkmode == LinkExternal || archreloc(r, s, &o) < 0)
diag("unknown reloc %d", r->type);
break;
+ case D_TLS:
+ r->done = 0;
+ o = 0;
+ break;
case D_ADDR:
- o = symaddr(r->sym) + r->add;
- if(isobj && r->sym->type != SCONST) {
- if(thechar == '6')
- o = 0;
- else {
- // set up addend for eventual relocation via outer symbol
- rs = r->sym;
- while(rs->outer != nil)
- rs = rs->outer;
- o -= symaddr(rs);
+ if(linkmode == LinkExternal && r->sym->type != SCONST) {
+ r->done = 0;
+
+ // set up addend for eventual relocation via outer symbol.
+ rs = r->sym;
+ r->xadd = r->add;
+ while(rs->outer != nil) {
+ r->xadd += symaddr(rs) - symaddr(rs->outer);
+ rs = rs->outer;
}
+ if(rs->type != SHOSTOBJ && rs->sect == nil)
+ diag("missing section for %s", rs->name);
+ r->xsym = rs;
+
+ o = r->xadd;
+ if(iself) {
+ if(thechar == '6')
+ o = 0;
+ } else if(HEADTYPE == Hdarwin) {
+ if(rs->type != SHOSTOBJ)
+ o += symaddr(rs);
+ } else {
+ diag("unhandled pcrel relocation for %s", headtype);
+ }
+ break;
}
+ o = symaddr(r->sym) + r->add;
break;
case D_PCREL:
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
+ if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != cursym->sect) {
+ r->done = 0;
+
+ // set up addend for eventual relocation via outer symbol.
+ rs = r->sym;
+ r->xadd = r->add;
+ while(rs->outer != nil) {
+ r->xadd += symaddr(rs) - symaddr(rs->outer);
+ rs = rs->outer;
+ }
+ r->xadd -= r->siz; // relative to address after the relocated chunk
+ if(rs->type != SHOSTOBJ && rs->sect == nil)
+ diag("missing section for %s", rs->name);
+ r->xsym = rs;
+
+ o = r->xadd;
+ if(iself) {
+ if(thechar == '6')
+ o = 0;
+ } else if(HEADTYPE == Hdarwin) {
+ if(rs->type != SHOSTOBJ)
+ o += symaddr(rs) - rs->sect->vaddr;
+ o -= r->off; // WTF?
+ } else {
+ diag("unhandled pcrel relocation for %s", headtype);
+ }
+ break;
+ }
o = 0;
if(r->sym)
o += symaddr(r->sym);
- o += r->add - (s->value + r->off + r->siz);
- if(isobj && r->sym->type != SCONST) {
- if(thechar == '6')
- o = 0;
- else
- o = r->add - r->siz;
- }
+ // NOTE: The (int32) cast on the next line works around a bug in Plan 9's 8c
+ // compiler. The expression s->value + r->off + r->siz is int32 + int32 +
+ // uchar, and Plan 9 8c incorrectly treats the expression as type uint32
+ // instead of int32, causing incorrect values when sign extended for adding
+ // to o. The bug only occurs on Plan 9, because this C program is compiled by
+ // the standard host compiler (gcc on most other systems).
+ o += r->add - (s->value + r->off + (int32)r->siz);
break;
case D_SIZE:
o = r->sym->size + r->add;
@@ -220,6 +265,13 @@ relocsym(Sym *s)
cursym = s;
diag("bad reloc size %#ux for %s", siz, r->sym->name);
case 4:
+ if(r->type == D_PCREL) {
+ if(o != (int32)o)
+ diag("pc-relative relocation address is too big: %#llx", o);
+ } else {
+ if(o != (int32)o && o != (uint32)o)
+ diag("non-pc-relative relocation address is too big: %#llux", o);
+ }
fl = o;
cast = (uchar*)&fl;
for(i=0; i<4; i++)
@@ -300,7 +352,7 @@ dynrelocsym(Sym *s)
for(r=s->r; r<s->r+s->nr; r++) {
if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256)
adddynrel(s, r);
- if(flag_shared && r->sym != S && (r->sym->dynimpname == nil || r->sym->dynexport) && r->type == D_ADDR
+ if(flag_shared && r->sym != S && s->type != SDYNIMPORT && r->type == D_ADDR
&& (s == got || s->type == SDATA || s->type == SGOSTRING || s->type == STYPE || s->type == SRODATA)) {
// Create address based RELATIVE relocation
adddynrela(rel, s, r);
@@ -342,11 +394,7 @@ symgrow(Sym *s, int32 siz)
s->maxp = 8;
while(s->maxp < siz)
s->maxp <<= 1;
- s->p = realloc(s->p, s->maxp);
- if(s->p == nil) {
- diag("out of memory");
- errorexit();
- }
+ s->p = erealloc(s->p, s->maxp);
memset(s->p+s->np, 0, s->maxp-s->np);
}
s->np = siz;
@@ -560,8 +608,10 @@ void
datblk(int32 addr, int32 size)
{
Sym *sym;
- int32 eaddr;
+ int32 i, eaddr;
uchar *p, *ep;
+ char *typ, *rsname;
+ Reloc *r;
if(debug['a'])
Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
@@ -581,23 +631,46 @@ datblk(int32 addr, int32 size)
if(sym->value >= eaddr)
break;
if(addr < sym->value) {
- Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(pre-pad)", addr);
+ Bprint(&bso, "\t%.8ux| 00 ...\n", addr);
addr = sym->value;
}
- Bprint(&bso, "%-20s %.8ux|", sym->name, (uint)addr);
+ Bprint(&bso, "%s\n\t%.8ux|", sym->name, (uint)addr);
p = sym->p;
ep = p + sym->np;
- while(p < ep)
+ while(p < ep) {
+ if(p > sym->p && (int)(p-sym->p)%16 == 0)
+ Bprint(&bso, "\n\t%.8ux|", (uint)(addr+(p-sym->p)));
Bprint(&bso, " %.2ux", *p++);
+ }
addr += sym->np;
for(; addr < sym->value+sym->size; addr++)
Bprint(&bso, " %.2ux", 0);
Bprint(&bso, "\n");
+
+ if(linkmode == LinkExternal) {
+ for(i=0; i<sym->nr; i++) {
+ r = &sym->r[i];
+ rsname = "";
+ if(r->sym)
+ rsname = r->sym->name;
+ typ = "?";
+ switch(r->type) {
+ case D_ADDR:
+ typ = "addr";
+ break;
+ case D_PCREL:
+ typ = "pcrel";
+ break;
+ }
+ Bprint(&bso, "\treloc %.8ux/%d %s %s+%#llx [%#llx]\n",
+ (uint)(sym->value+r->off), r->siz, typ, rsname, (vlong)r->add, (vlong)(r->sym->value+r->add));
+ }
+ }
}
if(addr < eaddr)
- Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(post-pad)", (uint)addr);
- Bprint(&bso, "%-20s %.8ux|\n", "", (uint)eaddr);
+ Bprint(&bso, "\t%.8ux| 00 ...\n", (uint)addr);
+ Bprint(&bso, "\t%.8ux|\n", (uint)eaddr);
}
void
@@ -656,7 +729,7 @@ addstring(Sym *s, char *str)
}
vlong
-setuintxx(Sym *s, vlong off, uint64 v, int wid)
+setuintxx(Sym *s, vlong off, uint64 v, vlong wid)
{
int32 i, fl;
vlong o;
@@ -696,7 +769,7 @@ setuintxx(Sym *s, vlong off, uint64 v, int wid)
vlong
adduintxx(Sym *s, uint64 v, int wid)
{
- int32 off;
+ vlong off;
off = s->size;
setuintxx(s, off, v, wid);
@@ -752,7 +825,7 @@ setuint64(Sym *s, vlong r, uint64 v)
}
vlong
-addaddrplus(Sym *s, Sym *t, int32 add)
+addaddrplus(Sym *s, Sym *t, vlong add)
{
vlong i;
Reloc *r;
@@ -773,7 +846,7 @@ addaddrplus(Sym *s, Sym *t, int32 add)
}
static vlong
-addaddrplus4(Sym *s, Sym *t, int32 add)
+addaddrplus4(Sym *s, Sym *t, vlong add)
{
vlong i;
Reloc *r;
@@ -794,7 +867,7 @@ addaddrplus4(Sym *s, Sym *t, int32 add)
}
vlong
-addpcrelplus(Sym *s, Sym *t, int32 add)
+addpcrelplus(Sym *s, Sym *t, vlong add)
{
vlong i;
Reloc *r;
@@ -821,7 +894,7 @@ addaddr(Sym *s, Sym *t)
}
vlong
-setaddrplus(Sym *s, vlong off, Sym *t, int32 add)
+setaddrplus(Sym *s, vlong off, Sym *t, vlong add)
{
Reloc *r;
@@ -883,42 +956,47 @@ dosymtype(void)
}
static int32
-alignsymsize(int32 s)
+symalign(Sym *s)
{
- if(s >= 8)
- s = rnd(s, 8);
- else if(s >= PtrSize)
- s = rnd(s, PtrSize);
- else if(s > 2)
- s = rnd(s, 4);
- return s;
+ int32 align;
+
+ if(s->align != 0)
+ return s->align;
+
+ align = MaxAlign;
+ while(align > s->size && align > 1)
+ align >>= 1;
+ if(align < s->align)
+ align = s->align;
+ return align;
+}
+
+static vlong
+aligndatsize(vlong datsize, Sym *s)
+{
+ return rnd(datsize, symalign(s));
}
+// maxalign returns the maximum required alignment for
+// the list of symbols s; the list stops when s->type exceeds type.
static int32
-aligndatsize(int32 datsize, Sym *s)
+maxalign(Sym *s, int type)
{
- int32 t;
-
- if(s->align != 0) {
- datsize = rnd(datsize, s->align);
- } else {
- t = alignsymsize(s->size);
- if(t & 1) {
- ;
- } else if(t & 2)
- datsize = rnd(datsize, 2);
- else if(t & 4)
- datsize = rnd(datsize, 4);
- else
- datsize = rnd(datsize, 8);
+ int32 align, max;
+
+ max = 0;
+ for(; s != S && s->type <= type; s = s->next) {
+ align = symalign(s);
+ if(max < align)
+ max = align;
}
- return datsize;
+ return max;
}
static void
-gcaddsym(Sym *gc, Sym *s, int32 off)
+gcaddsym(Sym *gc, Sym *s, vlong off)
{
- int32 a;
+ vlong a;
Sym *gotype;
if(s->size < PtrSize)
@@ -944,9 +1022,23 @@ gcaddsym(Sym *gc, Sym *s, int32 off)
}
void
+growdatsize(vlong *datsizep, Sym *s)
+{
+ vlong datsize;
+
+ datsize = *datsizep;
+ if(s->size < 0)
+ diag("negative size (datsize = %lld, s->size = %lld)", datsize, s->size);
+ if(datsize + s->size < datsize)
+ diag("symbol too large (datsize = %lld, s->size = %lld)", datsize, s->size);
+ *datsizep = datsize + s->size;
+}
+
+void
dodata(void)
{
- int32 t, datsize;
+ int32 n;
+ vlong datsize;
Section *sect;
Sym *s, *last, **l;
Sym *gcdata1, *gcbss1;
@@ -956,11 +1048,11 @@ dodata(void)
Bflush(&bso);
// define garbage collection symbols
- gcdata1 = lookup("gcdata1", 0);
- gcdata1->type = SGCDATA;
+ gcdata1 = lookup("gcdata", 0);
+ gcdata1->type = STYPE;
gcdata1->reachable = 1;
- gcbss1 = lookup("gcbss1", 0);
- gcbss1->type = SGCBSS;
+ gcbss1 = lookup("gcbss", 0);
+ gcbss1->type = STYPE;
gcbss1->reachable = 1;
// size of .data and .bss section. the zero value is later replaced by the actual size of the section.
@@ -995,7 +1087,11 @@ dodata(void)
* to assign addresses, record all the necessary
* dynamic relocations. these will grow the relocation
* symbol, which is itself data.
+ *
+ * on darwin, we need the symbol table numbers for dynreloc.
*/
+ if(HEADTYPE == Hdarwin)
+ machosymorder();
dynreloc();
/* some symbols may no longer belong in datap (Mach-O) */
@@ -1034,52 +1130,54 @@ dodata(void)
datsize = 0;
for(; s != nil && s->type < SNOPTRDATA; s = s->next) {
sect = addsection(&segdata, s->name, 06);
- if(s->align != 0)
- datsize = rnd(datsize, s->align);
+ sect->align = symalign(s);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
s->sect = sect;
s->type = SDATA;
s->value = datsize;
- datsize += rnd(s->size, PtrSize);
+ growdatsize(&datsize, s);
sect->len = datsize - sect->vaddr;
}
/* pointer-free data */
sect = addsection(&segdata, ".noptrdata", 06);
+ sect->align = maxalign(s, SDATARELRO-1);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("noptrdata", 0)->sect = sect;
lookup("enoptrdata", 0)->sect = sect;
for(; s != nil && s->type < SDATARELRO; s = s->next) {
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
s->type = SDATA;
- t = alignsymsize(s->size);
- datsize = aligndatsize(datsize, s);
s->value = datsize;
- datsize += t;
+ growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
/* dynamic relocated rodata */
if(flag_shared) {
sect = addsection(&segdata, ".data.rel.ro", 06);
+ sect->align = maxalign(s, SDATARELRO);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("datarelro", 0)->sect = sect;
lookup("edatarelro", 0)->sect = sect;
for(; s != nil && s->type == SDATARELRO; s = s->next) {
- if(s->align != 0)
- datsize = rnd(datsize, s->align);
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
s->type = SDATA;
s->value = datsize;
- datsize += rnd(s->size, PtrSize);
+ growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
}
/* data */
sect = addsection(&segdata, ".data", 06);
+ sect->align = maxalign(s, SBSS-1);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("data", 0)->sect = sect;
lookup("edata", 0)->sect = sect;
@@ -1090,158 +1188,166 @@ dodata(void)
}
s->sect = sect;
s->type = SDATA;
- t = alignsymsize(s->size);
datsize = aligndatsize(datsize, s);
s->value = datsize;
gcaddsym(gcdata1, s, datsize - sect->vaddr); // gc
- datsize += t;
+ growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
adduintxx(gcdata1, GC_END, PtrSize);
setuintxx(gcdata1, 0, sect->len, PtrSize);
/* bss */
sect = addsection(&segdata, ".bss", 06);
+ sect->align = maxalign(s, SNOPTRBSS-1);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("bss", 0)->sect = sect;
lookup("ebss", 0)->sect = sect;
for(; s != nil && s->type < SNOPTRBSS; s = s->next) {
s->sect = sect;
- t = alignsymsize(s->size);
datsize = aligndatsize(datsize, s);
s->value = datsize;
gcaddsym(gcbss1, s, datsize - sect->vaddr); // gc
- datsize += t;
+ growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
adduintxx(gcbss1, GC_END, PtrSize);
setuintxx(gcbss1, 0, sect->len, PtrSize);
/* pointer-free bss */
sect = addsection(&segdata, ".noptrbss", 06);
+ sect->align = maxalign(s, SNOPTRBSS);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("noptrbss", 0)->sect = sect;
lookup("enoptrbss", 0)->sect = sect;
- for(; s != nil; s = s->next) {
- if(s->type > SNOPTRBSS) {
- cursym = s;
- diag("unexpected symbol type %d", s->type);
- }
- s->sect = sect;
- t = alignsymsize(s->size);
+ for(; s != nil && s->type == SNOPTRBSS; s = s->next) {
datsize = aligndatsize(datsize, s);
+ s->sect = sect;
s->value = datsize;
- datsize += t;
+ growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
lookup("end", 0)->sect = sect;
+ // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
+ if(datsize != (uint32)datsize) {
+ diag("data or bss segment too large");
+ }
+
+ if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) {
+ sect = addsection(&segdata, ".tbss", 06);
+ sect->align = PtrSize;
+ sect->vaddr = 0;
+ datsize = 0;
+ for(; s != nil && s->type == STLSBSS; s = s->next) {
+ datsize = aligndatsize(datsize, s);
+ s->sect = sect;
+ s->value = datsize;
+ growdatsize(&datsize, s);
+ }
+ sect->len = datsize;
+ }
+
+ if(s != nil) {
+ cursym = nil;
+ diag("unexpected symbol type %d for %s", s->type, s->name);
+ }
+
/* we finished segdata, begin segtext */
+ s = datap;
/* read-only data */
sect = addsection(&segtext, ".rodata", 04);
+ sect->align = maxalign(s, STYPELINK-1);
sect->vaddr = 0;
lookup("rodata", 0)->sect = sect;
lookup("erodata", 0)->sect = sect;
datsize = 0;
- s = datap;
for(; s != nil && s->type < STYPELINK; s = s->next) {
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
- if(s->align != 0)
- datsize = rnd(datsize, s->align);
s->type = SRODATA;
s->value = datsize;
- datsize += rnd(s->size, PtrSize);
+ growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
- /* type */
+ /* typelink */
sect = addsection(&segtext, ".typelink", 04);
+ sect->align = maxalign(s, STYPELINK);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("typelink", 0)->sect = sect;
lookup("etypelink", 0)->sect = sect;
for(; s != nil && s->type == STYPELINK; s = s->next) {
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
s->type = SRODATA;
s->value = datsize;
- datsize += s->size;
- }
- sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
-
- /* gcdata */
- sect = addsection(&segtext, ".gcdata", 04);
- sect->vaddr = datsize;
- lookup("gcdata", 0)->sect = sect;
- lookup("egcdata", 0)->sect = sect;
- for(; s != nil && s->type == SGCDATA; s = s->next) {
- s->sect = sect;
- s->type = SRODATA;
- s->value = datsize;
- datsize += s->size;
- }
- sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
-
- /* gcbss */
- sect = addsection(&segtext, ".gcbss", 04);
- sect->vaddr = datsize;
- lookup("gcbss", 0)->sect = sect;
- lookup("egcbss", 0)->sect = sect;
- for(; s != nil && s->type == SGCBSS; s = s->next) {
- s->sect = sect;
- s->type = SRODATA;
- s->value = datsize;
- datsize += s->size;
+ growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
/* gosymtab */
sect = addsection(&segtext, ".gosymtab", 04);
+ sect->align = maxalign(s, SPCLNTAB-1);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("symtab", 0)->sect = sect;
lookup("esymtab", 0)->sect = sect;
for(; s != nil && s->type < SPCLNTAB; s = s->next) {
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
s->type = SRODATA;
s->value = datsize;
- datsize += s->size;
+ growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
/* gopclntab */
sect = addsection(&segtext, ".gopclntab", 04);
+ sect->align = maxalign(s, SELFROSECT-1);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("pclntab", 0)->sect = sect;
lookup("epclntab", 0)->sect = sect;
for(; s != nil && s->type < SELFROSECT; s = s->next) {
+ datsize = aligndatsize(datsize, s);
s->sect = sect;
s->type = SRODATA;
s->value = datsize;
- datsize += s->size;
+ growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
- datsize = rnd(datsize, PtrSize);
- /* read-only ELF sections */
+ /* read-only ELF, Mach-O sections */
for(; s != nil && s->type < SELFSECT; s = s->next) {
sect = addsection(&segtext, s->name, 04);
- if(s->align != 0)
- datsize = rnd(datsize, s->align);
+ sect->align = symalign(s);
+ datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
s->sect = sect;
s->type = SRODATA;
s->value = datsize;
- datsize += rnd(s->size, PtrSize);
+ growdatsize(&datsize, s);
sect->len = datsize - sect->vaddr;
}
+
+ // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
+ if(datsize != (uint32)datsize) {
+ diag("text segment too large");
+ }
+
+ /* number the sections */
+ n = 1;
+ for(sect = segtext.sect; sect != nil; sect = sect->next)
+ sect->extnum = n++;
+ for(sect = segdata.sect; sect != nil; sect = sect->next)
+ sect->extnum = n++;
}
// assign addresses to text
@@ -1259,6 +1365,7 @@ textaddress(void)
// Could parallelize, by assigning to text
// and then letting threads copy down, but probably not worth it.
sect = segtext.sect;
+ sect->align = FuncAlign;
lookup("text", 0)->sect = sect;
lookup("etext", 0)->sect = sect;
va = INITTEXT;
@@ -1282,11 +1389,6 @@ textaddress(void)
}
va += sym->size;
}
-
- // Align end of code so that rodata starts aligned.
- // 128 bytes is likely overkill but definitely cheap.
- va = rnd(va, 128);
-
sect->len = va - sect->vaddr;
}
@@ -1295,17 +1397,19 @@ void
address(void)
{
Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss, *datarelro;
- Section *gcdata, *gcbss, *typelink;
+ Section *typelink;
Sym *sym, *sub;
uvlong va;
+ vlong vlen;
va = INITTEXT;
segtext.rwx = 05;
segtext.vaddr = va;
segtext.fileoff = HEADR;
for(s=segtext.sect; s != nil; s=s->next) {
+ va = rnd(va, s->align);
s->vaddr = va;
- va += rnd(s->len, PtrSize);
+ va += s->len;
}
segtext.len = va - INITTEXT;
segtext.filelen = segtext.len;
@@ -1326,9 +1430,11 @@ address(void)
noptrbss = nil;
datarelro = nil;
for(s=segdata.sect; s != nil; s=s->next) {
+ vlen = s->len;
+ if(s->next)
+ vlen = s->next->vaddr - s->vaddr;
s->vaddr = va;
- va += s->len;
- segdata.filelen += s->len;
+ va += vlen;
segdata.len = va - segdata.vaddr;
if(strcmp(s->name, ".data") == 0)
data = s;
@@ -1341,14 +1447,12 @@ address(void)
if(strcmp(s->name, ".data.rel.ro") == 0)
datarelro = s;
}
- segdata.filelen -= bss->len + noptrbss->len; // deduct .bss
+ segdata.filelen = bss->vaddr - segdata.vaddr;
text = segtext.sect;
rodata = text->next;
typelink = rodata->next;
- gcdata = typelink->next;
- gcbss = gcdata->next;
- symtab = gcbss->next;
+ symtab = typelink->next;
pclntab = symtab->next;
for(sym = datap; sym != nil; sym = sym->next) {
@@ -1371,10 +1475,15 @@ address(void)
xdefine("datarelro", SRODATA, datarelro->vaddr);
xdefine("edatarelro", SRODATA, datarelro->vaddr + datarelro->len);
}
- xdefine("gcdata", SGCDATA, gcdata->vaddr);
- xdefine("egcdata", SGCDATA, gcdata->vaddr + gcdata->len);
- xdefine("gcbss", SGCBSS, gcbss->vaddr);
- xdefine("egcbss", SGCBSS, gcbss->vaddr + gcbss->len);
+
+ sym = lookup("gcdata", 0);
+ xdefine("egcdata", STYPE, symaddr(sym) + sym->size);
+ lookup("egcdata", 0)->sect = sym->sect;
+
+ sym = lookup("gcbss", 0);
+ xdefine("egcbss", STYPE, symaddr(sym) + sym->size);
+ lookup("egcbss", 0)->sect = sym->sect;
+
xdefine("symtab", SRODATA, symtab->vaddr);
xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len);
xdefine("pclntab", SRODATA, pclntab->vaddr);
diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go
index bad4e540f..3493f41d8 100644
--- a/src/cmd/ld/doc.go
+++ b/src/cmd/ld/doc.go
@@ -31,19 +31,19 @@ Options new in this version:
is statically linked and does not refer to a dynamic linker. Without this option
(the default), the binary's contents are identical but it is loaded with a dynamic
linker. This flag cannot be used when $GOOS is windows.
- -Hdarwin (only in 6l/8l)
+ -H darwin (only in 6l/8l)
Write Apple Mach-O binaries (default when $GOOS is darwin)
- -Hlinux
+ -H linux
Write Linux ELF binaries (default when $GOOS is linux)
- -Hfreebsd
+ -H freebsd
Write FreeBSD ELF binaries (default when $GOOS is freebsd)
- -Hnetbsd (only in 6l/8l)
+ -H netbsd
Write NetBSD ELF binaries (default when $GOOS is netbsd)
- -Hopenbsd (only in 6l/8l)
+ -H openbsd (only in 6l/8l)
Write OpenBSD ELF binaries (default when $GOOS is openbsd)
- -Hwindows (only in 6l/8l)
+ -H windows (only in 6l/8l)
Write Windows PE32+ Console binaries (default when $GOOS is windows)
- -Hwindowsgui (only in 6l/8l)
+ -H windowsgui (only in 6l/8l)
Write Windows PE32+ GUI binaries
-I interpreter
Set the ELF dynamic linker to use.
@@ -71,5 +71,22 @@ Options new in this version:
NOTE: it only eliminates false positives caused by other function
calls, not false positives caused by dead temporaries stored in
the current function call.
+ -linkmode argument
+ Set the linkmode. The argument must be one of
+ internal, external, or auto. The default is auto.
+ This sets the linking mode as described in
+ ../cgo/doc.go.
+ -tmpdir dir
+ Set the location to use for any temporary files. The
+ default is a newly created directory that is removed
+ after the linker completes. Temporary files are only
+ used in external linking mode.
+ -extld name
+ Set the name of the external linker to use in external
+ linking mode. The default is "gcc".
+ -extldflags flags
+ Set space-separated trailing flags to pass to the
+ external linker in external linking mode. The default
+ is to not pass any additional trailing flags.
*/
package main
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index d6a357e49..98b03f1c3 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -27,10 +27,16 @@
static vlong abbrevo;
static vlong abbrevsize;
+static Sym* abbrevsym;
+static vlong abbrevsympos;
static vlong lineo;
static vlong linesize;
+static Sym* linesym;
+static vlong linesympos;
static vlong infoo; // also the base for DWDie->offs and reference attributes.
static vlong infosize;
+static Sym* infosym;
+static vlong infosympos;
static vlong frameo;
static vlong framesize;
static vlong pubnameso;
@@ -42,6 +48,18 @@ static vlong arangessize;
static vlong gdbscripto;
static vlong gdbscriptsize;
+static Sym *infosec;
+static vlong inforeloco;
+static vlong inforelocsize;
+
+static Sym *arangessec;
+static vlong arangesreloco;
+static vlong arangesrelocsize;
+
+static Sym *linesec;
+static vlong linereloco;
+static vlong linerelocsize;
+
static char gdbscript[1024];
/*
@@ -150,6 +168,7 @@ enum
DW_ABRV_IFACETYPE,
DW_ABRV_MAPTYPE,
DW_ABRV_PTRTYPE,
+ DW_ABRV_BARE_PTRTYPE, // only for void*, no DW_AT_type attr to please gdb 6.
DW_ABRV_SLICETYPE,
DW_ABRV_STRINGTYPE,
DW_ABRV_STRUCTTYPE,
@@ -303,6 +322,12 @@ static struct DWAbbrev {
DW_AT_type, DW_FORM_ref_addr,
0, 0
},
+ /* BARE_PTRTYPE */
+ {
+ DW_TAG_pointer_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ 0, 0
+ },
/* SLICETYPE */
{
@@ -485,26 +510,43 @@ mkindex(DWDie *die)
die->hash = mal(HASHSIZE * sizeof(DWDie*));
}
+static DWDie*
+walktypedef(DWDie *die)
+{
+ DWAttr *attr;
+
+ // Resolve typedef if present.
+ if (die->abbrev == DW_ABRV_TYPEDECL) {
+ for (attr = die->attr; attr; attr = attr->link) {
+ if (attr->atr == DW_AT_type && attr->cls == DW_CLS_REFERENCE && attr->data != nil) {
+ return (DWDie*)attr->data;
+ }
+ }
+ }
+ return die;
+}
+
// Find child by AT_name using hashtable if available or linear scan
// if not.
static DWDie*
find(DWDie *die, char* name)
{
- DWDie *a, *b;
+ DWDie *a, *b, *die2;
int h;
+top:
if (die->hash == nil) {
for (a = die->child; a != nil; a = a->link)
if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
return a;
- return nil;
+ goto notfound;
}
h = hashstr(name);
a = die->hash[h];
if (a == nil)
- return nil;
+ goto notfound;
if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
@@ -522,6 +564,14 @@ find(DWDie *die, char* name)
a = b;
b = b->hlink;
}
+
+notfound:
+ die2 = walktypedef(die);
+ if(die2 != die) {
+ die = die2;
+ goto top;
+ }
+
return nil;
}
@@ -531,12 +581,40 @@ find_or_diag(DWDie *die, char* name)
DWDie *r;
r = find(die, name);
if (r == nil) {
- diag("dwarf find: %s has no %s", getattr(die, DW_AT_name)->data, name);
+ diag("dwarf find: %s %p has no %s", getattr(die, DW_AT_name)->data, die, name);
errorexit();
}
return r;
}
+static void
+adddwarfrel(Sym* sec, Sym* sym, vlong offsetbase, int siz, vlong addend)
+{
+ Reloc *r;
+
+ r = addrel(sec);
+ r->sym = sym;
+ r->xsym = sym;
+ r->off = cpos() - offsetbase;
+ r->siz = siz;
+ r->type = D_ADDR;
+ r->add = addend;
+ r->xadd = addend;
+ if(iself && thechar == '6')
+ addend = 0;
+ switch(siz) {
+ case 4:
+ LPUT(addend);
+ break;
+ case 8:
+ VPUT(addend);
+ break;
+ default:
+ diag("bad size in adddwarfrel");
+ break;
+ }
+}
+
static DWAttr*
newrefattr(DWDie *die, uint8 attr, DWDie* ref)
{
@@ -548,14 +626,32 @@ newrefattr(DWDie *die, uint8 attr, DWDie* ref)
static int fwdcount;
static void
-putattr(int form, int cls, vlong value, char *data)
+putattr(int abbrev, int form, int cls, vlong value, char *data)
{
+ vlong off;
+
switch(form) {
case DW_FORM_addr: // address
+ if(linkmode == LinkExternal) {
+ value -= ((Sym*)data)->value;
+ adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value);
+ break;
+ }
addrput(value);
break;
case DW_FORM_block1: // block
+ if(cls == DW_CLS_ADDRESS) {
+ cput(1+PtrSize);
+ cput(DW_OP_addr);
+ if(linkmode == LinkExternal) {
+ value -= ((Sym*)data)->value;
+ adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value);
+ break;
+ }
+ addrput(value);
+ break;
+ }
value &= 0xff;
cput(value);
while(value--)
@@ -591,6 +687,10 @@ putattr(int form, int cls, vlong value, char *data)
break;
case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
+ if(linkmode == LinkExternal && cls == DW_CLS_PTR) {
+ adddwarfrel(infosec, linesym, infoo, 4, value);
+ break;
+ }
LPUT(value);
break;
@@ -615,13 +715,25 @@ putattr(int form, int cls, vlong value, char *data)
break;
case DW_FORM_ref_addr: // reference to a DIE in the .info section
+ // In DWARF 2 (which is what we claim to generate),
+ // the ref_addr is the same size as a normal address.
+ // In DWARF 3 it is always 32 bits, unless emitting a large
+ // (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
if (data == nil) {
- diag("dwarf: null reference");
- LPUT(0); // invalid dwarf, gdb will complain.
+ diag("dwarf: null reference in %d", abbrev);
+ if(PtrSize == 8)
+ VPUT(0); // invalid dwarf, gdb will complain.
+ else
+ LPUT(0); // invalid dwarf, gdb will complain.
} else {
- if (((DWDie*)data)->offs == 0)
+ off = ((DWDie*)data)->offs;
+ if (off == 0)
fwdcount++;
- LPUT(((DWDie*)data)->offs);
+ if(linkmode == LinkExternal) {
+ adddwarfrel(infosec, infosym, infoo, PtrSize, off);
+ break;
+ }
+ addrput(off);
}
break;
@@ -654,12 +766,12 @@ putattrs(int abbrev, DWAttr* attr)
for(af = abbrevs[abbrev].attr; af->attr; af++)
if (attrs[af->attr])
- putattr(af->form,
+ putattr(abbrev, af->form,
attrs[af->attr]->cls,
attrs[af->attr]->value,
attrs[af->attr]->data);
else
- putattr(af->form, 0, 0, 0);
+ putattr(abbrev, af->form, 0, 0, nil);
}
static void putdie(DWDie* die);
@@ -729,16 +841,9 @@ newmemberoffsetattr(DWDie *die, int32 offs)
// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
// location expression that evals to a const.
static void
-newabslocexprattr(DWDie *die, vlong addr)
+newabslocexprattr(DWDie *die, vlong addr, Sym *sym)
{
- char block[10];
- int i;
-
- i = 0;
- block[i++] = DW_OP_constu;
- i += uleb128enc(addr, block+i);
- newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i));
- memmove(die->attr->data, block, i);
+ newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym);
}
@@ -766,6 +871,31 @@ lookup_or_diag(char *n)
return s;
}
+static void
+dotypedef(DWDie *parent, char *name, DWDie *def)
+{
+ DWDie *die;
+
+ // Only emit typedefs for real names.
+ if(strncmp(name, "map[", 4) == 0)
+ return;
+ if(strncmp(name, "struct {", 8) == 0)
+ return;
+ if(strncmp(name, "chan ", 5) == 0)
+ return;
+ if(*name == '[' || *name == '*')
+ return;
+ if(def == nil)
+ diag("dwarf: bad def in dotypedef");
+
+ // The typedef entry must be created after the def,
+ // so that future lookups will find the typedef instead
+ // of the real definition. This hooks the typedef into any
+ // circular definition loops, so that gdb can understand them.
+ die = newdie(parent, DW_ABRV_TYPEDECL, name);
+ newrefattr(die, DW_AT_type, def);
+}
+
// Define gotype, for composite ones recurse into constituents.
static DWDie*
defgotype(Sym *gotype)
@@ -840,6 +970,7 @@ defgotype(Sym *gotype)
case KindArray:
die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name);
+ dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
s = decodetype_arrayelem(gotype);
newrefattr(die, DW_AT_type, defgotype(s));
@@ -857,6 +988,7 @@ defgotype(Sym *gotype)
case KindFunc:
die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name);
+ dotypedef(&dwtypes, name, die);
newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void"));
nfields = decodetype_funcincount(gotype);
for (i = 0; i < nfields; i++) {
@@ -876,6 +1008,7 @@ defgotype(Sym *gotype)
case KindInterface:
die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name);
+ dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
nfields = decodetype_ifacemethodcount(gotype);
if (nfields == 0)
@@ -895,12 +1028,14 @@ defgotype(Sym *gotype)
case KindPtr:
die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
+ dotypedef(&dwtypes, name, die);
s = decodetype_ptrelem(gotype);
newrefattr(die, DW_AT_type, defgotype(s));
break;
case KindSlice:
die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name);
+ dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
s = decodetype_arrayelem(gotype);
newrefattr(die, DW_AT_internal_elem_type, defgotype(s));
@@ -913,6 +1048,7 @@ defgotype(Sym *gotype)
case KindStruct:
die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name);
+ dotypedef(&dwtypes, name, die);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
nfields = decodetype_structfieldcount(gotype);
for (i = 0; i < nfields; i++) {
@@ -927,8 +1063,7 @@ defgotype(Sym *gotype)
break;
case KindUnsafePointer:
- die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
- newrefattr(die, DW_AT_type, find(&dwtypes, "void"));
+ die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name);
break;
default:
@@ -998,7 +1133,7 @@ synthesizestringtypes(DWDie* die)
{
DWDie *prototype;
- prototype = defgotype(lookup_or_diag("type.runtime._string"));
+ prototype = walktypedef(defgotype(lookup_or_diag("type.runtime._string")));
if (prototype == nil)
return;
@@ -1014,7 +1149,7 @@ synthesizeslicetypes(DWDie *die)
{
DWDie *prototype, *elem;
- prototype = defgotype(lookup_or_diag("type.runtime.slice"));
+ prototype = walktypedef(defgotype(lookup_or_diag("type.runtime.slice")));
if (prototype == nil)
return;
@@ -1042,90 +1177,85 @@ mkinternaltypename(char *base, char *arg1, char *arg2)
return n;
}
-
// synthesizemaptypes is way too closely married to runtime/hashmap.c
enum {
- MaxValsize = 256 - 64
+ MaxKeySize = 128,
+ MaxValSize = 128,
+ BucketSize = 8,
};
static void
synthesizemaptypes(DWDie *die)
{
- DWDie *hash, *hash_subtable, *hash_entry,
- *dwh, *dwhs, *dwhe, *dwhash, *keytype, *valtype, *fld;
- int hashsize, keysize, valsize, datsize, valsize_in_hash, datavo;
+ DWDie *hash, *bucket, *dwh, *dwhk, *dwhv, *dwhb, *keytype, *valtype, *fld;
+ int indirect_key, indirect_val;
+ int keysize, valsize;
DWAttr *a;
- hash = defgotype(lookup_or_diag("type.runtime.hmap"));
- hash_subtable = defgotype(lookup_or_diag("type.runtime.hash_subtable"));
- hash_entry = defgotype(lookup_or_diag("type.runtime.hash_entry"));
-
- if (hash == nil || hash_subtable == nil || hash_entry == nil)
- return;
+ hash = walktypedef(defgotype(lookup_or_diag("type.runtime.hmap")));
+ bucket = walktypedef(defgotype(lookup_or_diag("type.runtime.bucket")));
- dwhash = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data;
- if (dwhash == nil)
+ if (hash == nil)
return;
- hashsize = getattr(dwhash, DW_AT_byte_size)->value;
-
for (; die != nil; die = die->link) {
if (die->abbrev != DW_ABRV_MAPTYPE)
continue;
- keytype = (DWDie*) getattr(die, DW_AT_internal_key_type)->data;
- valtype = (DWDie*) getattr(die, DW_AT_internal_val_type)->data;
+ keytype = walktypedef((DWDie*) getattr(die, DW_AT_internal_key_type)->data);
+ valtype = walktypedef((DWDie*) getattr(die, DW_AT_internal_val_type)->data);
+ // compute size info like hashmap.c does.
a = getattr(keytype, DW_AT_byte_size);
keysize = a ? a->value : PtrSize; // We don't store size with Pointers
-
a = getattr(valtype, DW_AT_byte_size);
valsize = a ? a->value : PtrSize;
+ indirect_key = 0;
+ indirect_val = 0;
+ if(keysize > MaxKeySize) {
+ keysize = PtrSize;
+ indirect_key = 1;
+ }
+ if(valsize > MaxValSize) {
+ valsize = PtrSize;
+ indirect_val = 1;
+ }
- // This is what happens in hash_init and makemap_c
- valsize_in_hash = valsize;
- if (valsize > MaxValsize)
- valsize_in_hash = PtrSize;
- datavo = keysize;
- if (valsize_in_hash >= PtrSize)
- datavo = rnd(keysize, PtrSize);
- datsize = datavo + valsize_in_hash;
- if (datsize < PtrSize)
- datsize = PtrSize;
- datsize = rnd(datsize, PtrSize);
-
- // Construct struct hash_entry<K,V>
- dwhe = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("hash_entry",
- getattr(keytype, DW_AT_name)->data,
- getattr(valtype, DW_AT_name)->data));
-
- fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "hash");
- newrefattr(fld, DW_AT_type, dwhash);
- newmemberoffsetattr(fld, 0);
-
- fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "key");
- newrefattr(fld, DW_AT_type, keytype);
- newmemberoffsetattr(fld, hashsize);
-
- fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "val");
- if (valsize > MaxValsize)
- valtype = defptrto(valtype);
- newrefattr(fld, DW_AT_type, valtype);
- newmemberoffsetattr(fld, hashsize + datavo);
- newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, nil);
+ // Construct type to represent an array of BucketSize keys
+ dwhk = newdie(&dwtypes, DW_ABRV_ARRAYTYPE,
+ mkinternaltypename("[]key",
+ getattr(keytype, DW_AT_name)->data, nil));
+ newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * keysize, 0);
+ newrefattr(dwhk, DW_AT_type, indirect_key ? defptrto(keytype) : keytype);
+ fld = newdie(dwhk, DW_ABRV_ARRAYRANGE, "size");
+ newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, BucketSize, 0);
+ newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
+
+ // Construct type to represent an array of BucketSize values
+ dwhv = newdie(&dwtypes, DW_ABRV_ARRAYTYPE,
+ mkinternaltypename("[]val",
+ getattr(valtype, DW_AT_name)->data, nil));
+ newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * valsize, 0);
+ newrefattr(dwhv, DW_AT_type, indirect_val ? defptrto(valtype) : valtype);
+ fld = newdie(dwhv, DW_ABRV_ARRAYRANGE, "size");
+ newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, BucketSize, 0);
+ newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
- // Construct hash_subtable<hash_entry<K,V>>
- dwhs = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("hash_subtable",
- getattr(keytype, DW_AT_name)->data,
- getattr(valtype, DW_AT_name)->data));
- copychildren(dwhs, hash_subtable);
- substitutetype(dwhs, "last", defptrto(dwhe));
- substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size
- newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(hash_subtable, DW_AT_byte_size)->value, nil);
+ // Construct bucket<K,V>
+ dwhb = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("bucket",
+ getattr(keytype, DW_AT_name)->data,
+ getattr(valtype, DW_AT_name)->data));
+ copychildren(dwhb, bucket);
+ fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys");
+ newrefattr(fld, DW_AT_type, dwhk);
+ newmemberoffsetattr(fld, BucketSize + PtrSize);
+ fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values");
+ newrefattr(fld, DW_AT_type, dwhv);
+ newmemberoffsetattr(fld, BucketSize + PtrSize + BucketSize * keysize);
+ newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize + PtrSize + BucketSize * keysize + BucketSize * valsize, 0);
+ substitutetype(dwhb, "overflow", defptrto(dwhb));
// Construct hash<K,V>
dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
@@ -1133,10 +1263,12 @@ synthesizemaptypes(DWDie *die)
getattr(keytype, DW_AT_name)->data,
getattr(valtype, DW_AT_name)->data));
copychildren(dwh, hash);
- substitutetype(dwh, "st", defptrto(dwhs));
+ substitutetype(dwh, "buckets", defptrto(dwhb));
+ substitutetype(dwh, "oldbuckets", defptrto(dwhb));
newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
getattr(hash, DW_AT_byte_size)->value, nil);
+ // make map type a pointer to hash<K,V>
newrefattr(die, DW_AT_type, defptrto(dwh));
}
}
@@ -1149,9 +1281,9 @@ synthesizechantypes(DWDie *die)
DWAttr *a;
int elemsize, sudogsize;
- sudog = defgotype(lookup_or_diag("type.runtime.sudog"));
- waitq = defgotype(lookup_or_diag("type.runtime.waitq"));
- hchan = defgotype(lookup_or_diag("type.runtime.hchan"));
+ sudog = walktypedef(defgotype(lookup_or_diag("type.runtime.sudog")));
+ waitq = walktypedef(defgotype(lookup_or_diag("type.runtime.waitq")));
+ hchan = walktypedef(defgotype(lookup_or_diag("type.runtime.hchan")));
if (sudog == nil || waitq == nil || hchan == nil)
return;
@@ -1220,7 +1352,7 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
case 'D':
case 'B':
dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s);
- newabslocexprattr(dv, v);
+ newabslocexprattr(dv, v, sym);
if (ver == 0)
newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0);
// fallthrough
@@ -1260,7 +1392,7 @@ dwarfaddfrag(int n, char *frag)
if (n >= ftabsize) {
s = ftabsize;
ftabsize = 1 + n + (n >> 2);
- ftab = realloc(ftab, ftabsize * sizeof(ftab[0]));
+ ftab = erealloc(ftab, ftabsize * sizeof(ftab[0]));
memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0]));
}
@@ -1342,7 +1474,7 @@ addhistfile(char *zentry)
if (histfilesize == histfilecap) {
histfilecap = 2 * histfilecap + 2;
- histfile = realloc(histfile, histfilecap * sizeof(char*));
+ histfile = erealloc(histfile, histfilecap * sizeof(char*));
}
if (histfilesize == 0)
histfile[histfilesize++] = "<eof>";
@@ -1412,7 +1544,7 @@ checknesting(void)
includestacksize += 1;
includestacksize <<= 2;
// print("checknesting: growing to %d\n", includestacksize);
- includestack = realloc(includestack, includestacksize * sizeof *includestack);
+ includestack = erealloc(includestack, includestacksize * sizeof *includestack);
}
}
@@ -1581,12 +1713,12 @@ mkvarname(char* name, int da)
// flush previous compilation unit.
static void
-flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length)
+flushunit(DWDie *dwinfo, vlong pc, Sym *pcsym, vlong unitstart, int32 header_length)
{
vlong here;
if (dwinfo != nil && pc != 0) {
- newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, 0);
+ newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, (char*)pcsym);
}
if (unitstart >= 0) {
@@ -1597,7 +1729,7 @@ flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length)
here = cpos();
cseek(unitstart);
LPUT(here - unitstart - sizeof(int32)); // unit_length
- WPUT(3); // dwarf version
+ WPUT(2); // dwarf version
LPUT(header_length); // header length starting here
cseek(here);
}
@@ -1607,7 +1739,7 @@ static void
writelines(void)
{
Prog *q;
- Sym *s;
+ Sym *s, *epcs;
Auto *a;
vlong unitstart, headerend, offs;
vlong pc, epc, lc, llc, lline;
@@ -1618,10 +1750,15 @@ writelines(void)
DWDie *varhash[HASHSIZE];
char *n, *nn;
+ if(linesec == S)
+ linesec = lookup(".dwarfline", 0);
+ linesec->nr = 0;
+
unitstart = -1;
headerend = -1;
pc = 0;
epc = 0;
+ epcs = S;
lc = 1;
llc = 1;
currfile = -1;
@@ -1637,7 +1774,7 @@ writelines(void)
// we're entering a new compilation unit
if (inithist(s->autom)) {
- flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
+ flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
unitstart = cpos();
if(debug['v'] > 1) {
@@ -1651,15 +1788,15 @@ writelines(void)
lang = guesslang(histfile[1]);
finddebugruntimepath();
- dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, strdup(histfile[1]));
+ dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup(histfile[1]));
newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0);
newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
- newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, 0);
+ newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, (char*)s);
// Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf
LPUT(0); // unit_length (*), will be filled in by flushunit.
- WPUT(3); // dwarf version (appendix F)
+ WPUT(2); // dwarf version (appendix F)
LPUT(0); // header_length (*), filled in by flushunit.
// cpos == unitstart + 4 + 2 + 4
cput(1); // minimum_instruction_length
@@ -1683,6 +1820,7 @@ writelines(void)
pc = s->text->pc;
epc = pc;
+ epcs = s;
currfile = 1;
lc = 1;
llc = 1;
@@ -1690,7 +1828,11 @@ writelines(void)
cput(0); // start extended opcode
uleb128put(1 + PtrSize);
cput(DW_LNE_set_address);
- addrput(pc);
+
+ if(linkmode == LinkExternal)
+ adddwarfrel(linesec, s, lineo, PtrSize, 0);
+ else
+ addrput(pc);
}
if(s->text == nil)
continue;
@@ -1701,9 +1843,9 @@ writelines(void)
}
dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name);
- newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, 0);
+ newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s);
epc = s->value + s->size;
- newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, 0);
+ newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, (char*)s);
if (s->version == 0)
newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0);
@@ -1785,7 +1927,7 @@ writelines(void)
dwfunc->hash = nil;
}
- flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
+ flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
linesize = cpos() - lineo;
}
@@ -1909,6 +2051,13 @@ writeinfo(void)
vlong unitstart, here;
fwdcount = 0;
+ if (infosec == S)
+ infosec = lookup(".dwarfinfo", 0);
+ infosec->nr = 0;
+
+ if(arangessec == S)
+ arangessec = lookup(".dwarfaranges", 0);
+ arangessec->nr = 0;
for (compunit = dwroot.child; compunit; compunit = compunit->link) {
unitstart = cpos();
@@ -1917,8 +2066,14 @@ writeinfo(void)
// Fields marked with (*) must be changed for 64-bit dwarf
// This must match COMPUNITHEADERSIZE above.
LPUT(0); // unit_length (*), will be filled in later.
- WPUT(3); // dwarf version (appendix F)
- LPUT(0); // debug_abbrev_offset (*)
+ WPUT(2); // dwarf version (appendix F)
+
+ // debug_abbrev_offset (*)
+ if(linkmode == LinkExternal)
+ adddwarfrel(infosec, abbrevsym, infoo, 4, 0);
+ else
+ LPUT(0);
+
cput(PtrSize); // address_size
putdie(compunit);
@@ -2006,6 +2161,7 @@ writearanges(void)
DWAttr *b, *e;
int headersize;
vlong sectionstart;
+ vlong value;
sectionstart = cpos();
headersize = rnd(4+2+4+1+1, PtrSize); // don't count unit_length field itself
@@ -2021,12 +2177,22 @@ writearanges(void)
// Write .debug_aranges Header + entry (sec 6.1.2)
LPUT(headersize + 4*PtrSize - 4); // unit_length (*)
WPUT(2); // dwarf version (appendix F)
- LPUT(compunit->offs - COMPUNITHEADERSIZE); // debug_info_offset
+
+ value = compunit->offs - COMPUNITHEADERSIZE; // debug_info_offset
+ if(linkmode == LinkExternal)
+ adddwarfrel(arangessec, infosym, sectionstart, 4, value);
+ else
+ LPUT(value);
+
cput(PtrSize); // address_size
cput(0); // segment_size
strnput("", headersize - (4+2+4+1+1)); // align to PtrSize
- addrput(b->value);
+ if(linkmode == LinkExternal)
+ adddwarfrel(arangessec, (Sym*)b->data, sectionstart, PtrSize, b->value-((Sym*)b->data)->value);
+ else
+ addrput(b->value);
+
addrput(e->value - b->value);
addrput(0);
addrput(0);
@@ -2057,6 +2223,27 @@ align(vlong size)
strnput("", rnd(size, PEFILEALIGN) - size);
}
+static vlong
+writedwarfreloc(Sym* s)
+{
+ int i;
+ vlong start;
+ Reloc *r;
+
+ start = cpos();
+ for(r = s->r; r < s->r+s->nr; r++) {
+ if(iself)
+ i = elfreloc1(r, r->off);
+ else if(HEADTYPE == Hdarwin)
+ i = machoreloc1(r, r->off);
+ else
+ i = -1;
+ if(i < 0)
+ diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
+ }
+ return start;
+}
+
/*
* This is the main entry point for generating dwarf. After emitting
* the mandatory debug_abbrev section, it calls writelines() to set up
@@ -2075,6 +2262,9 @@ dwarfemitdebugsections(void)
if(debug['w']) // disable dwarf
return;
+ if(linkmode == LinkExternal && !iself)
+ return;
+
// For diagnostic messages.
newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes");
@@ -2085,8 +2275,7 @@ dwarfemitdebugsections(void)
// Some types that must exist to define other ones.
newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>");
newdie(&dwtypes, DW_ABRV_NULLTYPE, "void");
- newrefattr(newdie(&dwtypes, DW_ABRV_PTRTYPE, "unsafe.Pointer"),
- DW_AT_type, find(&dwtypes, "void"));
+ newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer");
die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr"); // needed for array size
newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
@@ -2157,6 +2346,20 @@ dwarfemitdebugsections(void)
gdbscripto = writegdbscript();
gdbscriptsize = cpos() - gdbscripto;
align(gdbscriptsize);
+
+ while(cpos()&7)
+ cput(0);
+ inforeloco = writedwarfreloc(infosec);
+ inforelocsize = cpos() - inforeloco;
+ align(inforelocsize);
+
+ arangesreloco = writedwarfreloc(arangessec);
+ arangesrelocsize = cpos() - arangesreloco;
+ align(arangesrelocsize);
+
+ linereloco = writedwarfreloc(linesec);
+ linerelocsize = cpos() - linereloco;
+ align(linerelocsize);
}
/*
@@ -2176,6 +2379,9 @@ enum
ElfStrDebugRanges,
ElfStrDebugStr,
ElfStrGDBScripts,
+ ElfStrRelDebugInfo,
+ ElfStrRelDebugAranges,
+ ElfStrRelDebugLine,
NElfStrDbg
};
@@ -2199,13 +2405,72 @@ dwarfaddshstrings(Sym *shstrtab)
elfstrdbg[ElfStrDebugRanges] = addstring(shstrtab, ".debug_ranges");
elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str");
elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts");
+ if(linkmode == LinkExternal) {
+ if(thechar == '6') {
+ elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rela.debug_info");
+ elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rela.debug_aranges");
+ elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rela.debug_line");
+ } else {
+ elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rel.debug_info");
+ elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rel.debug_aranges");
+ elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rel.debug_line");
+ }
+
+ infosym = lookup(".debug_info", 0);
+ infosym->hide = 1;
+
+ abbrevsym = lookup(".debug_abbrev", 0);
+ abbrevsym->hide = 1;
+
+ linesym = lookup(".debug_line", 0);
+ linesym->hide = 1;
+ }
}
+// Add section symbols for DWARF debug info. This is called before
+// dwarfaddelfheaders.
void
-dwarfaddelfheaders(void)
+dwarfaddelfsectionsyms()
+{
+ if(infosym != nil) {
+ infosympos = cpos();
+ putelfsectionsym(infosym, 0);
+ }
+ if(abbrevsym != nil) {
+ abbrevsympos = cpos();
+ putelfsectionsym(abbrevsym, 0);
+ }
+ if(linesym != nil) {
+ linesympos = cpos();
+ putelfsectionsym(linesym, 0);
+ }
+}
+
+static void
+dwarfaddelfrelocheader(int elfstr, ElfShdr *shdata, vlong off, vlong size)
{
ElfShdr *sh;
+ sh = newElfShdr(elfstrdbg[elfstr]);
+ if(thechar == '6') {
+ sh->type = SHT_RELA;
+ } else {
+ sh->type = SHT_REL;
+ }
+ sh->entsize = PtrSize*(2+(sh->type==SHT_RELA));
+ sh->link = elfshname(".symtab")->shnum;
+ sh->info = shdata->shnum;
+ sh->off = off;
+ sh->size = size;
+ sh->addralign = PtrSize;
+
+}
+
+void
+dwarfaddelfheaders(void)
+{
+ ElfShdr *sh, *shinfo, *sharanges, *shline;
+
if(debug['w']) // disable dwarf
return;
@@ -2214,12 +2479,17 @@ dwarfaddelfheaders(void)
sh->off = abbrevo;
sh->size = abbrevsize;
sh->addralign = 1;
+ if(abbrevsympos > 0)
+ putelfsymshndx(abbrevsympos, sh->shnum);
sh = newElfShdr(elfstrdbg[ElfStrDebugLine]);
sh->type = SHT_PROGBITS;
sh->off = lineo;
sh->size = linesize;
sh->addralign = 1;
+ if(linesympos > 0)
+ putelfsymshndx(linesympos, sh->shnum);
+ shline = sh;
sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]);
sh->type = SHT_PROGBITS;
@@ -2232,6 +2502,9 @@ dwarfaddelfheaders(void)
sh->off = infoo;
sh->size = infosize;
sh->addralign = 1;
+ if(infosympos > 0)
+ putelfsymshndx(infosympos, sh->shnum);
+ shinfo = sh;
if (pubnamessize > 0) {
sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]);
@@ -2249,12 +2522,14 @@ dwarfaddelfheaders(void)
sh->addralign = 1;
}
+ sharanges = nil;
if (arangessize) {
sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]);
sh->type = SHT_PROGBITS;
sh->off = arangeso;
sh->size = arangessize;
sh->addralign = 1;
+ sharanges = sh;
}
if (gdbscriptsize) {
@@ -2264,6 +2539,15 @@ dwarfaddelfheaders(void)
sh->size = gdbscriptsize;
sh->addralign = 1;
}
+
+ if(inforelocsize)
+ dwarfaddelfrelocheader(ElfStrRelDebugInfo, shinfo, inforeloco, inforelocsize);
+
+ if(arangesrelocsize)
+ dwarfaddelfrelocheader(ElfStrRelDebugAranges, sharanges, arangesreloco, arangesrelocsize);
+
+ if(linerelocsize)
+ dwarfaddelfrelocheader(ElfStrRelDebugLine, shline, linereloco, linerelocsize);
}
/*
@@ -2298,42 +2582,42 @@ dwarfaddmachoheaders(void)
ms->fileoffset = fakestart;
ms->filesize = abbrevo-fakestart;
- msect = newMachoSect(ms, "__debug_abbrev");
+ msect = newMachoSect(ms, "__debug_abbrev", "__DWARF");
msect->off = abbrevo;
msect->size = abbrevsize;
ms->filesize += msect->size;
- msect = newMachoSect(ms, "__debug_line");
+ msect = newMachoSect(ms, "__debug_line", "__DWARF");
msect->off = lineo;
msect->size = linesize;
ms->filesize += msect->size;
- msect = newMachoSect(ms, "__debug_frame");
+ msect = newMachoSect(ms, "__debug_frame", "__DWARF");
msect->off = frameo;
msect->size = framesize;
ms->filesize += msect->size;
- msect = newMachoSect(ms, "__debug_info");
+ msect = newMachoSect(ms, "__debug_info", "__DWARF");
msect->off = infoo;
msect->size = infosize;
ms->filesize += msect->size;
if (pubnamessize > 0) {
- msect = newMachoSect(ms, "__debug_pubnames");
+ msect = newMachoSect(ms, "__debug_pubnames", "__DWARF");
msect->off = pubnameso;
msect->size = pubnamessize;
ms->filesize += msect->size;
}
if (pubtypessize > 0) {
- msect = newMachoSect(ms, "__debug_pubtypes");
+ msect = newMachoSect(ms, "__debug_pubtypes", "__DWARF");
msect->off = pubtypeso;
msect->size = pubtypessize;
ms->filesize += msect->size;
}
if (arangessize > 0) {
- msect = newMachoSect(ms, "__debug_aranges");
+ msect = newMachoSect(ms, "__debug_aranges", "__DWARF");
msect->off = arangeso;
msect->size = arangessize;
ms->filesize += msect->size;
@@ -2341,7 +2625,7 @@ dwarfaddmachoheaders(void)
// TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
if (gdbscriptsize > 0) {
- msect = newMachoSect(ms, "__debug_gdb_scripts");
+ msect = newMachoSect(ms, "__debug_gdb_scripts", "__DWARF");
msect->off = gdbscripto;
msect->size = gdbscriptsize;
ms->filesize += msect->size;
diff --git a/src/cmd/ld/dwarf_defs.h b/src/cmd/ld/dwarf_defs.h
index eed143dff..93e99ff74 100644
--- a/src/cmd/ld/dwarf_defs.h
+++ b/src/cmd/ld/dwarf_defs.h
@@ -93,6 +93,7 @@ enum
DW_CLS_FLAG,
DW_CLS_PTR, // lineptr, loclistptr, macptr, rangelistptr
DW_CLS_REFERENCE,
+ DW_CLS_ADDRLOC,
DW_CLS_STRING
};
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
index 630906653..daef5793f 100644
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -605,9 +605,7 @@ elfdynhash(void)
if(sy->dynimpvers)
need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers);
- name = sy->dynimpname;
- if(name == nil)
- name = sy->name;
+ name = sy->extname;
hc = elfhash((uchar*)name);
b = hc % nbucket;
@@ -760,9 +758,13 @@ elfshbits(Section *sect)
sh->flags |= SHF_EXECINSTR;
if(sect->rwx & 2)
sh->flags |= SHF_WRITE;
- if(!isobj)
+ if(strcmp(sect->name, ".tbss") == 0) {
+ sh->flags |= SHF_TLS;
+ sh->type = SHT_NOBITS;
+ }
+ if(linkmode != LinkExternal)
sh->addr = sect->vaddr;
- sh->addralign = PtrSize;
+ sh->addralign = sect->align;
sh->size = sect->len;
sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
@@ -781,7 +783,7 @@ elfshreloc(Section *sect)
// Also nothing to relocate in .shstrtab.
if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
return nil;
- if(strcmp(sect->name, ".shstrtab") == 0)
+ if(strcmp(sect->name, ".shstrtab") == 0 || strcmp(sect->name, ".tbss") == 0)
return nil;
if(thechar == '6') {
@@ -807,10 +809,9 @@ elfshreloc(Section *sect)
void
elfrelocsect(Section *sect, Sym *first)
{
- Sym *sym, *rs;
+ Sym *sym;
int32 eaddr;
Reloc *r;
- int64 add;
// If main section is SHT_NOBITS, nothing to relocate.
// Also nothing to relocate in .shstrtab.
@@ -836,28 +837,15 @@ elfrelocsect(Section *sect, Sym *first)
cursym = sym;
for(r = sym->r; r < sym->r+sym->nr; r++) {
- // Ignore relocations handled by reloc already.
- switch(r->type) {
- case D_SIZE:
+ if(r->done)
+ continue;
+ if(r->xsym == nil) {
+ diag("missing xsym in relocation");
continue;
- case D_ADDR:
- case D_PCREL:
- if(r->sym->type == SCONST)
- continue;
- break;
- }
-
- add = r->add;
- rs = r->sym;
- while(rs->outer != nil) {
- add += rs->value - rs->outer->value;
- rs = rs->outer;
}
-
- if(rs->elfsym == 0)
- diag("reloc %d to non-elf symbol %s (rs=%s) %d", r->type, r->sym->name, rs->name, rs->type);
-
- if(elfreloc1(r, sym->value - sect->vaddr + r->off, rs->elfsym, add) < 0)
+ if(r->xsym->elfsym == 0)
+ diag("reloc %d to non-elf symbol %s (outer=%s) %d", r->type, r->sym->name, r->xsym->name, r->sym->type);
+ if(elfreloc1(r, sym->value+r->off - sect->vaddr) < 0)
diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
}
}
@@ -899,6 +887,8 @@ doelf(void)
addstring(shstrtab, ".data");
addstring(shstrtab, ".bss");
addstring(shstrtab, ".noptrbss");
+ if(linkmode == LinkExternal && HEADTYPE != Hopenbsd)
+ addstring(shstrtab, ".tbss");
if(HEADTYPE == Hnetbsd)
addstring(shstrtab, ".note.netbsd.ident");
if(HEADTYPE == Hopenbsd)
@@ -915,7 +905,7 @@ doelf(void)
addstring(shstrtab, ".gosymtab");
addstring(shstrtab, ".gopclntab");
- if(isobj) {
+ if(linkmode == LinkExternal) {
debug['s'] = 0;
debug['d'] = 1;
@@ -940,6 +930,8 @@ doelf(void)
addstring(shstrtab, ".rel.noptrdata");
addstring(shstrtab, ".rel.data");
}
+ // add a .note.GNU-stack section to mark the stack as non-executable
+ addstring(shstrtab, ".note.GNU-stack");
}
if(!debug['s']) {
@@ -1120,7 +1112,7 @@ asmbelfsetup(void)
void
asmbelf(vlong symo)
{
- int a, o;
+ vlong a, o;
vlong startva, resoff;
ElfEhdr *eh;
ElfPhdr *ph, *pph, *pnote;
@@ -1147,7 +1139,7 @@ asmbelf(vlong symo)
resoff = ELFRESERVE;
pph = nil;
- if(isobj) {
+ if(linkmode == LinkExternal) {
/* skip program headers */
eh->phoff = 0;
eh->phentsize = 0;
@@ -1408,13 +1400,18 @@ elfobj:
for(sect=segdata.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
- if(isobj) {
+ if(linkmode == LinkExternal) {
for(sect=segtext.sect; sect!=nil; sect=sect->next)
elfshreloc(sect);
for(sect=segdata.sect; sect!=nil; sect=sect->next)
elfshreloc(sect);
+ // add a .note.GNU-stack section to mark the stack as non-executable
+ sh = elfshname(".note.GNU-stack");
+ sh->type = SHT_PROGBITS;
+ sh->addralign = 1;
+ sh->flags = 0;
}
-
+
if(!debug['s']) {
sh = elfshname(".symtab");
sh->type = SHT_SYMTAB;
@@ -1431,9 +1428,7 @@ elfobj:
sh->size = elfstrsize;
sh->addralign = 1;
- // TODO(rsc): Enable for isobj too, once we know it works.
- if(!isobj)
- dwarfaddelfheaders();
+ dwarfaddelfheaders();
}
/* Main header */
@@ -1456,12 +1451,12 @@ elfobj:
if(flag_shared)
eh->type = ET_DYN;
- else if(isobj)
+ else if(linkmode == LinkExternal)
eh->type = ET_REL;
else
eh->type = ET_EXEC;
- if(!isobj)
+ if(linkmode != LinkExternal)
eh->entry = entryvalue();
eh->version = EV_CURRENT;
@@ -1478,7 +1473,7 @@ elfobj:
a += elfwriteshdrs();
if(!debug['d'])
a += elfwriteinterp();
- if(!isobj) {
+ if(linkmode != LinkExternal) {
if(HEADTYPE == Hnetbsd)
a += elfwritenetbsdsig();
if(HEADTYPE == Hopenbsd)
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index 3e22125b2..24c0ac43e 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -855,7 +855,8 @@ struct Elf64_Shdr {
Elf64_Xword addralign; /* Alignment in bytes. */
Elf64_Xword entsize; /* Size of each entry in section. */
- int shnum; /* section number, not stored on disk */
+ int shnum; /* section number, not stored on disk */
+ Sym* secsym; /* section symbol, if needed; not on disk */
};
/*
@@ -998,6 +999,7 @@ void phsh(ElfPhdr*, ElfShdr*);
void doelf(void);
void elfsetupplt(void);
void dwarfaddshstrings(Sym*);
+void dwarfaddelfsectionsyms(void);
void dwarfaddelfheaders(void);
void asmbelf(vlong symo);
void asmbelfsetup(void);
@@ -1005,7 +1007,8 @@ extern char linuxdynld[];
extern char freebsddynld[];
extern char netbsddynld[];
extern char openbsddynld[];
-int elfreloc1(Reloc*, vlong off, int32 elfsym, vlong add);
+int elfreloc1(Reloc*, vlong sectoff);
+void putelfsectionsyms(void);
EXTERN int elfstrsize;
EXTERN char* elfstrdat;
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index b2527b13e..47fdbe944 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -59,7 +59,7 @@ ilookup(char *name)
if(x->name[0] == name[0] && strcmp(x->name, name) == 0)
return x;
x = mal(sizeof *x);
- x->name = strdup(name);
+ x->name = estrdup(name);
x->hash = ihash[h];
ihash[h] = x;
nimport++;
@@ -71,8 +71,6 @@ static void loadcgo(char*, char*, char*, int);
static int parsemethod(char**, char*, char**);
static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**);
-static Sym **dynexp;
-
void
ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
{
@@ -205,14 +203,14 @@ loadpkgdata(char *file, char *pkg, char *data, int len)
char *p, *ep, *prefix, *name, *def;
Import *x;
- file = strdup(file);
+ file = estrdup(file);
p = data;
ep = data + len;
while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) {
x = ilookup(name);
if(x->prefix == nil) {
x->prefix = prefix;
- x->def = strdup(def);
+ x->def = estrdup(def);
x->file = file;
} else if(strcmp(x->prefix, prefix) != 0) {
fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
@@ -244,7 +242,7 @@ expandpkg(char *t0, char *pkg)
n++;
if(n == 0)
- return strdup(t0);
+ return estrdup(t0);
// use malloc, not mal, so that caller can free
w0 = malloc(strlen(t0) + strlen(pkg)*n);
@@ -429,7 +427,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
*next++ = '\0';
free(p0);
- p0 = strdup(p); // save for error message
+ p0 = estrdup(p); // save for error message
nf = tokenize(p, f, nelem(f));
if(strcmp(f[0], "cgo_import_dynamic") == 0) {
@@ -465,11 +463,12 @@ loadcgo(char *file, char *pkg, char *p, int n)
s = lookup(local, 0);
if(local != f[1])
free(local);
- if(s->type == 0 || s->type == SXREF) {
+ if(s->type == 0 || s->type == SXREF || s->type == SHOSTOBJ) {
s->dynimplib = lib;
- s->dynimpname = remote;
+ s->extname = remote;
s->dynimpvers = q;
- s->type = SDYNIMPORT;
+ if(s->type != SHOSTOBJ)
+ s->type = SDYNIMPORT;
havedynamic = 1;
}
continue;
@@ -478,16 +477,18 @@ loadcgo(char *file, char *pkg, char *p, int n)
if(strcmp(f[0], "cgo_import_static") == 0) {
if(nf != 2)
goto err;
- if(isobj) {
- local = f[1];
- s = lookup(local, 0);
- s->type = SHOSTOBJ;
- s->size = 0;
- }
+ local = f[1];
+ s = lookup(local, 0);
+ s->type = SHOSTOBJ;
+ s->size = 0;
continue;
}
- if(strcmp(f[0], "cgo_export") == 0) {
+ if(strcmp(f[0], "cgo_export_static") == 0 || strcmp(f[0], "cgo_export_dynamic") == 0) {
+ // TODO: Remove once we know Windows is okay.
+ if(strcmp(f[0], "cgo_export_static") == 0 && HEADTYPE == Hwindows)
+ continue;
+
if(nf < 2 || nf > 3)
goto err;
local = f[1];
@@ -497,17 +498,30 @@ loadcgo(char *file, char *pkg, char *p, int n)
remote = local;
local = expandpkg(local, pkg);
s = lookup(local, 0);
+
+ // export overrides import, for openbsd/cgo.
+ // see issue 4878.
if(s->dynimplib != nil) {
- fprint(2, "%s: symbol is both imported and exported: %s\n", argv0, local);
- nerrors++;
+ s->dynimplib = nil;
+ s->extname = nil;
+ s->dynimpvers = nil;
+ s->type = 0;
}
- s->dynimpname = remote;
- s->dynexport = 1;
-
- if(ndynexp%32 == 0)
- dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
- dynexp[ndynexp++] = s;
+ if(s->cgoexport == 0) {
+ s->extname = remote;
+ if(ndynexp%32 == 0)
+ dynexp = erealloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
+ dynexp[ndynexp++] = s;
+ } else if(strcmp(s->extname, remote) != 0) {
+ fprint(2, "%s: conflicting cgo_export directives: %s as %s and %s\n", argv0, s->name, s->extname, remote);
+ nerrors++;
+ return;
+ }
+ if(strcmp(f[0], "cgo_export_static") == 0)
+ s->cgoexport |= CgoExportStatic;
+ else
+ s->cgoexport |= CgoExportDynamic;
if(local != f[1])
free(local);
continue;
@@ -524,10 +538,19 @@ loadcgo(char *file, char *pkg, char *p, int n)
return;
}
free(interpreter);
- interpreter = strdup(f[1]);
+ interpreter = estrdup(f[1]);
}
continue;
}
+
+ if(strcmp(f[0], "cgo_ldflag") == 0) {
+ if(nf != 2)
+ goto err;
+ if(nldflag%32 == 0)
+ ldflag = erealloc(ldflag, (nldflag+32)*sizeof ldflag[0]);
+ ldflag[nldflag++] = estrdup(f[1]);
+ continue;
+ }
}
free(p0);
return;
@@ -751,6 +774,9 @@ addexport(void)
{
int i;
+ if(HEADTYPE == Hdarwin)
+ return;
+
for(i=0; i<ndynexp; i++)
adddynsym(dynexp[i]);
}
@@ -829,7 +855,7 @@ getpkg(char *path)
if(strcmp(p->path, path) == 0)
return p;
p = mal(sizeof *p);
- p->path = strdup(path);
+ p->path = estrdup(path);
p->next = phash[h];
phash[h] = p;
p->all = pkgall;
@@ -853,7 +879,7 @@ imported(char *pkg, char *import)
i->mimpby *= 2;
if(i->mimpby == 0)
i->mimpby = 16;
- i->impby = realloc(i->impby, i->mimpby*sizeof i->impby[0]);
+ i->impby = erealloc(i->impby, i->mimpby*sizeof i->impby[0]);
}
i->impby[i->nimpby++] = p;
free(pkg);
@@ -899,27 +925,17 @@ importcycles(void)
cycle(p);
}
-static int
-scmp(const void *p1, const void *p2)
-{
- Sym *s1, *s2;
-
- s1 = *(Sym**)p1;
- s2 = *(Sym**)p2;
- return strcmp(s1->dynimpname, s2->dynimpname);
-}
void
-sortdynexp(void)
+setlinkmode(char *arg)
{
- int i;
-
- // On Mac OS X Mountain Lion, we must sort exported symbols
- // So we sort them here and pre-allocate dynid for them
- // See http://golang.org/issue/4029
- if(HEADTYPE != Hdarwin)
- return;
- qsort(dynexp, ndynexp, sizeof dynexp[0], scmp);
- for(i=0; i<ndynexp; i++) {
- dynexp[i]->dynid = -i-100; // also known to [68]l/asm.c:^adddynsym
+ if(strcmp(arg, "internal") == 0)
+ linkmode = LinkInternal;
+ else if(strcmp(arg, "external") == 0)
+ linkmode = LinkExternal;
+ else if(strcmp(arg, "auto") == 0)
+ linkmode = LinkAuto;
+ else {
+ fprint(2, "unknown link mode -linkmode %s\n", arg);
+ errorexit();
}
}
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index 2bbf4f83e..27041bc47 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -595,10 +595,8 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
s->sub = sect->sym->sub;
sect->sym->sub = s;
s->type = sect->sym->type | (s->type&~SMASK) | SSUB;
- if(!s->dynexport) {
+ if(!(s->cgoexport & CgoExportDynamic))
s->dynimplib = nil; // satisfy dynimport
- s->dynimpname = nil; // satisfy dynimport
- }
s->value = sym.value;
s->size = sym.size;
s->outer = sect->sym;
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
index 41852f17c..d384a5094 100644
--- a/src/cmd/ld/ldmacho.c
+++ b/src/cmd/ld/ldmacho.c
@@ -639,10 +639,8 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
s->size = (sym+1)->value - sym->value;
else
s->size = sect->addr + sect->size - sym->value;
- if(!s->dynexport) {
+ if(!(s->cgoexport & CgoExportDynamic))
s->dynimplib = nil; // satisfy dynimport
- s->dynimpname = nil; // satisfy dynimport
- }
if(outer->type == STEXT) {
Prog *p;
@@ -806,9 +804,9 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
//
// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
secaddr = c->seg.sect[rel->symnum-1].addr;
- rp->add = e->e32(s->p+rp->off) + rp->off + 4 - secaddr;
+ rp->add = (int32)e->e32(s->p+rp->off) + rp->off + 4 - secaddr;
} else
- rp->add = e->e32(s->p+rp->off);
+ rp->add = (int32)e->e32(s->p+rp->off);
// For i386 Mach-O PC-relative, the addend is written such that
// it *is* the PC being subtracted. Use that to make
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
index 39c15e6a1..033e522f2 100644
--- a/src/cmd/ld/ldpe.c
+++ b/src/cmd/ld/ldpe.c
@@ -135,7 +135,8 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
{
char *name;
int32 base;
- int i, j, l, numaux;
+ uint32 l;
+ int i, j, numaux;
PeObj *obj;
PeSect *sect, *rsect;
IMAGE_SECTION_HEADER sh;
@@ -170,11 +171,12 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
// TODO return error if found .cormeta
}
// load string table
- Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
- if(Bread(f, &l, sizeof l) != sizeof l)
+ Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
+ if(Bread(f, symbuf, 4) != 4)
goto bad;
+ l = le32(symbuf);
obj->snames = mal(l);
- Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
+ Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
if(Bread(f, obj->snames, l) != l)
goto bad;
// read symbols
@@ -209,6 +211,13 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
sect = &obj->sect[i];
if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
continue;
+
+ if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) {
+ // This has been seen for .idata sections, which we
+ // want to ignore. See issues 5106 and 5273.
+ continue;
+ }
+
if(map(obj, sect) < 0)
goto bad;
@@ -230,7 +239,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
s->type = STEXT;
break;
default:
- werrstr("unexpected flags for PE section %s", sect->name);
+ werrstr("unexpected flags %#08ux for PE section %s", sect->sh.Characteristics, sect->name);
goto bad;
}
s->p = sect->base;
@@ -248,6 +257,11 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
continue;
if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
continue;
+ if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) {
+ // This has been seen for .idata sections, which we
+ // want to ignore. See issues 5106 and 5273.
+ continue;
+ }
r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
@@ -277,7 +291,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
case IMAGE_REL_AMD64_ADDR32NB:
rp->type = D_PCREL;
- rp->add = le32(rsect->base+rp->off);
+ rp->add = (int32)le32(rsect->base+rp->off);
break;
case IMAGE_REL_I386_DIR32NB:
case IMAGE_REL_I386_DIR32:
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index 26fa4f2ac..0a6bd3e8f 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -31,6 +31,7 @@
#include "l.h"
#include "lib.h"
+#include "../ld/elf.h"
#include "../../pkg/runtime/stack.h"
#include <ar.h>
@@ -44,6 +45,12 @@ int nlibdir = 0;
static int maxlibdir = 0;
static int cout = -1;
+// Set if we see an object compiled by the host compiler that is not
+// from a package that is known to support internal linking mode.
+static int externalobj = 0;
+
+static void hostlinksetup(void);
+
char* goroot;
char* goarch;
char* goos;
@@ -59,11 +66,7 @@ Lflag(char *arg)
maxlibdir = 8;
else
maxlibdir *= 2;
- p = realloc(libdir, maxlibdir * sizeof(*p));
- if (p == nil) {
- print("too many -L's: %d\n", nlibdir);
- usage();
- }
+ p = erealloc(libdir, maxlibdir * sizeof(*p));
libdir = p;
}
libdir[nlibdir++] = arg;
@@ -95,7 +98,7 @@ libinit(void)
#endif
cout = create(outfile, 1, 0775);
if(cout < 0) {
- diag("cannot create %s", outfile);
+ diag("cannot create %s: %r", outfile);
errorexit();
}
@@ -242,7 +245,7 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg)
if(libraryp == nlibrary){
nlibrary = 50 + 2*libraryp;
- library = realloc(library, sizeof library[0] * nlibrary);
+ library = erealloc(library, sizeof library[0] * nlibrary);
}
l = &library[libraryp++];
@@ -288,13 +291,27 @@ loadinternal(char *name)
void
loadlib(void)
{
- int i;
+ int i, w, x;
+ Sym *s;
loadinternal("runtime");
if(thechar == '5')
loadinternal("math");
if(flag_race)
loadinternal("runtime/race");
+ if(linkmode == LinkExternal) {
+ // This indicates a user requested -linkmode=external.
+ // The startup code uses an import of runtime/cgo to decide
+ // whether to initialize the TLS. So give it one. This could
+ // be handled differently but it's an unusual case.
+ loadinternal("runtime/cgo");
+ // Pretend that we really imported the package.
+ // This will do no harm if we did in fact import it.
+ s = lookup("go.importpath.runtime/cgo.", 0);
+ s->type = SDATA;
+ s->dupok = 1;
+ s->reachable = 1;
+ }
for(i=0; i<libraryp; i++) {
if(debug['v'])
@@ -303,6 +320,45 @@ loadlib(void)
objfile(library[i].file, library[i].pkg);
}
+ if(linkmode == LinkAuto) {
+ if(iscgo && externalobj)
+ linkmode = LinkExternal;
+ else
+ linkmode = LinkInternal;
+ }
+
+ if(linkmode == LinkInternal) {
+ // Drop all the cgo_import_static declarations.
+ // Turns out we won't be needing them.
+ for(s = allsym; s != S; s = s->allsym)
+ if(s->type == SHOSTOBJ) {
+ // If a symbol was marked both
+ // cgo_import_static and cgo_import_dynamic,
+ // then we want to make it cgo_import_dynamic
+ // now.
+ if(s->extname != nil && s->dynimplib != nil && s->cgoexport == 0) {
+ s->type = SDYNIMPORT;
+ } else
+ s->type = 0;
+ }
+ }
+
+ // Now that we know the link mode, trim the dynexp list.
+ x = CgoExportDynamic;
+ if(linkmode == LinkExternal)
+ x = CgoExportStatic;
+ w = 0;
+ for(i=0; i<ndynexp; i++)
+ if(dynexp[i]->cgoexport & x)
+ dynexp[w++] = dynexp[i];
+ ndynexp = w;
+
+ // In internal link mode, read the host object files.
+ if(linkmode == LinkInternal)
+ hostobjs();
+ else
+ hostlinksetup();
+
// We've loaded all the code now.
// If there are no dynamic libraries needed, gcc disables dynamic linking.
// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
@@ -316,7 +372,6 @@ loadlib(void)
debug['d'] = 1;
importcycles();
- sortdynexp();
}
/*
@@ -375,7 +430,7 @@ objfile(char *file, char *pkg)
/* load it as a regular file */
l = Bseek(f, 0L, 2);
Bseek(f, 0L, 0);
- ldobj(f, pkg, l, file, FileObj);
+ ldobj(f, pkg, l, file, file, FileObj);
Bterm(f);
free(pkg);
return;
@@ -434,7 +489,7 @@ objfile(char *file, char *pkg)
l--;
snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name);
l = atolwhex(arhdr.size);
- ldobj(f, pkg, l, pname, ArchiveObj);
+ ldobj(f, pkg, l, pname, file, ArchiveObj);
}
out:
@@ -442,8 +497,257 @@ out:
free(pkg);
}
+static void
+dowrite(int fd, char *p, int n)
+{
+ int m;
+
+ while(n > 0) {
+ m = write(fd, p, n);
+ if(m <= 0) {
+ cursym = S;
+ diag("write error: %r");
+ errorexit();
+ }
+ n -= m;
+ p += m;
+ }
+}
+
+typedef struct Hostobj Hostobj;
+
+struct Hostobj
+{
+ void (*ld)(Biobuf*, char*, int64, char*);
+ char *pkg;
+ char *pn;
+ char *file;
+ int64 off;
+ int64 len;
+};
+
+Hostobj *hostobj;
+int nhostobj;
+int mhostobj;
+
+// These packages can use internal linking mode.
+// Others trigger external mode.
+const char *internalpkg[] = {
+ "crypto/x509",
+ "net",
+ "os/user",
+ "runtime/cgo",
+ "runtime/race"
+};
+
void
-ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
+ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file)
+{
+ int i, isinternal;
+ Hostobj *h;
+
+ isinternal = 0;
+ for(i=0; i<nelem(internalpkg); i++) {
+ if(strcmp(pkg, internalpkg[i]) == 0) {
+ isinternal = 1;
+ break;
+ }
+ }
+
+ if(!isinternal)
+ externalobj = 1;
+
+ if(nhostobj >= mhostobj) {
+ if(mhostobj == 0)
+ mhostobj = 16;
+ else
+ mhostobj *= 2;
+ hostobj = erealloc(hostobj, mhostobj*sizeof hostobj[0]);
+ }
+ h = &hostobj[nhostobj++];
+ h->ld = ld;
+ h->pkg = estrdup(pkg);
+ h->pn = estrdup(pn);
+ h->file = estrdup(file);
+ h->off = Boffset(f);
+ h->len = len;
+}
+
+void
+hostobjs(void)
+{
+ int i;
+ Biobuf *f;
+ Hostobj *h;
+
+ for(i=0; i<nhostobj; i++) {
+ h = &hostobj[i];
+ f = Bopen(h->file, OREAD);
+ if(f == nil) {
+ cursym = S;
+ diag("cannot reopen %s: %r", h->pn);
+ errorexit();
+ }
+ Bseek(f, h->off, 0);
+ h->ld(f, h->pkg, h->len, h->pn);
+ Bterm(f);
+ }
+}
+
+// provided by lib9
+int runcmd(char**);
+char* mktempdir(void);
+void removeall(char*);
+
+static void
+rmtemp(void)
+{
+ removeall(tmpdir);
+}
+
+static void
+hostlinksetup(void)
+{
+ char *p;
+
+ if(linkmode != LinkExternal)
+ return;
+
+ // create temporary directory and arrange cleanup
+ if(tmpdir == nil) {
+ tmpdir = mktempdir();
+ atexit(rmtemp);
+ }
+
+ // change our output to temporary object file
+ close(cout);
+ p = smprint("%s/go.o", tmpdir);
+ cout = create(p, 1, 0775);
+ if(cout < 0) {
+ diag("cannot create %s: %r", p);
+ errorexit();
+ }
+ free(p);
+}
+
+void
+hostlink(void)
+{
+ char *p, **argv;
+ int c, i, w, n, argc, len;
+ Hostobj *h;
+ Biobuf *f;
+ static char buf[64<<10];
+
+ if(linkmode != LinkExternal || nerrors > 0)
+ return;
+
+ c = 0;
+ p = extldflags;
+ while(p != nil) {
+ while(*p == ' ')
+ p++;
+ if(*p == '\0')
+ break;
+ c++;
+ p = strchr(p + 1, ' ');
+ }
+
+ argv = malloc((10+nhostobj+nldflag+c)*sizeof argv[0]);
+ argc = 0;
+ if(extld == nil)
+ extld = "gcc";
+ argv[argc++] = extld;
+ switch(thechar){
+ case '8':
+ argv[argc++] = "-m32";
+ break;
+ case '6':
+ argv[argc++] = "-m64";
+ break;
+ }
+ if(!debug['s'])
+ argv[argc++] = "-gdwarf-2";
+ if(HEADTYPE == Hdarwin)
+ argv[argc++] = "-Wl,-no_pie,-pagezero_size,4000000";
+ argv[argc++] = "-o";
+ argv[argc++] = outfile;
+
+ if(rpath)
+ argv[argc++] = smprint("-Wl,-rpath,%s", rpath);
+
+ // Force global symbols to be exported for dlopen, etc.
+ if(iself)
+ argv[argc++] = "-rdynamic";
+
+ // already wrote main object file
+ // copy host objects to temporary directory
+ for(i=0; i<nhostobj; i++) {
+ h = &hostobj[i];
+ f = Bopen(h->file, OREAD);
+ if(f == nil) {
+ cursym = S;
+ diag("cannot reopen %s: %r", h->pn);
+ errorexit();
+ }
+ Bseek(f, h->off, 0);
+ p = smprint("%s/%06d.o", tmpdir, i);
+ argv[argc++] = p;
+ w = create(p, 1, 0775);
+ if(w < 0) {
+ cursym = S;
+ diag("cannot create %s: %r", p);
+ errorexit();
+ }
+ len = h->len;
+ while(len > 0 && (n = Bread(f, buf, sizeof buf)) > 0){
+ if(n > len)
+ n = len;
+ dowrite(w, buf, n);
+ len -= n;
+ }
+ if(close(w) < 0) {
+ cursym = S;
+ diag("cannot write %s: %r", p);
+ errorexit();
+ }
+ Bterm(f);
+ }
+
+ argv[argc++] = smprint("%s/go.o", tmpdir);
+ for(i=0; i<nldflag; i++)
+ argv[argc++] = ldflag[i];
+
+ p = extldflags;
+ while(p != nil) {
+ while(*p == ' ')
+ *p++ = '\0';
+ if(*p == '\0')
+ break;
+ argv[argc++] = p;
+ p = strchr(p + 1, ' ');
+ }
+
+ argv[argc] = nil;
+
+ quotefmtinstall();
+ if(debug['v']) {
+ Bprint(&bso, "host link:");
+ for(i=0; i<argc; i++)
+ Bprint(&bso, " %q", argv[i]);
+ Bprint(&bso, "\n");
+ Bflush(&bso);
+ }
+
+ if(runcmd(argv) < 0) {
+ cursym = S;
+ diag("%s: running %s failed: %r", argv0, argv[0]);
+ errorexit();
+ }
+}
+
+void
+ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence)
{
char *line;
int n, c1, c2, c3, c4;
@@ -453,7 +757,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
eof = Boffset(f) + len;
- pn = strdup(pn);
+ pn = estrdup(pn);
c1 = Bgetc(f);
c2 = Bgetc(f);
@@ -466,18 +770,15 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
magic = c1<<24 | c2<<16 | c3<<8 | c4;
if(magic == 0x7f454c46) { // \x7F E L F
- ldelf(f, pkg, len, pn);
- free(pn);
+ ldhostobj(ldelf, f, pkg, len, pn, file);
return;
}
if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) {
- ldmacho(f, pkg, len, pn);
- free(pn);
+ ldhostobj(ldmacho, f, pkg, len, pn, file);
return;
}
if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
- ldpe(f, pkg, len, pn);
- free(pn);
+ ldhostobj(ldpe, f, pkg, len, pn, file);
return;
}
@@ -524,7 +825,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
line[n] = '\0';
if(n-10 > strlen(t)) {
if(theline == nil)
- theline = strdup(line+10);
+ theline = estrdup(line+10);
else if(strcmp(theline, line+10) != 0) {
line[n] = '\0';
diag("%s: object is [%s] expected [%s]", pn, line+10, theline);
@@ -599,22 +900,22 @@ _lookup(char *symb, int v, int creat)
Sym *s;
char *p;
int32 h;
- int l, c;
+ int c;
h = v;
for(p=symb; c = *p; p++)
h = h+h+h + c;
- l = (p - symb) + 1;
// not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
h &= 0xffffff;
h %= NHASH;
for(s = hash[h]; s != S; s = s->hash)
- if(memcmp(s->name, symb, l) == 0)
+ if(strcmp(s->name, symb) == 0)
return s;
if(!creat)
return nil;
s = newsym(symb, v);
+ s->extname = s->name;
s->hash = hash[h];
hash[h] = s;
@@ -1027,6 +1328,7 @@ addsection(Segment *seg, char *name, int rwx)
sect->rwx = rwx;
sect->name = name;
sect->seg = seg;
+ sect->align = PtrSize; // everything is at least pointer-aligned
*l = sect;
return sect;
}
@@ -1460,23 +1762,6 @@ Yconv(Fmt *fp)
vlong coutpos;
-static void
-dowrite(int fd, char *p, int n)
-{
- int m;
-
- while(n > 0) {
- m = write(fd, p, n);
- if(m <= 0) {
- cursym = S;
- diag("write error: %r");
- errorexit();
- }
- n -= m;
- p += m;
- }
-}
-
void
cflush(void)
{
@@ -1576,7 +1861,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
put(s, s->name, 'T', s->value, s->size, s->version, 0);
for(s=allsym; s!=S; s=s->allsym) {
- if(s->hide)
+ if(s->hide || (s->name[0] == '.' && s->version == 0 && strcmp(s->name, ".rathole") != 0))
continue;
switch(s->type&SMASK) {
case SCONST:
@@ -1591,8 +1876,6 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
case SSTRING:
case SGOSTRING:
case SWINDOWS:
- case SGCDATA:
- case SGCBSS:
if(!s->reachable)
continue;
put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
@@ -1630,7 +1913,10 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
/* frame, locals, args, auto and param after */
put(nil, ".frame", 'm', (uint32)s->text->to.offset+PtrSize, 0, 0, 0);
put(nil, ".locals", 'm', s->locals, 0, 0, 0);
- put(nil, ".args", 'm', s->args, 0, 0, 0);
+ if(s->text->textflag & NOSPLIT)
+ put(nil, ".args", 'm', ArgsSizeUnknown, 0, 0, 0);
+ else
+ put(nil, ".args", 'm', s->args, 0, 0, 0);
for(a=s->autom; a; a=a->link) {
// Emit a or p according to actual offset, even if label is wrong.
@@ -1664,3 +1950,27 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
Bprint(&bso, "symsize = %ud\n", symsize);
Bflush(&bso);
}
+
+char*
+estrdup(char *p)
+{
+ p = strdup(p);
+ if(p == nil) {
+ cursym = S;
+ diag("out of memory");
+ errorexit();
+ }
+ return p;
+}
+
+void*
+erealloc(void *p, long n)
+{
+ p = realloc(p, n);
+ if(p == nil) {
+ cursym = S;
+ diag("out of memory");
+ errorexit();
+ }
+ return p;
+}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index 94ad76ecc..e552deb02 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -34,30 +34,29 @@ enum
/* order here is order in output file */
STEXT,
- SMACHOPLT,
STYPE,
SSTRING,
SGOSTRING,
SRODATA,
STYPELINK,
- SGCDATA,
- SGCBSS,
SSYMTAB,
SPCLNTAB,
SELFROSECT,
+ SMACHOPLT,
SELFSECT,
+ SMACHO, /* Mach-O __nl_symbol_ptr */
+ SMACHOGOT,
SNOPTRDATA,
SDATARELRO,
SDATA,
- SMACHO, /* Mach-O __nl_symbol_ptr */
- SMACHOGOT,
SWINDOWS,
SBSS,
SNOPTRBSS,
+ STLSBSS,
SXREF,
- SMACHODYNSTR,
- SMACHODYNSYM,
+ SMACHOSYMSTR,
+ SMACHOSYMTAB,
SMACHOINDIRECTPLT,
SMACHOINDIRECTGOT,
SFILE,
@@ -72,6 +71,13 @@ enum
NHASH = 100003,
};
+enum
+{
+ // This value is known to the garbage collector and should be kept in
+ // sync with runtime/pkg/runtime.h
+ ArgsSizeUnknown = 0x80000000
+};
+
typedef struct Library Library;
struct Library
{
@@ -104,6 +110,8 @@ struct Segment
struct Section
{
uchar rwx;
+ int16 extnum;
+ int32 align;
char *name;
uvlong vaddr;
uvlong len;
@@ -138,20 +146,40 @@ EXTERN char* outfile;
EXTERN int32 nsymbol;
EXTERN char* thestring;
EXTERN int ndynexp;
+EXTERN Sym** dynexp;
+EXTERN int nldflag;
+EXTERN char** ldflag;
EXTERN int havedynamic;
EXTERN int iscgo;
-EXTERN int isobj;
EXTERN int elfglobalsymndx;
EXTERN int flag_race;
EXTERN int flag_shared;
EXTERN char* tracksym;
EXTERN char* interpreter;
+EXTERN char* tmpdir;
+EXTERN char* extld;
+EXTERN char* extldflags;
+
+enum
+{
+ LinkAuto = 0,
+ LinkInternal,
+ LinkExternal,
+};
+EXTERN int linkmode;
+
+// for dynexport field of Sym
+enum
+{
+ CgoExportDynamic = 1<<0,
+ CgoExportStatic = 1<<1,
+};
EXTERN Segment segtext;
EXTERN Segment segdata;
-EXTERN Segment segsym;
-EXTERN Segment segdwarf;
+EXTERN Segment segdwarf;
+void setlinkmode(char*);
void addlib(char *src, char *obj);
void addlibpath(char *srcref, char *objref, char *file, char *pkg);
Section* addsection(Segment*, char*, int);
@@ -185,7 +213,7 @@ void adddynrel(Sym*, Reloc*);
void adddynrela(Sym*, Sym*, Reloc*);
Sym* lookuprel(void);
void ldobj1(Biobuf *f, char*, int64 len, char *pn);
-void ldobj(Biobuf*, char*, int64, char*, int);
+void ldobj(Biobuf*, char*, int64, char*, char*, int);
void ldelf(Biobuf*, char*, int64, char*);
void ldmacho(Biobuf*, char*, int64, char*);
void ldpe(Biobuf*, char*, int64, char*);
@@ -207,11 +235,12 @@ vlong adduint8(Sym*, uint8);
vlong adduint16(Sym*, uint16);
vlong adduint32(Sym*, uint32);
vlong adduint64(Sym*, uint64);
+vlong adduintxx(Sym*, uint64, int);
vlong addaddr(Sym*, Sym*);
-vlong addaddrplus(Sym*, Sym*, int32);
-vlong addpcrelplus(Sym*, Sym*, int32);
+vlong addaddrplus(Sym*, Sym*, vlong);
+vlong addpcrelplus(Sym*, Sym*, vlong);
vlong addsize(Sym*, Sym*);
-vlong setaddrplus(Sym*, vlong, Sym*, int32);
+vlong setaddrplus(Sym*, vlong, Sym*, vlong);
vlong setaddr(Sym*, vlong, Sym*);
void setuint8(Sym*, vlong, uint8);
void setuint16(Sym*, vlong, uint16);
@@ -220,6 +249,8 @@ void setuint64(Sym*, vlong, uint64);
void asmsym(void);
void asmelfsym(void);
void asmplan9sym(void);
+void putelfsectionsym(Sym*, int);
+void putelfsymshndx(vlong, int);
void strnput(char*, int);
void dodata(void);
void dosymtype(void);
@@ -240,6 +271,10 @@ void usage(void);
void setinterp(char*);
Sym* listsort(Sym*, int(*cmp)(Sym*, Sym*), int);
int valuecmp(Sym*, Sym*);
+void hostobjs(void);
+void hostlink(void);
+char* estrdup(char*);
+void* erealloc(void*, long);
int pathchar(void);
void* mal(uint32);
@@ -359,5 +394,3 @@ char* decodetype_structfieldname(Sym*, int);
Sym* decodetype_structfieldtype(Sym*, int);
vlong decodetype_structfieldoffs(Sym*, int);
vlong decodetype_ifacemethodcount(Sym*);
-
-void sortdynexp(void);
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index 6781c25a4..d135a92da 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -14,9 +14,20 @@ static int macho64;
static MachoHdr hdr;
static MachoLoad *load;
static MachoSeg seg[16];
-static MachoDebug xdebug[16];
static int nload, mload, nseg, ndebug, nsect;
+enum
+{
+ SymKindLocal = 0,
+ SymKindExtdef,
+ SymKindUndef,
+ NumSymKind
+};
+
+static int nkind[NumSymKind];
+static Sym** sortsym;
+static int nsortsym;
+
// Amount of space left for adding load commands
// that refer to dynamic libraries. Because these have
// to go in the Mach-O header, we can't just pick a
@@ -25,6 +36,8 @@ static int nload, mload, nseg, ndebug, nsect;
// up about 1300 bytes; we overestimate that as 2k.
static int load_budget = INITIAL_MACHO_HEADR - 2*1024;
+static void machodysymtab(void);
+
void
machoinit(void)
{
@@ -56,11 +69,7 @@ newMachoLoad(uint32 type, uint32 ndata)
mload = 1;
else
mload *= 2;
- load = realloc(load, mload*sizeof load[0]);
- if(load == nil) {
- diag("out of memory");
- errorexit();
- }
+ load = erealloc(load, mload*sizeof load[0]);
}
if(macho64 && (ndata & 1))
@@ -90,7 +99,7 @@ newMachoSeg(char *name, int msect)
}
MachoSect*
-newMachoSect(MachoSeg *seg, char *name)
+newMachoSect(MachoSeg *seg, char *name, char *segname)
{
MachoSect *s;
@@ -100,21 +109,11 @@ newMachoSect(MachoSeg *seg, char *name)
}
s = &seg->sect[seg->nsect++];
s->name = name;
+ s->segname = segname;
nsect++;
return s;
}
-MachoDebug*
-newMachoDebug(void)
-{
- if(ndebug >= nelem(xdebug)) {
- diag("too many debugs");
- errorexit();
- }
- return &xdebug[ndebug++];
-}
-
-
// Generic linking code.
static char **dylib;
@@ -130,7 +129,6 @@ machowrite(void)
int i, j;
MachoSeg *s;
MachoSect *t;
- MachoDebug *d;
MachoLoad *l;
o1 = cpos();
@@ -152,7 +150,10 @@ machowrite(void)
LPUT(0xfeedface);
LPUT(hdr.cpu);
LPUT(hdr.subcpu);
- LPUT(2); /* file type - mach executable */
+ if(linkmode == LinkExternal)
+ LPUT(1); /* file type - mach object */
+ else
+ LPUT(2); /* file type - mach executable */
LPUT(nload+nseg+ndebug);
LPUT(loadsize);
LPUT(1); /* flags - no undefines */
@@ -190,7 +191,7 @@ machowrite(void)
t = &s->sect[j];
if(macho64) {
strnput(t->name, 16);
- strnput(s->name, 16);
+ strnput(t->segname, 16);
VPUT(t->addr);
VPUT(t->size);
LPUT(t->off);
@@ -203,7 +204,7 @@ machowrite(void)
LPUT(0); /* reserved */
} else {
strnput(t->name, 16);
- strnput(s->name, 16);
+ strnput(t->segname, 16);
LPUT(t->addr);
LPUT(t->size);
LPUT(t->off);
@@ -225,14 +226,6 @@ machowrite(void)
LPUT(l->data[j]);
}
- for(i=0; i<ndebug; i++) {
- d = &xdebug[i];
- LPUT(3); /* obsolete gdb debug info */
- LPUT(16); /* size of symseg command */
- LPUT(d->fileoffset);
- LPUT(d->filesize);
- }
-
return cpos() - o1;
}
@@ -245,31 +238,34 @@ domacho(void)
return;
// empirically, string table must begin with " \x00".
- s = lookup(".dynstr", 0);
- s->type = SMACHODYNSTR;
+ s = lookup(".machosymstr", 0);
+ s->type = SMACHOSYMSTR;
s->reachable = 1;
adduint8(s, ' ');
adduint8(s, '\0');
- s = lookup(".dynsym", 0);
- s->type = SMACHODYNSYM;
+ s = lookup(".machosymtab", 0);
+ s->type = SMACHOSYMTAB;
s->reachable = 1;
- s = lookup(".plt", 0); // will be __symbol_stub
- s->type = SMACHOPLT;
- s->reachable = 1;
+ if(linkmode != LinkExternal) {
+ s = lookup(".plt", 0); // will be __symbol_stub
+ s->type = SMACHOPLT;
+ s->reachable = 1;
- s = lookup(".got", 0); // will be __nl_symbol_ptr
- s->type = SMACHOGOT;
- s->reachable = 1;
+ s = lookup(".got", 0); // will be __nl_symbol_ptr
+ s->type = SMACHOGOT;
+ s->reachable = 1;
+ s->align = 4;
- s = lookup(".linkedit.plt", 0); // indirect table for .plt
- s->type = SMACHOINDIRECTPLT;
- s->reachable = 1;
+ s = lookup(".linkedit.plt", 0); // indirect table for .plt
+ s->type = SMACHOINDIRECTPLT;
+ s->reachable = 1;
- s = lookup(".linkedit.got", 0); // indirect table for .got
- s->type = SMACHOINDIRECTGOT;
- s->reachable = 1;
+ s = lookup(".linkedit.got", 0); // indirect table for .got
+ s->type = SMACHOINDIRECTGOT;
+ s->reachable = 1;
+ }
}
void
@@ -286,16 +282,62 @@ machoadddynlib(char *lib)
load_budget += 4096;
}
- if(ndylib%32 == 0) {
- dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
- if(dylib == nil) {
- diag("out of memory");
- errorexit();
- }
- }
+ if(ndylib%32 == 0)
+ dylib = erealloc(dylib, (ndylib+32)*sizeof dylib[0]);
dylib[ndylib++] = lib;
}
+static void
+machoshbits(MachoSeg *mseg, Section *sect, char *segname)
+{
+ MachoSect *msect;
+ char buf[40];
+ char *p;
+
+ snprint(buf, sizeof buf, "__%s", sect->name+1);
+ for(p=buf; *p; p++)
+ if(*p == '.')
+ *p = '_';
+
+ msect = newMachoSect(mseg, estrdup(buf), segname);
+ if(sect->rellen > 0) {
+ msect->reloc = sect->reloff;
+ msect->nreloc = sect->rellen / 8;
+ }
+
+ while(1<<msect->align < sect->align)
+ msect->align++;
+ msect->addr = sect->vaddr;
+ msect->size = sect->len;
+
+ if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) {
+ // data in file
+ if(sect->len > sect->seg->vaddr + sect->seg->filelen - sect->vaddr)
+ diag("macho cannot represent section %s crossing data and bss", sect->name);
+ msect->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
+ } else {
+ // zero fill
+ msect->off = 0;
+ msect->flag |= 1;
+ }
+
+ if(sect->rwx & 1)
+ msect->flag |= 0x400; /* has instructions */
+
+ if(strcmp(sect->name, ".plt") == 0) {
+ msect->name = "__symbol_stub1";
+ msect->flag = 0x80000408; /* only instructions, code, symbol stubs */
+ msect->res1 = 0;//nkind[SymKindLocal];
+ msect->res2 = 6;
+ }
+
+ if(strcmp(sect->name, ".got") == 0) {
+ msect->name = "__nl_symbol_ptr";
+ msect->flag = 6; /* section with nonlazy symbol pointers */
+ msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
+ }
+}
+
void
asmbmacho(void)
{
@@ -303,11 +345,9 @@ asmbmacho(void)
vlong va;
int a, i;
MachoHdr *mh;
- MachoSect *msect;
MachoSeg *ms;
- MachoDebug *md;
MachoLoad *ml;
- Sym *s;
+ Section *sect;
/* apple MACH */
va = INITTEXT - HEADR;
@@ -325,179 +365,305 @@ asmbmacho(void)
mh->subcpu = MACHO_SUBCPU_X86;
break;
}
+
+ ms = nil;
+ if(linkmode == LinkExternal) {
+ /* segment for entire file */
+ ms = newMachoSeg("", 40);
+ ms->fileoffset = segtext.fileoff;
+ ms->filesize = segdata.fileoff + segdata.filelen - segtext.fileoff;
+ }
/* segment for zero page */
- ms = newMachoSeg("__PAGEZERO", 0);
- ms->vsize = va;
+ if(linkmode != LinkExternal) {
+ ms = newMachoSeg("__PAGEZERO", 0);
+ ms->vsize = va;
+ }
/* text */
v = rnd(HEADR+segtext.len, INITRND);
- ms = newMachoSeg("__TEXT", 2);
- ms->vaddr = va;
- ms->vsize = v;
- ms->filesize = v;
- ms->prot1 = 7;
- ms->prot2 = 5;
-
- msect = newMachoSect(ms, "__text");
- msect->addr = INITTEXT;
- msect->size = segtext.sect->len;
- msect->off = INITTEXT - va;
- msect->flag = 0x400; /* flag - some instructions */
-
- s = lookup(".plt", 0);
- if(s->size > 0) {
- msect = newMachoSect(ms, "__symbol_stub1");
- msect->addr = symaddr(s);
- msect->size = s->size;
- msect->off = ms->fileoffset + msect->addr - ms->vaddr;
- msect->flag = 0x80000408; /* flag */
- msect->res1 = 0; /* index into indirect symbol table */
- msect->res2 = 6; /* size of stubs */
+ if(linkmode != LinkExternal) {
+ ms = newMachoSeg("__TEXT", 20);
+ ms->vaddr = va;
+ ms->vsize = v;
+ ms->fileoffset = 0;
+ ms->filesize = v;
+ ms->prot1 = 7;
+ ms->prot2 = 5;
}
+ for(sect=segtext.sect; sect!=nil; sect=sect->next)
+ machoshbits(ms, sect, "__TEXT");
+
/* data */
- w = segdata.len;
- ms = newMachoSeg("__DATA", 3);
- ms->vaddr = va+v;
- ms->vsize = w;
- ms->fileoffset = v;
- ms->filesize = segdata.filelen;
- ms->prot1 = 7;
- ms->prot2 = 3;
-
- msect = newMachoSect(ms, "__data");
- msect->addr = va+v;
- msect->off = v;
- msect->size = segdata.filelen;
-
- s = lookup(".got", 0);
- if(s->size > 0) {
- msect->size = symaddr(s) - msect->addr;
-
- msect = newMachoSect(ms, "__nl_symbol_ptr");
- msect->addr = symaddr(s);
- msect->size = s->size;
- msect->off = datoff(msect->addr);
- msect->align = 2;
- msect->flag = 6; /* section with nonlazy symbol pointers */
- msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
+ if(linkmode != LinkExternal) {
+ w = segdata.len;
+ ms = newMachoSeg("__DATA", 20);
+ ms->vaddr = va+v;
+ ms->vsize = w;
+ ms->fileoffset = v;
+ ms->filesize = segdata.filelen;
+ ms->prot1 = 3;
+ ms->prot2 = 3;
}
- msect = newMachoSect(ms, "__bss");
- msect->addr = va+v+segdata.filelen;
- msect->size = segdata.len - segdata.filelen;
- msect->flag = 1; /* flag - zero fill */
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ machoshbits(ms, sect, "__DATA");
- switch(thechar) {
- default:
- diag("unknown macho architecture");
- errorexit();
- case '6':
- ml = newMachoLoad(5, 42+2); /* unix thread */
- ml->data[0] = 4; /* thread type */
- ml->data[1] = 42; /* word count */
- ml->data[2+32] = entryvalue(); /* start pc */
- ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l
- break;
- case '8':
- ml = newMachoLoad(5, 16+2); /* unix thread */
- ml->data[0] = 1; /* thread type */
- ml->data[1] = 16; /* word count */
- ml->data[2+10] = entryvalue(); /* start pc */
- break;
+ if(linkmode != LinkExternal) {
+ switch(thechar) {
+ default:
+ diag("unknown macho architecture");
+ errorexit();
+ case '6':
+ ml = newMachoLoad(5, 42+2); /* unix thread */
+ ml->data[0] = 4; /* thread type */
+ ml->data[1] = 42; /* word count */
+ ml->data[2+32] = entryvalue(); /* start pc */
+ ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l
+ break;
+ case '8':
+ ml = newMachoLoad(5, 16+2); /* unix thread */
+ ml->data[0] = 1; /* thread type */
+ ml->data[1] = 16; /* word count */
+ ml->data[2+10] = entryvalue(); /* start pc */
+ break;
+ }
}
-
+
if(!debug['d']) {
Sym *s1, *s2, *s3, *s4;
// must match domacholink below
- s1 = lookup(".dynsym", 0);
+ s1 = lookup(".machosymtab", 0);
s2 = lookup(".linkedit.plt", 0);
s3 = lookup(".linkedit.got", 0);
- s4 = lookup(".dynstr", 0);
-
- ms = newMachoSeg("__LINKEDIT", 0);
- ms->vaddr = va+v+rnd(segdata.len, INITRND);
- ms->vsize = s1->size + s2->size + s3->size + s4->size;
- ms->fileoffset = linkoff;
- ms->filesize = ms->vsize;
- ms->prot1 = 7;
- ms->prot2 = 3;
+ s4 = lookup(".machosymstr", 0);
+
+ if(linkmode != LinkExternal) {
+ ms = newMachoSeg("__LINKEDIT", 0);
+ ms->vaddr = va+v+rnd(segdata.len, INITRND);
+ ms->vsize = s1->size + s2->size + s3->size + s4->size;
+ ms->fileoffset = linkoff;
+ ms->filesize = ms->vsize;
+ ms->prot1 = 7;
+ ms->prot2 = 3;
+ }
ml = newMachoLoad(2, 4); /* LC_SYMTAB */
ml->data[0] = linkoff; /* symoff */
- ml->data[1] = s1->size / (macho64 ? 16 : 12); /* nsyms */
+ ml->data[1] = nsortsym; /* nsyms */
ml->data[2] = linkoff + s1->size + s2->size + s3->size; /* stroff */
ml->data[3] = s4->size; /* strsize */
- ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
- ml->data[0] = 0; /* ilocalsym */
- ml->data[1] = 0; /* nlocalsym */
- ml->data[2] = 0; /* iextdefsym */
- ml->data[3] = ndynexp; /* nextdefsym */
- ml->data[4] = ndynexp; /* iundefsym */
- ml->data[5] = (s1->size / (macho64 ? 16 : 12)) - ndynexp; /* nundefsym */
- ml->data[6] = 0; /* tocoffset */
- ml->data[7] = 0; /* ntoc */
- ml->data[8] = 0; /* modtaboff */
- ml->data[9] = 0; /* nmodtab */
- ml->data[10] = 0; /* extrefsymoff */
- ml->data[11] = 0; /* nextrefsyms */
- ml->data[12] = linkoff + s1->size; /* indirectsymoff */
- ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */
- ml->data[14] = 0; /* extreloff */
- ml->data[15] = 0; /* nextrel */
- ml->data[16] = 0; /* locreloff */
- ml->data[17] = 0; /* nlocrel */
-
- ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */
- ml->data[0] = 12; /* offset to string */
- strcpy((char*)&ml->data[1], "/usr/lib/dyld");
-
- for(i=0; i<ndylib; i++) {
- ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */
- ml->data[0] = 24; /* offset of string from beginning of load */
- ml->data[1] = 0; /* time stamp */
- ml->data[2] = 0; /* version */
- ml->data[3] = 0; /* compatibility version */
- strcpy((char*)&ml->data[4], dylib[i]);
+ machodysymtab();
+
+ if(linkmode != LinkExternal) {
+ ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */
+ ml->data[0] = 12; /* offset to string */
+ strcpy((char*)&ml->data[1], "/usr/lib/dyld");
+
+ for(i=0; i<ndylib; i++) {
+ ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */
+ ml->data[0] = 24; /* offset of string from beginning of load */
+ ml->data[1] = 0; /* time stamp */
+ ml->data[2] = 0; /* version */
+ ml->data[3] = 0; /* compatibility version */
+ strcpy((char*)&ml->data[4], dylib[i]);
+ }
}
}
- if(!debug['s']) {
- Sym *s;
-
- md = newMachoDebug();
- s = lookup("symtab", 0);
- md->fileoffset = datoff(s->value);
- md->filesize = s->size;
-
- md = newMachoDebug();
- s = lookup("pclntab", 0);
- md->fileoffset = datoff(s->value);
- md->filesize = s->size;
-
+ // TODO: dwarf headers go in ms too
+ if(!debug['s'] && linkmode != LinkExternal)
dwarfaddmachoheaders();
- }
a = machowrite();
if(a > HEADR)
diag("HEADR too small: %d > %d", a, HEADR);
}
+static int
+symkind(Sym *s)
+{
+ if(s->type == SDYNIMPORT)
+ return SymKindUndef;
+ if(s->cgoexport)
+ return SymKindExtdef;
+ return SymKindLocal;
+}
+
+static void
+addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotype)
+{
+ USED(name);
+ USED(addr);
+ USED(size);
+ USED(ver);
+ USED(gotype);
+
+ if(s == nil)
+ return;
+
+ switch(type) {
+ default:
+ return;
+ case 'D':
+ case 'B':
+ case 'T':
+ break;
+ }
+
+ if(sortsym) {
+ sortsym[nsortsym] = s;
+ nkind[symkind(s)]++;
+ }
+ nsortsym++;
+}
+
+static int
+scmp(const void *p1, const void *p2)
+{
+ Sym *s1, *s2;
+ int k1, k2;
+
+ s1 = *(Sym**)p1;
+ s2 = *(Sym**)p2;
+
+ k1 = symkind(s1);
+ k2 = symkind(s2);
+ if(k1 != k2)
+ return k1 - k2;
+
+ return strcmp(s1->extname, s2->extname);
+}
+
+static void
+machogenasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+{
+ Sym *s;
+
+ genasmsym(put);
+ for(s=allsym; s; s=s->allsym)
+ if(s->type == SDYNIMPORT || s->type == SHOSTOBJ)
+ if(s->reachable)
+ put(s, nil, 'D', 0, 0, 0, nil);
+}
+
+void
+machosymorder(void)
+{
+ int i;
+
+ // On Mac OS X Mountain Lion, we must sort exported symbols
+ // So we sort them here and pre-allocate dynid for them
+ // See http://golang.org/issue/4029
+ for(i=0; i<ndynexp; i++)
+ dynexp[i]->reachable = 1;
+ machogenasmsym(addsym);
+ sortsym = mal(nsortsym * sizeof sortsym[0]);
+ nsortsym = 0;
+ machogenasmsym(addsym);
+ qsort(sortsym, nsortsym, sizeof sortsym[0], scmp);
+ for(i=0; i<nsortsym; i++)
+ sortsym[i]->dynid = i;
+}
+
+static void
+machosymtab(void)
+{
+ int i;
+ Sym *symtab, *symstr, *s, *o;
+
+ symtab = lookup(".machosymtab", 0);
+ symstr = lookup(".machosymstr", 0);
+
+ for(i=0; i<nsortsym; i++) {
+ s = sortsym[i];
+ adduint32(symtab, symstr->size);
+
+ // Only add _ to C symbols. Go symbols have dot in the name.
+ if(strstr(s->extname, ".") == nil)
+ adduint8(symstr, '_');
+ addstring(symstr, s->extname);
+ if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) {
+ adduint8(symtab, 0x01); // type N_EXT, external symbol
+ adduint8(symtab, 0); // no section
+ adduint16(symtab, 0); // desc
+ adduintxx(symtab, 0, PtrSize); // no value
+ } else {
+ if(s->cgoexport)
+ adduint8(symtab, 0x0f);
+ else
+ adduint8(symtab, 0x0e);
+ o = s;
+ while(o->outer != nil)
+ o = o->outer;
+ if(o->sect == nil) {
+ diag("missing section for %s", s->name);
+ adduint8(symtab, 0);
+ } else
+ adduint8(symtab, o->sect->extnum);
+ adduint16(symtab, 0); // desc
+ adduintxx(symtab, symaddr(s), PtrSize);
+ }
+ }
+}
+
+static void
+machodysymtab(void)
+{
+ int n;
+ MachoLoad *ml;
+ Sym *s1, *s2, *s3;
+
+ ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
+
+ n = 0;
+ ml->data[0] = n; /* ilocalsym */
+ ml->data[1] = nkind[SymKindLocal]; /* nlocalsym */
+ n += nkind[SymKindLocal];
+
+ ml->data[2] = n; /* iextdefsym */
+ ml->data[3] = nkind[SymKindExtdef]; /* nextdefsym */
+ n += nkind[SymKindExtdef];
+
+ ml->data[4] = n; /* iundefsym */
+ ml->data[5] = nkind[SymKindUndef]; /* nundefsym */
+
+ ml->data[6] = 0; /* tocoffset */
+ ml->data[7] = 0; /* ntoc */
+ ml->data[8] = 0; /* modtaboff */
+ ml->data[9] = 0; /* nmodtab */
+ ml->data[10] = 0; /* extrefsymoff */
+ ml->data[11] = 0; /* nextrefsyms */
+
+ // must match domacholink below
+ s1 = lookup(".machosymtab", 0);
+ s2 = lookup(".linkedit.plt", 0);
+ s3 = lookup(".linkedit.got", 0);
+ ml->data[12] = linkoff + s1->size; /* indirectsymoff */
+ ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */
+
+ ml->data[14] = 0; /* extreloff */
+ ml->data[15] = 0; /* nextrel */
+ ml->data[16] = 0; /* locreloff */
+ ml->data[17] = 0; /* nlocrel */
+}
+
vlong
domacholink(void)
{
int size;
Sym *s1, *s2, *s3, *s4;
+ machosymtab();
+
// write data that will be linkedit section
- s1 = lookup(".dynsym", 0);
- relocsym(s1);
+ s1 = lookup(".machosymtab", 0);
s2 = lookup(".linkedit.plt", 0);
s3 = lookup(".linkedit.got", 0);
- s4 = lookup(".dynstr", 0);
+ s4 = lookup(".machosymstr", 0);
// Force the linkedit section to end on a 16-byte
// boundary. This allows pure (non-cgo) Go binaries
@@ -533,3 +699,57 @@ domacholink(void)
return rnd(size, INITRND);
}
+
+
+void
+machorelocsect(Section *sect, Sym *first)
+{
+ Sym *sym;
+ int32 eaddr;
+ Reloc *r;
+
+ // If main section has no bits, nothing to relocate.
+ if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
+ return;
+
+ sect->reloff = cpos();
+ for(sym = first; sym != nil; sym = sym->next) {
+ if(!sym->reachable)
+ continue;
+ if(sym->value >= sect->vaddr)
+ break;
+ }
+
+ eaddr = sect->vaddr + sect->len;
+ for(; sym != nil; sym = sym->next) {
+ if(!sym->reachable)
+ continue;
+ if(sym->value >= eaddr)
+ break;
+ cursym = sym;
+
+ for(r = sym->r; r < sym->r+sym->nr; r++) {
+ if(r->done)
+ continue;
+ if(machoreloc1(r, sym->value+r->off - sect->vaddr) < 0)
+ diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
+ }
+ }
+
+ sect->rellen = cpos() - sect->reloff;
+}
+
+void
+machoemitreloc(void)
+{
+ Section *sect;
+
+ while(cpos()&7)
+ cput(0);
+
+ machorelocsect(segtext.sect, textp);
+ for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
+ machorelocsect(sect, datap);
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ machorelocsect(sect, datap);
+}
diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h
index baea6ff03..d759f4b0f 100644
--- a/src/cmd/ld/macho.h
+++ b/src/cmd/ld/macho.h
@@ -11,6 +11,7 @@ struct MachoHdr {
typedef struct MachoSect MachoSect;
struct MachoSect {
char* name;
+ char* segname;
uint64 addr;
uint64 size;
uint32 off;
@@ -44,19 +45,15 @@ struct MachoLoad {
uint32 *data;
};
-typedef struct MachoDebug MachoDebug;
-struct MachoDebug {
- uint32 fileoffset;
- uint32 filesize;
-};
-
MachoHdr* getMachoHdr(void);
MachoSeg* newMachoSeg(char*, int);
-MachoSect* newMachoSect(MachoSeg*, char*);
+MachoSect* newMachoSect(MachoSeg*, char*, char*);
MachoLoad* newMachoLoad(uint32, uint32);
-MachoDebug* newMachoDebug(void);
int machowrite(void);
void machoinit(void);
+void machosymorder(void);
+void machoemitreloc(void);
+int machoreloc1(Reloc*, vlong);
/*
* Total amount of space to reserve at the start of the file
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index f2903ba0f..090d083f5 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -195,7 +195,7 @@ initdynimport(void)
dr = nil;
m = nil;
for(s = allsym; s != S; s = s->allsym) {
- if(!s->reachable || !s->dynimpname || s->dynexport)
+ if(!s->reachable || s->type != SDYNIMPORT)
continue;
for(d = dr; d != nil; d = d->next) {
if(strcmp(d->name,s->dynimplib) == 0) {
@@ -262,7 +262,7 @@ addimports(IMAGE_SECTION_HEADER *datsect)
for(m = d->ms; m != nil; m = m->next) {
m->off = nextsectoff + cpos() - startoff;
wputl(0); // hint
- strput(m->s->dynimpname);
+ strput(m->s->extname);
}
}
@@ -325,7 +325,7 @@ scmp(const void *p1, const void *p2)
s1 = *(Sym**)p1;
s2 = *(Sym**)p2;
- return strcmp(s1->dynimpname, s2->dynimpname);
+ return strcmp(s1->extname, s2->extname);
}
static void
@@ -335,7 +335,7 @@ initdynexport(void)
nexport = 0;
for(s = allsym; s != S; s = s->allsym) {
- if(!s->reachable || !s->dynimpname || !s->dynexport)
+ if(!s->reachable || !(s->cgoexport & CgoExportDynamic))
continue;
if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
diag("pe dynexport table is full");
@@ -358,7 +358,7 @@ addexports(void)
size = sizeof e + 10*nexport + strlen(outfile) + 1;
for(i=0; i<nexport; i++)
- size += strlen(dexport[i]->dynimpname) + 1;
+ size += strlen(dexport[i]->extname) + 1;
if (nexport == 0)
return;
@@ -394,7 +394,7 @@ addexports(void)
v = e.Name + strlen(outfile)+1;
for(i=0; i<nexport; i++) {
lputl(v);
- v += strlen(dexport[i]->dynimpname)+1;
+ v += strlen(dexport[i]->extname)+1;
}
// put EXPORT Ordinal Table
for(i=0; i<nexport; i++)
@@ -402,7 +402,7 @@ addexports(void)
// put Names
strnput(outfile, strlen(outfile)+1);
for(i=0; i<nexport; i++)
- strnput(dexport[i]->dynimpname, strlen(dexport[i]->dynimpname)+1);
+ strnput(dexport[i]->extname, strlen(dexport[i]->extname)+1);
strnput("", sect->SizeOfRawData - size);
}
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index 89a594872..7c8ba642f 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -121,18 +121,53 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
// One pass for each binding: STB_LOCAL, STB_GLOBAL,
// maybe one day STB_WEAK.
- bind = (ver || (x->type & SHIDDEN)) ? STB_LOCAL : STB_GLOBAL;
+ bind = STB_GLOBAL;
+ if(ver || (x->type & SHIDDEN))
+ bind = STB_LOCAL;
+
+ // In external linking mode, we have to invoke gcc with -rdynamic
+ // to get the exported symbols put into the dynamic symbol table.
+ // To avoid filling the dynamic table with lots of unnecessary symbols,
+ // mark all Go symbols local (not global) in the final executable.
+ if(linkmode == LinkExternal && !(x->cgoexport&CgoExportStatic))
+ bind = STB_LOCAL;
+
if(bind != elfbind)
return;
off = putelfstr(s);
- if(isobj)
+ if(linkmode == LinkExternal)
addr -= xo->sect->vaddr;
putelfsyment(off, addr, size, (bind<<4)|(type&0xf), xo->sect->elfsect->shnum, (x->type & SHIDDEN) ? 2 : 0);
x->elfsym = numelfsym++;
}
void
+putelfsectionsym(Sym* s, int shndx)
+{
+ putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0);
+ s->elfsym = numelfsym++;
+}
+
+void
+putelfsymshndx(vlong sympos, int shndx)
+{
+ vlong here;
+
+ here = cpos();
+ switch(thechar) {
+ case '6':
+ cseek(sympos+6);
+ break;
+ default:
+ cseek(sympos+14);
+ break;
+ }
+ WPUT(shndx);
+ cseek(here);
+}
+
+void
asmelfsym(void)
{
Sym *s;
@@ -140,8 +175,30 @@ asmelfsym(void)
// the first symbol entry is reserved
putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0);
+ dwarfaddelfsectionsyms();
+
elfbind = STB_LOCAL;
genasmsym(putelfsym);
+
+ if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) {
+ s = lookup("runtime.m", 0);
+ if(s->sect == nil) {
+ cursym = nil;
+ diag("missing section for %s", s->name);
+ errorexit();
+ }
+ putelfsyment(putelfstr(s->name), 0, PtrSize, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0);
+ s->elfsym = numelfsym++;
+
+ s = lookup("runtime.g", 0);
+ if(s->sect == nil) {
+ cursym = nil;
+ diag("missing section for %s", s->name);
+ errorexit();
+ }
+ putelfsyment(putelfstr(s->name), PtrSize, PtrSize, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0);
+ s->elfsym = numelfsym++;
+ }
elfbind = STB_GLOBAL;
elfglobalsymndx = numelfsym;
@@ -317,7 +374,7 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
// type byte
if('A' <= t && t <= 'Z')
- c = t - 'A';
+ c = t - 'A' + (ver ? 26 : 0);
else if('a' <= t && t <= 'z')
c = t - 'a' + 26;
else {
@@ -424,10 +481,8 @@ symtab(void)
xdefine("datarelro", SDATARELRO, 0);
xdefine("edatarelro", SDATARELRO, 0);
}
- xdefine("gcdata", SGCDATA, 0);
- xdefine("egcdata", SGCDATA, 0);
- xdefine("gcbss", SGCBSS, 0);
- xdefine("egcbss", SGCBSS, 0);
+ xdefine("egcdata", STYPE, 0);
+ xdefine("egcbss", STYPE, 0);
xdefine("noptrdata", SNOPTRDATA, 0);
xdefine("enoptrdata", SNOPTRDATA, 0);
xdefine("data", SDATA, 0);
diff --git a/src/cmd/nm/nm.c b/src/cmd/nm/nm.c
index 668239035..aa056b882 100644
--- a/src/cmd/nm/nm.c
+++ b/src/cmd/nm/nm.c
@@ -275,11 +275,13 @@ psym(Sym *s, void* p)
return;
break;
case 'm':
+ if(!aflag || uflag || gflag)
+ return;
+ break;
case 'f': /* we only see a 'z' when the following is true*/
if(!aflag || uflag || gflag)
return;
- if (strcmp(s->name, ".frame"))
- zenter(s);
+ zenter(s);
break;
case 'a':
case 'p':
diff --git a/src/cmd/prof/Makefile b/src/cmd/prof/Makefile
deleted file mode 100644
index 3f528d751..000000000
--- a/src/cmd/prof/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# 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.dist
diff --git a/src/cmd/prof/doc.go b/src/cmd/prof/doc.go
deleted file mode 100644
index 2640167d3..000000000
--- a/src/cmd/prof/doc.go
+++ /dev/null
@@ -1,49 +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.
-
-// +build ignore
-
-/*
-
-Prof is a rudimentary real-time profiler.
-
-Given a command to run or the process id (pid) of a command already
-running, it samples the program's state at regular intervals and reports
-on its behavior. With no options, it prints a histogram of the locations
-in the code that were sampled during execution.
-
-Since it is a real-time profiler, unlike a traditional profiler it samples
-the program's state even when it is not running, such as when it is
-asleep or waiting for I/O. Each thread contributes equally to the
-statistics.
-
-Usage:
- go tool prof -p pid [-t total_secs] [-d delta_msec] [6.out args ...]
-
-The output modes (default -h) are:
-
- -P file.prof:
- Write the profile information to file.prof, in the format used by pprof.
- At the moment, this only works on Linux amd64 binaries and requires that the
- binary be written using 6l -e to produce ELF debug info.
- See http://code.google.com/p/google-perftools for details.
- -h: histograms
- How many times a sample occurred at each location.
- -f: dynamic functions
- At each sample period, print the name of the executing function.
- -l: dynamic file and line numbers
- At each sample period, print the file and line number of the executing instruction.
- -r: dynamic registers
- At each sample period, print the register contents.
- -s: dynamic function stack traces
- At each sample period, print the symbolic stack trace.
-
-Flag -t sets the maximum real time to sample, in seconds, and -d
-sets the sampling interval in milliseconds. The default is to sample
-every 100ms until the program completes.
-
-It is installed as go tool prof and is architecture-independent.
-
-*/
-package main
diff --git a/src/cmd/prof/main.c b/src/cmd/prof/main.c
deleted file mode 100644
index 6c591ba18..000000000
--- a/src/cmd/prof/main.c
+++ /dev/null
@@ -1,910 +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.
-
-// +build !plan9
-
-#include <u.h>
-#include <time.h>
-#include <libc.h>
-#include <bio.h>
-#include <ctype.h>
-
-#define Ureg Ureg_amd64
- #include <ureg_amd64.h>
-#undef Ureg
-#define Ureg Ureg_x86
- #include <ureg_x86.h>
-#undef Ureg
-#include <mach.h>
-
-char* file = "6.out";
-static Fhdr fhdr;
-int have_syms;
-int fd;
-struct Ureg_amd64 ureg_amd64;
-struct Ureg_x86 ureg_x86;
-int total_sec = 0;
-int delta_msec = 100;
-int nsample;
-int nsamplethread;
-
-// pprof data, stored as sequences of N followed by N PC values.
-// See http://code.google.com/p/google-perftools .
-uvlong *ppdata; // traces
-Biobuf* pproffd; // file descriptor to write trace info
-long ppstart; // start position of current trace
-long nppdata; // length of data
-long ppalloc; // size of allocated data
-char ppmapdata[10*1024]; // the map information for the output file
-
-// output formats
-int pprof; // print pprof output to named file
-int functions; // print functions
-int histograms; // print histograms
-int linenums; // print file and line numbers rather than function names
-int registers; // print registers
-int stacks; // print stack traces
-
-int pid; // main process pid
-
-int nthread; // number of threads
-int thread[32]; // thread pids
-Map *map[32]; // thread maps
-
-void
-Usage(void)
-{
- fprint(2, "Usage: prof -p pid [-t total_secs] [-d delta_msec]\n");
- fprint(2, " prof [-t total_secs] [-d delta_msec] 6.out args ...\n");
- fprint(2, "\tformats (default -h):\n");
- fprint(2, "\t\t-P file.prof: write [c]pprof output to file.prof\n");
- fprint(2, "\t\t-h: histograms\n");
- fprint(2, "\t\t-f: dynamic functions\n");
- fprint(2, "\t\t-l: dynamic file and line numbers\n");
- fprint(2, "\t\t-r: dynamic registers\n");
- fprint(2, "\t\t-s: dynamic function stack traces\n");
- fprint(2, "\t\t-hs: include stack info in histograms\n");
- exit(2);
-}
-
-typedef struct PC PC;
-struct PC {
- uvlong pc;
- uvlong callerpc;
- unsigned int count;
- PC* next;
-};
-
-enum {
- Ncounters = 256
-};
-
-PC *counters[Ncounters];
-
-// Set up by setarch() to make most of the code architecture-independent.
-typedef struct Arch Arch;
-struct Arch {
- char* name;
- void (*regprint)(void);
- int (*getregs)(Map*);
- int (*getPC)(Map*);
- int (*getSP)(Map*);
- uvlong (*uregPC)(void);
- uvlong (*uregSP)(void);
- void (*ppword)(uvlong w);
-};
-
-void
-amd64_regprint(void)
-{
- fprint(2, "ax\t0x%llux\n", ureg_amd64.ax);
- fprint(2, "bx\t0x%llux\n", ureg_amd64.bx);
- fprint(2, "cx\t0x%llux\n", ureg_amd64.cx);
- fprint(2, "dx\t0x%llux\n", ureg_amd64.dx);
- fprint(2, "si\t0x%llux\n", ureg_amd64.si);
- fprint(2, "di\t0x%llux\n", ureg_amd64.di);
- fprint(2, "bp\t0x%llux\n", ureg_amd64.bp);
- fprint(2, "r8\t0x%llux\n", ureg_amd64.r8);
- fprint(2, "r9\t0x%llux\n", ureg_amd64.r9);
- fprint(2, "r10\t0x%llux\n", ureg_amd64.r10);
- fprint(2, "r11\t0x%llux\n", ureg_amd64.r11);
- fprint(2, "r12\t0x%llux\n", ureg_amd64.r12);
- fprint(2, "r13\t0x%llux\n", ureg_amd64.r13);
- fprint(2, "r14\t0x%llux\n", ureg_amd64.r14);
- fprint(2, "r15\t0x%llux\n", ureg_amd64.r15);
- fprint(2, "ds\t0x%llux\n", ureg_amd64.ds);
- fprint(2, "es\t0x%llux\n", ureg_amd64.es);
- fprint(2, "fs\t0x%llux\n", ureg_amd64.fs);
- fprint(2, "gs\t0x%llux\n", ureg_amd64.gs);
- fprint(2, "type\t0x%llux\n", ureg_amd64.type);
- fprint(2, "error\t0x%llux\n", ureg_amd64.error);
- fprint(2, "pc\t0x%llux\n", ureg_amd64.ip);
- fprint(2, "cs\t0x%llux\n", ureg_amd64.cs);
- fprint(2, "flags\t0x%llux\n", ureg_amd64.flags);
- fprint(2, "sp\t0x%llux\n", ureg_amd64.sp);
- fprint(2, "ss\t0x%llux\n", ureg_amd64.ss);
-}
-
-int
-amd64_getregs(Map *map)
-{
- int i;
- union {
- uvlong regs[1];
- struct Ureg_amd64 ureg;
- } u;
-
- for(i = 0; i < sizeof ureg_amd64; i+=8) {
- if(get8(map, (uvlong)i, &u.regs[i/8]) < 0)
- return -1;
- }
- ureg_amd64 = u.ureg;
- return 0;
-}
-
-int
-amd64_getPC(Map *map)
-{
- uvlong x;
- int r;
-
- r = get8(map, offsetof(struct Ureg_amd64, ip), &x);
- ureg_amd64.ip = x;
- return r;
-}
-
-int
-amd64_getSP(Map *map)
-{
- uvlong x;
- int r;
-
- r = get8(map, offsetof(struct Ureg_amd64, sp), &x);
- ureg_amd64.sp = x;
- return r;
-}
-
-uvlong
-amd64_uregPC(void)
-{
- return ureg_amd64.ip;
-}
-
-uvlong
-amd64_uregSP(void)
-{
- return ureg_amd64.sp;
-}
-
-void
-amd64_ppword(uvlong w)
-{
- uchar buf[8];
-
- buf[0] = w;
- buf[1] = w >> 8;
- buf[2] = w >> 16;
- buf[3] = w >> 24;
- buf[4] = w >> 32;
- buf[5] = w >> 40;
- buf[6] = w >> 48;
- buf[7] = w >> 56;
- Bwrite(pproffd, buf, 8);
-}
-
-void
-x86_regprint(void)
-{
- fprint(2, "ax\t0x%ux\n", ureg_x86.ax);
- fprint(2, "bx\t0x%ux\n", ureg_x86.bx);
- fprint(2, "cx\t0x%ux\n", ureg_x86.cx);
- fprint(2, "dx\t0x%ux\n", ureg_x86.dx);
- fprint(2, "si\t0x%ux\n", ureg_x86.si);
- fprint(2, "di\t0x%ux\n", ureg_x86.di);
- fprint(2, "bp\t0x%ux\n", ureg_x86.bp);
- fprint(2, "ds\t0x%ux\n", ureg_x86.ds);
- fprint(2, "es\t0x%ux\n", ureg_x86.es);
- fprint(2, "fs\t0x%ux\n", ureg_x86.fs);
- fprint(2, "gs\t0x%ux\n", ureg_x86.gs);
- fprint(2, "cs\t0x%ux\n", ureg_x86.cs);
- fprint(2, "flags\t0x%ux\n", ureg_x86.flags);
- fprint(2, "pc\t0x%ux\n", ureg_x86.pc);
- fprint(2, "sp\t0x%ux\n", ureg_x86.sp);
- fprint(2, "ss\t0x%ux\n", ureg_x86.ss);
-}
-
-int
-x86_getregs(Map *map)
-{
- int i;
-
- for(i = 0; i < sizeof ureg_x86; i+=4) {
- if(get4(map, (uvlong)i, &((uint32*)&ureg_x86)[i/4]) < 0)
- return -1;
- }
- return 0;
-}
-
-int
-x86_getPC(Map* map)
-{
- return get4(map, offsetof(struct Ureg_x86, pc), &ureg_x86.pc);
-}
-
-int
-x86_getSP(Map* map)
-{
- return get4(map, offsetof(struct Ureg_x86, sp), &ureg_x86.sp);
-}
-
-uvlong
-x86_uregPC(void)
-{
- return (uvlong)ureg_x86.pc;
-}
-
-uvlong
-x86_uregSP(void)
-{
- return (uvlong)ureg_x86.sp;
-}
-
-void
-x86_ppword(uvlong w)
-{
- uchar buf[4];
-
- buf[0] = w;
- buf[1] = w >> 8;
- buf[2] = w >> 16;
- buf[3] = w >> 24;
- Bwrite(pproffd, buf, 4);
-}
-
-Arch archtab[] = {
- {
- "amd64",
- amd64_regprint,
- amd64_getregs,
- amd64_getPC,
- amd64_getSP,
- amd64_uregPC,
- amd64_uregSP,
- amd64_ppword,
- },
- {
- "386",
- x86_regprint,
- x86_getregs,
- x86_getPC,
- x86_getSP,
- x86_uregPC,
- x86_uregSP,
- x86_ppword,
- },
- {
- nil
- }
-};
-
-Arch *arch;
-
-int
-setarch(void)
-{
- int i;
-
- if(mach != nil) {
- for(i = 0; archtab[i].name != nil; i++) {
- if (strcmp(mach->name, archtab[i].name) == 0) {
- arch = &archtab[i];
- return 0;
- }
- }
- }
- return -1;
-}
-
-int
-getthreads(void)
-{
- int i, j, curn, found;
- Map *curmap[nelem(map)];
- int curthread[nelem(map)];
- static int complained = 0;
-
- curn = procthreadpids(pid, curthread, nelem(curthread));
- if(curn <= 0)
- return curn;
-
- if(curn > nelem(map)) {
- if(complained == 0) {
- fprint(2, "prof: too many threads; limiting to %d\n", nthread, nelem(map));
- complained = 1;
- }
- curn = nelem(map);
- }
- if(curn == nthread && memcmp(thread, curthread, curn*sizeof(*thread)) == 0)
- return curn; // no changes
-
- // Number of threads has changed (might be the init case).
- // A bit expensive but rare enough not to bother being clever.
- for(i = 0; i < curn; i++) {
- found = 0;
- for(j = 0; j < nthread; j++) {
- if(curthread[i] == thread[j]) {
- found = 1;
- curmap[i] = map[j];
- map[j] = nil;
- break;
- }
- }
- if(found)
- continue;
-
- // map new thread
- curmap[i] = attachproc(curthread[i], &fhdr);
- if(curmap[i] == nil) {
- fprint(2, "prof: can't attach to %d: %r\n", curthread[i]);
- return -1;
- }
- }
-
- for(j = 0; j < nthread; j++)
- if(map[j] != nil)
- detachproc(map[j]);
-
- nthread = curn;
- memmove(thread, curthread, nthread*sizeof thread[0]);
- memmove(map, curmap, sizeof map);
- return nthread;
-}
-
-int
-sample(Map *map)
-{
- static int n;
-
- n++;
- if(registers) {
- if(arch->getregs(map) < 0)
- goto bad;
- } else {
- // we need only two registers
- if(arch->getPC(map) < 0)
- goto bad;
- if(arch->getSP(map) < 0)
- goto bad;
- }
- return 1;
-bad:
- if(n == 1)
- fprint(2, "prof: can't read registers: %r\n");
- return 0;
-}
-
-void
-addtohistogram(uvlong pc, uvlong callerpc, uvlong sp)
-{
- int h;
- PC *x;
-
- USED(sp);
-
- h = (pc + callerpc*101) % Ncounters;
- for(x = counters[h]; x != NULL; x = x->next) {
- if(x->pc == pc && x->callerpc == callerpc) {
- x->count++;
- return;
- }
- }
- x = malloc(sizeof(PC));
- if(x == nil)
- sysfatal("out of memory");
- x->pc = pc;
- x->callerpc = callerpc;
- x->count = 1;
- x->next = counters[h];
- counters[h] = x;
-}
-
-void
-addppword(uvlong pc)
-{
- if(pc == 0) {
- return;
- }
- if(nppdata == ppalloc) {
- ppalloc = (1000+nppdata)*2;
- ppdata = realloc(ppdata, ppalloc * sizeof ppdata[0]);
- if(ppdata == nil) {
- fprint(2, "prof: realloc failed: %r\n");
- exit(2);
- }
- }
- ppdata[nppdata++] = pc;
-}
-
-void
-startpptrace(void)
-{
- ppstart = nppdata;
- addppword(~0);
-}
-
-void
-endpptrace(void)
-{
- ppdata[ppstart] = nppdata-ppstart-1;
-}
-
-uvlong nextpc;
-
-void
-xptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym)
-{
- USED(map);
-
- char buf[1024];
- if(sym == nil){
- fprint(2, "syms\n");
- return;
- }
- if(histograms)
- addtohistogram(nextpc, pc, sp);
- if(!histograms || stacks > 1 || pprof) {
- if(nextpc == 0)
- nextpc = sym->value;
- if(stacks){
- fprint(2, "%s(", sym->name);
- fprint(2, ")");
- if(nextpc != sym->value)
- fprint(2, "+%#llux ", nextpc - sym->value);
- if(have_syms && linenums && fileline(buf, sizeof buf, pc)) {
- fprint(2, " %s", buf);
- }
- fprint(2, "\n");
- }
- if (pprof) {
- addppword(nextpc);
- }
- }
- nextpc = pc;
-}
-
-void
-stacktracepcsp(Map *map, uvlong pc, uvlong sp)
-{
- nextpc = pc;
- if(pprof){
- startpptrace();
- }
- if(machdata->ctrace==nil)
- fprint(2, "no machdata->ctrace\n");
- else if(machdata->ctrace(map, pc, sp, 0, xptrace) <= 0)
- fprint(2, "no stack frame: pc=%#p sp=%#p\n", pc, sp);
- else {
- addtohistogram(nextpc, 0, sp);
- if(stacks)
- fprint(2, "\n");
- }
- if(pprof){
- endpptrace();
- }
-}
-
-void
-printpc(Map *map, uvlong pc, uvlong sp)
-{
- char buf[1024];
- if(registers)
- arch->regprint();
- if(have_syms > 0 && linenums && fileline(buf, sizeof buf, pc))
- fprint(2, "%s\n", buf);
- if(have_syms > 0 && functions) {
- symoff(buf, sizeof(buf), pc, CANY);
- fprint(2, "%s\n", buf);
- }
- if(stacks || pprof){
- stacktracepcsp(map, pc, sp);
- }
- else if(histograms){
- addtohistogram(pc, 0, sp);
- }
-}
-
-void
-ppmaps(void)
-{
- int fd, n;
- char tmp[100];
- Seg *seg;
-
- // If it's Linux, the info is in /proc/$pid/maps
- snprint(tmp, sizeof tmp, "/proc/%d/maps", pid);
- fd = open(tmp, 0);
- if(fd >= 0) {
- n = read(fd, ppmapdata, sizeof ppmapdata - 1);
- close(fd);
- if(n < 0) {
- fprint(2, "prof: can't read %s: %r\n", tmp);
- exit(2);
- }
- ppmapdata[n] = 0;
- return;
- }
-
- // It's probably a mac. Synthesize an entry for the text file.
- // The register segment may come first but it has a zero offset, so grab the first non-zero offset segment.
- for(n = 0; n < 3; n++){
- seg = &map[0]->seg[n];
- if(seg->b == 0) {
- continue;
- }
- snprint(ppmapdata, sizeof ppmapdata,
- "%.16x-%.16x r-xp %d 00:00 34968549 %s\n",
- seg->b, seg->e, seg->f, "/home/r/6.out"
- );
- return;
- }
- fprint(2, "prof: no text segment in maps for %s\n", file);
- exit(2);
-}
-
-void
-samples(void)
-{
- int i, pid, msec;
- struct timespec req;
- int getmaps;
-
- req.tv_sec = delta_msec/1000;
- req.tv_nsec = 1000000*(delta_msec % 1000);
- getmaps = 0;
- if(pprof)
- getmaps= 1;
- for(msec = 0; total_sec <= 0 || msec < 1000*total_sec; msec += delta_msec) {
- nsample++;
- nsamplethread += nthread;
- for(i = 0; i < nthread; i++) {
- pid = thread[i];
- if(ctlproc(pid, "stop") < 0)
- return;
- if(!sample(map[i])) {
- ctlproc(pid, "start");
- return;
- }
- printpc(map[i], arch->uregPC(), arch->uregSP());
- ctlproc(pid, "start");
- }
- nanosleep(&req, NULL);
- getthreads();
- if(nthread == 0)
- break;
- if(getmaps) {
- getmaps = 0;
- ppmaps();
- }
- }
-}
-
-typedef struct Func Func;
-struct Func
-{
- Func *next;
- Symbol s;
- uint onstack;
- uint leaf;
-};
-
-Func *func[257];
-int nfunc;
-
-Func*
-findfunc(uvlong pc)
-{
- Func *f;
- uint h;
- Symbol s;
-
- if(pc == 0)
- return nil;
-
- if(!findsym(pc, CTEXT, &s))
- return nil;
-
- h = s.value % nelem(func);
- for(f = func[h]; f != NULL; f = f->next)
- if(f->s.value == s.value)
- return f;
-
- f = malloc(sizeof *f);
- if(f == nil)
- sysfatal("out of memory");
- memset(f, 0, sizeof *f);
- f->s = s;
- f->next = func[h];
- func[h] = f;
- nfunc++;
- return f;
-}
-
-int
-compareleaf(const void *va, const void *vb)
-{
- Func *a, *b;
-
- a = *(Func**)va;
- b = *(Func**)vb;
- if(a->leaf != b->leaf)
- return b->leaf - a->leaf;
- if(a->onstack != b->onstack)
- return b->onstack - a->onstack;
- return strcmp(a->s.name, b->s.name);
-}
-
-void
-dumphistogram(void)
-{
- int i, h, n;
- PC *x;
- Func *f, **ff;
-
- if(!histograms)
- return;
-
- // assign counts to functions.
- for(h = 0; h < Ncounters; h++) {
- for(x = counters[h]; x != NULL; x = x->next) {
- f = findfunc(x->pc);
- if(f) {
- f->onstack += x->count;
- f->leaf += x->count;
- }
- f = findfunc(x->callerpc);
- if(f)
- f->leaf -= x->count;
- }
- }
-
- // build array
- ff = malloc(nfunc*sizeof ff[0]);
- if(ff == nil)
- sysfatal("out of memory");
- n = 0;
- for(h = 0; h < nelem(func); h++)
- for(f = func[h]; f != NULL; f = f->next)
- ff[n++] = f;
-
- // sort by leaf counts
- qsort(ff, nfunc, sizeof ff[0], compareleaf);
-
- // print.
- fprint(2, "%d samples (avg %.1g threads)\n", nsample, (double)nsamplethread/nsample);
- for(i = 0; i < nfunc; i++) {
- f = ff[i];
- fprint(2, "%6.2f%%\t", 100.0*(double)f->leaf/nsample);
- if(stacks)
- fprint(2, "%6.2f%%\t", 100.0*(double)f->onstack/nsample);
- fprint(2, "%s\n", f->s.name);
- }
-}
-
-typedef struct Trace Trace;
-struct Trace {
- int count;
- int npc;
- uvlong *pc;
- Trace *next;
-};
-
-void
-dumppprof(void)
-{
- uvlong i, n, *p, *e;
- int ntrace;
- Trace *trace, *tp, *up, *prev;
-
- if(!pprof)
- return;
- e = ppdata + nppdata;
- // Create list of traces. First, count the traces
- ntrace = 0;
- for(p = ppdata; p < e;) {
- n = *p++;
- p += n;
- if(n == 0)
- continue;
- ntrace++;
- }
- if(ntrace <= 0)
- return;
- // Allocate and link the traces together.
- trace = malloc(ntrace * sizeof(Trace));
- if(trace == nil)
- sysfatal("out of memory");
- tp = trace;
- for(p = ppdata; p < e;) {
- n = *p++;
- if(n == 0)
- continue;
- tp->count = 1;
- tp->npc = n;
- tp->pc = p;
- tp->next = tp+1;
- tp++;
- p += n;
- }
- trace[ntrace-1].next = nil;
- // Eliminate duplicates. Lousy algorithm, although not as bad as it looks because
- // the list collapses fast.
- for(tp = trace; tp != nil; tp = tp->next) {
- prev = tp;
- for(up = tp->next; up != nil; up = up->next) {
- if(up->npc == tp->npc && memcmp(up->pc, tp->pc, up->npc*sizeof up->pc[0]) == 0) {
- tp->count++;
- prev->next = up->next;
- } else {
- prev = up;
- }
- }
- }
- // Write file.
- // See http://code.google.com/p/google-perftools/source/browse/trunk/doc/cpuprofile-fileformat.html
- // 1) Header
- arch->ppword(0); // must be zero
- arch->ppword(3); // 3 words follow in header
- arch->ppword(0); // must be zero
- arch->ppword(delta_msec * 1000); // sampling period in microseconds
- arch->ppword(0); // must be zero (padding)
- // 2) One record for each trace.
- for(tp = trace; tp != nil; tp = tp->next) {
- arch->ppword(tp->count);
- arch->ppword(tp->npc);
- for(i = 0; i < tp->npc; i++) {
- arch->ppword(tp->pc[i]);
- }
- }
- // 3) Binary trailer
- arch->ppword(0); // must be zero
- arch->ppword(1); // must be one
- arch->ppword(0); // must be zero
- // 4) Mapped objects.
- Bwrite(pproffd, ppmapdata, strlen(ppmapdata));
- // 5) That's it.
- Bterm(pproffd);
-}
-
-int
-startprocess(char **argv)
-{
- int pid;
-
- if((pid = fork()) == 0) {
- pid = getpid();
- if(ctlproc(pid, "hang") < 0){
- fprint(2, "prof: child process could not hang\n");
- exits(0);
- }
- execv(argv[0], argv);
- fprint(2, "prof: could not exec %s: %r\n", argv[0]);
- exits(0);
- }
-
- if(pid == -1) {
- fprint(2, "prof: could not fork\n");
- exit(1);
- }
- if(ctlproc(pid, "attached") < 0 || ctlproc(pid, "waitstop") < 0) {
- fprint(2, "prof: could not attach to child process: %r\n");
- exit(1);
- }
- return pid;
-}
-
-void
-detach(void)
-{
- int i;
-
- for(i = 0; i < nthread; i++)
- detachproc(map[i]);
-}
-
-int
-main(int argc, char *argv[])
-{
- int i;
- char *ppfile;
-
- ARGBEGIN{
- case 'P':
- pprof =1;
- ppfile = EARGF(Usage());
- pproffd = Bopen(ppfile, OWRITE);
- if(pproffd == nil) {
- fprint(2, "prof: cannot open %s: %r\n", ppfile);
- exit(2);
- }
- break;
- case 'd':
- delta_msec = atoi(EARGF(Usage()));
- break;
- case 't':
- total_sec = atoi(EARGF(Usage()));
- break;
- case 'p':
- pid = atoi(EARGF(Usage()));
- break;
- case 'f':
- functions = 1;
- break;
- case 'h':
- histograms = 1;
- break;
- case 'l':
- linenums = 1;
- break;
- case 'r':
- registers = 1;
- break;
- case 's':
- stacks++;
- break;
- default:
- Usage();
- }ARGEND
- if(pid <= 0 && argc == 0)
- Usage();
- if(functions+linenums+registers+stacks+pprof == 0)
- histograms = 1;
- if(!machbyname("amd64")) {
- fprint(2, "prof: no amd64 support\n", pid);
- exit(1);
- }
- if(argc > 0)
- file = argv[0];
- else if(pid) {
- file = proctextfile(pid);
- if (file == NULL) {
- fprint(2, "prof: can't find file for pid %d: %r\n", pid);
- fprint(2, "prof: on Darwin, need to provide file name explicitly\n");
- exit(1);
- }
- }
- fd = open(file, 0);
- if(fd < 0) {
- fprint(2, "prof: can't open %s: %r\n", file);
- exit(1);
- }
- if(crackhdr(fd, &fhdr)) {
- have_syms = syminit(fd, &fhdr);
- if(!have_syms) {
- fprint(2, "prof: no symbols for %s: %r\n", file);
- }
- } else {
- fprint(2, "prof: crack header for %s: %r\n", file);
- exit(1);
- }
- if(pid <= 0)
- pid = startprocess(argv);
- attachproc(pid, &fhdr); // initializes thread list
- if(setarch() < 0) {
- detach();
- fprint(2, "prof: can't identify binary architecture for pid %d\n", pid);
- exit(1);
- }
- if(getthreads() <= 0) {
- detach();
- fprint(2, "prof: can't find threads for pid %d\n", pid);
- exit(1);
- }
- for(i = 0; i < nthread; i++)
- ctlproc(thread[i], "start");
- samples();
- detach();
- dumphistogram();
- dumppprof();
- exit(0);
-}
diff --git a/src/cmd/vet/Makefile b/src/cmd/vet/Makefile
index 307f4729c..67c7e1997 100644
--- a/src/cmd/vet/Makefile
+++ b/src/cmd/vet/Makefile
@@ -2,7 +2,13 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
+# Assumes go/types is installed
test testshort:
- go build -tags vet_test
- ../../../test/errchk ./vet -compositewhitelist=false -printfuncs='Warn:1,Warnf:1' *.go
+ go build -tags 'vet_test gotypes'
+ ../../../test/errchk ./vet -printfuncs='Warn:1,Warnf:1' test_*.go test_*.s
+test_notypes:
+ go build -tags 'vet_test'
+ # Only those tests that do not depend on types.
+ # Excluded: test_print.go
+ ../../../test/errchk ./vet -printfuncs='Warn:1,Warnf:1' test_asm.go test_assign.go test_atomic.go test_buildtag.go test_buildtag_bad.go test_deadcode.go test_method.go test_rangeloop.go test_structtag.go test_taglit.go test_*.s
diff --git a/src/cmd/vet/asmdecl.go b/src/cmd/vet/asmdecl.go
new file mode 100644
index 000000000..c23514c28
--- /dev/null
+++ b/src/cmd/vet/asmdecl.go
@@ -0,0 +1,533 @@
+// Copyright 2013 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.
+
+// Identify mismatches between assembly files and Go func declarations.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/ast"
+ "go/token"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+// 'kind' is a kind of assembly variable.
+// The kinds 1, 2, 4, 8 stand for values of that size.
+type asmKind int
+
+// These special kinds are not valid sizes.
+const (
+ asmString asmKind = 100 + iota
+ asmSlice
+ asmInterface
+ asmEmptyInterface
+)
+
+// An asmArch describes assembly parameters for an architecture
+type asmArch struct {
+ name string
+ ptrSize int
+ intSize int
+ bigEndian bool
+}
+
+// An asmFunc describes the expected variables for a function on a given architecture.
+type asmFunc struct {
+ arch *asmArch
+ size int // size of all arguments
+ vars map[string]*asmVar
+ varByOffset map[int]*asmVar
+}
+
+// An asmVar describes a single assembly variable.
+type asmVar struct {
+ name string
+ kind asmKind
+ typ string
+ off int
+ size int
+ inner []*asmVar
+}
+
+var (
+ asmArch386 = asmArch{"386", 4, 4, false}
+ asmArchArm = asmArch{"arm", 4, 4, false}
+ asmArchAmd64 = asmArch{"amd64", 8, 8, false}
+
+ arches = []*asmArch{
+ &asmArch386,
+ &asmArchArm,
+ &asmArchAmd64,
+ }
+)
+
+var (
+ re = regexp.MustCompile
+ asmPlusBuild = re(`//\s+\+build\s+([^\n]+)`)
+ asmTEXT = re(`\bTEXT\b.*·([^\(]+)\(SB\)(?:\s*,\s*([0-9]+))?(?:\s*,\s*\$([0-9]+)(?:-([0-9]+))?)?`)
+ asmDATA = re(`\b(DATA|GLOBL)\b`)
+ asmNamedFP = re(`([a-zA-Z0-9_\xFF-\x{10FFFF}]+)(?:\+([0-9]+))\(FP\)`)
+ asmUnnamedFP = re(`[^+\-0-9]](([0-9]+)\(FP\))`)
+ asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`)
+)
+
+func asmCheck(pkg *Package) {
+ if !vet("asmdecl") {
+ return
+ }
+
+ // No work if no assembly files.
+ if !pkg.hasFileWithSuffix(".s") {
+ return
+ }
+
+ // Gather declarations. knownFunc[name][arch] is func description.
+ knownFunc := make(map[string]map[string]*asmFunc)
+
+ for _, f := range pkg.files {
+ if f.file != nil {
+ for _, decl := range f.file.Decls {
+ if decl, ok := decl.(*ast.FuncDecl); ok && decl.Body == nil {
+ knownFunc[decl.Name.Name] = f.asmParseDecl(decl)
+ }
+ }
+ }
+ }
+
+ var fn *asmFunc
+ for _, f := range pkg.files {
+ if !strings.HasSuffix(f.name, ".s") {
+ continue
+ }
+ Println("Checking file", f.name)
+
+ // Determine architecture from file name if possible.
+ var arch string
+ for _, a := range arches {
+ if strings.HasSuffix(f.name, "_"+a.name+".s") {
+ arch = a.name
+ break
+ }
+ }
+
+ lines := strings.SplitAfter(string(f.content), "\n")
+ for lineno, line := range lines {
+ lineno++
+
+ warnf := func(format string, args ...interface{}) {
+ f.Warnf(token.NoPos, "%s:%d: [%s] %s", f.name, lineno, arch, fmt.Sprintf(format, args...))
+ }
+
+ if arch == "" {
+ // Determine architecture from +build line if possible.
+ if m := asmPlusBuild.FindStringSubmatch(line); m != nil {
+ Fields:
+ for _, fld := range strings.Fields(m[1]) {
+ for _, a := range arches {
+ if a.name == fld {
+ arch = a.name
+ break Fields
+ }
+ }
+ }
+ }
+ }
+
+ if m := asmTEXT.FindStringSubmatch(line); m != nil {
+ if arch == "" {
+ f.Warnf(token.NoPos, "%s: cannot determine architecture for assembly file", f.name)
+ return
+ }
+ fn = knownFunc[m[1]][arch]
+ if fn != nil {
+ size, _ := strconv.Atoi(m[4])
+ if size != fn.size && (m[2] != "7" || size != 0) {
+ warnf("wrong argument size %d; expected $...-%d", size, fn.size)
+ }
+ }
+ continue
+ } else if strings.Contains(line, "TEXT") && strings.Contains(line, "SB") {
+ // function, but not visible from Go (didn't match asmTEXT), so stop checking
+ fn = nil
+ continue
+ }
+
+ if asmDATA.FindStringSubmatch(line) != nil {
+ fn = nil
+ }
+ if fn == nil {
+ continue
+ }
+
+ for _, m := range asmUnnamedFP.FindAllStringSubmatch(line, -1) {
+ warnf("use of unnamed argument %s", m[1])
+ }
+
+ for _, m := range asmNamedFP.FindAllStringSubmatch(line, -1) {
+ name := m[1]
+ off := 0
+ if m[2] != "" {
+ off, _ = strconv.Atoi(m[2])
+ }
+ v := fn.vars[name]
+ if v == nil {
+ // Allow argframe+0(FP).
+ if name == "argframe" && off == 0 {
+ continue
+ }
+ v = fn.varByOffset[off]
+ if v != nil {
+ warnf("unknown variable %s; offset %d is %s+%d(FP)", name, off, v.name, v.off)
+ } else {
+ warnf("unknown variable %s", name)
+ }
+ continue
+ }
+ asmCheckVar(warnf, fn, line, m[0], off, v)
+ }
+ }
+ }
+}
+
+// asmParseDecl parses a function decl for expected assembly variables.
+func (f *File) asmParseDecl(decl *ast.FuncDecl) map[string]*asmFunc {
+ var (
+ arch *asmArch
+ fn *asmFunc
+ offset int
+ failed bool
+ )
+
+ addVar := func(outer string, v asmVar) {
+ if vo := fn.vars[outer]; vo != nil {
+ vo.inner = append(vo.inner, &v)
+ }
+ fn.vars[v.name] = &v
+ for i := 0; i < v.size; i++ {
+ fn.varByOffset[v.off+i] = &v
+ }
+ }
+
+ addParams := func(list []*ast.Field) {
+ for i, fld := range list {
+ // Determine alignment, size, and kind of type in declaration.
+ var align, size int
+ var kind asmKind
+ names := fld.Names
+ typ := f.gofmt(fld.Type)
+ switch t := fld.Type.(type) {
+ default:
+ switch typ {
+ default:
+ f.Warnf(fld.Type.Pos(), "unknown assembly argument type %s", typ)
+ failed = true
+ return
+ case "int8", "uint8", "byte", "bool":
+ size = 1
+ case "int16", "uint16":
+ size = 2
+ case "int32", "uint32", "float32":
+ size = 4
+ case "int64", "uint64", "float64":
+ align = arch.ptrSize
+ size = 8
+ case "int", "uint":
+ size = arch.intSize
+ case "uintptr", "iword", "Word", "Errno", "unsafe.Pointer":
+ size = arch.ptrSize
+ case "string":
+ size = arch.ptrSize * 2
+ align = arch.ptrSize
+ kind = asmString
+ }
+ case *ast.ChanType, *ast.FuncType, *ast.MapType, *ast.StarExpr:
+ size = arch.ptrSize
+ case *ast.InterfaceType:
+ align = arch.ptrSize
+ size = 2 * arch.ptrSize
+ if len(t.Methods.List) > 0 {
+ kind = asmInterface
+ } else {
+ kind = asmEmptyInterface
+ }
+ case *ast.ArrayType:
+ if t.Len == nil {
+ size = arch.ptrSize + 2*arch.intSize
+ align = arch.ptrSize
+ kind = asmSlice
+ break
+ }
+ f.Warnf(fld.Type.Pos(), "unsupported assembly argument type %s", typ)
+ failed = true
+ case *ast.StructType:
+ f.Warnf(fld.Type.Pos(), "unsupported assembly argument type %s", typ)
+ failed = true
+ }
+ if align == 0 {
+ align = size
+ }
+ if kind == 0 {
+ kind = asmKind(size)
+ }
+ offset += -offset & (align - 1)
+
+ // Create variable for each name being declared with this type.
+ if len(names) == 0 {
+ name := "unnamed"
+ if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 && &list[0] == &decl.Type.Results.List[0] && i == 0 {
+ // Assume assembly will refer to single unnamed result as r.
+ name = "ret"
+ }
+ names = []*ast.Ident{{Name: name}}
+ }
+ for _, id := range names {
+ name := id.Name
+ addVar("", asmVar{
+ name: name,
+ kind: kind,
+ typ: typ,
+ off: offset,
+ size: size,
+ })
+ switch kind {
+ case 8:
+ if arch.ptrSize == 4 {
+ w1, w2 := "lo", "hi"
+ if arch.bigEndian {
+ w1, w2 = w2, w1
+ }
+ addVar(name, asmVar{
+ name: name + "_" + w1,
+ kind: 4,
+ typ: "half " + typ,
+ off: offset,
+ size: 4,
+ })
+ addVar(name, asmVar{
+ name: name + "_" + w2,
+ kind: 4,
+ typ: "half " + typ,
+ off: offset + 4,
+ size: 4,
+ })
+ }
+
+ case asmEmptyInterface:
+ addVar(name, asmVar{
+ name: name + "_type",
+ kind: asmKind(arch.ptrSize),
+ typ: "interface type",
+ off: offset,
+ size: arch.ptrSize,
+ })
+ addVar(name, asmVar{
+ name: name + "_data",
+ kind: asmKind(arch.ptrSize),
+ typ: "interface data",
+ off: offset + arch.ptrSize,
+ size: arch.ptrSize,
+ })
+
+ case asmInterface:
+ addVar(name, asmVar{
+ name: name + "_itable",
+ kind: asmKind(arch.ptrSize),
+ typ: "interface itable",
+ off: offset,
+ size: arch.ptrSize,
+ })
+ addVar(name, asmVar{
+ name: name + "_data",
+ kind: asmKind(arch.ptrSize),
+ typ: "interface data",
+ off: offset + arch.ptrSize,
+ size: arch.ptrSize,
+ })
+
+ case asmSlice:
+ addVar(name, asmVar{
+ name: name + "_base",
+ kind: asmKind(arch.ptrSize),
+ typ: "slice base",
+ off: offset,
+ size: arch.ptrSize,
+ })
+ addVar(name, asmVar{
+ name: name + "_len",
+ kind: asmKind(arch.intSize),
+ typ: "slice len",
+ off: offset + arch.ptrSize,
+ size: arch.intSize,
+ })
+ addVar(name, asmVar{
+ name: name + "_cap",
+ kind: asmKind(arch.intSize),
+ typ: "slice cap",
+ off: offset + arch.ptrSize + arch.intSize,
+ size: arch.intSize,
+ })
+
+ case asmString:
+ addVar(name, asmVar{
+ name: name + "_base",
+ kind: asmKind(arch.ptrSize),
+ typ: "string base",
+ off: offset,
+ size: arch.ptrSize,
+ })
+ addVar(name, asmVar{
+ name: name + "_len",
+ kind: asmKind(arch.intSize),
+ typ: "string len",
+ off: offset + arch.ptrSize,
+ size: arch.intSize,
+ })
+ }
+ offset += size
+ }
+ }
+ }
+
+ m := make(map[string]*asmFunc)
+ for _, arch = range arches {
+ fn = &asmFunc{
+ arch: arch,
+ vars: make(map[string]*asmVar),
+ varByOffset: make(map[int]*asmVar),
+ }
+ offset = 0
+ addParams(decl.Type.Params.List)
+ if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 {
+ offset += -offset & (arch.ptrSize - 1)
+ addParams(decl.Type.Results.List)
+ }
+ fn.size = offset
+ m[arch.name] = fn
+ }
+
+ if failed {
+ return nil
+ }
+ return m
+}
+
+// asmCheckVar checks a single variable reference.
+func asmCheckVar(warnf func(string, ...interface{}), fn *asmFunc, line, expr string, off int, v *asmVar) {
+ m := asmOpcode.FindStringSubmatch(line)
+ if m == nil {
+ warnf("cannot find assembly opcode")
+ }
+
+ // Determine operand sizes from instruction.
+ // Typically the suffix suffices, but there are exceptions.
+ var src, dst, kind asmKind
+ op := m[1]
+ switch fn.arch.name + "." + op {
+ case "386.FMOVLP":
+ src, dst = 8, 4
+ case "arm.MOVD":
+ src = 8
+ case "arm.MOVW":
+ src = 4
+ case "arm.MOVH", "arm.MOVHU":
+ src = 2
+ case "arm.MOVB", "arm.MOVBU":
+ src = 1
+ default:
+ if fn.arch.name == "386" || fn.arch.name == "amd64" {
+ if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "D") || strings.HasSuffix(op, "DP")) {
+ // FMOVDP, FXCHD, etc
+ src = 8
+ break
+ }
+ if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "F") || strings.HasSuffix(op, "FP")) {
+ // FMOVFP, FXCHF, etc
+ src = 4
+ break
+ }
+ if strings.HasSuffix(op, "SD") {
+ // MOVSD, SQRTSD, etc
+ src = 8
+ break
+ }
+ if strings.HasSuffix(op, "SS") {
+ // MOVSS, SQRTSS, etc
+ src = 4
+ break
+ }
+ if strings.HasPrefix(op, "SET") {
+ // SETEQ, etc
+ src = 1
+ break
+ }
+ switch op[len(op)-1] {
+ case 'B':
+ src = 1
+ case 'W':
+ src = 2
+ case 'L':
+ src = 4
+ case 'D', 'Q':
+ src = 8
+ }
+ }
+ }
+ if dst == 0 {
+ dst = src
+ }
+
+ // Determine whether the match we're holding
+ // is the first or second argument.
+ if strings.Index(line, expr) > strings.Index(line, ",") {
+ kind = dst
+ } else {
+ kind = src
+ }
+
+ vk := v.kind
+ vt := v.typ
+ switch vk {
+ case asmInterface, asmEmptyInterface, asmString, asmSlice:
+ // allow reference to first word (pointer)
+ vk = v.inner[0].kind
+ vt = v.inner[0].typ
+ }
+
+ if off != v.off {
+ var inner bytes.Buffer
+ for i, vi := range v.inner {
+ if len(v.inner) > 1 {
+ fmt.Fprintf(&inner, ",")
+ }
+ fmt.Fprintf(&inner, " ")
+ if i == len(v.inner)-1 {
+ fmt.Fprintf(&inner, "or ")
+ }
+ fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
+ }
+ warnf("invalid offset %s; expected %s+%d(FP)%s", expr, v.name, v.off, inner.String())
+ return
+ }
+ if kind != 0 && kind != vk {
+ var inner bytes.Buffer
+ if len(v.inner) > 0 {
+ fmt.Fprintf(&inner, " containing")
+ for i, vi := range v.inner {
+ if i > 0 && len(v.inner) > 2 {
+ fmt.Fprintf(&inner, ",")
+ }
+ fmt.Fprintf(&inner, " ")
+ if i > 0 && i == len(v.inner)-1 {
+ fmt.Fprintf(&inner, "and ")
+ }
+ fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
+ }
+ }
+ warnf("invalid %s of %s; %s is %d-byte value%s", op, expr, vt, vk, inner.String())
+ }
+}
diff --git a/src/cmd/vet/assign.go b/src/cmd/vet/assign.go
new file mode 100644
index 000000000..a11f0f875
--- /dev/null
+++ b/src/cmd/vet/assign.go
@@ -0,0 +1,44 @@
+// Copyright 2013 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.
+
+/*
+This file contains the code to check for useless assignments.
+*/
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+ "reflect"
+)
+
+// TODO: should also check for assignments to struct fields inside methods
+// that are on T instead of *T.
+
+// checkAssignStmt checks for assignments of the form "<expr> = <expr>".
+// These are almost always useless, and even when they aren't they are usually a mistake.
+func (f *File) checkAssignStmt(stmt *ast.AssignStmt) {
+ if !vet("assign") {
+ return
+ }
+ if stmt.Tok != token.ASSIGN {
+ return // ignore :=
+ }
+ if len(stmt.Lhs) != len(stmt.Rhs) {
+ // If LHS and RHS have different cardinality, they can't be the same.
+ return
+ }
+ for i, lhs := range stmt.Lhs {
+ rhs := stmt.Rhs[i]
+ if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
+ continue // short-circuit the heavy-weight gofmt check
+ }
+ le := f.gofmt(lhs)
+ re := f.gofmt(rhs)
+ if le == re {
+ f.Warnf(stmt.Pos(), "self-assignment of %s to %s", re, le)
+ }
+ }
+}
diff --git a/src/cmd/vet/buildtag.go b/src/cmd/vet/buildtag.go
index 4b7580457..0ab13cb8a 100644
--- a/src/cmd/vet/buildtag.go
+++ b/src/cmd/vet/buildtag.go
@@ -72,7 +72,7 @@ func checkBuildTag(name string, data []byte) {
elem = elem[1:]
}
for _, c := range elem {
- if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' {
+ if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
fmt.Fprintf(os.Stderr, "%s:%d: invalid non-alphanumeric build constraint: %s\n", name, i+1, arg)
setExit(1)
break Args
diff --git a/src/cmd/vet/deadcode.go b/src/cmd/vet/deadcode.go
new file mode 100644
index 000000000..f90fc14a4
--- /dev/null
+++ b/src/cmd/vet/deadcode.go
@@ -0,0 +1,280 @@
+// Copyright 2013 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.
+
+// Check for syntactically unreachable code.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+type deadState struct {
+ f *File
+ hasBreak map[ast.Stmt]bool
+ hasGoto map[string]bool
+ labels map[string]ast.Stmt
+ breakTarget ast.Stmt
+
+ reachable bool
+}
+
+// checkUnreachable checks a function body for dead code.
+func (f *File) checkUnreachable(body *ast.BlockStmt) {
+ if !vet("unreachable") || body == nil {
+ return
+ }
+
+ d := &deadState{
+ f: f,
+ hasBreak: make(map[ast.Stmt]bool),
+ hasGoto: make(map[string]bool),
+ labels: make(map[string]ast.Stmt),
+ }
+
+ d.findLabels(body)
+
+ d.reachable = true
+ d.findDead(body)
+}
+
+// findLabels gathers information about the labels defined and used by stmt
+// and about which statements break, whether a label is involved or not.
+func (d *deadState) findLabels(stmt ast.Stmt) {
+ switch x := stmt.(type) {
+ default:
+ d.f.Warnf(x.Pos(), "internal error in findLabels: unexpected statement %T", x)
+
+ case *ast.AssignStmt,
+ *ast.BadStmt,
+ *ast.DeclStmt,
+ *ast.DeferStmt,
+ *ast.EmptyStmt,
+ *ast.ExprStmt,
+ *ast.GoStmt,
+ *ast.IncDecStmt,
+ *ast.ReturnStmt,
+ *ast.SendStmt:
+ // no statements inside
+
+ case *ast.BlockStmt:
+ for _, stmt := range x.List {
+ d.findLabels(stmt)
+ }
+
+ case *ast.BranchStmt:
+ switch x.Tok {
+ case token.GOTO:
+ d.hasGoto[x.Label.Name] = true
+
+ case token.BREAK:
+ stmt := d.breakTarget
+ if x.Label != nil {
+ stmt = d.labels[x.Label.Name]
+ }
+ if stmt != nil {
+ d.hasBreak[stmt] = true
+ }
+ }
+
+ case *ast.IfStmt:
+ d.findLabels(x.Body)
+ if x.Else != nil {
+ d.findLabels(x.Else)
+ }
+
+ case *ast.LabeledStmt:
+ d.labels[x.Label.Name] = x.Stmt
+ d.findLabels(x.Stmt)
+
+ // These cases are all the same, but the x.Body only works
+ // when the specific type of x is known, so the cases cannot
+ // be merged.
+ case *ast.ForStmt:
+ outer := d.breakTarget
+ d.breakTarget = x
+ d.findLabels(x.Body)
+ d.breakTarget = outer
+
+ case *ast.RangeStmt:
+ outer := d.breakTarget
+ d.breakTarget = x
+ d.findLabels(x.Body)
+ d.breakTarget = outer
+
+ case *ast.SelectStmt:
+ outer := d.breakTarget
+ d.breakTarget = x
+ d.findLabels(x.Body)
+ d.breakTarget = outer
+
+ case *ast.SwitchStmt:
+ outer := d.breakTarget
+ d.breakTarget = x
+ d.findLabels(x.Body)
+ d.breakTarget = outer
+
+ case *ast.TypeSwitchStmt:
+ outer := d.breakTarget
+ d.breakTarget = x
+ d.findLabels(x.Body)
+ d.breakTarget = outer
+
+ case *ast.CommClause:
+ for _, stmt := range x.Body {
+ d.findLabels(stmt)
+ }
+
+ case *ast.CaseClause:
+ for _, stmt := range x.Body {
+ d.findLabels(stmt)
+ }
+ }
+}
+
+// findDead walks the statement looking for dead code.
+// If d.reachable is false on entry, stmt itself is dead.
+// When findDead returns, d.reachable tells whether the
+// statement following stmt is reachable.
+func (d *deadState) findDead(stmt ast.Stmt) {
+ // Is this a labeled goto target?
+ // If so, assume it is reachable due to the goto.
+ // This is slightly conservative, in that we don't
+ // check that the goto is reachable, so
+ // L: goto L
+ // will not provoke a warning.
+ // But it's good enough.
+ if x, isLabel := stmt.(*ast.LabeledStmt); isLabel && d.hasGoto[x.Label.Name] {
+ d.reachable = true
+ }
+
+ if !d.reachable {
+ switch stmt.(type) {
+ case *ast.EmptyStmt:
+ // do not warn about unreachable empty statements
+ default:
+ d.f.Warnf(stmt.Pos(), "unreachable code")
+ d.reachable = true // silence error about next statement
+ }
+ }
+
+ switch x := stmt.(type) {
+ default:
+ d.f.Warnf(x.Pos(), "internal error in findDead: unexpected statement %T", x)
+
+ case *ast.AssignStmt,
+ *ast.BadStmt,
+ *ast.DeclStmt,
+ *ast.DeferStmt,
+ *ast.EmptyStmt,
+ *ast.GoStmt,
+ *ast.IncDecStmt,
+ *ast.SendStmt:
+ // no control flow
+
+ case *ast.BlockStmt:
+ for _, stmt := range x.List {
+ d.findDead(stmt)
+ }
+
+ case *ast.BranchStmt:
+ switch x.Tok {
+ case token.BREAK, token.GOTO, token.FALLTHROUGH:
+ d.reachable = false
+ case token.CONTINUE:
+ // NOTE: We accept "continue" statements as terminating.
+ // They are not necessary in the spec definition of terminating,
+ // because a continue statement cannot be the final statement
+ // before a return. But for the more general problem of syntactically
+ // identifying dead code, continue redirects control flow just
+ // like the other terminating statements.
+ d.reachable = false
+ }
+
+ case *ast.ExprStmt:
+ // Call to panic?
+ call, ok := x.X.(*ast.CallExpr)
+ if ok {
+ name, ok := call.Fun.(*ast.Ident)
+ if ok && name.Name == "panic" && name.Obj == nil {
+ d.reachable = false
+ }
+ }
+
+ case *ast.ForStmt:
+ d.findDead(x.Body)
+ d.reachable = x.Cond != nil || d.hasBreak[x]
+
+ case *ast.IfStmt:
+ d.findDead(x.Body)
+ if x.Else != nil {
+ r := d.reachable
+ d.reachable = true
+ d.findDead(x.Else)
+ d.reachable = d.reachable || r
+ } else {
+ // might not have executed if statement
+ d.reachable = true
+ }
+
+ case *ast.LabeledStmt:
+ d.findDead(x.Stmt)
+
+ case *ast.RangeStmt:
+ d.findDead(x.Body)
+ d.reachable = true
+
+ case *ast.ReturnStmt:
+ d.reachable = false
+
+ case *ast.SelectStmt:
+ // NOTE: Unlike switch and type switch below, we don't care
+ // whether a select has a default, because a select without a
+ // default blocks until one of the cases can run. That's different
+ // from a switch without a default, which behaves like it has
+ // a default with an empty body.
+ anyReachable := false
+ for _, comm := range x.Body.List {
+ d.reachable = true
+ for _, stmt := range comm.(*ast.CommClause).Body {
+ d.findDead(stmt)
+ }
+ anyReachable = anyReachable || d.reachable
+ }
+ d.reachable = anyReachable || d.hasBreak[x]
+
+ case *ast.SwitchStmt:
+ anyReachable := false
+ hasDefault := false
+ for _, cas := range x.Body.List {
+ cc := cas.(*ast.CaseClause)
+ if cc.List == nil {
+ hasDefault = true
+ }
+ d.reachable = true
+ for _, stmt := range cc.Body {
+ d.findDead(stmt)
+ }
+ anyReachable = anyReachable || d.reachable
+ }
+ d.reachable = anyReachable || d.hasBreak[x] || !hasDefault
+
+ case *ast.TypeSwitchStmt:
+ anyReachable := false
+ hasDefault := false
+ for _, cas := range x.Body.List {
+ cc := cas.(*ast.CaseClause)
+ if cc.List == nil {
+ hasDefault = true
+ }
+ d.reachable = true
+ for _, stmt := range cc.Body {
+ d.findDead(stmt)
+ }
+ anyReachable = anyReachable || d.reachable
+ }
+ d.reachable = anyReachable || d.hasBreak[x] || !hasDefault
+ }
+}
diff --git a/src/cmd/vet/doc.go b/src/cmd/vet/doc.go
index f164eaca2..eb1e436f0 100644
--- a/src/cmd/vet/doc.go
+++ b/src/cmd/vet/doc.go
@@ -9,6 +9,12 @@ calls whose arguments do not align with the format string. Vet uses heuristics
that do not guarantee all reports are genuine problems, but it can find errors
not caught by the compilers.
+Its exit code is 2 for erroneous invocation of the tool, 1 if a
+problem was reported, and 0 otherwise. Note that the tool does not
+check every possible problem and depends on unreliable heuristics
+so it should be used as guidance only, not as a firm indicator of
+program correctness.
+
By default all checks are performed, but if explicit flags are provided, only
those identified by the flags are performed.
diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go
index 20f6cca1a..2fefa0b47 100644
--- a/src/cmd/vet/main.go
+++ b/src/cmd/vet/main.go
@@ -15,7 +15,6 @@ import (
"go/parser"
"go/printer"
"go/token"
- "go/types"
"io/ioutil"
"os"
"path/filepath"
@@ -29,14 +28,17 @@ var exitCode = 0
// Flags to control which checks to perform. "all" is set to true here, and disabled later if
// a flag is set explicitly.
var report = map[string]*bool{
- "all": flag.Bool("all", true, "check everything; disabled if any explicit check is requested"),
- "atomic": flag.Bool("atomic", false, "check for common mistaken usages of the sync/atomic package"),
- "buildtags": flag.Bool("buildtags", false, "check that +build tags are valid"),
- "composites": flag.Bool("composites", false, "check that composite literals used type-tagged elements"),
- "methods": flag.Bool("methods", false, "check that canonically named methods are canonically defined"),
- "printf": flag.Bool("printf", false, "check printf-like invocations"),
- "structtags": flag.Bool("structtags", false, "check that struct field tags have canonical format"),
- "rangeloops": flag.Bool("rangeloops", false, "check that range loop variables are used correctly"),
+ "all": flag.Bool("all", true, "check everything; disabled if any explicit check is requested"),
+ "asmdecl": flag.Bool("asmdecl", false, "check assembly against Go declarations"),
+ "assign": flag.Bool("assign", false, "check for useless assignments"),
+ "atomic": flag.Bool("atomic", false, "check for common mistaken usages of the sync/atomic package"),
+ "buildtags": flag.Bool("buildtags", false, "check that +build tags are valid"),
+ "composites": flag.Bool("composites", false, "check that composite literals used type-tagged elements"),
+ "methods": flag.Bool("methods", false, "check that canonically named methods are canonically defined"),
+ "printf": flag.Bool("printf", false, "check printf-like invocations"),
+ "rangeloops": flag.Bool("rangeloops", false, "check that range loop variables are used correctly"),
+ "structtags": flag.Bool("structtags", false, "check that struct field tags have canonical format"),
+ "unreachable": flag.Bool("unreachable", false, "check for unreachable code"),
}
// vet tells whether to report errors for the named check, a flag name.
@@ -64,11 +66,12 @@ func Usage() {
// File is a wrapper for the state of a file used in the parser.
// The parse tree walkers are all methods of this type.
type File struct {
- pkg *Package
- fset *token.FileSet
- name string
- file *ast.File
- b bytes.Buffer // for use by methods
+ pkg *Package
+ fset *token.FileSet
+ name string
+ content []byte
+ file *ast.File
+ b bytes.Buffer // for use by methods
}
func main() {
@@ -163,6 +166,7 @@ func doPackageDir(directory string) {
names = append(names, pkg.GoFiles...)
names = append(names, pkg.CgoFiles...)
names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
+ names = append(names, pkg.SFiles...)
prefixDirectory(directory, names)
doPackage(names)
// Is there also a "foo_test" package? If so, do that one as well.
@@ -174,8 +178,9 @@ func doPackageDir(directory string) {
}
type Package struct {
- types map[ast.Expr]types.Type
+ types map[ast.Expr]Type
values map[ast.Expr]interface{}
+ files []*File
}
// doPackage analyzes the single package constructed from the named files.
@@ -186,50 +191,48 @@ func doPackage(names []string) {
for _, name := range names {
f, err := os.Open(name)
if err != nil {
- errorf("%s: %s", name, err)
+ // Warn but continue to next package.
+ warnf("%s: %s", name, err)
+ return
}
defer f.Close()
data, err := ioutil.ReadAll(f)
if err != nil {
- errorf("%s: %s", name, err)
+ warnf("%s: %s", name, err)
+ return
}
checkBuildTag(name, data)
- parsedFile, err := parser.ParseFile(fs, name, bytes.NewReader(data), 0)
- if err != nil {
- errorf("%s: %s", name, err)
+ var parsedFile *ast.File
+ if strings.HasSuffix(name, ".go") {
+ parsedFile, err = parser.ParseFile(fs, name, bytes.NewReader(data), 0)
+ if err != nil {
+ warnf("%s: %s", name, err)
+ return
+ }
+ astFiles = append(astFiles, parsedFile)
}
- files = append(files, &File{fset: fs, name: name, file: parsedFile})
- astFiles = append(astFiles, parsedFile)
+ files = append(files, &File{fset: fs, content: data, name: name, file: parsedFile})
}
pkg := new(Package)
- pkg.types = make(map[ast.Expr]types.Type)
- pkg.values = make(map[ast.Expr]interface{})
- exprFn := func(x ast.Expr, typ types.Type, val interface{}) {
- pkg.types[x] = typ
- if val != nil {
- pkg.values[x] = val
- }
- }
- // By providing the Context with our own error function, it will continue
- // past the first error. There is no need for that function to do anything.
- context := types.Context{
- Expr: exprFn,
- Error: func(error) {},
- }
+ pkg.files = files
// Type check the package.
- _, err := context.Check(fs, astFiles)
+ err := pkg.check(fs, astFiles)
if err != nil && *verbose {
warnf("%s", err)
}
for _, file := range files {
file.pkg = pkg
- file.walkFile(file.name, file.file)
+ if file.file != nil {
+ file.walkFile(file.name, file.file)
+ }
}
+ asmCheck(pkg)
}
func visit(path string, f os.FileInfo, err error) error {
if err != nil {
- errorf("walk error: %s", err)
+ warnf("walk error: %s", err)
+ return err
}
// One package per directory. Ignore the files themselves.
if !f.IsDir() {
@@ -239,7 +242,16 @@ func visit(path string, f os.FileInfo, err error) error {
return nil
}
-// walkDir recursively walks the tree looking for .go files.
+func (pkg *Package) hasFileWithSuffix(suffix string) bool {
+ for _, f := range pkg.files {
+ if strings.HasSuffix(f.name, suffix) {
+ return true
+ }
+ }
+ return false
+}
+
+// walkDir recursively walks the tree looking for Go packages.
func walkDir(root string) {
filepath.Walk(root, visit)
}
@@ -287,6 +299,9 @@ func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
}
func (f *File) loc(pos token.Pos) string {
+ if pos == token.NoPos {
+ return ""
+ }
// Do not print columns. Because the pos often points to the start of an
// expression instead of the inner part with the actual error, the
// precision can mislead.
@@ -322,7 +337,9 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
case *ast.Field:
f.walkFieldTag(n)
case *ast.FuncDecl:
- f.walkMethodDecl(n)
+ f.walkFuncDecl(n)
+ case *ast.FuncLit:
+ f.walkFuncLit(n)
case *ast.InterfaceType:
f.walkInterfaceType(n)
case *ast.RangeStmt:
@@ -333,6 +350,7 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
// walkAssignStmt walks an assignment statement
func (f *File) walkAssignStmt(stmt *ast.AssignStmt) {
+ f.checkAssignStmt(stmt)
f.checkAtomicAssignment(stmt)
}
@@ -364,18 +382,22 @@ func (f *File) walkFieldTag(field *ast.Field) {
f.checkCanonicalFieldTag(field)
}
-// walkMethodDecl walks the method's signature.
+// walkMethod walks the method's signature.
func (f *File) walkMethod(id *ast.Ident, t *ast.FuncType) {
f.checkCanonicalMethod(id, t)
}
-// walkMethodDecl walks the method signature in the declaration.
-func (f *File) walkMethodDecl(d *ast.FuncDecl) {
- if d.Recv == nil {
- // not a method
- return
+// walkFuncDecl walks a function declaration.
+func (f *File) walkFuncDecl(d *ast.FuncDecl) {
+ f.checkUnreachable(d.Body)
+ if d.Recv != nil {
+ f.walkMethod(d.Name, d.Type)
}
- f.walkMethod(d.Name, d.Type)
+}
+
+// walkFuncLit walks a function literal.
+func (f *File) walkFuncLit(x *ast.FuncLit) {
+ f.checkUnreachable(x.Body)
}
// walkInterfaceType walks the method signatures of an interface.
diff --git a/src/cmd/vet/method.go b/src/cmd/vet/method.go
index bf982dc7a..8064235f4 100644
--- a/src/cmd/vet/method.go
+++ b/src/cmd/vet/method.go
@@ -93,7 +93,7 @@ func (f *File) checkCanonicalMethod(id *ast.Ident, t *ast.FuncType) {
actual = strings.TrimPrefix(actual, "func")
actual = id.Name + actual
- f.Warnf(id.Pos(), "method %s should have signature %s", actual, expectFmt)
+ f.Badf(id.Pos(), "method %s should have signature %s", actual, expectFmt)
}
}
diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go
index fb0fb9f9b..debfbf0bf 100644
--- a/src/cmd/vet/print.go
+++ b/src/cmd/vet/print.go
@@ -10,7 +10,6 @@ import (
"flag"
"go/ast"
"go/token"
- "go/types"
"strconv"
"strings"
"unicode/utf8"
@@ -302,59 +301,6 @@ func (f *File) checkPrintfArg(call *ast.CallExpr, verb rune, flags []byte, argNu
f.Badf(call.Pos(), "unrecognized printf verb %q", verb)
}
-func (f *File) matchArgType(t printfArgType, arg ast.Expr) bool {
- // TODO: for now, we can only test builtin types and untyped constants.
- typ := f.pkg.types[arg]
- if typ == nil {
- return true
- }
- basic, ok := typ.(*types.Basic)
- if !ok {
- return true
- }
- switch basic.Kind {
- case types.Bool:
- return t&argBool != 0
- case types.Int, types.Int8, types.Int16, types.Int32, types.Int64:
- fallthrough
- case types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.Uintptr:
- return t&argInt != 0
- case types.Float32, types.Float64, types.Complex64, types.Complex128:
- return t&argFloat != 0
- case types.String:
- return t&argString != 0
- case types.UnsafePointer:
- return t&(argPointer|argInt) != 0
- case types.UntypedBool:
- return t&argBool != 0
- case types.UntypedComplex:
- return t&argFloat != 0
- case types.UntypedFloat:
- // If it's integral, we can use an int format.
- switch f.pkg.values[arg].(type) {
- case int, int8, int16, int32, int64:
- return t&(argInt|argFloat) != 0
- case uint, uint8, uint16, uint32, uint64:
- return t&(argInt|argFloat) != 0
- }
- return t&argFloat != 0
- case types.UntypedInt:
- return t&argInt != 0
- case types.UntypedRune:
- return t&(argInt|argRune) != 0
- case types.UntypedString:
- return t&argString != 0
- case types.UntypedNil:
- return t&argPointer != 0 // TODO?
- case types.Invalid:
- if *verbose {
- f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", arg)
- }
- return true // Probably a type check problem.
- }
- return false
-}
-
// checkPrint checks a call to an unformatted print routine such as Println.
// call.Args[firstArg] is the first argument to be printed.
func (f *File) checkPrint(call *ast.CallExpr, name string, firstArg int) {
@@ -366,7 +312,7 @@ func (f *File) checkPrint(call *ast.CallExpr, name string, firstArg int) {
if sel, ok := args[0].(*ast.SelectorExpr); ok {
if x, ok := sel.X.(*ast.Ident); ok {
if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
- f.Warnf(call.Pos(), "first argument to %s is %s.%s", name, x.Name, sel.Sel.Name)
+ f.Badf(call.Pos(), "first argument to %s is %s.%s", name, x.Name, sel.Sel.Name)
}
}
}
@@ -403,64 +349,3 @@ func (f *File) checkPrint(call *ast.CallExpr, name string, firstArg int) {
}
}
}
-
-// numArgsInSignature tells how many formal arguments the function type
-// being called has.
-func (f *File) numArgsInSignature(call *ast.CallExpr) int {
- // Check the type of the function or method declaration
- typ := f.pkg.types[call.Fun]
- if typ == nil {
- return 0
- }
- // The type must be a signature, but be sure for safety.
- sig, ok := typ.(*types.Signature)
- if !ok {
- return 0
- }
- return len(sig.Params)
-}
-
-// isErrorMethodCall reports whether the call is of a method with signature
-// func Error() string
-// where "string" is the universe's string type. We know the method is called "Error".
-func (f *File) isErrorMethodCall(call *ast.CallExpr) bool {
- // Is it a selector expression? Otherwise it's a function call, not a method call.
- sel, ok := call.Fun.(*ast.SelectorExpr)
- if !ok {
- return false
- }
- // The package is type-checked, so if there are no arguments, we're done.
- if len(call.Args) > 0 {
- return false
- }
- // Check the type of the method declaration
- typ := f.pkg.types[sel]
- if typ == nil {
- return false
- }
- // The type must be a signature, but be sure for safety.
- sig, ok := typ.(*types.Signature)
- if !ok {
- return false
- }
- // There must be a receiver for it to be a method call. Otherwise it is
- // a function, not something that satisfies the error interface.
- if sig.Recv == nil {
- return false
- }
- // There must be no arguments. Already verified by type checking, but be thorough.
- if len(sig.Params) > 0 {
- return false
- }
- // Finally the real questions.
- // There must be one result.
- if len(sig.Results) != 1 {
- return false
- }
- // It must have return type "string" from the universe.
- result := sig.Results[0].Type
- if types.IsIdentical(result, types.Typ[types.String]) {
- return true
- }
- return false
-}
diff --git a/src/cmd/vet/structtag.go b/src/cmd/vet/structtag.go
index 545e420c1..d83578836 100644
--- a/src/cmd/vet/structtag.go
+++ b/src/cmd/vet/structtag.go
@@ -23,7 +23,7 @@ func (f *File) checkCanonicalFieldTag(field *ast.Field) {
tag, err := strconv.Unquote(field.Tag.Value)
if err != nil {
- f.Warnf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
+ f.Badf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
return
}
@@ -31,7 +31,7 @@ func (f *File) checkCanonicalFieldTag(field *ast.Field) {
// new key:value to end and checking that
// the tag parsing code can find it.
if reflect.StructTag(tag+` _gofix:"_magic"`).Get("_gofix") != "_magic" {
- f.Warnf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get", field.Tag.Value)
+ f.Badf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get", field.Tag.Value)
return
}
}
diff --git a/src/cmd/vet/taglit.go b/src/cmd/vet/taglit.go
index 0324e37b0..bcad2fe0a 100644
--- a/src/cmd/vet/taglit.go
+++ b/src/cmd/vet/taglit.go
@@ -9,32 +9,52 @@ package main
import (
"flag"
"go/ast"
- "go/types"
"strings"
)
var compositeWhiteList = flag.Bool("compositewhitelist", true, "use composite white list; for testing only")
-// checkUntaggedLiteral checks if a composite literal is an struct literal with
+// checkUntaggedLiteral checks if a composite literal is a struct literal with
// untagged fields.
func (f *File) checkUntaggedLiteral(c *ast.CompositeLit) {
if !vet("composites") {
return
}
- // Check that the CompositeLit's type is a slice or array (which needs no tag), if possible.
- typ := f.pkg.types[c]
- if typ != nil {
- // If it's a named type, pull out the underlying type.
- if namedType, ok := typ.(*types.NamedType); ok {
- typ = namedType.Underlying
- }
- switch typ.(type) {
- case *types.Slice:
- return
- case *types.Array:
- return
+ typ := c.Type
+ for {
+ if typ1, ok := c.Type.(*ast.ParenExpr); ok {
+ typ = typ1
+ continue
}
+ break
+ }
+
+ switch typ.(type) {
+ case *ast.ArrayType:
+ return
+ case *ast.MapType:
+ return
+ case *ast.StructType:
+ return // a literal struct type does not need to use tags
+ case *ast.Ident:
+ // A simple type name like t or T does not need tags either,
+ // since it is almost certainly declared in the current package.
+ // (The exception is names being used via import . "pkg", but
+ // those are already breaking the Go 1 compatibility promise,
+ // so not reporting potential additional breakage seems okay.)
+ return
+ }
+
+ // Otherwise the type is a selector like pkg.Name.
+ // We only care if pkg.Name is a struct, not if it's a map, array, or slice.
+ isStruct, typeString := f.pkg.isStruct(c)
+ if !isStruct {
+ return
+ }
+
+ if typeString == "" { // isStruct doesn't know
+ typeString = f.gofmt(typ)
}
// It's a struct, or we can't tell it's not a struct because we don't have types.
@@ -64,7 +84,7 @@ func (f *File) checkUntaggedLiteral(c *ast.CompositeLit) {
// Convert the package name to an import path, and compare to a whitelist.
path := pkgPath(f, pkg.Name)
if path == "" {
- f.Warnf(c.Pos(), "unresolvable package for %s.%s literal", pkg.Name, s.Sel.Name)
+ f.Badf(c.Pos(), "unresolvable package for %s.%s literal", pkg.Name, s.Sel.Name)
return
}
typeName := path + "." + s.Sel.Name
@@ -72,7 +92,7 @@ func (f *File) checkUntaggedLiteral(c *ast.CompositeLit) {
return
}
- f.Warnf(c.Pos(), "%s composite literal uses untagged fields", typ)
+ f.Warn(c.Pos(), typeString+" composite literal uses untagged fields")
}
// pkgPath returns the import path "image/png" for the package name "png".
@@ -119,8 +139,6 @@ var untaggedLiteralWhitelist = map[string]bool{
"encoding/xml.CharData": true,
"encoding/xml.Comment": true,
"encoding/xml.Directive": true,
- "exp/norm.Decomposition": true,
- "exp/types.ObjList": true,
"go/scanner.ErrorList": true,
"image/color.Palette": true,
"net.HardwareAddr": true,
diff --git a/src/cmd/vet/test_asm.go b/src/cmd/vet/test_asm.go
new file mode 100644
index 000000000..098bdd15c
--- /dev/null
+++ b/src/cmd/vet/test_asm.go
@@ -0,0 +1,24 @@
+// 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.
+
+// +build ignore
+
+// This file contains declarations to test the assembly in test_asm.s.
+
+package main
+
+func arg1(x int8, y uint8)
+func arg2(x int16, y uint16)
+func arg4(x int32, y uint32)
+func arg8(x int64, y uint64)
+func argint(x int, y uint)
+func argptr(x *byte, y *byte, c chan int, m map[int]int, f func())
+func argstring(x, y string)
+func argslice(x, y []string)
+func argiface(x interface{}, y interface {
+ m()
+})
+func returnint() int
+func returnbyte(x int) byte
+func returnnamed(x byte) (r1 int, r2 int16, r3 string, r4 byte)
diff --git a/src/cmd/vet/test_asm1.s b/src/cmd/vet/test_asm1.s
new file mode 100644
index 000000000..8cd9eeab6
--- /dev/null
+++ b/src/cmd/vet/test_asm1.s
@@ -0,0 +1,247 @@
+// Copyright 2013 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.
+
+// +build amd64
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+ MOVB x+0(FP), AX
+ MOVB y+1(FP), BX
+ MOVW x+0(FP), AX // ERROR "\[amd64\] invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+ MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
+ MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
+ MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
+ MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ TESTB x+0(FP), AX
+ TESTB y+1(FP), BX
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
+ TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
+ TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
+ TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
+ TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ RET
+
+TEXT ·arg2(SB),0,$0-4
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
+ MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+ MOVW x+0(FP), AX
+ MOVW y+2(FP), BX
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
+ MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
+ MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
+ MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
+ TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
+ TESTW x+0(FP), AX
+ TESTW y+2(FP), BX
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
+ TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
+ TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
+ TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
+ MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVL y+4(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
+ MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
+ MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
+ TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
+ TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
+ TESTL x+0(FP), AX
+ TESTL y+4(FP), AX
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
+ TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
+ TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value"
+ MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
+ TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
+ TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value"
+ TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value"
+ TESTQ x+0(FP), AX
+ TESTQ y+8(FP), AX
+ TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int is 8-byte value"
+ MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 8-byte value"
+ TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint is 8-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 8-byte value"
+ TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint is 8-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int is 8-byte value"
+ TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint is 8-byte value"
+ TESTQ x+0(FP), AX
+ TESTQ y+8(FP), AX
+ TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); \*byte is 8-byte value"
+ MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); \*byte is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 8-byte value"
+ TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); \*byte is 8-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 8-byte value"
+ TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); \*byte is 8-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); \*byte is 8-byte value"
+ TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); \*byte is 8-byte value"
+ TESTQ x+0(FP), AX
+ TESTQ y+8(FP), AX
+ TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ MOVL c+16(FP), AX // ERROR "invalid MOVL of c\+16\(FP\); chan int is 8-byte value"
+ MOVL m+24(FP), AX // ERROR "invalid MOVL of m\+24\(FP\); map\[int\]int is 8-byte value"
+ MOVL f+32(FP), AX // ERROR "invalid MOVL of f\+32\(FP\); func\(\) is 8-byte value"
+ RET
+
+TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); string base is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
+ MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); string base is 8-byte value"
+ MOVQ x_base+0(FP), AX
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
+ MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); string len is 8-byte value"
+ MOVQ x_len+8(FP), AX
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
+ MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
+ RET
+
+TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); slice base is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
+ MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); slice base is 8-byte value"
+ MOVQ x_base+0(FP), AX
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
+ MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); slice len is 8-byte value"
+ MOVQ x_len+8(FP), AX
+ MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVW x_cap+16(FP), AX // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
+ MOVL x_cap+16(FP), AX // ERROR "invalid MOVL of x_cap\+16\(FP\); slice cap is 8-byte value"
+ MOVQ x_cap+16(FP), AX
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
+ MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
+ MOVQ y_cap+16(FP), AX // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
+ RET
+
+TEXT ·argiface(SB),0,$0-32
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); interface type is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
+ MOVL x_type+0(FP), AX // ERROR "invalid MOVL of x_type\+0\(FP\); interface type is 8-byte value"
+ MOVQ x_type+0(FP), AX
+ MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+ MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+ MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVW x_data+8(FP), AX // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
+ MOVL x_data+8(FP), AX // ERROR "invalid MOVL of x_data\+8\(FP\); interface data is 8-byte value"
+ MOVQ x_data+8(FP), AX
+ MOVW y+16(FP), AX // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
+ MOVL y+16(FP), AX // ERROR "invalid MOVL of y\+16\(FP\); interface itable is 8-byte value"
+ MOVQ y+16(FP), AX
+ MOVW y_itable+16(FP), AX // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
+ MOVL y_itable+16(FP), AX // ERROR "invalid MOVL of y_itable\+16\(FP\); interface itable is 8-byte value"
+ MOVQ y_itable+16(FP), AX
+ MOVQ y_type+16(FP), AX // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
+ MOVW y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVL y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVQ y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVW y_data+24(FP), AX // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
+ MOVL y_data+24(FP), AX // ERROR "invalid MOVL of y_data\+24\(FP\); interface data is 8-byte value"
+ MOVQ y_data+24(FP), AX
+ RET
+
+TEXT ·returnint(SB),0,$0-8
+ MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
+ MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
+ MOVL AX, ret+0(FP) // ERROR "invalid MOVL of ret\+0\(FP\); int is 8-byte value"
+ MOVQ AX, ret+0(FP)
+ MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+ MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+ RET
+
+TEXT ·returnbyte(SB),0,$0-9
+ MOVQ x+0(FP), AX
+ MOVB AX, ret+8(FP)
+ MOVW AX, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
+ MOVL AX, ret+8(FP) // ERROR "invalid MOVL of ret\+8\(FP\); byte is 1-byte value"
+ MOVQ AX, ret+8(FP) // ERROR "invalid MOVQ of ret\+8\(FP\); byte is 1-byte value"
+ MOVB AX, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
+ RET
+
+TEXT ·returnnamed(SB),0,$0-41
+ MOVB x+0(FP), AX
+ MOVQ AX, r1+8(FP)
+ MOVW AX, r2+16(FP)
+ MOVQ AX, r3+24(FP)
+ MOVQ AX, r3_base+24(FP)
+ MOVQ AX, r3_len+32(FP)
+ MOVB AX, r4+40(FP)
+ MOVL AX, r1+8(FP) // ERROR "invalid MOVL of r1\+8\(FP\); int is 8-byte value"
+ RET
diff --git a/src/cmd/vet/test_asm2.s b/src/cmd/vet/test_asm2.s
new file mode 100644
index 000000000..d8679c574
--- /dev/null
+++ b/src/cmd/vet/test_asm2.s
@@ -0,0 +1,251 @@
+// Copyright 2013 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.
+
+// +build 386
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+ MOVB x+0(FP), AX
+ MOVB y+1(FP), BX
+ MOVW x+0(FP), AX // ERROR "\[386\] invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+ MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
+ MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
+ MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
+ MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ TESTB x+0(FP), AX
+ TESTB y+1(FP), BX
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
+ TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
+ TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
+ TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
+ TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ RET
+
+TEXT ·arg2(SB),0,$0-4
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
+ MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+ MOVW x+0(FP), AX
+ MOVW y+2(FP), BX
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
+ MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
+ MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
+ MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
+ TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
+ TESTW x+0(FP), AX
+ TESTW y+2(FP), BX
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
+ TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
+ TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
+ TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
+ MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVL y+4(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
+ MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
+ MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
+ TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
+ TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
+ TESTL x+0(FP), AX
+ TESTL y+4(FP), AX
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
+ TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
+ TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
+ MOVL x_lo+0(FP), AX
+ MOVL x_hi+4(FP), AX
+ MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
+ MOVL y_lo+8(FP), AX
+ MOVL y_hi+12(FP), AX
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
+ TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
+ TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
+ TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
+ TESTQ x+0(FP), AX
+ TESTQ y+8(FP), AX
+ TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 4-byte value"
+ MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVL y+4(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int is 4-byte value"
+ MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint is 4-byte value"
+ MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 4-byte value"
+ TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint is 4-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 4-byte value"
+ TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint is 4-byte value"
+ TESTL x+0(FP), AX
+ TESTL y+4(FP), AX
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int is 4-byte value"
+ TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint is 4-byte value"
+ TESTQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 4-byte value"
+ MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); \*byte is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVL y+4(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); \*byte is 4-byte value"
+ MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); \*byte is 4-byte value"
+ MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 4-byte value"
+ TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); \*byte is 4-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 4-byte value"
+ TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); \*byte is 4-byte value"
+ TESTL x+0(FP), AX
+ TESTL y+4(FP), AX
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); \*byte is 4-byte value"
+ TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); \*byte is 4-byte value"
+ TESTQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ MOVW c+8(FP), AX // ERROR "invalid MOVW of c\+8\(FP\); chan int is 4-byte value"
+ MOVW m+12(FP), AX // ERROR "invalid MOVW of m\+12\(FP\); map\[int\]int is 4-byte value"
+ MOVW f+16(FP), AX // ERROR "invalid MOVW of f\+16\(FP\); func\(\) is 4-byte value"
+ RET
+
+TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); string base is 4-byte value"
+ MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 4-byte value"
+ MOVL x_base+0(FP), AX
+ MOVQ x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); string base is 4-byte value"
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVW x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); string len is 4-byte value"
+ MOVL x_len+4(FP), AX
+ MOVQ x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); string len is 4-byte value"
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
+ MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
+ RET
+
+TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); slice base is 4-byte value"
+ MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 4-byte value"
+ MOVL x_base+0(FP), AX
+ MOVQ x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); slice base is 4-byte value"
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVW x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); slice len is 4-byte value"
+ MOVL x_len+4(FP), AX
+ MOVQ x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); slice len is 4-byte value"
+ MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVW x_cap+8(FP), AX // ERROR "invalid MOVW of x_cap\+8\(FP\); slice cap is 4-byte value"
+ MOVL x_cap+8(FP), AX
+ MOVQ x_cap+8(FP), AX // ERROR "invalid MOVQ of x_cap\+8\(FP\); slice cap is 4-byte value"
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
+ MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
+ MOVQ y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
+ RET
+
+TEXT ·argiface(SB),0,$0-16
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); interface type is 4-byte value"
+ MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 4-byte value"
+ MOVL x_type+0(FP), AX
+ MOVQ x_type+0(FP), AX // ERROR "invalid MOVQ of x_type\+0\(FP\); interface type is 4-byte value"
+ MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+ MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+ MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVW x_data+4(FP), AX // ERROR "invalid MOVW of x_data\+4\(FP\); interface data is 4-byte value"
+ MOVL x_data+4(FP), AX
+ MOVQ x_data+4(FP), AX // ERROR "invalid MOVQ of x_data\+4\(FP\); interface data is 4-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); interface itable is 4-byte value"
+ MOVL y+8(FP), AX
+ MOVQ y+8(FP), AX // ERROR "invalid MOVQ of y\+8\(FP\); interface itable is 4-byte value"
+ MOVW y_itable+8(FP), AX // ERROR "invalid MOVW of y_itable\+8\(FP\); interface itable is 4-byte value"
+ MOVL y_itable+8(FP), AX
+ MOVQ y_itable+8(FP), AX // ERROR "invalid MOVQ of y_itable\+8\(FP\); interface itable is 4-byte value"
+ MOVQ y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
+ MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVL y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVQ y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVW y_data+12(FP), AX // ERROR "invalid MOVW of y_data\+12\(FP\); interface data is 4-byte value"
+ MOVL y_data+12(FP), AX
+ MOVQ y_data+12(FP), AX // ERROR "invalid MOVQ of y_data\+12\(FP\); interface data is 4-byte value"
+ RET
+
+TEXT ·returnint(SB),0,$0-4
+ MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value"
+ MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 4-byte value"
+ MOVL AX, ret+0(FP)
+ MOVQ AX, ret+0(FP) // ERROR "invalid MOVQ of ret\+0\(FP\); int is 4-byte value"
+ MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+ MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+ RET
+
+TEXT ·returnbyte(SB),0,$0-5
+ MOVL x+0(FP), AX
+ MOVB AX, ret+4(FP)
+ MOVW AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
+ MOVL AX, ret+4(FP) // ERROR "invalid MOVL of ret\+4\(FP\); byte is 1-byte value"
+ MOVQ AX, ret+4(FP) // ERROR "invalid MOVQ of ret\+4\(FP\); byte is 1-byte value"
+ MOVB AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
+ RET
+
+TEXT ·returnnamed(SB),0,$0-21
+ MOVB x+0(FP), AX
+ MOVL AX, r1+4(FP)
+ MOVW AX, r2+8(FP)
+ MOVL AX, r3+12(FP)
+ MOVL AX, r3_base+12(FP)
+ MOVL AX, r3_len+16(FP)
+ MOVB AX, r4+20(FP)
+ MOVQ AX, r1+4(FP) // ERROR "invalid MOVQ of r1\+4\(FP\); int is 4-byte value"
+ RET
diff --git a/src/cmd/vet/test_asm3.s b/src/cmd/vet/test_asm3.s
new file mode 100644
index 000000000..bf98805a2
--- /dev/null
+++ b/src/cmd/vet/test_asm3.s
@@ -0,0 +1,166 @@
+// Copyright 2013 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.
+
+// +build arm
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+ MOVB x+0(FP), AX
+ MOVB y+1(FP), BX
+ MOVH x+0(FP), AX // ERROR "\[arm\] invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
+ MOVH y+1(FP), AX // ERROR "invalid MOVH of y\+1\(FP\); uint8 is 1-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+ MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
+ MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ RET
+
+TEXT ·arg2(SB),0,$0-4
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
+ MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+ MOVH x+0(FP), AX
+ MOVH y+2(FP), BX
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int16 is 2-byte value"
+ MOVW y+2(FP), AX // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
+ MOVH x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ MOVH y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
+ MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVW y+4(FP), AX
+ MOVW x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVW y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
+ MOVH y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
+ MOVW x_lo+0(FP), AX
+ MOVW x_hi+4(FP), AX
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
+ MOVW y_lo+8(FP), AX
+ MOVW y_hi+12(FP), AX
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int is 4-byte value"
+ MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVW y+4(FP), AX
+ MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 4-byte value"
+ MOVH y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); \*byte is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVW y+4(FP), AX
+ MOVQ x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ MOVH c+8(FP), AX // ERROR "invalid MOVH of c\+8\(FP\); chan int is 4-byte value"
+ MOVH m+12(FP), AX // ERROR "invalid MOVH of m\+12\(FP\); map\[int\]int is 4-byte value"
+ MOVH f+16(FP), AX // ERROR "invalid MOVH of f\+16\(FP\); func\(\) is 4-byte value"
+ RET
+
+TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); string base is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVH x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 4-byte value"
+ MOVW x_base+0(FP), AX
+ MOVH x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVH x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); string len is 4-byte value"
+ MOVW x_len+4(FP), AX
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
+ MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
+ RET
+
+TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); slice base is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVH x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 4-byte value"
+ MOVW x_base+0(FP), AX
+ MOVH x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVH x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); slice len is 4-byte value"
+ MOVW x_len+4(FP), AX
+ MOVH x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVH x_cap+8(FP), AX // ERROR "invalid MOVH of x_cap\+8\(FP\); slice cap is 4-byte value"
+ MOVW x_cap+8(FP), AX
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
+ MOVQ y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
+ MOVQ y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
+ RET
+
+TEXT ·argiface(SB),0,$0-16
+ MOVH x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); interface type is 4-byte value"
+ MOVW x+0(FP), AX
+ MOVH x_type+0(FP), AX // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 4-byte value"
+ MOVW x_type+0(FP), AX
+ MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+ MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+ MOVH x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVH x_data+4(FP), AX // ERROR "invalid MOVH of x_data\+4\(FP\); interface data is 4-byte value"
+ MOVW x_data+4(FP), AX
+ MOVH y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); interface itable is 4-byte value"
+ MOVW y+8(FP), AX
+ MOVH y_itable+8(FP), AX // ERROR "invalid MOVH of y_itable\+8\(FP\); interface itable is 4-byte value"
+ MOVW y_itable+8(FP), AX
+ MOVQ y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
+ MOVH y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVQ y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVH y_data+12(FP), AX // ERROR "invalid MOVH of y_data\+12\(FP\); interface data is 4-byte value"
+ MOVW y_data+12(FP), AX
+ RET
+
+TEXT ·returnint(SB),0,$0-4
+ MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value"
+ MOVH AX, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 4-byte value"
+ MOVW AX, ret+0(FP)
+ MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+ MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+ RET
+
+TEXT ·returnbyte(SB),0,$0-5
+ MOVW x+0(FP), AX
+ MOVB AX, ret+4(FP)
+ MOVH AX, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value"
+ MOVW AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
+ MOVB AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
+ RET
+
+TEXT ·returnnamed(SB),0,$0-21
+ MOVB x+0(FP), AX
+ MOVW AX, r1+4(FP)
+ MOVH AX, r2+8(FP)
+ MOVW AX, r3+12(FP)
+ MOVW AX, r3_base+12(FP)
+ MOVW AX, r3_len+16(FP)
+ MOVB AX, r4+20(FP)
+ MOVB AX, r1+4(FP) // ERROR "invalid MOVB of r1\+4\(FP\); int is 4-byte value"
+ RET
diff --git a/src/cmd/vet/test_assign.go b/src/cmd/vet/test_assign.go
new file mode 100644
index 000000000..8e0f45e53
--- /dev/null
+++ b/src/cmd/vet/test_assign.go
@@ -0,0 +1,20 @@
+// Copyright 2013 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.
+
+// This file contains tests for the useless-assignment checker.
+
+// +build vet_test
+
+package main
+
+type ST struct {
+ x int
+}
+
+func (s *ST) SetX(x int) {
+ // Accidental self-assignment; it should be "s.x = x"
+ x = x // ERROR "self-assignment of x to x"
+ // Another mistake
+ s.x = s.x // ERROR "self-assignment of s.x to s.x"
+}
diff --git a/src/cmd/vet/buildtag_bad.go b/src/cmd/vet/test_buildtag_bad.go
index 4dca6a443..0a0a39bd1 100644
--- a/src/cmd/vet/buildtag_bad.go
+++ b/src/cmd/vet/test_buildtag_bad.go
@@ -8,4 +8,8 @@
// +build @#$ // ERROR "invalid non-alphanumeric build constraint"
// +build toolate // ERROR "build comment appears too late in file"
-package main
+package bad
+
+// This is package 'bad' rather than 'main' so the erroneous build
+// tag doesn't end up looking like a package doc for the vet command
+// when examined by godoc.
diff --git a/src/cmd/vet/test_deadcode.go b/src/cmd/vet/test_deadcode.go
new file mode 100644
index 000000000..d08e57782
--- /dev/null
+++ b/src/cmd/vet/test_deadcode.go
@@ -0,0 +1,2121 @@
+// Copyright 2013 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.
+
+// +build vet_test
+// +build ignore
+
+// This file contains tests for the dead code checker.
+
+package main
+
+type T int
+
+var x interface{}
+var c chan int
+
+func external() int // ok
+
+func _() int {
+}
+
+func _() int {
+ print(1)
+}
+
+func _() int {
+ print(1)
+ return 2
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ print(1)
+ goto L
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ panic(2)
+ println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+func _() int {
+ var panic = func(int) {}
+ print(1)
+ panic(2)
+ println() // ok
+}
+
+func _() int {
+ {
+ print(1)
+ return 2
+ println() // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ {
+ print(1)
+ return 2
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ {
+ print(1)
+ goto L
+ println() // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ {
+ print(1)
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ {
+ panic(2)
+ }
+}
+
+func _() int {
+ print(1)
+ {
+ panic(2)
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ {
+ panic(2)
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ return 2
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+L:
+ print(1)
+ goto L
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ {
+ print(1)
+ return 2
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+func _() int {
+L:
+ {
+ print(1)
+ goto L
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+func _() int {
+ print(1)
+ {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+func _() int {
+ {
+ print(1)
+ return 2
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+L:
+ {
+ print(1)
+ goto L
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ {
+ panic(2)
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ } else {
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x == 1 {
+ return 0
+ } else if x != 2 {
+ panic(3)
+ } else {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+// if-else chain missing final else is not okay, even if the
+// conditions cover every possible case.
+
+func _() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x != nil {
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x == 1 {
+ return 0
+ } else if x != 1 {
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ for {
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ for {
+ for {
+ break
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ for {
+ for {
+ break
+ println() // ERROR "unreachable code"
+ }
+ }
+}
+
+func _() int {
+ for {
+ for {
+ continue
+ println() // ERROR "unreachable code"
+ }
+ }
+}
+
+func _() int {
+ for {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ for {
+ break
+ }
+ println() // ok
+}
+
+func _() int {
+ for {
+ for {
+ }
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ for {
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ for x == nil {
+ }
+ println() // ok
+}
+
+func _() int {
+ for x == nil {
+ for {
+ break
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ for x == nil {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ for true {
+ }
+ println() // ok
+}
+
+func _() int {
+ for true {
+ for {
+ break
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ for true {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ select {}
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ for {
+ }
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ for {
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ case c <- 1:
+ print(2)
+ goto L
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ case c <- 1:
+ print(2)
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ default:
+ select {}
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ default:
+ select {}
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ goto L // ERROR "unreachable code"
+ case c <- 1:
+ print(2)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ default:
+ print(2)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ select {
+ default:
+ break
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ select {
+ case <-c:
+ print(2)
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ case c <- 1:
+ print(2)
+ break L
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ select {
+ case <-c:
+ print(1)
+ panic("abc")
+ default:
+ select {}
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ case 1:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch {
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ case 2:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 2:
+ return 4
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ case 2:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ break L // ERROR "unreachable code"
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ break // ERROR "unreachable code"
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ switch x {
+ case 1:
+ print(2)
+ for {
+ break L
+ }
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ case int:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ print(1)
+ switch {
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ case float64:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case float64:
+ return 4
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ case float64:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ break L // ERROR "unreachable code"
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ break // ERROR "unreachable code"
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+func _() int {
+ print(1)
+L:
+ switch x.(type) {
+ case int:
+ print(2)
+ for {
+ break L
+ }
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+// again, but without the leading print(1).
+// testing that everything works when the terminating statement is first.
+
+func _() int {
+ println() // ok
+}
+
+func _() int {
+ return 2
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ goto L
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ panic(2)
+ println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+func _() int {
+ var panic = func(int) {}
+ panic(2)
+ println() // ok
+}
+
+func _() int {
+ {
+ return 2
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ {
+ return 2
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+ {
+ goto L
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+L:
+ {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ {
+ panic(2)
+ println() // ERROR "unreachable code"
+ }
+}
+
+func _() int {
+ {
+ panic(2)
+ }
+ println() // ERROR "unreachable code"
+}
+
+func _() int {
+ return 2
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ goto L
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ {
+ return 2
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ {
+ goto L
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+func _() int {
+ {
+ return 2
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+L:
+ {
+ goto L
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+func _() int {
+ {
+ panic(2)
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+// again, with func literals
+
+var _ = func() int {
+}
+
+var _ = func() int {
+ print(1)
+}
+
+var _ = func() int {
+ print(1)
+ return 2
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ print(1)
+ goto L
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ panic(2)
+ println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+var _ = func() int {
+ var panic = func(int) {}
+ print(1)
+ panic(2)
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ print(1)
+ return 2
+ println() // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ print(1)
+ return 2
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ {
+ print(1)
+ goto L
+ println() // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ {
+ print(1)
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ {
+ panic(2)
+ }
+}
+
+var _ = func() int {
+ print(1)
+ {
+ panic(2)
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ {
+ panic(2)
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ return 2
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+L:
+ print(1)
+ goto L
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ {
+ print(1)
+ return 2
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+var _ = func() int {
+L:
+ {
+ print(1)
+ goto L
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+var _ = func() int {
+ print(1)
+ {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ }
+}
+
+var _ = func() int {
+ {
+ print(1)
+ return 2
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+L:
+ {
+ print(1)
+ goto L
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ {
+ panic(2)
+ }
+ { // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ } else {
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x == 1 {
+ return 0
+ } else if x != 2 {
+ panic(3)
+ } else {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+// if-else chain missing final else is not okay, even if the
+// conditions cover every possible case.
+
+var _ = func() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x != nil {
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ if x == nil {
+ panic(2)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ print(1)
+ if x == nil {
+ panic(2)
+ } else if x == 1 {
+ return 0
+ } else if x != 1 {
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ for {
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ for {
+ for {
+ break
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ for {
+ for {
+ break
+ println() // ERROR "unreachable code"
+ }
+ }
+}
+
+var _ = func() int {
+ for {
+ for {
+ continue
+ println() // ERROR "unreachable code"
+ }
+ }
+}
+
+var _ = func() int {
+ for {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ for {
+ break
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ for {
+ for {
+ }
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ for {
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ for x == nil {
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ for x == nil {
+ for {
+ break
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ for x == nil {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ for true {
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ for true {
+ for {
+ break
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ for true {
+ L:
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ select {}
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ for {
+ }
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ for {
+ }
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ case c <- 1:
+ print(2)
+ goto L
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ case c <- 1:
+ print(2)
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ println() // ERROR "unreachable code"
+ default:
+ select {}
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ default:
+ select {}
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ goto L // ERROR "unreachable code"
+ case c <- 1:
+ print(2)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ default:
+ print(2)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ default:
+ break
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ select {
+ case <-c:
+ print(2)
+ for {
+ break L
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ select {
+ case <-c:
+ print(2)
+ panic("abc")
+ case c <- 1:
+ print(2)
+ break L
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ select {
+ case <-c:
+ print(1)
+ panic("abc")
+ default:
+ select {}
+ break // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ case 1:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch {
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ case 2:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 2:
+ return 4
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ fallthrough
+ case 2:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ switch x {
+ case 1:
+ print(2)
+ panic(3)
+ break L // ERROR "unreachable code"
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x {
+ default:
+ return 4
+ break // ERROR "unreachable code"
+ case 1:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ switch x {
+ case 1:
+ print(2)
+ for {
+ break L
+ }
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ case int:
+ print(2)
+ panic(3)
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ default:
+ return 4
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ print(1)
+ switch {
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ case float64:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case float64:
+ return 4
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ fallthrough
+ case float64:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ switch x.(type) {
+ case int:
+ print(2)
+ panic(3)
+ break L // ERROR "unreachable code"
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+ switch x.(type) {
+ default:
+ return 4
+ break // ERROR "unreachable code"
+ case int:
+ print(2)
+ panic(3)
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ print(1)
+L:
+ switch x.(type) {
+ case int:
+ print(2)
+ for {
+ break L
+ }
+ default:
+ return 4
+ }
+ println() // ok
+}
+
+// again, but without the leading print(1).
+// testing that everything works when the terminating statement is first.
+
+var _ = func() int {
+ println() // ok
+}
+
+var _ = func() int {
+ return 2
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ goto L
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ panic(2)
+ println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+var _ = func() int {
+ var panic = func(int) {}
+ panic(2)
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ return 2
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ {
+ return 2
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+ {
+ goto L
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+L:
+ {
+ goto L
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ {
+ panic(2)
+ println() // ERROR "unreachable code"
+ }
+}
+
+var _ = func() int {
+ {
+ panic(2)
+ }
+ println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+ return 2
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ goto L
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ return 2
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ {
+ goto L
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ panic(2)
+ { // ERROR "unreachable code"
+ }
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ return 2
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+L:
+ {
+ goto L
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
+
+var _ = func() int {
+ {
+ panic(2)
+ }
+ { // ERROR "unreachable code"
+ }
+ println() // ok
+}
diff --git a/src/cmd/vet/test_taglit.go b/src/cmd/vet/test_taglit.go
index 0d83b18fd..f34062f18 100644
--- a/src/cmd/vet/test_taglit.go
+++ b/src/cmd/vet/test_taglit.go
@@ -15,6 +15,40 @@ import (
"go/scanner"
)
+var Okay1 = []string{
+ "Name",
+ "Usage",
+ "DefValue",
+}
+
+var Okay2 = map[string]bool{
+ "Name": true,
+ "Usage": true,
+ "DefValue": true,
+}
+
+var Okay3 = struct {
+ X string
+ Y string
+ Z string
+}{
+ "Name",
+ "Usage",
+ "DefValue",
+}
+
+type MyStruct struct {
+ X string
+ Y string
+ Z string
+}
+
+var Okay4 = MyStruct{
+ "Name",
+ "Usage",
+ "DefValue",
+}
+
// Testing is awkward because we need to reference things from a separate package
// to trigger the warnings.
diff --git a/src/cmd/vet/types.go b/src/cmd/vet/types.go
new file mode 100644
index 000000000..75f195b0f
--- /dev/null
+++ b/src/cmd/vet/types.go
@@ -0,0 +1,179 @@
+// 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.
+
+// +build gotypes
+
+// This file contains the pieces of the tool that require the go/types package.
+// To compile this file, you must first run
+// $ go get code.google.com/p/go.exp/go/types
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+
+ "code.google.com/p/go.exp/go/types"
+)
+
+// Type is equivalent to go/types.Type. Repeating it here allows us to avoid
+// depending on the go/types package.
+type Type interface {
+ String() string
+}
+
+func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
+ pkg.types = make(map[ast.Expr]Type)
+ pkg.values = make(map[ast.Expr]interface{})
+ exprFn := func(x ast.Expr, typ types.Type, val interface{}) {
+ pkg.types[x] = typ
+ if val != nil {
+ pkg.values[x] = val
+ }
+ }
+ // By providing the Context with our own error function, it will continue
+ // past the first error. There is no need for that function to do anything.
+ context := types.Context{
+ Expr: exprFn,
+ Error: func(error) {},
+ }
+ _, err := context.Check(fs, astFiles)
+ return err
+}
+
+// isStruct reports whether the composite literal c is a struct.
+// If it is not (probably a struct), it returns a printable form of the type.
+func (pkg *Package) isStruct(c *ast.CompositeLit) (bool, string) {
+ // Check that the CompositeLit's type is a slice or array (which needs no tag), if possible.
+ typ := pkg.types[c]
+ // If it's a named type, pull out the underlying type.
+ actual := typ
+ if namedType, ok := typ.(*types.NamedType); ok {
+ actual = namedType.Underlying
+ }
+ if actual == nil {
+ // No type information available. Assume true, so we do the check.
+ return true, ""
+ }
+ switch actual.(type) {
+ case *types.Struct:
+ return true, typ.String()
+ default:
+ return false, ""
+ }
+}
+
+func (f *File) matchArgType(t printfArgType, arg ast.Expr) bool {
+ // TODO: for now, we can only test builtin types and untyped constants.
+ typ := f.pkg.types[arg]
+ if typ == nil {
+ return true
+ }
+ basic, ok := typ.(*types.Basic)
+ if !ok {
+ return true
+ }
+ switch basic.Kind {
+ case types.Bool:
+ return t&argBool != 0
+ case types.Int, types.Int8, types.Int16, types.Int32, types.Int64:
+ fallthrough
+ case types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.Uintptr:
+ return t&argInt != 0
+ case types.Float32, types.Float64, types.Complex64, types.Complex128:
+ return t&argFloat != 0
+ case types.String:
+ return t&argString != 0
+ case types.UnsafePointer:
+ return t&(argPointer|argInt) != 0
+ case types.UntypedBool:
+ return t&argBool != 0
+ case types.UntypedComplex:
+ return t&argFloat != 0
+ case types.UntypedFloat:
+ // If it's integral, we can use an int format.
+ switch f.pkg.values[arg].(type) {
+ case int, int8, int16, int32, int64:
+ return t&(argInt|argFloat) != 0
+ case uint, uint8, uint16, uint32, uint64:
+ return t&(argInt|argFloat) != 0
+ }
+ return t&argFloat != 0
+ case types.UntypedInt:
+ return t&argInt != 0
+ case types.UntypedRune:
+ return t&(argInt|argRune) != 0
+ case types.UntypedString:
+ return t&argString != 0
+ case types.UntypedNil:
+ return t&argPointer != 0 // TODO?
+ case types.Invalid:
+ if *verbose {
+ f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", arg)
+ }
+ return true // Probably a type check problem.
+ }
+ return false
+}
+
+// numArgsInSignature tells how many formal arguments the function type
+// being called has.
+func (f *File) numArgsInSignature(call *ast.CallExpr) int {
+ // Check the type of the function or method declaration
+ typ := f.pkg.types[call.Fun]
+ if typ == nil {
+ return 0
+ }
+ // The type must be a signature, but be sure for safety.
+ sig, ok := typ.(*types.Signature)
+ if !ok {
+ return 0
+ }
+ return len(sig.Params)
+}
+
+// isErrorMethodCall reports whether the call is of a method with signature
+// func Error() string
+// where "string" is the universe's string type. We know the method is called "Error".
+func (f *File) isErrorMethodCall(call *ast.CallExpr) bool {
+ // Is it a selector expression? Otherwise it's a function call, not a method call.
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return false
+ }
+ // The package is type-checked, so if there are no arguments, we're done.
+ if len(call.Args) > 0 {
+ return false
+ }
+ // Check the type of the method declaration
+ typ := f.pkg.types[sel]
+ if typ == nil {
+ return false
+ }
+ // The type must be a signature, but be sure for safety.
+ sig, ok := typ.(*types.Signature)
+ if !ok {
+ return false
+ }
+ // There must be a receiver for it to be a method call. Otherwise it is
+ // a function, not something that satisfies the error interface.
+ if sig.Recv == nil {
+ return false
+ }
+ // There must be no arguments. Already verified by type checking, but be thorough.
+ if len(sig.Params) > 0 {
+ return false
+ }
+ // Finally the real questions.
+ // There must be one result.
+ if len(sig.Results) != 1 {
+ return false
+ }
+ // It must have return type "string" from the universe.
+ result := sig.Results[0].Type
+ if types.IsIdentical(result, types.Typ[types.String]) {
+ return true
+ }
+ return false
+}
diff --git a/src/cmd/vet/typestub.go b/src/cmd/vet/typestub.go
new file mode 100644
index 000000000..fabbbe19d
--- /dev/null
+++ b/src/cmd/vet/typestub.go
@@ -0,0 +1,45 @@
+// 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.
+
+// +build !gotypes
+
+// This file contains stubs for the pieces of the tool that require the go/types package,
+// to be used if go/types is not available.
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+// Type is equivalent to go/types.Type. Repeating it here allows us to avoid
+// depending on the go/types package.
+type Type interface {
+ String() string
+}
+
+func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
+ return nil
+}
+
+func (pkg *Package) isStruct(c *ast.CompositeLit) (bool, string) {
+ return true, "" // Assume true, so we do the check.
+}
+
+func (f *File) matchArgType(t printfArgType, arg ast.Expr) bool {
+ return true // We can't tell without types.
+}
+
+func (f *File) numArgsInSignature(call *ast.CallExpr) int {
+ return 0 // We don't know.
+}
+
+func (f *File) isErrorMethodCall(call *ast.CallExpr) bool {
+ // Is it a selector expression? Otherwise it's a function call, not a method call.
+ if _, ok := call.Fun.(*ast.SelectorExpr); !ok {
+ return false
+ }
+ return true // Best guess we can make without types.
+}
diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go
index 0c18f93b6..76b3aeac5 100644
--- a/src/cmd/yacc/yacc.go
+++ b/src/cmd/yacc/yacc.go
@@ -3164,7 +3164,6 @@ func ungetrune(f *bufio.Reader, c rune) {
func write(f *bufio.Writer, b []byte, n int) int {
panic("write")
- return 0
}
func open(s string) *bufio.Reader {