Skip to content

Don't warn E31106/E31107 on compiler-synthesized parameter groups#11986

Merged
expipiplus1 merged 4 commits into
shader-slang:masterfrom
expipiplus1:fix-11825-param-group-warning
Jul 10, 2026
Merged

Don't warn E31106/E31107 on compiler-synthesized parameter groups#11986
expipiplus1 merged 4 commits into
shader-slang:masterfrom
expipiplus1:fix-11825-param-group-warning

Conversation

@expipiplus1

@expipiplus1 expipiplus1 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Motivation

Compiling this shader with -target hlsl or -target spirv produces three warnings with no source location:

[shader("compute")]
[numthreads(1, 1, 1)]
void testMain(uint3 tid : SV_DispatchThreadID, Texture2D<float4> texture, RWTexture2D<float4> rw_texture, uniform int2 dim)
{
    if (all(tid.xy < dim))
        rw_texture[tid.xy] = texture[tid.xy];
}
warning[E31106]: Parameter group type includes some members with types which cannot be included in the same binding...
warning[E31107]: This member cannot be included in the same binding as some other parts of this struct...
warning[E31107]: This member cannot be included in the same binding as some other parts of this struct...

The user wrote a flat parameter list, not a parameter group. The compiler gathers the entry-point uniform/resource parameters into a synthesized ConstantBuffer<EntryPointParams>, and when the textures then "leak" out of that constant buffer during type legalization we warn — but that regrouping is inherent to how we lower entry-point parameters, so there is nothing for the user to restructure. The warnings are also locationless (the synthesized type has no source loc), which is exactly the confusing case #11825 reports.

The warning is correct and useful for user-authored mixed groups (its original purpose, PR #10158), so we only suppress it for the compiler-synthesized case.

Proposed solution

Mark the compiler-synthesized parameter-group element struct with a new SynthesizedParameterGroupDecoration at the places we synthesize such a struct (entry-point uniform collection and global-uniform collection), and skip the E31106/E31107 diagnostic in legalizeTypeImpl when the constant buffer's element carries that marker. User-authored ConstantBuffer<S> groups are unmarked and continue to warn, with a location.

Change summary

File What
slang-ir-insts.lua, slang-ir-insts-stable-names.lua, slang-ir-insts.h Add the SynthesizedParameterGroupDecoration IR op (+ stable name + addSynthesizedParameterGroupDecoration builder helper).
slang-ir.h Bump k_maxSupportedModuleVersion 24 → 25 for the new IR op.
slang-ir.cpp Add the marker to isSimpleDecoration so re-attaching it deduplicates.
slang-ir-entry-point-uniforms.cpp Mark the synthesized EntryPointParams struct.
slang-ir-collect-global-uniforms.cpp Mark the synthesized GlobalParams struct.
slang-legalize-types.cpp Skip the leak diagnostic for a marked element; re-add the marker onto the original struct at the struct-splitting site so it survives transferDecorationsTo and later legalization passes.
tests/diagnostics/entry-point-uniform-no-parameter-group-leak-warning.slang, .../global-uniform-...slang Regression tests: the synthesized entry-point and global-scope groups compile silently on HLSL and SPIRV.

Concepts and vocabulary

  • Synthesized parameter group — the implicit ConstantBuffer<EntryPointParams> / ConstantBuffer<GlobalParams> the compiler builds to hold entry-point uniform/resource parameters or global-scope shader parameters. The user never writes this grouping.
  • transferDecorationsTo — moves all decorations off one inst onto another. Struct legalization uses it to hand the original struct's decorations to the new "ordinary" struct it builds for the non-resource fields, leaving the original as a husk.
  • pair LegalType — the result of legalizing a struct that mixes resource and ordinary fields: an "ordinary" part plus a "special" (resource) part. A pair element inside a ConstantBuffer is exactly the "resource leaks out of the group" condition the warning fires on.

Process report

Marking the synthesized structs. The two producers that synthesize a parameter-group element struct and are reachable by the leak diagnostic are CollectEntryPointUniformParams::ensureCollectedParamAndTypeHaveBeenCreated (EntryPointParams) and collectGlobalUniformParameters (GlobalParams). Marking the struct at construction is the right layer — the marker is a true property of these structs, not a downstream repair. This answers the input-shape check: the "constant buffer whose element leaks a resource" shape reaching the diagnostic is valid for user code, so we don't change the diagnostic's contract; we only distinguish the synthesized producer, at the producer. (The analogous OptiX shader-record synthesis site was investigated too, but the leak diagnostic is not reachable there — CUDA/OptiX legalizes resource params without a pair-leak out of the constant buffer, verified with a breakpoint on the diagnose site — so no marking is added there, since nothing would test it.)

Skipping the diagnostic. In legalizeTypeImpl the leak warning fires when legalElementType.flavor == pair && as<IRConstantBufferType>(type). We add && !isSynthesizedGroup, read from the element struct's marker before the recursive legalizeType call.

Preserving the marker across legalization (the cascading part). The first attempt (just checking the marker at the buffer site) still warned. Tracing it: the buffer ConstantBuffer<EntryPointParams> is legalized, and legalizing its element struct hits the mixed-resource/ordinary path that builds a new ordinaryStructType and calls originalStructType->transferDecorationsTo(ordinaryStructType) — which moves the marker off the original struct. The buffer is then legalized a second time on the same pointer (resource legalization runs as more than one pass over the module), and on that pass the element struct no longer carries the marker, so the warning fired. Debug tracing confirmed the same buf/elem pointers legalized twice: first synth=1 flavor=simple (no warning), then synth=0 flavor=pair (warning).

The fix re-adds the marker onto the original struct at the struct-splitting site in legalizeTypeImpl (right after transferDecorationsTo), so the buffer is still recognized as synthesized on subsequent passes. The preservation is deliberately kept site-local rather than folded into the shared copyNameHintAndDebugDecorations helper: that helper is also used to flatten varying-IO structs and to create debug variables, where the "synthesized parameter group" marker has no meaning, so cloning it there would make the marker's scope ambient. Keeping it at the parameter-group struct-splitting site keeps the marker's meaning narrow. Combined with adding the op to isSimpleDecoration, re-adding the marker deduplicates rather than accumulating.

Confirmed behavior after the fix: the issue repro compiles with zero E31106/E31107 on both HLSL and SPIRV; the global-scope repro (global-uniform-...slang) likewise; a user ConstantBuffer<S> mixing a resource and ordinary data still emits both warnings with a location (existing tests/diagnostics/parameter-group-special-type-leak-location*.slang continue to pass).

Entry-point uniform/resource parameters (and global-scope shader
parameters) are gathered by the compiler into a synthesized
ConstantBuffer<EntryPointParams>/<GlobalParams>. When a resource then
leaks out of that buffer during type legalization we no longer emit the
"special type leaks from parameter group" warnings: the user wrote a
flat parameter/global list, not the grouping, so there is nothing to
restructure (and the warnings had no source location).

Mark the synthesized element struct with a new
SynthesizedParameterGroupDecoration and skip the diagnostic for it.
The marker is preserved across type legalization (which moves the
original struct's decorations onto a new ordinary struct), so the buffer
is still recognized as synthesized when it is re-legalized.

User-authored ConstantBuffer<S> groups that mix resources and ordinary
data still warn, with a location.

Fixes shader-slang#11825
@expipiplus1
expipiplus1 requested a review from a team as a code owner July 7, 2026 23:49
@expipiplus1
expipiplus1 requested review from bmillsNV and Copilot and removed request for a team July 7, 2026 23:49
@expipiplus1 expipiplus1 added the pr: non-breaking PRs without breaking changes label Jul 7, 2026
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The compiler now marks synthesized parameter-group structs with a dedicated IR decoration, preserves that marker through type legalization, suppresses corresponding leak diagnostics, updates IR metadata, and adds global and entry-point regression tests.

Synthesized parameter group decoration

Layer / File(s) Summary
IR decoration definition and registration
source/slang/slang-ir-insts.h, source/slang/slang-ir-insts.lua, source/slang/slang-ir-insts-stable-names.lua, source/slang/slang-ir.cpp, source/slang/slang-ir.h
Defines and registers SynthesizedParameterGroupDecoration, adds its builder helper and simple-decoration handling, and raises the supported module version to 25.
Decoration application
source/slang/slang-ir-collect-global-uniforms.cpp, source/slang/slang-ir-entry-point-uniforms.cpp
Marks synthesized GlobalParams and EntryPointParams structs with the new decoration.
Legalization and diagnostic handling
source/slang/slang-legalize-types.cpp
Preserves the marker during tuple decoration transfer and suppresses parameter-group leak diagnostics for synthesized groups.
Regression coverage
tests/diagnostics/entry-point-uniform-no-parameter-group-leak-warning.slang, tests/diagnostics/global-uniform-no-parameter-group-leak-warning.slang
Adds SPIR-V and HLSL diagnostic tests covering entry-point and global uniform synthesis.

Suggested reviewers: bmillsNV

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly matches the main change: suppressing E31106/E31107 for compiler-synthesized parameter groups.
Description check ✅ Passed The description is detailed and directly describes the same diagnostic-suppression and marker changes in the patch.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

Pull request overview

This PR suppresses E31106/E31107 “special type leaks from parameter group” warnings when the offending parameter group was compiler-synthesized (entry-point uniform/resource collection and global-uniform collection), avoiding confusing, locationless diagnostics that users cannot act on.

Changes:

  • Introduces SynthesizedParameterGroupDecoration to tag compiler-synthesized parameter-group element structs.
  • Applies the decoration when synthesizing EntryPointParams and GlobalParams, and suppresses the leak warning in type legalization when the marker is present (while preserving it across transferDecorationsTo).
  • Adds a diagnostics regression test ensuring the entry-point synthesized case is silent for HLSL and SPIR-V.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/diagnostics/entry-point-uniform-no-parameter-group-leak-warning.slang Regression test asserting no diagnostics for the synthesized entry-point parameter group case on HLSL/SPIR-V.
source/slang/slang-legalize-types.cpp Suppresses E31106/E31107 for marked synthesized groups and preserves the marker across decoration transfer during struct legalization.
source/slang/slang-ir-insts.lua Adds the IR decoration opcode definition for SynthesizedParameterGroupDecoration.
source/slang/slang-ir-insts.h Declares the new decoration type and adds an IRBuilder helper to attach it.
source/slang/slang-ir-insts-stable-names.lua Adds a stable-name entry for the new decoration.
source/slang/slang-ir-entry-point-uniforms.cpp Marks the synthesized EntryPointParams struct as a synthesized parameter group.
source/slang/slang-ir-collect-global-uniforms.cpp Marks the synthesized GlobalParams wrapper struct as a synthesized parameter group.

Comment thread source/slang/slang-ir-insts.h
Comment thread source/slang/slang-ir-collect-global-uniforms.cpp

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f97deb36-c1d0-46e7-b257-d986bb3c11fc

📥 Commits

Reviewing files that changed from the base of the PR and between 33f9ed0 and 010b99f.

📒 Files selected for processing (7)
  • source/slang/slang-ir-collect-global-uniforms.cpp
  • source/slang/slang-ir-entry-point-uniforms.cpp
  • source/slang/slang-ir-insts-stable-names.lua
  • source/slang/slang-ir-insts.h
  • source/slang/slang-ir-insts.lua
  • source/slang/slang-legalize-types.cpp
  • tests/diagnostics/entry-point-uniform-no-parameter-group-leak-warning.slang

Comment thread source/slang/slang-ir-collect-global-uniforms.cpp
github-actions[bot]

This comment was marked as outdated.

@slangbot

slangbot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ IR Instruction Files Changed

This PR modifies IR instruction definition files. Please review if you need to update the following constants in source/slang/slang-ir.h:

  • k_minSupportedModuleVersion: Should be incremented if you're removing instructions or making breaking changes
  • k_maxSupportedModuleVersion: Should be incremented when adding new instructions

These version numbers help ensure compatibility between different versions of compiled modules.

- Bump k_maxSupportedModuleVersion for the new IR op so older compilers
  reject modules that use it.
- Mark the OptiX shader-record (SBT) synthesized param struct too, so
  ray-tracing entry points don't hit the same locationless warning.
- Add SynthesizedParameterGroupDecoration to isSimpleDecoration so
  re-attaching the marker deduplicates instead of accumulating.
- Fold the marker preservation into copyNameHintAndDebugDecorations
  rather than a one-off re-add, keeping one source of truth for
  decorations that must survive transferDecorationsTo.
- Add a global-scope regression test covering the GlobalParams
  synthesis path.

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
source/slang/slang-legalize-types.cpp (1)

1246-1256: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Stale rationale: the marker is restored onto originalElementType after legalizeType.

The comment states Whether this parameter group was synthesized by the compiler rather than written by the user. We check for the marker before legalizing the element type below: legalizing a struct with mixed resource/ordinary fields creates a new "ordinary" struct and calls transferDecorationsTo to move the original struct's decorations (including this marker) onto it, so after legalizeType the marker is no longer on originalElementType.

However, TupleTypeBuilder::getResult() (this same file) calls originalStructType->transferDecorationsTo(ordinaryStructType); ... copyNameHintAndDebugDecorations(originalStructType, ordinaryStructType); right after the transfer, and copyNameHintAndDebugDecorations explicitly clones SynthesizedParameterGroupDecoration back onto dest (originalStructType == originalElementType). So by the time legalizeType(context, originalElementType) returns, the marker is back on originalElementType, contradicting the comment's claim. Checking before the call is still harmless, but the stated justification is inaccurate and could mislead a future reader reasoning about this invariant — especially since this exact preservation mechanism was already the subject of prior review discussion.

Consider rewording to something like "we capture the marker before the call for simplicity/clarity, though it is in fact restored onto originalElementType afterward via copyNameHintAndDebugDecorations."


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4fb43173-f274-4602-8d05-4f0ae9a88571

📥 Commits

Reviewing files that changed from the base of the PR and between 010b99f and a6d4f29.

📒 Files selected for processing (6)
  • source/slang/slang-ir-optix-entry-point-uniforms.cpp
  • source/slang/slang-ir-util.cpp
  • source/slang/slang-ir.cpp
  • source/slang/slang-ir.h
  • source/slang/slang-legalize-types.cpp
  • tests/diagnostics/global-uniform-no-parameter-group-leak-warning.slang

github-actions[bot]

This comment was marked as outdated.

The OptiX shader-record synthesis site is not reached by the E31106/E31107
leak diagnostic: CUDA/OptiX legalizes resource parameters without letting
them leak as a pair type out of the ConstantBuffer, so the diagnose site is
never hit (verified with a breakpoint on a raygeneration entry point with
mixed resource + uniform parameters). Since no test fails without the marking
there, remove it rather than keep speculative defensive code.

Also correct the rationale comment at the buffer-legalization read site: the
marker is now restored onto the original struct by
copyNameHintAndDebugDecorations, so explain that we read it before
legalizeType to stay independent of that restore rather than because it is
gone afterwards.
github-actions[bot]

This comment was marked as outdated.

Revert the addition of SynthesizedParameterGroupDecoration to the shared
copyNameHintAndDebugDecorations helper: that helper is also used to flatten
varying-IO structs and to create debug variables, where the marker has no
meaning, so cloning it there makes the marker's scope ambient. Instead re-add
the marker on the original struct at the parameter-group struct-splitting site
in legalizeTypeImpl, keeping its meaning narrow to parameter-group structs.

@github-actions github-actions Bot 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.

Verdict: ✅ Clean — no significant issues found

Adds an IRSynthesizedParameterGroupDecoration marker to compiler-synthesized parameter-group element structs (EntryPointParams, GlobalParams) and skips the E31106/E31107 "special type leaks from parameter group" diagnostic for them in legalizeTypeImpl, while leaving user-authored ConstantBuffer<S> groups warning as before. Four reviewer passes (code-quality, IR-correctness, security, test-coverage) plus a clarity pass surfaced no findings that survive verification.

Changes Overview

New IR op (slang-ir-insts.lua, slang-ir-insts-stable-names.lua, slang-ir-insts.h, slang-ir.cpp, slang-ir.h)

  • Adds the operand-less SynthesizedParameterGroupDecoration (stable name 891, next after 890), an addSynthesizedParameterGroupDecoration builder helper, registers it in isSimpleDecoration so re-attaching dedups, and bumps k_maxSupportedModuleVersion 24→25. Stable-name serialization means older compilers map the unknown op to kIROp_Unrecognized (harmless: a suppression is simply not applied).

Marking the synthesis sites (slang-ir-entry-point-uniforms.cpp, slang-ir-collect-global-uniforms.cpp)

  • Marks the synthesized element struct at construction — the correct producer layer.

Diagnostic suppression + marker preservation (slang-legalize-types.cpp)

  • Reads isSynthesizedGroup off the element struct before legalizing it and adds && !isSynthesizedGroup to the leak-warning guard; re-adds the marker onto the original struct after transferDecorationsTo moves it, so the group is still recognized on later legalization passes (each pass builds a fresh legalization context).

Regression tests (tests/diagnostics/entry-point-uniform-...slang, global-uniform-...slang)

  • Exhaustive DIAGNOSTIC_TEST on SPIRV + HLSL asserting both synthesis sites compile silently; the pre-existing parameter-group-special-type-leak-location*.slang remain as the positive control that user-authored groups still warn.

reviewed: ad3ee98 · diff sha256 f97d3512b558

@expipiplus1
expipiplus1 enabled auto-merge July 10, 2026 07:02

@jvepsalainen-nv jvepsalainen-nv 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.

LGTM

@expipiplus1
expipiplus1 added this pull request to the merge queue Jul 10, 2026
Merged via the queue into shader-slang:master with commit 258a984 Jul 10, 2026
91 of 93 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr: non-breaking PRs without breaking changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants