mirror of
https://github.com/golang/go
synced 2024-11-25 01:08:02 -07:00
gc: five bug fixes, one better error.
* check for struct literal assignment to private fields. * record, fix crash involving parallel map assignment. * avoid infinite recursion in exportassignok. * make floating point bounds check precise. * avoid crash on invalid receiver. * add context to error about implicit assignment. Fixes #86. Fixes #88. Fixes #158. Fixes #174. Fixes #201. Fixes #204. R=ken2 https://golang.org/cl/154144
This commit is contained in:
parent
a967f57d19
commit
a338231526
@ -495,10 +495,11 @@ typeinit(void)
|
|||||||
mpatofix(maxintval[TUINT32], "0xffffffff");
|
mpatofix(maxintval[TUINT32], "0xffffffff");
|
||||||
mpatofix(maxintval[TUINT64], "0xffffffffffffffff");
|
mpatofix(maxintval[TUINT64], "0xffffffffffffffff");
|
||||||
|
|
||||||
mpatoflt(maxfltval[TFLOAT32], "3.40282347e+38");
|
/* f is valid float if min < f < max. (min and max are not themselves valid.) */
|
||||||
mpatoflt(minfltval[TFLOAT32], "-3.40282347e+38");
|
mpatoflt(maxfltval[TFLOAT32], "33554431p103"); /* 2^24-1 p (127-23) + 1/2 ulp*/
|
||||||
mpatoflt(maxfltval[TFLOAT64], "1.7976931348623157e+308");
|
mpatoflt(minfltval[TFLOAT32], "-33554431p103");
|
||||||
mpatoflt(minfltval[TFLOAT64], "-1.7976931348623157e+308");
|
mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970"); /* 2^53-1 p (1023-52) + 1/2 ulp */
|
||||||
|
mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970");
|
||||||
|
|
||||||
/* for walk to use in error messages */
|
/* for walk to use in error messages */
|
||||||
types[TFUNC] = functype(N, nil, nil);
|
types[TFUNC] = functype(N, nil, nil);
|
||||||
|
@ -261,8 +261,8 @@ overflow(Val v, Type *t)
|
|||||||
case CTFLT:
|
case CTFLT:
|
||||||
if(!isfloat[t->etype])
|
if(!isfloat[t->etype])
|
||||||
fatal("overflow: %T floating-point constant", t);
|
fatal("overflow: %T floating-point constant", t);
|
||||||
if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) < 0
|
if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) <= 0
|
||||||
|| mpcmpfltflt(v.u.fval, maxfltval[t->etype]) > 0)
|
|| mpcmpfltflt(v.u.fval, maxfltval[t->etype]) >= 0)
|
||||||
yyerror("constant %#F overflows %T", v.u.fval, t);
|
yyerror("constant %#F overflows %T", v.u.fval, t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -302,11 +302,27 @@ NodeList*
|
|||||||
variter(NodeList *vl, Node *t, NodeList *el)
|
variter(NodeList *vl, Node *t, NodeList *el)
|
||||||
{
|
{
|
||||||
int doexpr;
|
int doexpr;
|
||||||
Node *v, *e;
|
Node *v, *e, *as2;
|
||||||
NodeList *init;
|
NodeList *init;
|
||||||
|
|
||||||
init = nil;
|
init = nil;
|
||||||
doexpr = el != nil;
|
doexpr = el != nil;
|
||||||
|
|
||||||
|
if(count(el) == 1 && count(vl) > 1) {
|
||||||
|
e = el->n;
|
||||||
|
as2 = nod(OAS2, N, N);
|
||||||
|
as2->list = vl;
|
||||||
|
as2->rlist = list1(e);
|
||||||
|
for(; vl; vl=vl->next) {
|
||||||
|
v = vl->n;
|
||||||
|
v->op = ONAME;
|
||||||
|
declare(v, dclcontext);
|
||||||
|
v->ntype = t;
|
||||||
|
v->defn = as2;
|
||||||
|
}
|
||||||
|
return list1(as2);
|
||||||
|
}
|
||||||
|
|
||||||
for(; vl; vl=vl->next) {
|
for(; vl; vl=vl->next) {
|
||||||
if(doexpr) {
|
if(doexpr) {
|
||||||
if(el == nil) {
|
if(el == nil) {
|
||||||
|
@ -1048,8 +1048,8 @@ void typechecklist(NodeList*, int);
|
|||||||
void typecheckswitch(Node*);
|
void typecheckswitch(Node*);
|
||||||
void typecheckselect(Node*);
|
void typecheckselect(Node*);
|
||||||
void typecheckrange(Node*);
|
void typecheckrange(Node*);
|
||||||
Node* typecheckconv(Node*, Node*, Type*, int);
|
Node* typecheckconv(Node*, Node*, Type*, int, char*);
|
||||||
int checkconv(Type*, Type*, int, int*, int*);
|
int checkconv(Type*, Type*, int, int*, int*, char*);
|
||||||
Node* typecheck(Node**, int);
|
Node* typecheck(Node**, int);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1087,6 +1087,8 @@ xfndcl:
|
|||||||
LFUNC fndcl fnbody
|
LFUNC fndcl fnbody
|
||||||
{
|
{
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
|
if($$ == N)
|
||||||
|
break;
|
||||||
$$->nbody = $3;
|
$$->nbody = $3;
|
||||||
funcbody($$);
|
funcbody($$);
|
||||||
}
|
}
|
||||||
@ -1111,10 +1113,19 @@ fndcl:
|
|||||||
{
|
{
|
||||||
Node *rcvr, *t;
|
Node *rcvr, *t;
|
||||||
|
|
||||||
|
$$ = N;
|
||||||
|
if($2 == nil) {
|
||||||
|
yyerror("method has no receiver");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if($2->next != nil) {
|
||||||
|
yyerror("method has multiple receivers");
|
||||||
|
break;
|
||||||
|
}
|
||||||
rcvr = $2->n;
|
rcvr = $2->n;
|
||||||
if($2->next != nil || $2->n->op != ODCLFIELD) {
|
if(rcvr->op != ODCLFIELD) {
|
||||||
yyerror("bad receiver in method");
|
yyerror("bad receiver in method");
|
||||||
rcvr = N;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$$ = nod(ODCLFUNC, N, N);
|
$$ = nod(ODCLFUNC, N, N);
|
||||||
|
@ -114,6 +114,7 @@ ieeedtod(uint64 *ieee, double native)
|
|||||||
double fr, ho, f;
|
double fr, ho, f;
|
||||||
int exp;
|
int exp;
|
||||||
uint32 h, l;
|
uint32 h, l;
|
||||||
|
uint64 bits;
|
||||||
|
|
||||||
if(native < 0) {
|
if(native < 0) {
|
||||||
ieeedtod(ieee, -native);
|
ieeedtod(ieee, -native);
|
||||||
@ -129,13 +130,20 @@ ieeedtod(uint64 *ieee, double native)
|
|||||||
fr = modf(fr*f, &ho);
|
fr = modf(fr*f, &ho);
|
||||||
h = ho;
|
h = ho;
|
||||||
h &= 0xfffffL;
|
h &= 0xfffffL;
|
||||||
h |= (exp+1022L) << 20;
|
|
||||||
f = 65536L;
|
f = 65536L;
|
||||||
fr = modf(fr*f, &ho);
|
fr = modf(fr*f, &ho);
|
||||||
l = ho;
|
l = ho;
|
||||||
l <<= 16;
|
l <<= 16;
|
||||||
l |= (int32)(fr*f);
|
l |= (int32)(fr*f);
|
||||||
*ieee = ((uint64)h << 32) | l;
|
bits = ((uint64)h<<32) | l;
|
||||||
|
if(exp < -1021) {
|
||||||
|
// gradual underflow
|
||||||
|
bits |= 1LL<<52;
|
||||||
|
bits >>= -1021 - exp;
|
||||||
|
exp = -1022;
|
||||||
|
}
|
||||||
|
bits |= (uint64)(exp+1022L) << 52;
|
||||||
|
*ieee = bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -66,12 +66,12 @@ typecheckrange(Node *n)
|
|||||||
|
|
||||||
if(v1->defn == n)
|
if(v1->defn == n)
|
||||||
v1->type = t1;
|
v1->type = t1;
|
||||||
else if(v1->type != T && checkconv(t1, v1->type, 0, &op, &et) < 0)
|
else if(v1->type != T && checkconv(t1, v1->type, 0, &op, &et, "range") < 0)
|
||||||
yyerror("cannot assign type %T to %+N", t1, v1);
|
yyerror("cannot assign type %T to %+N", t1, v1);
|
||||||
if(v2) {
|
if(v2) {
|
||||||
if(v2->defn == n)
|
if(v2->defn == n)
|
||||||
v2->type = t2;
|
v2->type = t2;
|
||||||
else if(v2->type != T && checkconv(t2, v2->type, 0, &op, &et) < 0)
|
else if(v2->type != T && checkconv(t2, v2->type, 0, &op, &et, "range") < 0)
|
||||||
yyerror("cannot assign type %T to %+N", t1, v1);
|
yyerror("cannot assign type %T to %+N", t1, v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,12 @@ init1(Node *n, NodeList **out)
|
|||||||
print("%S\n", n->sym);
|
print("%S\n", n->sym);
|
||||||
*out = list(*out, n->defn);
|
*out = list(*out, n->defn);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OAS2FUNC:
|
||||||
|
for(l=n->defn->rlist; l; l=l->next)
|
||||||
|
init1(l->n, out);
|
||||||
|
*out = list(*out, n->defn);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n->initorder = 1;
|
n->initorder = 1;
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
static void implicitstar(Node**);
|
static void implicitstar(Node**);
|
||||||
static int onearg(Node*);
|
static int onearg(Node*);
|
||||||
static int lookdot(Node*, Type*);
|
static int lookdot(Node*, Type*);
|
||||||
static void typecheckaste(int, Type*, NodeList*);
|
static void typecheckaste(int, Type*, NodeList*, char*);
|
||||||
static int exportassignok(Type*);
|
static int exportassignok(Type*, char*);
|
||||||
static Type* lookdot1(Sym *s, Type *t, Type *f);
|
static Type* lookdot1(Sym *s, Type *t, Type *f);
|
||||||
static int nokeys(NodeList*);
|
static int nokeys(NodeList*);
|
||||||
static void typecheckcomplit(Node**);
|
static void typecheckcomplit(Node**);
|
||||||
@ -673,7 +673,7 @@ reswitch:
|
|||||||
|
|
||||||
case ODOTMETH:
|
case ODOTMETH:
|
||||||
n->op = OCALLMETH;
|
n->op = OCALLMETH;
|
||||||
typecheckaste(OCALL, getthisx(t), list1(l->left));
|
typecheckaste(OCALL, getthisx(t), list1(l->left), "method receiver");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -684,7 +684,7 @@ reswitch:
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
typecheckaste(OCALL, getinargx(t), n->list);
|
typecheckaste(OCALL, getinargx(t), n->list, "function argument");
|
||||||
ok |= Etop;
|
ok |= Etop;
|
||||||
if(t->outtuple == 0)
|
if(t->outtuple == 0)
|
||||||
goto ret;
|
goto ret;
|
||||||
@ -768,7 +768,7 @@ reswitch:
|
|||||||
convlit1(&n->left, n->type, 1);
|
convlit1(&n->left, n->type, 1);
|
||||||
if((t = n->left->type) == T || n->type == T)
|
if((t = n->left->type) == T || n->type == T)
|
||||||
goto error;
|
goto error;
|
||||||
n = typecheckconv(n, n->left, n->type, 1);
|
n = typecheckconv(n, n->left, n->type, 1, "conversion");
|
||||||
if(n->type == T)
|
if(n->type == T)
|
||||||
goto error;
|
goto error;
|
||||||
goto ret;
|
goto ret;
|
||||||
@ -960,7 +960,7 @@ reswitch:
|
|||||||
typechecklist(n->list, Erv | Efnstruct);
|
typechecklist(n->list, Erv | Efnstruct);
|
||||||
if(curfn->type->outnamed && n->list == nil)
|
if(curfn->type->outnamed && n->list == nil)
|
||||||
goto ret;
|
goto ret;
|
||||||
typecheckaste(ORETURN, getoutargx(curfn->type), n->list);
|
typecheckaste(ORETURN, getoutargx(curfn->type), n->list, "return argument");
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
case OSELECT:
|
case OSELECT:
|
||||||
@ -1206,13 +1206,11 @@ nokeys(NodeList *l)
|
|||||||
* check implicit or explicit conversion from node type nt to type t.
|
* check implicit or explicit conversion from node type nt to type t.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
checkconv(Type *nt, Type *t, int explicit, int *op, int *et)
|
checkconv(Type *nt, Type *t, int explicit, int *op, int *et, char *desc)
|
||||||
{
|
{
|
||||||
*op = OCONV;
|
*op = OCONV;
|
||||||
*et = 0;
|
*et = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// preexisting error
|
// preexisting error
|
||||||
if(t == T || t->etype == TFORW)
|
if(t == T || t->etype == TFORW)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1229,7 +1227,7 @@ checkconv(Type *nt, Type *t, int explicit, int *op, int *et)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(eqtype(t, nt)) {
|
if(eqtype(t, nt)) {
|
||||||
exportassignok(t);
|
exportassignok(t, desc);
|
||||||
*op = OCONVNOP;
|
*op = OCONVNOP;
|
||||||
if(!explicit || t == nt)
|
if(!explicit || t == nt)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1334,15 +1332,17 @@ checkconv(Type *nt, Type *t, int explicit, int *op, int *et)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Node*
|
Node*
|
||||||
typecheckconv(Node *nconv, Node *n, Type *t, int explicit)
|
typecheckconv(Node *nconv, Node *n, Type *t, int explicit, char *desc)
|
||||||
{
|
{
|
||||||
int et, op;
|
int et, op;
|
||||||
Node *n1;
|
Node *n1;
|
||||||
|
char *prefix;
|
||||||
|
|
||||||
convlit1(&n, t, explicit);
|
convlit1(&n, t, explicit);
|
||||||
if(n->type == T)
|
if(n->type == T)
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
|
|
||||||
if(n->op == OLITERAL)
|
if(n->op == OLITERAL)
|
||||||
if(explicit || isideal(n->type))
|
if(explicit || isideal(n->type))
|
||||||
if(cvttype(t, n->type)) {
|
if(cvttype(t, n->type)) {
|
||||||
@ -1354,12 +1354,17 @@ typecheckconv(Node *nconv, Node *n, Type *t, int explicit)
|
|||||||
return n1;
|
return n1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(checkconv(n->type, t, explicit, &op, &et)) {
|
prefix = "";
|
||||||
|
if(desc != nil)
|
||||||
|
prefix = " in ";
|
||||||
|
else
|
||||||
|
desc = "";
|
||||||
|
switch(checkconv(n->type, t, explicit, &op, &et, desc)) {
|
||||||
case -1:
|
case -1:
|
||||||
if(explicit)
|
if(explicit)
|
||||||
yyerror("cannot convert %+N to type %T", n, t);
|
yyerror("cannot convert %+N to type %T%s%s", n, t, prefix, desc);
|
||||||
else
|
else
|
||||||
yyerror("cannot use %+N as type %T", n, t);
|
yyerror("cannot use %+N as type %T%s%s", n, t, prefix, desc);
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
@ -1386,7 +1391,7 @@ typecheckconv(Node *nconv, Node *n, Type *t, int explicit)
|
|||||||
* typecheck assignment: type list = expression list
|
* typecheck assignment: type list = expression list
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
typecheckaste(int op, Type *tstruct, NodeList *nl)
|
typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
|
||||||
{
|
{
|
||||||
Type *t, *tl, *tn;
|
Type *t, *tl, *tn;
|
||||||
Node *n;
|
Node *n;
|
||||||
@ -1409,8 +1414,8 @@ typecheckaste(int op, Type *tstruct, NodeList *nl)
|
|||||||
}
|
}
|
||||||
if(isddd(tl->type))
|
if(isddd(tl->type))
|
||||||
goto out;
|
goto out;
|
||||||
if(checkconv(tn->type, tl->type, 0, &xx, &yy) < 0)
|
if(checkconv(tn->type, tl->type, 0, &xx, &yy, desc) < 0)
|
||||||
yyerror("cannot use type %T as type %T", tn->type, tl->type);
|
yyerror("cannot use type %T as type %T in %s", tn->type, tl->type, desc);
|
||||||
tn = tn->down;
|
tn = tn->down;
|
||||||
}
|
}
|
||||||
if(tn != T)
|
if(tn != T)
|
||||||
@ -1434,7 +1439,7 @@ typecheckaste(int op, Type *tstruct, NodeList *nl)
|
|||||||
n = nl->n;
|
n = nl->n;
|
||||||
setlineno(nl->n);
|
setlineno(nl->n);
|
||||||
if(n->type != T)
|
if(n->type != T)
|
||||||
nl->n = typecheckconv(nil, n, t, 0);
|
nl->n = typecheckconv(nil, n, t, 0, desc);
|
||||||
nl = nl->next;
|
nl = nl->next;
|
||||||
}
|
}
|
||||||
if(nl != nil) {
|
if(nl != nil) {
|
||||||
@ -1452,13 +1457,17 @@ out:
|
|||||||
* an unavailable field.
|
* an unavailable field.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
exportassignok(Type *t)
|
exportassignok(Type *t, char *desc)
|
||||||
{
|
{
|
||||||
Type *f;
|
Type *f;
|
||||||
Sym *s;
|
Sym *s;
|
||||||
|
|
||||||
if(t == T)
|
if(t == T)
|
||||||
return 1;
|
return 1;
|
||||||
|
if(t->trecur)
|
||||||
|
return 1;
|
||||||
|
t->trecur = 1;
|
||||||
|
|
||||||
switch(t->etype) {
|
switch(t->etype) {
|
||||||
default:
|
default:
|
||||||
// most types can't contain others; they're all fine.
|
// most types can't contain others; they're all fine.
|
||||||
@ -1471,22 +1480,34 @@ exportassignok(Type *t)
|
|||||||
// s == nil doesn't happen for embedded fields (they get the type symbol).
|
// s == nil doesn't happen for embedded fields (they get the type symbol).
|
||||||
// it only happens for fields in a ... struct.
|
// it only happens for fields in a ... struct.
|
||||||
if(s != nil && !exportname(s->name) && strcmp(package, s->package) != 0) {
|
if(s != nil && !exportname(s->name) && strcmp(package, s->package) != 0) {
|
||||||
yyerror("implicit assignment of %T field '%s'", t, s->name);
|
char *prefix;
|
||||||
return 0;
|
|
||||||
|
prefix = "";
|
||||||
|
if(desc != nil)
|
||||||
|
prefix = " in ";
|
||||||
|
else
|
||||||
|
desc = "";
|
||||||
|
yyerror("implicit assignment of %T field '%s'%s%s", t, s->name, prefix, desc);
|
||||||
|
goto no;
|
||||||
}
|
}
|
||||||
if(!exportassignok(f->type))
|
if(!exportassignok(f->type, desc))
|
||||||
return 0;
|
goto no;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TARRAY:
|
case TARRAY:
|
||||||
if(t->bound < 0) // slices are pointers; that's fine
|
if(t->bound < 0) // slices are pointers; that's fine
|
||||||
break;
|
break;
|
||||||
if(!exportassignok(t->type))
|
if(!exportassignok(t->type, desc))
|
||||||
return 0;
|
goto no;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
t->trecur = 0;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
no:
|
||||||
|
t->trecur = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1600,6 +1621,7 @@ typecheckcomplit(Node **np)
|
|||||||
Node *l, *n, *hash[101];
|
Node *l, *n, *hash[101];
|
||||||
NodeList *ll;
|
NodeList *ll;
|
||||||
Type *t, *f;
|
Type *t, *f;
|
||||||
|
Sym *s;
|
||||||
|
|
||||||
n = *np;
|
n = *np;
|
||||||
|
|
||||||
@ -1630,11 +1652,11 @@ typecheckcomplit(Node **np)
|
|||||||
}
|
}
|
||||||
typecheck(&l->right, Erv);
|
typecheck(&l->right, Erv);
|
||||||
defaultlit(&l->right, t->type);
|
defaultlit(&l->right, t->type);
|
||||||
l->right = typecheckconv(nil, l->right, t->type, 0);
|
l->right = typecheckconv(nil, l->right, t->type, 0, "array index");
|
||||||
} else {
|
} else {
|
||||||
typecheck(&ll->n, Erv);
|
typecheck(&ll->n, Erv);
|
||||||
defaultlit(&ll->n, t->type);
|
defaultlit(&ll->n, t->type);
|
||||||
ll->n = typecheckconv(nil, ll->n, t->type, 0);
|
ll->n = typecheckconv(nil, ll->n, t->type, 0, "array index");
|
||||||
ll->n = nod(OKEY, nodintconst(i), ll->n);
|
ll->n = nod(OKEY, nodintconst(i), ll->n);
|
||||||
ll->n->left->type = types[TINT];
|
ll->n->left->type = types[TINT];
|
||||||
ll->n->left->typecheck = 1;
|
ll->n->left->typecheck = 1;
|
||||||
@ -1670,8 +1692,8 @@ typecheckcomplit(Node **np)
|
|||||||
typecheck(&l->right, Erv);
|
typecheck(&l->right, Erv);
|
||||||
defaultlit(&l->left, t->down);
|
defaultlit(&l->left, t->down);
|
||||||
defaultlit(&l->right, t->type);
|
defaultlit(&l->right, t->type);
|
||||||
l->left = typecheckconv(nil, l->left, t->down, 0);
|
l->left = typecheckconv(nil, l->left, t->down, 0, "map key");
|
||||||
l->right = typecheckconv(nil, l->right, t->type, 0);
|
l->right = typecheckconv(nil, l->right, t->type, 0, "map value");
|
||||||
keydup(l->left, hash, nelem(hash));
|
keydup(l->left, hash, nelem(hash));
|
||||||
}
|
}
|
||||||
n->op = OMAPLIT;
|
n->op = OMAPLIT;
|
||||||
@ -1689,7 +1711,10 @@ typecheckcomplit(Node **np)
|
|||||||
yyerror("too many values in struct initializer");
|
yyerror("too many values in struct initializer");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ll->n = typecheckconv(nil, ll->n, f->type, 0);
|
s = f->sym;
|
||||||
|
if(s != nil && !exportname(s->name) && strcmp(package, s->package) != 0)
|
||||||
|
yyerror("implicit assignment of %T field '%s' in struct literal", t, s->name);
|
||||||
|
ll->n = typecheckconv(nil, ll->n, f->type, 0, "field value");
|
||||||
ll->n = nod(OKEY, newname(f->sym), ll->n);
|
ll->n = nod(OKEY, newname(f->sym), ll->n);
|
||||||
ll->n->left->typecheck = 1;
|
ll->n->left->typecheck = 1;
|
||||||
f = f->down;
|
f = f->down;
|
||||||
@ -1706,19 +1731,23 @@ typecheckcomplit(Node **np)
|
|||||||
typecheck(&ll->n, Erv);
|
typecheck(&ll->n, Erv);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(l->left->sym == S) {
|
s = l->left->sym;
|
||||||
|
if(s == S) {
|
||||||
yyerror("invalid field name %#N in struct initializer", l->left);
|
yyerror("invalid field name %#N in struct initializer", l->left);
|
||||||
typecheck(&l->right, Erv);
|
typecheck(&l->right, Erv);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
l->left = newname(l->left->sym);
|
l->left = newname(s);
|
||||||
l->left->typecheck = 1;
|
l->left->typecheck = 1;
|
||||||
f = lookdot1(l->left->sym, t, t->type);
|
f = lookdot1(s, t, t->type);
|
||||||
typecheck(&l->right, Erv);
|
typecheck(&l->right, Erv);
|
||||||
if(f == nil)
|
if(f == nil) {
|
||||||
|
yyerror("unknown %T field '%s' in struct literal", t, s->name);
|
||||||
continue;
|
continue;
|
||||||
fielddup(newname(f->sym), hash, nelem(hash));
|
}
|
||||||
l->right = typecheckconv(nil, l->right, f->type, 0);
|
s = f->sym;
|
||||||
|
fielddup(newname(s), hash, nelem(hash));
|
||||||
|
l->right = typecheckconv(nil, l->right, f->type, 0, "field value");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n->op = OSTRUCTLIT;
|
n->op = OSTRUCTLIT;
|
||||||
@ -1879,7 +1908,7 @@ typecheckas(Node *n)
|
|||||||
checkassign(n->left);
|
checkassign(n->left);
|
||||||
typecheck(&n->right, Erv);
|
typecheck(&n->right, Erv);
|
||||||
if(n->left->type != T && n->right && n->right->type != T)
|
if(n->left->type != T && n->right && n->right->type != T)
|
||||||
n->right = typecheckconv(nil, n->right, n->left->type, 0);
|
n->right = typecheckconv(nil, n->right, n->left->type, 0, nil);
|
||||||
if(n->left->defn == n && n->left->ntype == N) {
|
if(n->left->defn == n && n->left->ntype == N) {
|
||||||
defaultlit(&n->right, T);
|
defaultlit(&n->right, T);
|
||||||
n->left->type = n->right->type;
|
n->left->type = n->right->type;
|
||||||
@ -1919,7 +1948,7 @@ typecheckas2(Node *n)
|
|||||||
// easy
|
// easy
|
||||||
for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) {
|
for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) {
|
||||||
if(ll->n->type != T && lr->n->type != T)
|
if(ll->n->type != T && lr->n->type != T)
|
||||||
lr->n = typecheckconv(nil, lr->n, ll->n->type, 0);
|
lr->n = typecheckconv(nil, lr->n, ll->n->type, 0, nil);
|
||||||
if(ll->n->defn == n && ll->n->ntype == N) {
|
if(ll->n->defn == n && ll->n->ntype == N) {
|
||||||
defaultlit(&lr->n, T);
|
defaultlit(&lr->n, T);
|
||||||
ll->n->type = lr->n->type;
|
ll->n->type = lr->n->type;
|
||||||
@ -1937,9 +1966,9 @@ typecheckas2(Node *n)
|
|||||||
if(l->type == T)
|
if(l->type == T)
|
||||||
goto out;
|
goto out;
|
||||||
n->op = OAS2MAPW;
|
n->op = OAS2MAPW;
|
||||||
n->rlist->n = typecheckconv(nil, r, l->type->down, 0);
|
n->rlist->n = typecheckconv(nil, r, l->type->down, 0, nil);
|
||||||
r = n->rlist->next->n;
|
r = n->rlist->next->n;
|
||||||
n->rlist->next->n = typecheckconv(nil, r, types[TBOOL], 0);
|
n->rlist->next->n = typecheckconv(nil, r, types[TBOOL], 0, nil);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1960,7 +1989,7 @@ typecheckas2(Node *n)
|
|||||||
t = structfirst(&s, &r->type);
|
t = structfirst(&s, &r->type);
|
||||||
for(ll=n->list; ll; ll=ll->next) {
|
for(ll=n->list; ll; ll=ll->next) {
|
||||||
if(ll->n->type != T)
|
if(ll->n->type != T)
|
||||||
if(checkconv(t->type, ll->n->type, 0, &op, &et) < 0)
|
if(checkconv(t->type, ll->n->type, 0, &op, &et, nil) < 0)
|
||||||
yyerror("cannot assign type %T to %+N", t->type, ll->n);
|
yyerror("cannot assign type %T to %+N", t->type, ll->n);
|
||||||
if(ll->n->defn == n && ll->n->ntype == N)
|
if(ll->n->defn == n && ll->n->ntype == N)
|
||||||
ll->n->type = t->type;
|
ll->n->type = t->type;
|
||||||
@ -1984,12 +2013,12 @@ typecheckas2(Node *n)
|
|||||||
case ODOTTYPE:
|
case ODOTTYPE:
|
||||||
n->op = OAS2DOTTYPE;
|
n->op = OAS2DOTTYPE;
|
||||||
common:
|
common:
|
||||||
if(l->type != T && checkconv(r->type, l->type, 0, &op, &et) < 0)
|
if(l->type != T && checkconv(r->type, l->type, 0, &op, &et, nil) < 0)
|
||||||
yyerror("cannot assign %+N to %+N", r, l);
|
yyerror("cannot assign %+N to %+N", r, l);
|
||||||
if(l->defn == n)
|
if(l->defn == n)
|
||||||
l->type = r->type;
|
l->type = r->type;
|
||||||
l = n->list->next->n;
|
l = n->list->next->n;
|
||||||
if(l->type != T && checkconv(types[TBOOL], l->type, 0, &op, &et) < 0)
|
if(l->type != T && checkconv(types[TBOOL], l->type, 0, &op, &et, nil) < 0)
|
||||||
yyerror("cannot assign bool value to %+N", l);
|
yyerror("cannot assign bool value to %+N", l);
|
||||||
if(l->defn == n && l->ntype == N)
|
if(l->defn == n && l->ntype == N)
|
||||||
l->type = types[TBOOL];
|
l->type = types[TBOOL];
|
||||||
|
@ -1922,7 +1922,7 @@ vmatch1(Node *l, Node *r)
|
|||||||
/*
|
/*
|
||||||
* isolate all left sides
|
* isolate all left sides
|
||||||
*/
|
*/
|
||||||
if(l == N)
|
if(l == N || r == N)
|
||||||
return 0;
|
return 0;
|
||||||
switch(l->op) {
|
switch(l->op) {
|
||||||
case ONAME:
|
case ONAME:
|
||||||
|
@ -599,8 +599,13 @@ ieeedtof(Ieee *e)
|
|||||||
exp++;
|
exp++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(exp <= -126 || exp >= 130)
|
if(-148 <= exp && exp <= -126) {
|
||||||
diag("double fp to single fp overflow");
|
v |= 1<<23;
|
||||||
|
v >>= -125 - exp;
|
||||||
|
exp = -126;
|
||||||
|
}
|
||||||
|
else if(exp < -148 || exp >= 130)
|
||||||
|
diag("double fp to single fp overflow: %.17g", ieeedtod(e));
|
||||||
v |= ((exp + 126) & 0xffL) << 23;
|
v |= ((exp + 126) & 0xffL) << 23;
|
||||||
v |= e->h & 0x80000000L;
|
v |= e->h & 0x80000000L;
|
||||||
return v;
|
return v;
|
||||||
@ -620,14 +625,18 @@ ieeedtod(Ieee *ieeep)
|
|||||||
}
|
}
|
||||||
if(ieeep->l == 0 && ieeep->h == 0)
|
if(ieeep->l == 0 && ieeep->h == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
exp = (ieeep->h>>20) & ((1L<<11)-1L);
|
||||||
|
exp -= (1L<<10) - 2L;
|
||||||
fr = ieeep->l & ((1L<<16)-1L);
|
fr = ieeep->l & ((1L<<16)-1L);
|
||||||
fr /= 1L<<16;
|
fr /= 1L<<16;
|
||||||
fr += (ieeep->l>>16) & ((1L<<16)-1L);
|
fr += (ieeep->l>>16) & ((1L<<16)-1L);
|
||||||
fr /= 1L<<16;
|
fr /= 1L<<16;
|
||||||
fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
|
if(exp == -(1L<<10) - 2L) {
|
||||||
|
fr += (ieeep->h & (1L<<20)-1L);
|
||||||
|
exp++;
|
||||||
|
} else
|
||||||
|
fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
|
||||||
fr /= 1L<<21;
|
fr /= 1L<<21;
|
||||||
exp = (ieeep->h>>20) & ((1L<<11)-1L);
|
|
||||||
exp -= (1L<<10) - 2L;
|
|
||||||
return ldexp(fr, exp);
|
return ldexp(fr, exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package math_test
|
package math_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt";
|
||||||
. "math";
|
. "math";
|
||||||
"testing";
|
"testing";
|
||||||
)
|
)
|
||||||
@ -272,3 +273,29 @@ func TestHypot(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that math constants are accepted by compiler
|
||||||
|
// and have right value (assumes strconv.Atof works).
|
||||||
|
// http://code.google.com/p/go/issues/detail?id=201
|
||||||
|
|
||||||
|
type floatTest struct {
|
||||||
|
val interface{};
|
||||||
|
name string;
|
||||||
|
str string;
|
||||||
|
}
|
||||||
|
|
||||||
|
var floatTests = []floatTest{
|
||||||
|
floatTest{float64(MaxFloat64), "MaxFloat64", "1.7976931348623157e+308"},
|
||||||
|
floatTest{float64(MinFloat64), "MinFloat64", "5e-324"},
|
||||||
|
floatTest{float32(MaxFloat32), "MaxFloat32", "3.4028235e+38"},
|
||||||
|
floatTest{float32(MinFloat32), "MinFloat32", "1e-45"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFloatMinMax(t *testing.T) {
|
||||||
|
for _, tt := range floatTests {
|
||||||
|
s := fmt.Sprint(tt.val);
|
||||||
|
if s != tt.str {
|
||||||
|
t.Errorf("Sprint(%v) = %s, want %s", tt.name, s, tt.str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// errchk $G $D/$F.go
|
// errchk $G -e $D/$F.go
|
||||||
|
|
||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
@ -34,4 +34,12 @@ func main() {
|
|||||||
x = y; // ERROR "assignment.*Mutex"
|
x = y; // ERROR "assignment.*Mutex"
|
||||||
_ = x;
|
_ = x;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
x := sync.Mutex{0, 0}; // ERROR "assignment.*Mutex"
|
||||||
|
_ = x;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
x := sync.Mutex{key: 0}; // ERROR "(unknown|assignment).*Mutex"
|
||||||
|
_ = x;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
15
test/fixedbugs/bug214.go
Normal file
15
test/fixedbugs/bug214.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// $G $D/$F.go || echo BUG: bug214
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Used to crash the compiler.
|
||||||
|
// http://code.google.com/p/go/issues/detail?id=88
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
x := make(map[int]int, 10);
|
||||||
|
x[0], x[1] = 2, 6;
|
||||||
|
}
|
16
test/fixedbugs/bug215.go
Normal file
16
test/fixedbugs/bug215.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// errchk $G $D/$F.go
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Used to crash the compiler.
|
||||||
|
// http://code.google.com/p/go/issues/detail?id=158
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
type A struct {
|
||||||
|
a A;
|
||||||
|
} // ERROR "recursive"
|
||||||
|
func foo() { new(A).bar() }
|
||||||
|
func (a A) bar() {}
|
20
test/fixedbugs/bug216.go
Normal file
20
test/fixedbugs/bug216.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// $G $D/$F.go || echo BUG: bug216
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Used to be rejected
|
||||||
|
// http://code.google.com/p/go/issues/detail?id=188
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func complexSqrt(i int) (int, int) { return 0, 1 }
|
||||||
|
|
||||||
|
var re, im = complexSqrt(-1)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if re != 0 || im != 1 {
|
||||||
|
println("BUG: bug216: want 0,-1 have ", re, im)
|
||||||
|
}
|
||||||
|
}
|
15
test/fixedbugs/bug217.go
Normal file
15
test/fixedbugs/bug217.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// errchk $G $D/$F.go
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Used to crash
|
||||||
|
// http://code.google.com/p/go/issues/detail?id=204
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func () x() // ERROR "no receiver"
|
||||||
|
|
||||||
|
func (a b, c d) x() // ERROR "multiple receiver"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user