diff options
| -rw-r--r-- | c/c.c | 44 | ||||
| -rw-r--r-- | c/eval.c | 35 | ||||
| -rw-r--r-- | test/17-misc.c | 13 |
3 files changed, 62 insertions, 30 deletions
@@ -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); } @@ -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)); |