From 07ead54177dbbc28ce0665f0091f6be0940f5763 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Tue, 19 Feb 2019 12:43:29 -0800 Subject: Add missing lvalue conversions typeintpromote and typeargpromote assume they are dealing with an unqualified type, and return an incorrect result if they are given a qualified one. So, add an assert here. This was causing const integer types to get promoted to themselves due to missing lvalue conversions. Thanks to Andrew Chambers for the bug report and test case. --- expr.c | 4 ++++ tests/lvalue-conversion.c | 6 ++++++ tests/lvalue-conversion.qbe | 14 ++++++++++++++ type.c | 2 ++ 4 files changed, 26 insertions(+) create mode 100644 tests/lvalue-conversion.c create mode 100644 tests/lvalue-conversion.qbe diff --git a/expr.c b/expr.c index aad7cbc..46d81e8 100644 --- a/expr.c +++ b/expr.c @@ -473,6 +473,7 @@ postfixexpr(struct scope *s, struct expression *r) if (!p && !t->func.isvararg && t->func.paraminfo) error(&tok.loc, "too many arguments for function call"); *end = assignexpr(s); + lvalueconvert(*end); if (!t->func.isprototype || (t->func.isvararg && !p)) *end = exprconvert(*end, typeargpromote((*end)->type)); else @@ -585,17 +586,20 @@ unaryexpr(struct scope *s) case TADD: next(); e = castexpr(s); + lvalueconvert(e); e = exprconvert(e, typeintpromote(e->type)); break; case TSUB: next(); e = castexpr(s); + lvalueconvert(e); e = exprconvert(e, typeintpromote(e->type)); e = mkbinaryexpr(&tok.loc, TSUB, mkconstexpr(&typeint, 0), e); break; case TBNOT: next(); e = castexpr(s); + lvalueconvert(e); e = exprconvert(e, typeintpromote(e->type)); e = mkbinaryexpr(&tok.loc, TXOR, e, mkconstexpr(e->type, -1)); break; diff --git a/tests/lvalue-conversion.c b/tests/lvalue-conversion.c new file mode 100644 index 0000000..6bbc326 --- /dev/null +++ b/tests/lvalue-conversion.c @@ -0,0 +1,6 @@ +void g(); +void f(void) { + static const unsigned char c = 0; + g(c); + g(~c); +} diff --git a/tests/lvalue-conversion.qbe b/tests/lvalue-conversion.qbe new file mode 100644 index 0000000..ac5fbc3 --- /dev/null +++ b/tests/lvalue-conversion.qbe @@ -0,0 +1,14 @@ +data $.Lc.2 = align 1 { b 0, } +export +function $f() { +@start.1 +@body.2 + %.1 =w loadub $.Lc.2 + %.2 =w extub %.1 + call $g(w %.2) + %.3 =w loadub $.Lc.2 + %.4 =w extub %.3 + %.5 =w xor %.4, 18446744073709551615 + call $g(w %.5) + ret +} diff --git a/type.c b/type.c index 97def21..d5550d3 100644 --- a/type.c +++ b/type.c @@ -237,6 +237,7 @@ typeunqual(struct type *t, enum typequalifier *tq) struct type * typeintpromote(struct type *t) { + assert(t->kind != TYPEQUALIFIED); if (typeprop(t) & PROPINT && typerank(t) <= typerank(&typeint)) return t->size < typeint.size || t->basic.issigned ? &typeint : &typeuint; return t; @@ -245,6 +246,7 @@ typeintpromote(struct type *t) struct type * typeargpromote(struct type *t) { + assert(t->kind != TYPEQUALIFIED); if (t == &typefloat) return &typedouble; return typeintpromote(t); -- cgit v1.2.3