Sitelet https://github.com/microsoft/DirectXShaderCompiler/pull/8989
Skip to content

Make conditional operators on objects rvalues - #8989

Open
Joel Kiptoo (Kiptoo-Deus) wants to merge 1 commit into
microsoft:mainfrom
Kiptoo-Deus:fix-conditional-object-lvalue
Open

Joel Kiptoo (Kiptoo-Deus) wants to merge 1 commit into
microsoft:mainfrom
Kiptoo-Deus:fix-conditional-object-lvalue

Conversation

@Kiptoo-Deus

@Kiptoo-Deus Joel Kiptoo (Kiptoo-Deus) commented Sep 30, 2026 •

Copy link
Copy Markdown

Fixes #8579.

HLSLExternalSource::CheckVectorConditional converts the operands of ?: to rvalues, but when both operands are objects of the same type (e.g. two RWByteAddressBuffers) it returned early without doing that. The operands stayed lvalues, so C++ classification treated the conditional as an lvalue while the expression was built as an rvalue:

  • (true ? a : b) = gBuf1; (the case from the issue) asserts with getValueKind() == VK_LValue in debug builds and is silently dropped in release builds.
  • Calling a method directly on such a conditional, e.g. (false ? a : b).Store(4, 2);, hits the same assert.

The object case now converts both operands to rvalues like the other branches, so assigning to the conditional gets the same expression is not assignable error DXC already reports for scalars, vectors and matrices, and the method call compiles. I also fixed the check just above it, which tested leftObjectKind twice instead of left and right (harmless because of the leftType == rightType check that follows).

Testing (macOS arm64, Release build with assertions):

  • Added SemaHLSL/conditional-object-not-assignable.hlsl (-verify): the resource and uint assignments are errors, and copying a conditional of resources into a local and calling Store on one still compile.
  • RWByteAddressBuffer c = true ? gBuf0 : gBuf1; produces identical DXIL before and after. (false ? gBuf0 : gBuf1).Store(4, 2) now compiles and stores through the handle for u1.

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 microsoft#8579
Copilot AI balanced review requested due to automatic review settings September 30, 2026 02:32
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The focused implementation matches existing conditional semantics and includes appropriate regression coverage and release documentation.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes conditional expressions on HLSL object/resource types being incorrectly classified as lvalues.

Changes:

  • Converts object operands to rvalues and corrects the right-operand object check.
  • Adds regression coverage for assignment rejection and valid resource usage.
  • Documents the user-visible fix.
File Description
tools/​clang/​lib/​Sema/​SemaHLSL.cpp Corrects object conditional classification.
tools/​clang/​test/​SemaHLSL/​conditional-object-not-assignable.hlsl Adds regression tests.
docs/​ReleaseNotes.md Records the compiler bug fix.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@damyanp

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@damyanp

Copy link
Copy Markdown
Member

lit doesn't configure in my local build, so I ran each test's RUN: lines directly: the 304 SemaHLSL tests give identical results with and without the change, and so do the 326 tests in HLSLFileCheck/hlsl/functions/arguments, operators and objects.

I've seen this in a few PRs. This sort of commentary doesn't really belong in the PR description when we get to merging it. FWIW, I'm pretty sure lit is supported on MacOS, so I'd encourage you to figure out how to properly test this end to end on your local config.

@llvm-beanz

Copy link
Copy Markdown
Collaborator
  • lit doesn't configure in my local build, so I ran each test's RUN: lines directly: the 304 SemaHLSL tests give identical results with and without the change, and so do the 326 tests in HLSLFileCheck/hlsl/functions/arguments, operators and objects.

Did you try just running the ninja check-all target? That 100% works on arm64 macOS. I use it constantly.

@llvm-beanz Chris B (llvm-beanz) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks correct for HLSL 2021, but may need to be revised for newer versions of HLSL as we work though the proposal to adopt C++ ternary operator semantics:

https://hlsl-tc57.github.io/tc57/proposal/0017/

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())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we want to gate this behavior on the language version, and preserve this older behavior, according to this document:
https://hlsl-tc57.github.io/tc57/proposal/0017/
See if you can add a condition here to ensure that the language version is at least 202x.

@bob80905 Joshua Batista (bob80905) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talked offline, gating on language version is a later concern. LGTM

@Kiptoo-Deus

Copy link
Copy Markdown
Author

Thanks both, and fair point. I hadn't tried check-all, I'll get it running properly here and use it from now on. I'll also take that paragraph out of the descriptions.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: New

Development

Successfully merging this pull request may close these issues.

[Crash + miscompile] (cond ? a : b) = expr; with HLSL resource types asserts in debug, silently drops in release

5 participants