From: Francis De Brabandere <francisdb@gmail.com> VT_CY stores values scaled by 10000 in .int64, so the all-ones-Imp- Null check must compare to -10000 (not -1) for CCur(-1). Add right- Null conformance rows for I2/I4/R8/UI1 and a manual CY -1 case. --- dlls/oleaut32/tests/vartest.c | 20 ++++++++++++++++++++ dlls/oleaut32/variant.c | 3 ++- dlls/vbscript/tests/lang.vbs | 10 ++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/dlls/oleaut32/tests/vartest.c b/dlls/oleaut32/tests/vartest.c index c362f9854fe..dc85f04c0ae 100644 --- a/dlls/oleaut32/tests/vartest.c +++ b/dlls/oleaut32/tests/vartest.c @@ -9759,6 +9759,26 @@ static void test_VarImp(void) V_I8(&result), -3); } + /* All-ones left Imp Null returns Null for every numeric type: the + * three-valued "True Imp unknown = unknown" rule applies to any bit + * pattern that matches VARIANT_TRUE in the operand's width, including + * VT_UI1 0xFF (despite being unsigned). */ + VARIMP(I2,-1,NULL,0,NULL,0); + VARIMP(I4,-1,NULL,0,NULL,0); + VARIMP(R8,-1.0,NULL,0,NULL,0); + VARIMP(UI1,255,NULL,0,NULL,0); + + /* VT_CY stores values scaled by 10000 in .int64, so CY -1 has .int64 of + * -10000 (not -1). Previously Wine's all-ones check compared against -1 + * and never fired, producing a bitwise result instead of Null. */ + V_VT(&left) = VT_CY; + V_CY(&left).int64 = -10000; + V_VT(&right) = VT_NULL; + V_I4(&right) = 0; + V_VT(&exp) = VT_NULL; + V_I4(&exp) = 0; + test_var_call2(__LINE__, pVarImp, &left, &right, &exp); + SysFreeString(false_str); SysFreeString(true_str); } diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index 4695ca66bb0..6f78b52423b 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -5960,7 +5960,8 @@ HRESULT WINAPI VarImp(LPVARIANT left, LPVARIANT right, LPVARIANT result) case VT_BOOL: if (V_BOOL(left) == VARIANT_TRUE) resvt = VT_NULL; break; case VT_R4: if (V_R4(left) == -1.0) resvt = VT_NULL; break; case VT_R8: if (V_R8(left) == -1.0) resvt = VT_NULL; break; - case VT_CY: if (V_CY(left).int64 == -1) resvt = VT_NULL; break; + /* VT_CY stores values scaled by 10000, so -1 is -10000 in .int64. */ + case VT_CY: if (V_CY(left).int64 == -10000) resvt = VT_NULL; break; case VT_DECIMAL: if (V_DECIMAL(left).Hi32 == 0xffffffff) resvt = VT_NULL; diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index b990863ab2d..4062c3f826d 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -206,6 +206,16 @@ Call ok((CInt(0) And Null) = 0, "CInt(0) And Null is not 0") Call ok(getVT(CInt(0) And Null) = "VT_I2", "getVT(CInt(0) And Null) = " & getVT(CInt(0) And Null)) Call ok(isNull(CInt(5) And Null), "CInt(5) And Null is not Null") +' Smoke checks that VBScript's sibling logical operators reach Var* +' correctly and propagate the result payload. The full conformance tables +' live in dlls/oleaut32/tests/vartest.c. +Call ok((True Or Null) = True, "True Or Null is not True") +Call ok(isNull(False Or Null), "False Or Null is not Null") +Call ok(isNull(CInt(5) Xor Null), "CInt(5) Xor Null is not Null") +Call ok(isNull(CInt(5) Eqv Null), "CInt(5) Eqv Null is not Null") +Call ok(isNull(CByte(255) Imp Null), "CByte(255) Imp Null is not Null") +Call ok((Not CLng(0)) = -1, "Not CLng(0) is not -1") + Call ok(2 >= 1, "! 2 >= 1") Call ok(2 >= 2, "! 2 >= 2") Call ok(2 => 1, "! 2 => 1") -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10673