aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--c/c.c44
-rw-r--r--c/eval.c35
-rw-r--r--test/17-misc.c13
3 files changed, 62 insertions, 30 deletions
diff --git a/c/c.c b/c/c.c
index 87087e7..c7a6eac 100644
--- a/c/c.c
+++ b/c/c.c
@@ -476,17 +476,23 @@ subscriptcheck(const struct expr *ex, const struct expr *rhs, const struct span
return ty;
}
-static void /* 6.5.3.4 The sizeof and _Alignof operators */
+static uint /* 6.5.3.4 The sizeof and _Alignof operators */
sizeofalignofcheck(const struct span *span, enum toktag tt, union type ty, const struct expr *ex)
{
- if (isincomplete(ty))
+ uint r = (tt == TKWsizeof ? typesize : typealign)(ty);
+ if (ty.t == TYVOID) {
+ if (ccopt.pedant) warn(span, "applying %'tt to void type", tt);
+ r = 1;
+ } else if (isincomplete(ty)) {
error(span, "cannot apply %'tt to incomplete type '%ty'", tt, ty);
- else if (ty.t == TYFUNC)
+ } else if (ty.t == TYFUNC) {
error(span, "cannot apply %'tt to function type '%ty'", tt, ty);
- else if (tt == TKWsizeof && ex && ex->t == EGETF && ex->fld.bitsiz)
+ } else if (tt == TKWsizeof && ex && ex->t == EGETF && ex->fld.bitsiz) {
error(span, "cannot apply %'tt to bitfield", tt);
+ }
if (tt != TKWsizeof && ex && ccopt.pedant)
warn(span, "%'tt applied to an expression is a GNU extension", tt);
+ return r;
}
static bool /* 6.5.8 Relational operators */
@@ -506,9 +512,11 @@ static bool
isnullpo(const struct expr *ex) /* match '0' or '(void *) 0' */
{
static const union type voidptr = {{ TYPTR, .flag = TFCHLDPRIM, .child = TYVOID }};
- if (ex->t == ECAST && ex->ty.bits == voidptr.bits)
+ while (ex->t == ECAST && ex->ty.bits == voidptr.bits)
ex = ex->sub;
- return iszero(*ex);
+ if (iszero(*ex)) return 1;
+ return eval((struct expr *)ex, EVINTCONST) /* GNU extension. should we warn? */
+ && iszero(*ex);
}
static bool /* 6.5.9 Equality operators */
@@ -531,14 +539,14 @@ condtype(const struct expr *a, const struct expr *b)
union type t1 = typedecay(a->ty), t2 = typedecay(b->ty), s1, s2;
if (isarith(t1) && isarith(t2)) return cvtarith(t1, t2);
if (t1.bits == t2.bits) return t1;
+ if (t1.t == TYPTR && isnullpo(b)) return t1;
+ if (isnullpo(a) && t2.t == TYPTR) return t2;
if (t1.t == TYPTR && t2.t == TYPTR) {
s1 = typechild(t1), s2 = typechild(t2);
if (s1.bits == s2.bits || s2.t == TYVOID || s1.t == TYVOID) {
return mkptrtype(s1.t == TYVOID ? s1 : s2, (t1.flag | t2.flag) & TFCHLDQUAL);
}
}
- if (t1.t == TYPTR && isnullpo(b)) return t1;
- if (isnullpo(a) && t2.t == TYPTR) return t2;
return mktype(0);
}
@@ -1114,30 +1122,30 @@ Unary:
ex = mkexpr(ESYM, tk.span, decl->ty, .qual = decl->qual, .decl = decl - declsbuf.p);
}
break; }
- case TKWsizeof: case TKW_Alignof: case TKWalignof:
+ case TKWsizeof: case TKW_Alignof: case TKWalignof: {
+ enum toktag tt = tk.t;
+ uint res;
span = tk.span;
if (!match(cm, NULL, '(')) /* sizeof/alignof expr */
goto Unops;
else if (isdecltok(cm)) { /* sizeof/alignof (type) */
- enum toktag tt = tk.t;
struct declstate st = { DCASTEXPR };
ty = pdecl(&st, cm).ty;
peek(cm, &tk);
if (expect(cm, ')', NULL))
joinspan(&span.ex, tk.span.ex);
- sizeofalignofcheck(&span, tt, ty, NULL);
+ res = sizeofalignofcheck(&span, tt, ty, NULL);
} else { /* sizeof/alignof expr */
- enum toktag tt = tk.t;
struct expr tmp = commaexpr(cm);
peek(cm, &tk);
if (expect(cm, ')', NULL))
joinspan(&span.ex, tk.span.ex);
ppostfixopers(cm, &tmp);
ty = tmp.ty;
- sizeofalignofcheck(&span, tt, ty, &tmp);
+ res = sizeofalignofcheck(&span, tt, ty, &tmp);
}
- ex = mkexpr(ENUMLIT, span, mktype(targ_sizetype), .u = typesize(ty));
- break;
+ ex = mkexpr(ENUMLIT, span, mktype(targ_sizetype), .u = res);
+ break; }
case TKW__builtin_va_arg:
span = tk.span;
ex = vaargexpr(cm, &span);
@@ -1187,7 +1195,7 @@ Unary:
case '*':
if (ex.ty.t == TYPTR || ex.ty.t == TYARRAY) {
ty = typechild(ex.ty);
- if (isincomplete(typedecay(ty))) {
+ if (ty.t != TYVOID && isincomplete(typedecay(ty))) {
error(&span, "cannot dereference pointer to incomplete type '%ty'", ty);
ty = mktype(TYINT);
}
@@ -1206,8 +1214,8 @@ Unary:
ex = mkexpr(EADDROF, span, mkptrtype(ex.ty, ex.qual), .sub = exprdup(cm, &ex));
break;
case TKWsizeof: case TKW_Alignof: case TKWalignof:
- sizeofalignofcheck(&span, unops[nunop].tt, ex.ty, &ex);
- ex = mkexpr(ENUMLIT, span, mktype(targ_sizetype), .u = typesize(ex.ty));
+ ex = mkexpr(ENUMLIT, span, mktype(targ_sizetype),
+ .u = sizeofalignofcheck(&span, unops[nunop].tt, ex.ty, &ex));
break;
default: assert(0);
}
diff --git a/c/eval.c b/c/eval.c
index e2d67d7..839ff7a 100644
--- a/c/eval.c
+++ b/c/eval.c
@@ -215,15 +215,16 @@ binop(struct expr *ex, enum evalmode mode)
if (ex->ty.t == TYPTR) mode = EVFOLD;
if (!eval(lhs, mode)) return 0;
- if (!eval(rhs, mode)) return 0;
if (in_range(ex->t, EADD, ESHR))
oty = ex->ty;
else
oty = cvtarith(lhs->ty, rhs->ty);
- if (!numcast(oty, lhs, lhs)) return 0;
- if (!numcast(oty, rhs, rhs)) return 0;
flt = isflt(oty);
sgn = issigned(oty);
+ if (ex->t != ELOGAND && ex->t != ELOGIOR) {
+ if (!numcast(oty, lhs, lhs)) return 0;
+ if (!eval(rhs, mode) || !numcast(oty, rhs, rhs)) return 0;
+ }
switch (ex->t) {
#define ef else if
case EADD: if (flt) lhs->f += rhs->f;
@@ -264,14 +265,6 @@ binop(struct expr *ex, enum evalmode mode)
ef (sgn) lhs->i >>= rhs->i;
else lhs->u >>= rhs->u;
break;
- case ELOGAND: if (flt) t = lhs->f && rhs->f;
- else t = lhs->u && rhs->u;
- lhs->u = t;
- break;
- case ELOGIOR: if (flt) t = lhs->f || rhs->f;
- else t = lhs->u || rhs->u;
- lhs->u = t;
- break;
case EEQU: if (flt) t = lhs->f == rhs->f;
else t = lhs->u == rhs->u;
lhs->u = t;
@@ -300,12 +293,30 @@ binop(struct expr *ex, enum evalmode mode)
else t = lhs->u >= rhs->u;
lhs->u = t;
break;
+ case ELOGAND: if (flt) t = lhs->f; else t = lhs->u;
+ if (t) {
+ if (!eval(rhs, mode) || !numcast(oty, rhs, rhs)) return 0;
+ if (flt) t = t && lhs->f;
+ else t = t && lhs->u;
+ }
+ lhs->u = t;
+ break;
+ case ELOGIOR: if (flt) t = lhs->f; else t = lhs->u;
+ if (!t) {
+ if (!eval(rhs, mode) || !numcast(oty, rhs, rhs)) return 0;
+ if (flt) t = t || lhs->f;
+ else t = t || lhs->u;
+ }
+ lhs->u = t;
+ break;
default: return 0;
#undef ef
}
- if (!in_range(ex->t, EADD, ESHR))
+ if (!in_range(ex->t, EADD, ESHR)) {
+ lhs->t = ENUMLIT;
lhs->ty = mktype(TYINT);
+ }
return numcast(ex->ty, ex, lhs);
}
diff --git a/test/17-misc.c b/test/17-misc.c
index ecff06c..521b948 100644
--- a/test/17-misc.c
+++ b/test/17-misc.c
@@ -13,6 +13,19 @@ int fn1(uvlong p_9) {
return q;
}
+/* Excerpt from linux/kernel.h */
+/*
+ * This returns a constant expression while determining if an argument is
+ * a constant expression, most importantly without evaluating the argument.
+ * Glory to Martin Uecker <Martin.Uecker@med.uni-goettingen.de>
+ */
+#define __is_constexpr(x) \
+ (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))
+
+_Static_assert(__is_constexpr(5 &&(1<<3) || 0/0), "");
+_Static_assert(!__is_constexpr(5/0), "");
+_Static_assert(!__is_constexpr(fn1(0)), "");
+
extern int printf(const char *, ...);
int main() {
printf("%d\n", fn1(-77ull));