cproc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/cproc
Log | Files | Refs | Submodules | README | LICENSE

commit 07ead54177dbbc28ce0665f0091f6be0940f5763
parent d13019290ee2e7f41369f1d31ce903efd26cfd05
Author: Michael Forney <mforney@mforney.org>
Date:   Tue, 19 Feb 2019 12:43:29 -0800

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.

Diffstat:
Mexpr.c | 4++++
Atests/lvalue-conversion.c | 6++++++
Atests/lvalue-conversion.qbe | 14++++++++++++++
Mtype.c | 2++
4 files changed, 26 insertions(+), 0 deletions(-)

diff --git 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 @@ -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 @@ -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 @@ -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);