1
0
mirror of https://github.com/golang/go synced 2024-11-24 06:10:05 -07:00

runtime: turn run time errors checks into panics

R=ken2, r
CC=golang-dev
https://golang.org/cl/871042
This commit is contained in:
Russ Cox 2010-04-01 22:31:27 -07:00
parent d6589377c6
commit f75d0d224f
29 changed files with 241 additions and 225 deletions

View File

@ -573,7 +573,7 @@ agen(Node *n, Node *res)
regfree(&n4);
regfree(&n5);
p1 = gbranch(optoas(OGT, types[TUINT32]), T);
ginscall(throwindex, 0);
ginscall(panicindex, 0);
patch(p1, pc);
}
@ -627,7 +627,7 @@ agen(Node *n, Node *res)
gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
regfree(&n4);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
ginscall(throwindex, 0);
ginscall(panicindex, 0);
patch(p1, pc);
}

View File

@ -60,8 +60,8 @@ EXTERN Node* curfn;
EXTERN Node* newproc;
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
EXTERN Node* throwindex;
EXTERN Node* throwslice;
EXTERN Node* panicindex;
EXTERN Node* panicslice;
EXTERN Node* throwreturn;
EXTERN long unmappedzero;
EXTERN int maxstksize;

View File

@ -23,8 +23,8 @@ compile(Node *fn)
newproc = sysfunc("newproc");
deferproc = sysfunc("deferproc");
deferreturn = sysfunc("deferreturn");
throwindex = sysfunc("throwindex");
throwslice = sysfunc("throwslice");
panicindex = sysfunc("panicindex");
panicslice = sysfunc("panicslice");
throwreturn = sysfunc("throwreturn");
}
@ -142,8 +142,8 @@ ginscall(Node *f, int proc)
afunclit(&p->to);
break;
// TODO(kaib): unify newproc and defer if you can figure out how not to break things
case 1: // call in new proc (go)
case 2: // deferred call (defer)
regalloc(&r, types[tptr], N);
p = gins(AMOVW, N, &r);
p->from.type = D_OREG;
@ -173,71 +173,23 @@ ginscall(Node *f, int proc)
p->to.offset = 4;
regfree(&r);
ginscall(newproc, 0);
if(proc == 1)
ginscall(newproc, 0);
else
ginscall(deferproc, 0);
regalloc(&r, types[tptr], N);
p = gins(AMOVW, N, &r);
p->from.type = D_OREG;
nodreg(&r, types[tptr], 1);
p = gins(AMOVW, N, N);
p->from.type = D_CONST;
p->from.reg = REGSP;
p->from.offset = 0;
p = gins(AMOVW, &r, N);
p->to.type = D_OREG;
p->from.offset = 12;
p->to.reg = REGSP;
p->to.offset = 12;
p->scond |= C_WBIT;
regfree(&r);
p->to.type = D_REG;
break;
case 2: // deferred call (defer)
regalloc(&r, types[tptr], N);
p = gins(AMOVW, N, &r);
p->from.type = D_OREG;
p->from.reg = REGSP;
p = gins(AMOVW, &r, N);
p->to.type = D_OREG;
p->to.reg = REGSP;
p->to.offset = -8;
p->scond |= C_WBIT;
memset(&n1, 0, sizeof n1);
n1.op = OADDR;
n1.left = f;
gins(AMOVW, &n1, &r);
p = gins(AMOVW, &r, N);
p->to.type = D_OREG;
p->to.reg = REGSP;
p->to.offset = 8;
nodconst(&con, types[TINT32], argsize(f->type));
gins(AMOVW, &con, &r);
p = gins(AMOVW, &r, N);
p->to.type = D_OREG;
p->to.reg = REGSP;
p->to.offset = 4;
regfree(&r);
ginscall(deferproc, 0);
nodreg(&r, types[tptr], D_R1);
p = gins(AMOVW, N, &r);
p->from.type = D_OREG;
p->from.reg = REGSP;
p->from.offset = 0;
p = gins(AMOVW, &r, N);
p->to.type = D_OREG;
p->to.reg = REGSP;
p->to.offset = 8;
p->scond |= C_WBIT;
if(proc == 2) {
nodconst(&con, types[TINT32], 0);
nodreg(&r, types[tptr], D_R0);
gins(ACMP, &con, &r);
p = gins(ACMP, &con, N);
p->reg = 0;
patch(gbranch(ABNE, T), pret);
}
break;
@ -773,7 +725,7 @@ cmpandthrow(Node *nl, Node *nr)
if(cl > cr) {
if(throwpc == nil) {
throwpc = pc;
ginscall(throwslice, 0);
ginscall(panicslice, 0);
} else
patch(gbranch(AB, T), throwpc);
}
@ -807,7 +759,7 @@ cmpandthrow(Node *nl, Node *nr)
if(throwpc == nil) {
p1 = gbranch(optoas(op, types[TUINT32]), T);
throwpc = pc;
ginscall(throwslice, 0);
ginscall(panicslice, 0);
patch(p1, pc);
} else {
op = brcom(op);

View File

@ -1724,7 +1724,7 @@ oindex:
gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3);
regfree(&n3);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
ginscall(throwindex, 0);
ginscall(panicindex, 0);
patch(p1, pc);
}
@ -1780,7 +1780,7 @@ oindex_const:
regfree(&n4);
regfree(&n3);
p1 = gbranch(optoas(OGT, types[TUINT32]), T);
ginscall(throwindex, 0);
ginscall(panicindex, 0);
patch(p1, pc);
}

View File

@ -527,7 +527,7 @@ agen(Node *n, Node *res)
nodconst(&n2, types[TUINT64], v);
gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
p1 = gbranch(optoas(OGT, types[TUINT32]), T);
ginscall(throwindex, 0);
ginscall(panicindex, 0);
patch(p1, pc);
}
@ -573,7 +573,7 @@ agen(Node *n, Node *res)
nodconst(&n1, types[TUINT64], nl->type->bound);
gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
ginscall(throwindex, 0);
ginscall(panicindex, 0);
patch(p1, pc);
}

View File

@ -54,8 +54,8 @@ EXTERN Node* curfn;
EXTERN Node* newproc;
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
EXTERN Node* throwindex;
EXTERN Node* throwslice;
EXTERN Node* panicindex;
EXTERN Node* panicslice;
EXTERN Node* throwreturn;
EXTERN vlong unmappedzero;

View File

@ -23,8 +23,8 @@ compile(Node *fn)
newproc = sysfunc("newproc");
deferproc = sysfunc("deferproc");
deferreturn = sysfunc("deferreturn");
throwindex = sysfunc("throwindex");
throwslice = sysfunc("throwslice");
panicindex = sysfunc("panicindex");
panicslice = sysfunc("panicslice");
throwreturn = sysfunc("throwreturn");
}
@ -1119,7 +1119,7 @@ cmpandthrow(Node *nl, Node *nr)
if(cl > cr) {
if(throwpc == nil) {
throwpc = pc;
ginscall(throwslice, 0);
ginscall(panicslice, 0);
} else
patch(gbranch(AJMP, T), throwpc);
}
@ -1137,7 +1137,7 @@ cmpandthrow(Node *nl, Node *nr)
if(throwpc == nil) {
p1 = gbranch(optoas(op, types[TUINT32]), T);
throwpc = pc;
ginscall(throwslice, 0);
ginscall(panicslice, 0);
patch(p1, pc);
} else {
op = brcom(op);

View File

@ -1867,7 +1867,7 @@ oindex:
}
gins(optoas(OCMP, types[TUINT32]), reg1, &n2);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
ginscall(throwindex, 0);
ginscall(panicindex, 0);
patch(p1, pc);
}
@ -1924,7 +1924,7 @@ oindex_const:
nodconst(&n2, types[TUINT64], v);
gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
p1 = gbranch(optoas(OGT, types[TUINT32]), T);
ginscall(throwindex, 0);
ginscall(panicindex, 0);
patch(p1, pc);
}
@ -1958,7 +1958,7 @@ oindex_const_sudo:
p1 = gins(optoas(OCMP, types[TUINT32]), N, &n2);
p1->from = *a;
p1 = gbranch(optoas(OGT, types[TUINT32]), T);
ginscall(throwindex, 0);
ginscall(panicindex, 0);
patch(p1, pc);
a->offset -= Array_nel;
}

View File

@ -1555,10 +1555,10 @@ noreturn(Prog *p)
int i;
if(symlist[0] == S) {
symlist[0] = pkglookup("throwindex", runtimepkg);
symlist[1] = pkglookup("throwslice", runtimepkg);
symlist[0] = pkglookup("panicindex", runtimepkg);
symlist[1] = pkglookup("panicslice", runtimepkg);
symlist[2] = pkglookup("throwinit", runtimepkg);
symlist[3] = pkglookup("panicl", runtimepkg);
symlist[3] = pkglookup("panic", runtimepkg);
}
s = p->to.sym;

View File

@ -549,7 +549,7 @@ agen(Node *n, Node *res)
nodconst(&n2, types[TUINT32], v);
gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
p1 = gbranch(optoas(OGT, types[TUINT32]), T);
ginscall(throwindex, 0);
ginscall(panicindex, 0);
patch(p1, pc);
}
@ -595,7 +595,7 @@ agen(Node *n, Node *res)
nodconst(&n1, types[TUINT32], nl->type->bound);
gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
ginscall(throwindex, 0);
ginscall(panicindex, 0);
patch(p1, pc);
}

View File

@ -64,8 +64,8 @@ EXTERN Node* curfn;
EXTERN Node* newproc;
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
EXTERN Node* throwindex;
EXTERN Node* throwslice;
EXTERN Node* panicindex;
EXTERN Node* panicslice;
EXTERN Node* throwreturn;
EXTERN int maxstksize;
extern uint32 unmappedzero;

View File

@ -23,8 +23,8 @@ compile(Node *fn)
newproc = sysfunc("newproc");
deferproc = sysfunc("deferproc");
deferreturn = sysfunc("deferreturn");
throwindex = sysfunc("throwindex");
throwslice = sysfunc("throwslice");
panicindex = sysfunc("panicindex");
panicslice = sysfunc("panicslice");
throwreturn = sysfunc("throwreturn");
}
@ -824,7 +824,7 @@ cmpandthrow(Node *nl, Node *nr)
if(cl > cr) {
if(throwpc == nil) {
throwpc = pc;
ginscall(throwslice, 0);
ginscall(panicslice, 0);
} else
patch(gbranch(AJMP, T), throwpc);
}
@ -842,7 +842,7 @@ cmpandthrow(Node *nl, Node *nr)
if(throwpc == nil) {
p1 = gbranch(optoas(op, types[TUINT32]), T);
throwpc = pc;
ginscall(throwslice, 0);
ginscall(panicslice, 0);
patch(p1, pc);
} else {
op = brcom(op);

View File

@ -1447,10 +1447,10 @@ noreturn(Prog *p)
int i;
if(symlist[0] == S) {
symlist[0] = pkglookup("throwindex", runtimepkg);
symlist[1] = pkglookup("throwslice", runtimepkg);
symlist[0] = pkglookup("panicindex", runtimepkg);
symlist[1] = pkglookup("panicslice", runtimepkg);
symlist[2] = pkglookup("throwinit", runtimepkg);
symlist[3] = pkglookup("panicl", runtimepkg);
symlist[3] = pkglookup("panic", runtimepkg);
}
s = p->to.sym;

View File

@ -201,10 +201,10 @@ missing(uvlong pc, uvlong epc)
}
if(epc - pc == 5) {
// check for CALL sys.throwindex
// check for CALL sys.panicindex
buf[0] = 0;
machdata->das(text, pc, 0, buf, sizeof buf);
if(strstr(buf, "throwindex"))
if(strstr(buf, "panicindex"))
return;
}

View File

@ -1,7 +1,8 @@
char *runtimeimport =
"package runtime\n"
"func \"\".mal (? int32) *any\n"
"func \"\".throwindex ()\n"
"func \"\".panicindex ()\n"
"func \"\".panicslice ()\n"
"func \"\".throwreturn ()\n"
"func \"\".throwinit ()\n"
"func \"\".panic (? interface { })\n"

View File

@ -276,7 +276,10 @@ exprfmt(Fmt *f, Node *n, int prec)
case ODOTTYPE:
exprfmt(f, n->left, 7);
fmtprint(f, ".(");
exprfmt(f, n->right, 0);
if(n->right != N)
exprfmt(f, n->right, 0);
else
fmtprint(f, "%T", n->type);
fmtprint(f, ")");
break;

View File

@ -11,7 +11,8 @@ package PACKAGE
// emitted by compiler, not referred to by go programs
func mal(int32) *any
func throwindex()
func panicindex()
func panicslice()
func throwreturn()
func throwinit()

View File

@ -1846,8 +1846,6 @@ walkprint(Node *nn, NodeList **init, int defer)
if(defer) {
if(op == OPRINTN)
fmtprint(&fmt, "\n");
if(op == OPANIC)
fmtprint(&fmt, "%%!");
on = syslook("printf", 1);
on->type = functype(nil, intypes, nil);
args->n = nod(OLITERAL, N, N);
@ -1863,10 +1861,7 @@ walkprint(Node *nn, NodeList **init, int defer)
typechecklist(calls, Etop);
walkexprlist(calls, init);
if(op == OPANIC)
r = mkcall("panicl", T, nil);
else
r = nod(OEMPTY, N, N);
r = nod(OEMPTY, N, N);
typecheck(&r, Etop);
walkexpr(&r, init);
r->ninit = calls;

View File

@ -20,7 +20,7 @@ void
b = -b;
if(a <= b) {
if(b == 0)
throw("complex divide");
panicstring("complex divide by zero");
ratio = denreal/denimag;
denom = denreal*ratio + denimag;
quoreal = (numreal*ratio + numimag) / denom;

View File

@ -7,7 +7,12 @@ package runtime
// The Error interface identifies a run time error.
type Error interface {
String() string
RuntimeError() // no-op that uniquely identifies runtime.Error
// RuntimeError is a no-op function but
// serves to distinguish types that are runtime
// errors from ordinary os.Errors: a type is a
// runtime error if it has a RuntimeError method.
RuntimeError()
}
// A TypeAssertionError explains a failed type assertion.
@ -21,6 +26,8 @@ type TypeAssertionError struct {
missingMethod string // one method needed by Interface, missing from Concrete
}
func (*TypeAssertionError) RuntimeError() {}
func (e *TypeAssertionError) String() string {
inter := e.interfaceString
if inter == "" {
@ -57,8 +64,6 @@ func (e *TypeAssertionError) MissingMethod() string {
return e.missingMethod
}
func (*TypeAssertionError) RuntimeError() {}
// For calling from C.
func newTypeAssertionError(pt1, pt2, pt3 *Type, ps1, ps2, ps3 *string, pmeth *string, ret *interface{}) {
var t1, t2, t3 Type
@ -88,12 +93,26 @@ func newTypeAssertionError(pt1, pt2, pt3 *Type, ps1, ps2, ps3 *string, pmeth *st
*ret = &TypeAssertionError{t1, t2, t3, s1, s2, s3, meth}
}
// An errorString represents a runtime error described by a single string.
type errorString string
func (e errorString) RuntimeError() {}
func (e errorString) String() string {
return "runtime error: " + string(e)
}
// For calling from C.
func newErrorString(s string, ret *interface{}) {
*ret = errorString(s)
}
type stringer interface {
String() string
}
// For calling from C.
// Prints an argument to panic.
// Prints an argument passed to panic.
// There's room for arbitrary complexity here, but we keep it
// simple and handle just a few important cases: int, string, and Stringer.
func printany(i interface{}) {

View File

@ -770,10 +770,6 @@ void
mapaccess(h, ak, av, &pres);
// new spec -- all elements have "zero" value
// if(!pres)
// throw("runtime.mapaccess1: key not in map");
if(debug) {
prints("runtime.mapaccess1: map=");
·printpointer(h);

View File

@ -457,6 +457,7 @@ static uintptr
ifacehash1(void *data, Type *t)
{
int32 alg, wid;
Eface err;
if(t == nil)
return 0;
@ -464,12 +465,10 @@ ifacehash1(void *data, Type *t)
alg = t->alg;
wid = t->size;
if(algarray[alg].hash == nohash) {
// calling nohash will throw too,
// calling nohash will panic too,
// but we can print a better error.
printf("hash of unhashable type %S\n", *t->string);
if(alg == AFAKE)
throw("fake interface hash");
throw("interface hash");
·newErrorString(catstring(gostring((byte*)"hash of unhashable type "), *t->string), &err);
·panic(err);
}
if(wid <= sizeof(data))
return algarray[alg].hash(wid, &data);
@ -494,17 +493,16 @@ static bool
ifaceeq1(void *data1, void *data2, Type *t)
{
int32 alg, wid;
Eface err;
alg = t->alg;
wid = t->size;
if(algarray[alg].equal == noequal) {
// calling noequal will throw too,
// calling noequal will panic too,
// but we can print a better error.
printf("comparing uncomparable type %S\n", *t->string);
if(alg == AFAKE)
throw("fake interface compare");
throw("interface compare");
·newErrorString(catstring(gostring((byte*)"comparing uncomparable type "), *t->string), &err);
·panic(err);
}
if(wid <= sizeof(data1))

View File

@ -42,27 +42,29 @@ panic(int32 unused)
}
void
·throwindex(void)
·panicindex(void)
{
throw("index out of range");
panicstring("index out of range");
}
void
·throwslice(void)
·panicslice(void)
{
throw("slice out of range");
panicstring("slice bounds out of range");
}
void
·throwreturn(void)
{
throw("no return at end of a typed function");
// can only happen if compiler is broken
throw("no return at end of a typed function - compiler is broken");
}
void
·throwinit(void)
{
throw("recursive call during initialization");
// can only happen with linker skew
throw("recursive call during initialization - linker skew");
}
void
@ -75,6 +77,15 @@ throw(int8 *s)
exit(1); // even more not reached
}
void
panicstring(int8 *s)
{
Eface err;
·newErrorString(gostring((byte*)s), &err);
·panic(err);
}
void
mcpy(byte *t, byte *f, uint32 n)
{
@ -421,7 +432,7 @@ nohash(uint32 s, void *a)
{
USED(s);
USED(a);
throw("hash of unhashable type");
panicstring("hash of unhashable type");
return 0;
}
@ -431,27 +442,10 @@ noequal(uint32 s, void *a, void *b)
USED(s);
USED(a);
USED(b);
throw("comparing uncomparable types");
panicstring("comparing uncomparable types");
return 0;
}
static void
noprint(uint32 s, void *a)
{
USED(s);
USED(a);
throw("print of unprintable type");
}
static void
nocopy(uint32 s, void *a, void *b)
{
USED(s);
USED(a);
USED(b);
throw("copy of uncopyable type");
}
Alg
algarray[] =
{
@ -460,7 +454,6 @@ algarray[] =
[ASTRING] { strhash, strequal, strprint, memcopy },
[AINTER] { interhash, interequal, interprint, memcopy },
[ANILINTER] { nilinterhash, nilinterequal, nilinterprint, memcopy },
[AFAKE] { nohash, noequal, noprint, nocopy },
};
#pragma textflag 7

View File

@ -300,7 +300,6 @@ enum
ASTRING,
AINTER,
ANILINTER,
AFAKE,
Amax
};
@ -369,6 +368,7 @@ void goargs(void);
void FLUSH(void*);
void* getu(void);
void throw(int8*);
void panicstring(int8*);
uint32 rnd(uint32, uint32);
void prints(int8*);
void printf(int8*, ...);
@ -379,6 +379,7 @@ void memmove(void*, void*, uint32);
void* mal(uintptr);
void* malx(uintptr size, int32 skip_delta);
uint32 cmpstring(String, String);
String catstring(String, String);
String gostring(byte*);
String gostringw(uint16*);
void initsig(void);
@ -416,6 +417,7 @@ void free(void *v);
void addfinalizer(void*, void(*fn)(void*), int32);
void walkfintab(void (*fn)(void*));
void runpanic(Panic*);
void* getcallersp(void*);
void exit(int32);
void breakpoint(void);
@ -531,13 +533,15 @@ void runtime_printslice(Slice);
void runtime_printcomplex(Complex128);
void reflect·call(byte*, byte*, uint32);
void ·panic(Eface);
void ·panicindex(void);
void ·panicslice(void);
/*
* runtime c-called (but written in Go)
*/
void ·newError(String, Eface*);
void ·printany(Eface);
void ·newTypeAssertionError(Type*, Type*, Type*, String*, String*, String*, String*, Eface*);
void ·newErrorString(String, Eface*);
/*
* wrapped for go users

View File

@ -36,19 +36,6 @@ void
}
}
static void
throwslice(uint32 lb, uint32 hb, uint32 n)
{
prints("slice[");
·printint(lb);
prints(":");
·printint(hb);
prints("] of [");
·printint(n);
prints("] array\n");
throw("array slice");
}
// sliceslice(old []any, lb int, hb int, width int) (ary []any);
void
·sliceslice(Slice old, uint32 lb, uint32 hb, uint32 width, Slice ret)
@ -71,7 +58,7 @@ void
·printint(old.cap);
prints("\n");
}
throwslice(lb, hb, old.cap);
·panicslice();
}
// new array is inside old array
@ -116,7 +103,7 @@ void
·printint(old.cap);
prints("\n");
}
throwslice(lb, old.len, old.cap);
·panicslice();
}
// new array is inside old array
@ -165,7 +152,7 @@ void
·printint(width);
prints("\n");
}
throwslice(lb, hb, nel);
·panicslice();
}
// new array is inside old array

View File

@ -78,34 +78,25 @@ gostringw(uint16 *str)
return s;
}
func catstring(s1 String, s2 String) (s3 String) {
if(s1.len == 0) {
s3 = s2;
goto out;
}
if(s2.len == 0) {
s3 = s1;
goto out;
}
String
catstring(String s1, String s2)
{
String s3;
if(s1.len == 0)
return s2;
if(s2.len == 0)
return s1;
s3 = gostringsize(s1.len + s2.len);
mcpy(s3.str, s1.str, s1.len);
mcpy(s3.str+s1.len, s2.str, s2.len);
out:
return s3;
}
static void
prbounds(int8* s, int32 a, int32 b, int32 c)
{
prints(s);
prints(" ");
·printint(a);
prints("<");
·printint(b);
prints(">");
·printint(c);
prints("\n");
throw("string bounds");
func catstring(s1 String, s2 String) (s3 String) {
s3 = catstring(s1, s2);
}
uint32
@ -159,9 +150,7 @@ func slicestring(si String, lindex int32, hindex int32) (so String) {
if(lindex < 0 || lindex > si.len ||
hindex < lindex || hindex > si.len) {
·printpc(&si);
prints(" ");
prbounds("slice", lindex, si.len, hindex);
·panicslice();
}
l = hindex-lindex;
@ -177,9 +166,7 @@ func slicestring1(si String, lindex int32) (so String) {
int32 l;
if(lindex < 0 || lindex > si.len) {
·printpc(&si);
prints(" ");
prbounds("slice", lindex, si.len, si.len);
·panicslice();
}
l = si.len-lindex;
@ -193,9 +180,7 @@ func slicestring1(si String, lindex int32) (so String) {
func indexstring(s String, i int32) (b byte) {
if(i < 0 || i >= s.len) {
·printpc(&s);
prints(" ");
prbounds("index", 0, i, s.len);
·panicindex();
}
b = s.str[i];

View File

@ -2,26 +2,22 @@
== ./
=========== ./cmp2.go
comparing uncomparable type []int
throw: interface compare
panic: runtime error: comparing uncomparable type []int
panic PC=xxx
=========== ./cmp3.go
comparing uncomparable type []int
throw: interface compare
panic: runtime error: comparing uncomparable type []int
panic PC=xxx
=========== ./cmp4.go
hash of unhashable type []int
throw: interface hash
panic: runtime error: hash of unhashable type []int
panic PC=xxx
=========== ./cmp5.go
hash of unhashable type []int
throw: interface hash
panic: runtime error: hash of unhashable type []int
panic PC=xxx

View File

@ -23,21 +23,21 @@ func main() {
}
func die() {
runtime.Breakpoint() // can't depend on panic
runtime.Breakpoint() // can't depend on panic
}
func mustRecover(x interface{}) {
mustNotRecover() // because it's not a defer call
mustNotRecover() // because it's not a defer call
v := recover()
if v == nil {
println("missing recover")
die() // panic is useless here
die() // panic is useless here
}
if v != x {
println("wrong value", v, x)
die()
}
// the value should be gone now regardless
v = recover()
if v != nil {
@ -49,19 +49,19 @@ func mustRecover(x interface{}) {
func mustNotRecover() {
v := recover()
if v != nil {
println("spurious recover")
println("spurious recover", v)
die()
}
}
func withoutRecover() {
mustNotRecover() // because it's a sub-call
mustNotRecover() // because it's a sub-call
}
func test1() {
defer mustNotRecover() // because mustRecover will squelch it
defer mustRecover(1) // because of panic below
defer withoutRecover() // should be no-op, leaving for mustRecover to find
defer mustNotRecover() // because mustRecover will squelch it
defer mustRecover(1) // because of panic below
defer withoutRecover() // should be no-op, leaving for mustRecover to find
panic(1)
}
@ -102,14 +102,14 @@ func test2() {
// It does not see the panic when called from a call within a deferred call (too late)
// nor does it see the panic when it *is* the deferred call (too early).
defer mustRecover(2)
defer recover() // should be no-op
defer recover() // should be no-op
panic(2)
}
func test3() {
defer mustNotRecover()
defer func() {
recover() // should squelch
recover() // should squelch
}()
panic(3)
}
@ -118,7 +118,7 @@ func test4() {
// Equivalent to test3 but using defer to make the call.
defer mustNotRecover()
defer func() {
defer recover() // should squelch
defer recover() // should squelch
}()
panic(4)
}
@ -154,8 +154,8 @@ func test5() {
println("wrong value", v, 5)
die()
}
s := try(func() { }, "hi").(string)
s := try(func() {}, "hi").(string)
if s != "hi" {
println("wrong value", s, "hi")
die()
@ -166,8 +166,8 @@ func test5() {
println("try1 wrong value", v, 5)
die()
}
s = try1(func() { }, "hi").(string)
s = try1(func() {}, "hi").(string)
if s != "hi" {
println("try1 wrong value", s, "hi")
die()
@ -183,7 +183,7 @@ func big(mustRecover bool) {
x[0] = 1
x[99999] = 1
_ = x
v := recover()
if mustRecover {
if v == nil {

86
test/recover2.go Normal file
View File

@ -0,0 +1,86 @@
// $G $D/$F.go && $L $F.$A && ./$A.out
// 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.
// Test of recover for run-time errors.
// TODO(rsc):
// integer divide by zero?
// null pointer accesses
package main
import (
"os"
"strings"
)
var x = make([]byte, 10)
func main() {
test1()
test2()
test3()
test4()
test5()
test6()
test7()
}
func mustRecover(s string) {
v := recover()
if v == nil {
panic("expected panic")
}
if e := v.(os.Error).String(); strings.Index(e, s) < 0 {
panic("want: " + s + "; have: " + e)
}
}
func test1() {
defer mustRecover("index")
println(x[123])
}
func test2() {
defer mustRecover("slice")
println(x[5:15])
}
func test3() {
defer mustRecover("slice")
println(x[11:9])
}
func test4() {
defer mustRecover("interface")
var x interface{} = 1
println(x.(float))
}
type T struct {
a, b int
}
func test5() {
defer mustRecover("uncomparable")
var x T
var z interface{} = x
println(z != z)
}
func test6() {
defer mustRecover("unhashable")
var x T
var z interface{} = x
m := make(map[interface{}]int)
m[z] = 1
}
func test7() {
defer mustRecover("complex divide by zero")
var x, y complex
println(x / y)
}