diff --git a/src/ctfe.h b/src/ctfe.h index 6636047b575d..d5d729080ac1 100644 --- a/src/ctfe.h +++ b/src/ctfe.h @@ -182,6 +182,12 @@ int comparePointers(Loc loc, enum TOK op, Type *type, Expression *agg1, dinteger Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type, Expression *eptr, Expression *e2); +// True if conversion from type 'from' to 'to' involves a reinterpret_cast +// floating point -> integer or integer -> floating point +bool isFloatIntPaint(Type *to, Type *from); + +// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'. +Expression *paintFloatInt(Expression *fromVal, Type *to); /// Return true if t is an AA, or AssociativeArray!(key, value) bool isAssocArray(Type *t); diff --git a/src/ctfeexpr.c b/src/ctfeexpr.c index 93d79c97adfc..ca6be1dfc6ad 100644 --- a/src/ctfeexpr.c +++ b/src/ctfeexpr.c @@ -760,6 +760,66 @@ int comparePointers(Loc loc, enum TOK op, Type *type, Expression *agg1, dinteger return cmp; } +union UnionFloatInt +{ + float f; + d_int32 x; +}; + +union UnionDoubleLong +{ + double f; + d_int64 x; +}; + +// True if conversion from type 'from' to 'to' involves a reinterpret_cast +// floating point -> integer or integer -> floating point +bool isFloatIntPaint(Type *to, Type *from) +{ + return (from->size() == to->size()) && + ( (from->isintegral() && to->isfloating()) + || (from->isfloating() && to->isintegral()) ); +} + +// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'. +Expression *paintFloatInt(Expression *fromVal, Type *to) +{ + if (exceptionOrCantInterpret(fromVal)) + return fromVal; + + if (to->size() == 4) + { + UnionFloatInt u; + if (to->isintegral()) + { + u.f = fromVal->toReal(); + return new IntegerExp(fromVal->loc, u.x, to); + } + else + { + u.x = fromVal->toInteger(); + return new RealExp(fromVal->loc, u.f, to); + } + } + else if (to->size() == 8) + { + UnionDoubleLong v; + if (to->isintegral()) + { + v.f = fromVal->toReal(); + return new IntegerExp(fromVal->loc, v.x, to); + } + else + { + v.x = fromVal->toInteger(); + return new RealExp(fromVal->loc, v.f, to); + } + } + else + assert(0); +} + + /*********************************************** Primitive integer operations ***********************************************/ diff --git a/src/interpret.c b/src/interpret.c index a68c16144ea6..2c13a27b5283 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -4806,6 +4806,22 @@ Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) #if LOG printf("%s PtrExp::interpret() %s\n", loc.toChars(), toChars()); #endif + + // Check for int<->float and long<->double casts. + + if ( e1->op == TOKsymoff && ((SymOffExp *)e1)->offset == 0 + && isFloatIntPaint(type, ((SymOffExp *)e1)->var->type) ) + { // *(cast(int*)&v, where v is a float variable + return paintFloatInt(getVarExp(loc, istate, ((SymOffExp *)e1)->var, ctfeNeedRvalue), + type); + } + else if (e1->op == TOKcast && ((CastExp *)e1)->e1->op == TOKaddress) + { // *(cast(int *))&x where x is a float expression + Expression *x = ((AddrExp *)(((CastExp *)e1)->e1))->e1; + if ( isFloatIntPaint(type, x->type) ) + return paintFloatInt(x->interpret(istate), type); + } + // Constant fold *(&structliteral + offset) if (e1->op == TOKadd) { AddExp *ae = (AddExp *)e1; diff --git a/test/compilable/interpret3.d b/test/compilable/interpret3.d index 13127fb77d87..f2079285b51c 100644 --- a/test/compilable/interpret3.d +++ b/test/compilable/interpret3.d @@ -3329,6 +3329,56 @@ static assert(!is(typeof(compiles!(badpointer(6))))); static assert(!is(typeof(compiles!(badpointer(7))))); static assert(!is(typeof(compiles!(badpointer(8))))); +/************************************************** + 9170 Allow reinterpret casts float<->int +**************************************************/ +int f9170(float x) { + return *(cast(int*)&x); +} + +float i9170(int x) { + return *(cast(float*)&x); +} + +float u9170(uint x) { + return *(cast(float*)&x); +} + +int f9170arr(float[] x) { + return *(cast(int*)&(x[1])); +} + +long d9170(double x) { + return *(cast(long*)&x); +} + +int fref9170(ref float x) { + return *(cast(int*)&x); +} + +long dref9170(ref double x) { + return *(cast(long*)&x); +} + +bool bug9170() +{ + float f = 1.25; + double d = 1.25; + assert(f9170(f) == 0x3FA0_0000); + assert(fref9170(f) == 0x3FA0_0000); + assert(d9170(d)==0x3FF4_0000_0000_0000L); + assert(dref9170(d)==0x3FF4_0000_0000_0000L); + float [3] farr = [0, 1.25, 0]; + assert(f9170arr(farr) == 0x3FA0_0000); + int i = 0x3FA0_0000; + assert(i9170(i) == 1.25); + uint u = 0x3FA0_0000; + assert(u9170(u) == 1.25); + return true; +} + +static assert(bug9170()); + /************************************************** 6792 ICE with pointer cast of indexed array **************************************************/