aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eval.c11
-rw-r--r--test/initializer-pointer-int-cast.c2
-rw-r--r--test/initializer-pointer-int-cast.qbe2
3 files changed, 13 insertions, 2 deletions
diff --git a/eval.c b/eval.c
index c4974b8..48053c4 100644
--- a/eval.c
+++ b/eval.c
@@ -137,8 +137,15 @@ eval(struct expr *expr, enum evalkind kind)
else
expr->constant = l->constant;
cast(expr);
- } else if (l->type->kind == TYPEPOINTER && expr->type->kind == TYPEPOINTER) {
- expr = l;
+ } else if (l->type->kind == TYPEPOINTER) {
+ /*
+ A cast from a pointer to integer is not a valid constant
+ expression, but C11 allows implementations to recognize
+ other forms of constant expressions (6.6p10), and some
+ programs expect this functionality.
+ */
+ if (expr->type->kind == TYPEPOINTER || expr->type->prop & PROPINT && expr->type->size == typelong.size)
+ expr = l;
}
break;
case EXPRBINARY:
diff --git a/test/initializer-pointer-int-cast.c b/test/initializer-pointer-int-cast.c
new file mode 100644
index 0000000..75963b2
--- /dev/null
+++ b/test/initializer-pointer-int-cast.c
@@ -0,0 +1,2 @@
+int x;
+long p = (long)&x;
diff --git a/test/initializer-pointer-int-cast.qbe b/test/initializer-pointer-int-cast.qbe
new file mode 100644
index 0000000..a996882
--- /dev/null
+++ b/test/initializer-pointer-int-cast.qbe
@@ -0,0 +1,2 @@
+export data $p = align 8 { l $x, }
+export data $x = align 4 { z 4 }