summaryrefslogtreecommitdiff
path: root/src/cmd/gc/const.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/const.c')
-rw-r--r--src/cmd/gc/const.c134
1 files changed, 130 insertions, 4 deletions
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index f82ba9420..83e62bde1 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -78,6 +78,7 @@ convlit1(Node **np, Type *t, int explicit)
if(!explicit && !isideal(n->type))
return;
+
if(n->op == OLITERAL) {
nn = nod(OXXX, N, N);
*nn = *n;
@@ -953,10 +954,6 @@ ret:
*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.
@@ -1449,3 +1446,132 @@ cmplxdiv(Mpcplx *v, Mpcplx *rv)
mpsubfltflt(&v->imag, &ad); // bc-ad
mpdivfltflt(&v->imag, &cc_plus_dd); // (bc+ad)/(cc+dd)
}
+
+static int hascallchan(Node*);
+
+// Is n a Go language constant (as opposed to a compile-time constant)?
+// Expressions derived from nil, like string([]byte(nil)), while they
+// may be known at compile time, are not Go language constants.
+// Only called for expressions known to evaluated to compile-time
+// constants.
+int
+isgoconst(Node *n)
+{
+ Node *l;
+ Type *t;
+
+ if(n->orig != N)
+ n = n->orig;
+
+ switch(n->op) {
+ case OADD:
+ case OADDSTR:
+ case OAND:
+ case OANDAND:
+ case OANDNOT:
+ case OCOM:
+ case ODIV:
+ case OEQ:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OLSH:
+ case OLT:
+ case OMINUS:
+ case OMOD:
+ case OMUL:
+ case ONE:
+ case ONOT:
+ case OOR:
+ case OOROR:
+ case OPLUS:
+ case ORSH:
+ case OSUB:
+ case OXOR:
+ case OCONV:
+ case OIOTA:
+ case OCOMPLEX:
+ case OREAL:
+ case OIMAG:
+ if(isgoconst(n->left) && (n->right == N || isgoconst(n->right)))
+ return 1;
+ break;
+
+ case OLEN:
+ case OCAP:
+ l = n->left;
+ if(isgoconst(l))
+ return 1;
+ // Special case: len/cap is constant when applied to array or
+ // pointer to array when the expression does not contain
+ // function calls or channel receive operations.
+ t = l->type;
+ if(t != T && isptr[t->etype])
+ t = t->type;
+ if(isfixedarray(t) && !hascallchan(l))
+ return 1;
+ break;
+
+ case OLITERAL:
+ if(n->val.ctype != CTNIL)
+ return 1;
+ break;
+
+ case ONAME:
+ l = n->sym->def;
+ if(l->op == OLITERAL && n->val.ctype != CTNIL)
+ return 1;
+ break;
+
+ case ONONAME:
+ if(n->sym->def != N && n->sym->def->op == OIOTA)
+ return 1;
+ break;
+
+ case OCALL:
+ // Only constant calls are unsafe.Alignof, Offsetof, and Sizeof.
+ l = n->left;
+ while(l->op == OPAREN)
+ l = l->left;
+ if(l->op != ONAME || l->sym->pkg != unsafepkg)
+ break;
+ if(strcmp(l->sym->name, "Alignof") == 0 ||
+ strcmp(l->sym->name, "Offsetof") == 0 ||
+ strcmp(l->sym->name, "Sizeof") == 0)
+ return 1;
+ break;
+ }
+
+ //dump("nonconst", n);
+ return 0;
+}
+
+static int
+hascallchan(Node *n)
+{
+ NodeList *l;
+
+ if(n == N)
+ return 0;
+ switch(n->op) {
+ case OCALL:
+ case OCALLFUNC:
+ case OCALLMETH:
+ case OCALLINTER:
+ case ORECV:
+ return 1;
+ }
+
+ if(hascallchan(n->left) ||
+ hascallchan(n->right))
+ return 1;
+
+ for(l=n->list; l; l=l->next)
+ if(hascallchan(l->n))
+ return 1;
+ for(l=n->rlist; l; l=l->next)
+ if(hascallchan(l->n))
+ return 1;
+
+ return 0;
+}