diff options
| author | Michael Forney <mforney@mforney.org> | 2021-10-25 15:59:54 -0700 | 
|---|---|---|
| committer | Michael Forney <mforney@mforney.org> | 2021-10-25 17:01:43 -0700 | 
| commit | e79005956c888e7bafb602df1137f881b34775ec (patch) | |
| tree | 2267161bfb9b9cc5e065691cb75ef9679ca4b5ad | |
| parent | 9540626e5793583b6feb36d025dc640c7cb97cc8 (diff) | |
| download | cproc-e79005956c888e7bafb602df1137f881b34775ec.tar.xz | |
eval: Fix int-to-float conversions
Also, add bounds checks for float-to-int conversions. If the integer
part can't be represented in the result type, C behavior is undefined.
Although this means the result is arbitrary, we need to avoid
undefined behavior in cproc itself when given such a program as
input.
| -rw-r--r-- | eval.c | 28 | ||||
| -rw-r--r-- | test/initializer-cast-float-int.c | 1 | ||||
| -rw-r--r-- | test/initializer-cast-float-int.qbe | 1 | ||||
| -rw-r--r-- | test/initializer-cast-int-float.c | 1 | ||||
| -rw-r--r-- | test/initializer-cast-int-float.qbe | 1 | 
5 files changed, 25 insertions, 7 deletions
| @@ -91,7 +91,9 @@ eval(struct expr *expr, enum evalkind kind)  {  	struct expr *l, *r, *c;  	struct decl *d; +	struct type *t; +	t = expr->type;  	switch (expr->kind) {  	case EXPRIDENT:  		if (expr->ident.decl->kind != DECLCONST) @@ -102,7 +104,7 @@ eval(struct expr *expr, enum evalkind kind)  	case EXPRCOMPOUND:  		if (kind != EVALINIT)  			break; -		d = mkdecl(DECLOBJECT, expr->type, expr->qual, LINKNONE); +		d = mkdecl(DECLOBJECT, t, expr->qual, LINKNONE);  		d->value = mkglobal(NULL, true);  		emitdata(d, expr->compound.init);  		expr->kind = EXPRIDENT; @@ -130,12 +132,24 @@ eval(struct expr *expr, enum evalkind kind)  		l = eval(expr->base, kind);  		if (l->kind == EXPRCONST) {  			expr->kind = EXPRCONST; -			if (l->type->prop & PROPINT && expr->type->prop & PROPFLOAT) -				expr->constant.f = l->constant.u; -			else if (l->type->prop & PROPFLOAT && expr->type->prop & PROPINT) -				expr->constant.u = l->constant.f; -			else +			if (l->type->prop & PROPINT && t->prop & PROPFLOAT) { +				if (l->type->basic.issigned) +					expr->constant.f = l->constant.i; +				else +					expr->constant.f = l->constant.u; +			} else if (l->type->prop & PROPFLOAT && t->prop & PROPINT) { +				if (t->basic.issigned) { +					if (l->constant.f < INT64_MIN || l->constant.f > INT64_MAX) +						error(&tok.loc, "integer part of floating-point constant %g cannot be represented as signed integer", l->constant.f); +					expr->constant.i = l->constant.f; +				} else { +					if (l->constant.f < 0 || l->constant.f > UINT64_MAX) +						error(&tok.loc, "integer part of floating-point constant %g cannot be represented as unsigned integer", l->constant.f); +					expr->constant.u = l->constant.f; +				} +			} else {  				expr->constant = l->constant; +			}  			cast(expr);  		} else if (l->type->kind == TYPEPOINTER) {  			/* @@ -144,7 +158,7 @@ eval(struct expr *expr, enum evalkind kind)  			other forms of constant expressions (6.6p10), and some  			programs expect this functionality.  			*/ -			if (expr->type->kind == TYPEPOINTER || expr->type->prop & PROPINT && expr->type->size == typelong.size) +			if (t->kind == TYPEPOINTER || t->prop & PROPINT && t->size == typelong.size)  				expr = l;  		}  		break; diff --git a/test/initializer-cast-float-int.c b/test/initializer-cast-float-int.c new file mode 100644 index 0000000..42296e9 --- /dev/null +++ b/test/initializer-cast-float-int.c @@ -0,0 +1 @@ +int x = -1.0; diff --git a/test/initializer-cast-float-int.qbe b/test/initializer-cast-float-int.qbe new file mode 100644 index 0000000..675fc96 --- /dev/null +++ b/test/initializer-cast-float-int.qbe @@ -0,0 +1 @@ +export data $x = align 4 { w 18446744073709551615, } diff --git a/test/initializer-cast-int-float.c b/test/initializer-cast-int-float.c new file mode 100644 index 0000000..e041d90 --- /dev/null +++ b/test/initializer-cast-int-float.c @@ -0,0 +1 @@ +double x = -1; diff --git a/test/initializer-cast-int-float.qbe b/test/initializer-cast-int-float.qbe new file mode 100644 index 0000000..80b905e --- /dev/null +++ b/test/initializer-cast-int-float.qbe @@ -0,0 +1 @@ +export data $x = align 8 { d d_-1, } | 
