diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index d97cee7769a3..bacb1729c449 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -14931,6 +14931,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { //printf("EqualExp::semantic('%s')\n", exp.toErrMsg()); + static Expression floatingNaNConst(Expression e) + { + auto optimized = e.optimize(WANTvalue); + if (!optimized || optimized.isConst() != 1) + return null; + + if (optimized.type.isReal()) + return CTFloat.isNaN(optimized.toReal()) ? optimized : null; + if (optimized.type.isImaginary()) + return CTFloat.isNaN(optimized.toImaginary()) ? optimized : null; + return null; + } + exp.setNoderefOperands(); if (auto e = binSemanticProp(exp, sc)) @@ -15007,6 +15020,22 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Type t1 = exp.e1.type.toBasetype(); Type t2 = exp.e2.type.toBasetype(); + if (t1.isFloating() && t2.isFloating()) + { + auto nan1 = floatingNaNConst(exp.e1); + auto nan2 = floatingNaNConst(exp.e2); + auto nan = nan1 ? nan1 : nan2; + if (nan) + { + const(char)* cmpResult = exp.op == EXP.equal ? "false" : "true"; + error(exp.loc, "comparison with `%s` is always %s; use `%s` instead", + nan.toErrMsg(), + cmpResult, + "!is".ptr + (exp.op == EXP.equal)); + return setError(); + } + } + static bool unifyArrayTypes(Type t1, Type t2, Scope* sc) { Type t1n = t1.nextOf().toBasetype(); diff --git a/compiler/test/compilable/test19227.d b/compiler/test/compilable/test19227.d index 2a1d325d7580..0b282ac87595 100644 --- a/compiler/test/compilable/test19227.d +++ b/compiler/test/compilable/test19227.d @@ -20,8 +20,5 @@ struct T void main() { static assert(S.init is S.init); - static assert(S.init != S.init); - static assert(T.init is T.init); - static assert(T.init != T.init); } diff --git a/compiler/test/fail_compilation/fail18531.d b/compiler/test/fail_compilation/fail18531.d new file mode 100644 index 000000000000..3b486653ceeb --- /dev/null +++ b/compiler/test/fail_compilation/fail18531.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail18531.d(16): Error: comparison with `float.nan` is always false; use `is` instead +fail_compilation/fail18531.d(18): Error: comparison with `float.nan` is always true; use `!is` instead +fail_compilation/fail18531.d(20): Error: comparison with `float.nan` is always false; use `is` instead +fail_compilation/fail18531.d(22): Error: comparison with `double.nan` is always false; use `is` instead +--- +*/ + +enum myNaN = double.nan; + +void main() +{ + float a = float.nan; + assert(a == float.nan); + float b = 0.0; + assert(b != float.nan); + float c = float.init; + assert(c == float.init); + assert(a == c); + assert(myNaN == double.nan); +} diff --git a/compiler/test/runnable/constfold.d b/compiler/test/runnable/constfold.d index 4aa7a968ae0a..38255e90a73b 100644 --- a/compiler/test/runnable/constfold.d +++ b/compiler/test/runnable/constfold.d @@ -148,13 +148,6 @@ static assert((7.2 != 6.2) == 1); static assert((7.2 == 7.2) == 1); static assert((7.2 != 7.2) == 0); -static assert((7.2 == double.nan) == 0); -static assert((7.2 != double.nan) == 1); -static assert((double.nan == double.nan) == 0); -static assert((double.nan != double.nan) == 1); -static assert((double.nan == 7.2) == 0); -static assert((double.nan != 7.2) == 1); - static assert((5 is 5) == 1); static assert((5 is 4) == 0); static assert((5 !is 5) == 0); @@ -228,6 +221,17 @@ void test3() assert(signbit(m) != 0); } +void testNaN() +{ + double nan = double.nan; + assert((7.2 == nan) == 0); + assert((7.2 != nan) == 1); + assert((nan == nan) == 0); + assert((nan != nan) == 1); + assert((nan == 7.2) == 0); + assert((nan != 7.2) == 1); +} + /************************************/ struct A4 { char [] a; } @@ -587,6 +591,7 @@ int main() test1(); test2(); test3(); + testNaN(); test3697and(); test3697or(); test6077(); diff --git a/compiler/test/runnable/nan.d b/compiler/test/runnable/nan.d index 9b97699b8bae..d878aecf8b71 100644 --- a/compiler/test/runnable/nan.d +++ b/compiler/test/runnable/nan.d @@ -2,8 +2,6 @@ import core.stdc.stdio; enum real er1 = real.nan; enum real er2 = 1; -static assert(er1 != er2); -static assert(!(er1 == er2)); static assert(!(er1 < er2)); static assert(!(er1 > er2)); static assert(!(er1 >= er2)); @@ -11,8 +9,6 @@ static assert(!(er1 <= er2)); enum double ed1 = real.nan; enum double ed2 = 1; -static assert(ed1 != ed2); -static assert(!(ed1 == ed2)); static assert(!(ed1 < ed2)); static assert(!(ed1 > ed2)); static assert(!(ed1 >= ed2)); @@ -70,33 +66,33 @@ void test2(T)() bool test() { - real r1 = real.nan; - real r2 = 1; - b = (r1 != r2); assert(b); - b = (r1 == r2); assert(!b); - b = (r1 < r2); assert(!b); - b = (r1 > r2); assert(!b); - b = (r1 <= r2); assert(!b); - b = (r1 >= r2); assert(!b); + real r1 = real.nan; + real r2 = 1; + b = (r1 != r2); assert(b); + b = (r1 == r2); assert(!b); + b = (r1 < r2); assert(!b); + b = (r1 > r2); assert(!b); + b = (r1 <= r2); assert(!b); + b = (r1 >= r2); assert(!b); - double d1 = double.nan; - double d2 = 1; - b = (d1 != d2); assert(b); - b = (d1 == d2); assert(!b); - b = (d1 < d2); assert(!b); - b = (d1 > d2); assert(!b); - b = (d1 <= d2); assert(!b); - b = (d1 >= d2); assert(!b); + double d1 = double.nan; + double d2 = 1; + b = (d1 != d2); assert(b); + b = (d1 == d2); assert(!b); + b = (d1 < d2); assert(!b); + b = (d1 > d2); assert(!b); + b = (d1 <= d2); assert(!b); + b = (d1 >= d2); assert(!b); - float f1 = float.nan; - float f2 = 1; - b = (f1 != f2); assert(b); - b = (f1 == f2); assert(!b); - b = (f1 < f2); assert(!b); - b = (f1 > f2); assert(!b); - b = (f1 <= f2); assert(!b); - b = (f1 >= f2); assert(!b); - return true; + float f1 = float.nan; + float f2 = 1; + b = (f1 != f2); assert(b); + b = (f1 == f2); assert(!b); + b = (f1 < f2); assert(!b); + b = (f1 > f2); assert(!b); + b = (f1 <= f2); assert(!b); + b = (f1 >= f2); assert(!b); + return true; } void main()