return t == ct || (ct == CTINT && t == CTRUNE);
}
+static Node*
+saveorig(Node *n)
+{
+ Node *n1;
+
+ if(n == n->orig) {
+ // duplicate node for n->orig.
+ n1 = nod(OLITERAL, N, N);
+ n->orig = n1;
+ *n1 = *n;
+ }
+ return n->orig;
+}
+
/*
* if n is constant, rewrite as OLITERAL node.
*/
}
ret:
- if(n == n->orig) {
- // duplicate node for n->orig.
- norig = nod(OLITERAL, N, N);
- *norig = *n;
- } else
- norig = n->orig;
+ norig = saveorig(n);
*n = *nl;
// restore value of n->orig.
n->orig = norig;
+ if(norig->op == OCONV) {
+ dump("N", n);
+ dump("NORIG", norig);
+ }
n->val = v;
// check range.
return;
settrue:
+ norig = saveorig(n);
*n = *nodbool(1);
+ n->orig = norig;
return;
setfalse:
+ norig = saveorig(n);
*n = *nodbool(0);
+ n->orig = norig;
return;
}
case CTCPLX:
if((fp->flags & FmtSharp) || fmtmode == FExp)
return fmtprint(fp, "(%F+%Fi)", &v->u.cval->real, &v->u.cval->imag);
- return fmtprint(fp, "(%#F + %#Fi)", &v->u.cval->real, &v->u.cval->imag);
+ if(mpcmpfltc(&v->u.cval->real, 0) == 0)
+ return fmtprint(fp, "%#Fi", &v->u.cval->imag);
+ if(mpcmpfltc(&v->u.cval->imag, 0) == 0)
+ return fmtprint(fp, "%#F", &v->u.cval->real);
+ if(mpcmpfltc(&v->u.cval->imag, 0) < 0)
+ return fmtprint(fp, "(%#F%#Fi)", &v->u.cval->real, &v->u.cval->imag);
+ return fmtprint(fp, "(%#F+%#Fi)", &v->u.cval->real, &v->u.cval->imag);
case CTSTR:
return fmtprint(fp, "\"%Z\"", v->u.sval);
case CTBOOL:
case CTNIL:
return fmtstrcpy(fp, "nil");
}
- return fmtprint(fp, "<%d>", v->ctype);
+ return fmtprint(fp, "<ctype=%d>", v->ctype);
}
// Fmt "%Z": escaped string literals
case OLITERAL: // this is a bit of a mess
if(fmtmode == FErr && n->sym != S)
return fmtprint(f, "%S", n->sym);
- if(n->val.ctype == CTNIL && n->orig != N)
- n = n->orig; // if this node was a nil decorated with at type, print the original naked nil
+ if(n->val.ctype == CTNIL && n->orig != N && n->orig != n)
+ return exprfmt(f, n->orig, prec);
if(n->type != T && n->type != types[n->type->etype] && n->type != idealbool && n->type != idealstring) {
// Need parens when type begins with what might
// be misinterpreted as a unary operator: * or <-.
static void checkassignlist(NodeList*);
static void stringtoarraylit(Node**);
static Node* resolve(Node*);
+static void checkdefergo(Node*);
static NodeList* typecheckdefstack;
if(!iscomplex[t->etype])
goto badcall1;
if(isconst(l, CTCPLX)){
+ r = n;
if(n->op == OREAL)
n = nodfltconst(&l->val.u.cval->real);
else
n = nodfltconst(&l->val.u.cval->imag);
+ n->orig = r;
}
n->type = types[cplxsubtype(t->etype)];
goto ret;
}
if(l->op == OLITERAL && r->op == OLITERAL) {
// make it a complex literal
- n = nodcplxlit(l->val, r->val);
+ r = nodcplxlit(l->val, r->val);
+ r->orig = n;
+ n = r;
}
n->type = t;
goto ret;
switch(n->op) {
case OCONVNOP:
if(n->left->op == OLITERAL) {
+ r = nod(OXXX, N, N);
+ n->op = OCONV;
+ n->orig = r;
+ *r = *n;
n->op = OLITERAL;
n->val = n->left->val;
}
case ODEFER:
ok |= Etop;
- typecheck(&n->left, Etop);
+ typecheck(&n->left, Etop|Erv);
+ if(!n->left->diag)
+ checkdefergo(n);
goto ret;
case OPROC:
ok |= Etop;
- typecheck(&n->left, Etop|Eproc);
+ typecheck(&n->left, Etop|Eproc|Erv);
+ checkdefergo(n);
goto ret;
case OFOR:
}
if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) {
if(n->diag == 0) {
- yyerror("%N not used", n);
+ yyerror("%N evaluated but not used", n);
n->diag = 1;
}
goto error;
*np = n;
}
+static void
+checkdefergo(Node *n)
+{
+ char *what;
+
+ what = "defer";
+ if(n->op == OPROC)
+ what = "go";
+
+ switch(n->left->op) {
+ case OCALLINTER:
+ case OCALLMETH:
+ case OCALLFUNC:
+ case OCLOSE:
+ case OCOPY:
+ case ODELETE:
+ case OPANIC:
+ case OPRINT:
+ case OPRINTN:
+ case ORECOVER:
+ // ok
+ break;
+ case OAPPEND:
+ case OCAP:
+ case OCOMPLEX:
+ case OIMAG:
+ case OLEN:
+ case OMAKE:
+ case OMAKESLICE:
+ case OMAKECHAN:
+ case OMAKEMAP:
+ case ONEW:
+ case OREAL:
+ case OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
+ if(n->left->orig != N && n->left->orig->op == OCONV)
+ goto conv;
+ yyerror("%s discards result of %N", what, n->left);
+ break;
+ default:
+ conv:
+ if(!n->diag) {
+ // The syntax made sure it was a call, so this must be
+ // a conversion.
+ n->diag = 1;
+ yyerror("%s requires function call, not conversion", what);
+ }
+ break;
+ }
+}
+
static void
implicitstar(Node **nn)
{
(println("bar"))
(recover())
- go append(a, 0) // ERROR "not used"
- go cap(a) // ERROR "not used"
- go complex(1, 2) // ERROR "not used"
- go imag(1i) // ERROR "not used"
- go len(a) // ERROR "not used"
- go make([]int, 10) // ERROR "not used"
- go new(int) // ERROR "not used"
- go real(1i) // ERROR "not used"
- go unsafe.Alignof(a) // ERROR "not used"
- go unsafe.Offsetof(s.f) // ERROR "not used"
- go unsafe.Sizeof(a) // ERROR "not used"
+ go append(a, 0) // ERROR "discards result"
+ go cap(a) // ERROR "discards result"
+ go complex(1, 2) // ERROR "discards result"
+ go imag(1i) // ERROR "discards result"
+ go len(a) // ERROR "discards result"
+ go make([]int, 10) // ERROR "discards result"
+ go new(int) // ERROR "discards result"
+ go real(1i) // ERROR "discards result"
+ go unsafe.Alignof(a) // ERROR "discards result"
+ go unsafe.Offsetof(s.f) // ERROR "discards result"
+ go unsafe.Sizeof(a) // ERROR "discards result"
go close(c)
go copy(a, a)
go println("bar")
go recover()
- defer append(a, 0) // ERROR "not used"
- defer cap(a) // ERROR "not used"
- defer complex(1, 2) // ERROR "not used"
- defer imag(1i) // ERROR "not used"
- defer len(a) // ERROR "not used"
- defer make([]int, 10) // ERROR "not used"
- defer new(int) // ERROR "not used"
- defer real(1i) // ERROR "not used"
- defer unsafe.Alignof(a) // ERROR "not used"
- defer unsafe.Offsetof(s.f) // ERROR "not used"
- defer unsafe.Sizeof(a) // ERROR "not used"
+ defer append(a, 0) // ERROR "discards result"
+ defer cap(a) // ERROR "discards result"
+ defer complex(1, 2) // ERROR "discards result"
+ defer imag(1i) // ERROR "discards result"
+ defer len(a) // ERROR "discards result"
+ defer make([]int, 10) // ERROR "discards result"
+ defer new(int) // ERROR "discards result"
+ defer real(1i) // ERROR "discards result"
+ defer unsafe.Alignof(a) // ERROR "discards result"
+ defer unsafe.Offsetof(s.f) // ERROR "discards result"
+ defer unsafe.Sizeof(a) // ERROR "discards result"
defer close(c)
defer copy(a, a)
--- /dev/null
+// errorcheck
+
+// 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.
+
+// Issue 4654.
+// Check error for conversion and 'not used' in defer/go.
+
+package p
+
+import "unsafe"
+
+func f() {
+ defer int(0) // ERROR "defer requires function call, not conversion"
+ go string([]byte("abc")) // ERROR "go requires function call, not conversion"
+
+ var c complex128
+ var f float64
+ var t struct {X int}
+
+ var x []int
+ defer append(x, 1) // ERROR "defer discards result of append"
+ defer cap(x) // ERROR "defer discards result of cap"
+ defer complex(1, 2) // ERROR "defer discards result of complex"
+ defer complex(f, 1) // ERROR "defer discards result of complex"
+ defer imag(1i) // ERROR "defer discards result of imag"
+ defer imag(c) // ERROR "defer discards result of imag"
+ defer len(x) // ERROR "defer discards result of len"
+ defer make([]int, 1) // ERROR "defer discards result of make"
+ defer make(chan bool) // ERROR "defer discards result of make"
+ defer make(map[string]int) // ERROR "defer discards result of make"
+ defer new(int) // ERROR "defer discards result of new"
+ defer real(1i) // ERROR "defer discards result of real"
+ defer real(c) // ERROR "defer discards result of real"
+ defer append(x, 1) // ERROR "defer discards result of append"
+ defer append(x, 1) // ERROR "defer discards result of append"
+ defer unsafe.Alignof(t.X) // ERROR "defer discards result of unsafe.Alignof"
+ defer unsafe.Offsetof(t.X) // ERROR "defer discards result of unsafe.Offsetof"
+ defer unsafe.Sizeof(t) // ERROR "defer discards result of unsafe.Sizeof"
+
+ defer copy(x, x) // ok
+ m := make(map[int]int)
+ defer delete(m, 1) // ok
+ defer panic(1) // ok
+ defer print(1) // ok
+ defer println(1) // ok
+ defer recover() // ok
+
+ int(0) // ERROR "int\(0\) not used"
+ string([]byte("abc")) // ERROR "string\(\[\]byte literal\) not used"
+
+ append(x, 1) // ERROR "not used"
+ cap(x) // ERROR "not used"
+ complex(1, 2) // ERROR "not used"
+ complex(f, 1) // ERROR "not used"
+ imag(1i) // ERROR "not used"
+ imag(c) // ERROR "not used"
+ len(x) // ERROR "not used"
+ make([]int, 1) // ERROR "not used"
+ make(chan bool) // ERROR "not used"
+ make(map[string]int) // ERROR "not used"
+ new(int) // ERROR "not used"
+ real(1i) // ERROR "not used"
+ real(c) // ERROR "not used"
+ append(x, 1) // ERROR "not used"
+ append(x, 1) // ERROR "not used"
+ unsafe.Alignof(t.X) // ERROR "not used"
+ unsafe.Offsetof(t.X) // ERROR "not used"
+ unsafe.Sizeof(t) // ERROR "not used"
+}