From 57b440b49c4fd10479b02e03d39c02b1bbdd640e Mon Sep 17 00:00:00 2001 From: Joel Kiptoo Date: Wed, 30 Sep 2026 05:31:41 +0300 Subject: [PATCH] Make conditional operators on objects rvalues CheckVectorConditional converts the operands of a conditional operator to rvalues, except when both are objects of the same type, where it returned early. The result was then classified as an lvalue, so '(c ? a : b) = buf' with resources hit an assert in debug builds and was silently dropped in release builds, and calling a method on such a conditional asserted as well. Convert the operands to rvalues in that case too, so the assignment gets the usual 'expression is not assignable' error. Also check rightObjectKind instead of leftObjectKind twice. Fixes #8579 --- docs/ReleaseNotes.md | 4 ++++ tools/clang/lib/Sema/SemaHLSL.cpp | 8 ++++++- .../conditional-object-not-assignable.hlsl | 22 +++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 tools/clang/test/SemaHLSL/conditional-object-not-assignable.hlsl diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 4da2a4f644..429dc56831 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -67,6 +67,10 @@ line upon naming the release. Refer to previous for appropriate section names. - Fixed an optimizer crash when scalarizing an out-of-bounds vector access [#8940](https://github.com/microsoft/DirectXShaderCompiler/issues/8940). +- Assigning to a conditional operator on objects, such as `(c ? a : b) = buf` + with resources, is now an "expression is not assignable" error like for + other types, instead of asserting or being silently dropped + [#8579](https://github.com/microsoft/DirectXShaderCompiler/issues/8579). ### Upcoming Preview Release diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index 5d480a99ee..bf68852696 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -11159,8 +11159,14 @@ HLSLExternalSource::CheckVectorConditional(ExprResult &Cond, ExprResult &LHS, rightObjectKind == AR_TOBJ_MATRIX; if (!leftIsSimple || !rightIsSimple) { - if (leftObjectKind == AR_TOBJ_OBJECT && leftObjectKind == AR_TOBJ_OBJECT) { + if (leftObjectKind == AR_TOBJ_OBJECT && rightObjectKind == AR_TOBJ_OBJECT) { if (leftType == rightType) { + // As for the other types, the result is not an lvalue, so it can't be + // assigned to. + if (LHS.get()->isLValue()) + LHS.set(CreateLValueToRValueCast(LHS.get())); + if (RHS.get()->isLValue()) + RHS.set(CreateLValueToRValueCast(RHS.get())); return leftType; } } diff --git a/tools/clang/test/SemaHLSL/conditional-object-not-assignable.hlsl b/tools/clang/test/SemaHLSL/conditional-object-not-assignable.hlsl new file mode 100644 index 0000000000..9b72ce7fcf --- /dev/null +++ b/tools/clang/test/SemaHLSL/conditional-object-not-assignable.hlsl @@ -0,0 +1,22 @@ +// RUN: %dxc -Tcs_6_0 -verify %s + +// Like for scalars, vectors and matrices, a conditional operator on objects +// yields an rvalue, so it can't be assigned to. + +RWByteAddressBuffer gBuf0 : register(u0); +RWByteAddressBuffer gBuf1 : register(u1); + +[numthreads(1, 1, 1)] +void main(uint3 tid : SV_DispatchThreadID) { + RWByteAddressBuffer a = gBuf0; + RWByteAddressBuffer b = gBuf1; + (true ? a : b) = gBuf1; /* expected-error {{expression is not assignable}} */ + + uint x = 1, y = 2; + (true ? x : y) = 5; /* expected-error {{expression is not assignable}} */ + + // Using the result as an rvalue is still fine. + RWByteAddressBuffer c = true ? a : b; + c.Store(0, 1); + (false ? a : b).Store(4, 2); +}