diff options
author | Michael Forney <mforney@mforney.org> | 2019-02-19 12:43:29 -0800 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2019-02-19 13:25:27 -0800 |
commit | 07ead54177dbbc28ce0665f0091f6be0940f5763 (patch) | |
tree | ab5c47e87a85c9ed05fb39006f0c9ae59eec7ef2 | |
parent | d13019290ee2e7f41369f1d31ce903efd26cfd05 (diff) |
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.
-rw-r--r-- | expr.c | 4 | ||||
-rw-r--r-- | tests/lvalue-conversion.c | 6 | ||||
-rw-r--r-- | tests/lvalue-conversion.qbe | 14 | ||||
-rw-r--r-- | type.c | 2 |
4 files changed, 26 insertions, 0 deletions
@@ -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 +} @@ -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); |