From: Francis De Brabandere <francisdb@gmail.com> Verify that VBScript's And/Or/Xor/Eqv/Imp/Not operators propagate the oleaut32 VarAnd/VarOr/... results correctly through the interpreter for a few representative Null combinations. --- dlls/oleaut32/variant.c | 44 ++++++++++++++---------------------- dlls/vbscript/tests/lang.vbs | 29 ++++++++++++++++++++---- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/dlls/oleaut32/variant.c b/dlls/oleaut32/variant.c index c24b32fa9f0..4c60ffa3257 100644 --- a/dlls/oleaut32/variant.c +++ b/dlls/oleaut32/variant.c @@ -3056,7 +3056,6 @@ HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result) * Both orderings must produce the same result. */ VARIANT *other; VARTYPE othervt; - BOOL nonzero = FALSE; if (leftvt == VT_NULL && rightvt == VT_NULL) { @@ -3077,23 +3076,23 @@ HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result) switch (othervt) { - case VT_EMPTY: break; - case VT_I1: nonzero = V_I1(other) != 0; break; - case VT_UI1: nonzero = V_UI1(other) != 0; break; - case VT_I2: nonzero = V_I2(other) != 0; break; - case VT_UI2: nonzero = V_UI2(other) != 0; break; - case VT_I4: nonzero = V_I4(other) != 0; break; - case VT_UI4: nonzero = V_UI4(other) != 0; break; - case VT_I8: nonzero = V_I8(other) != 0; break; - case VT_UI8: nonzero = V_UI8(other) != 0; break; - case VT_INT: nonzero = V_INT(other) != 0; break; - case VT_UINT: nonzero = V_UINT(other) != 0; break; - case VT_BOOL: nonzero = V_BOOL(other) != VARIANT_FALSE; break; - case VT_R4: nonzero = V_R4(other) != 0.0f; break; - case VT_R8: nonzero = V_R8(other) != 0.0; break; - case VT_DATE: nonzero = V_DATE(other) != 0.0; break; - case VT_CY: nonzero = V_CY(other).int64 != 0; break; - case VT_DECIMAL: nonzero = V_DECIMAL(other).Hi32 || V_DECIMAL(other).Lo64; break; + case VT_EMPTY: break; + case VT_I1: if (V_I1(other)) resvt = VT_NULL; break; + case VT_UI1: if (V_UI1(other)) resvt = VT_NULL; break; + case VT_I2: if (V_I2(other)) resvt = VT_NULL; break; + case VT_UI2: if (V_UI2(other)) resvt = VT_NULL; break; + case VT_I4: if (V_I4(other)) resvt = VT_NULL; break; + case VT_UI4: if (V_UI4(other)) resvt = VT_NULL; break; + case VT_I8: if (V_I8(other)) resvt = VT_NULL; break; + case VT_UI8: if (V_UI8(other)) resvt = VT_NULL; break; + case VT_INT: if (V_INT(other)) resvt = VT_NULL; break; + case VT_UINT: if (V_UINT(other)) resvt = VT_NULL; break; + case VT_BOOL: if (V_BOOL(other) != VARIANT_FALSE) resvt = VT_NULL; break; + case VT_R4: if (V_R4(other) != 0.0f) resvt = VT_NULL; break; + case VT_R8: if (V_R8(other) != 0.0) resvt = VT_NULL; break; + case VT_DATE: if (V_DATE(other) != 0.0) resvt = VT_NULL; break; + case VT_CY: if (V_CY(other).int64) resvt = VT_NULL; break; + case VT_DECIMAL: if (V_DECIMAL(other).Hi32 || V_DECIMAL(other).Lo64) resvt = VT_NULL; break; case VT_BSTR: { VARIANT_BOOL b; @@ -3115,12 +3114,6 @@ HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result) goto VarAnd_Exit; } - if (nonzero) - { - V_VT(result) = VT_NULL; - goto VarAnd_Exit; - } - V_VT(result) = resvt; switch (resvt) { @@ -3135,9 +3128,6 @@ HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result) case VT_UI8: V_UI8(result) = 0; break; case VT_INT: V_INT(result) = 0; break; case VT_UINT: V_UINT(result) = 0; break; - default: - V_VT(result) = VT_NULL; - break; } goto VarAnd_Exit; } diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index bec0fd456a5..0788bb6d1fe 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -231,10 +231,31 @@ call ok(false imp false, "false does not imp false?") call ok(not (true imp false), "true imp false?") call ok(false imp null, "false imp null is false?") -' For VT_UI1 Imp VT_NULL, native VBScript keeps UI1 width and returns -' the bitwise complement of the left operand, rather than applying -' VarImp's three-valued all-ones rule. interp_imp has a narrow special -' case to match this native behavior. +' Smoke check that VBScript's `And` operator reaches VarAnd correctly and +' propagates the result payload. The full VarAnd+Null conformance table +' lives in dlls/oleaut32/tests/vartest.c. +Call ok((False And Null) = False, "False And Null is not False") +Call ok(isNull(True And Null), "True And Null is not Null") +Call ok(isNull(Null And Null), "Null And Null is not Null") +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(CDate(-1) Imp Null), "CDate(-1) Imp Null is not Null") +Call ok((Not CLng(0)) = -1, "Not CLng(0) is not -1") + +' VBScript-specific: for VT_UI1 Imp VT_NULL, native VBScript keeps UI1 +' width and returns the bitwise complement of the left operand, rather +' than applying VarImp's three-valued "all-ones Imp unknown = unknown" +' rule (which returns VT_NULL at the C level for UI1 0xFF). interp_imp +' has a narrow special case to match this native behavior. Call ok((CByte(0) Imp Null) = 255, "CByte(0) Imp Null is not 255") Call ok(getVT(CByte(0) Imp Null) = "VT_UI1", "getVT(CByte(0) Imp Null) = " & getVT(CByte(0) Imp Null)) Call ok((CByte(170) Imp Null) = 85, "CByte(170) Imp Null is not 85") -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10673