Repository: shader-slang/slang (2026-03-30T08:33:06Z)

Issue:
ICE when interface implementation contains Atomic<T> field
## Issue Description

When a struct implementing an interface contains an `Atomic<int>` field, the compiler crashes with "Unimplemented type packing" (error 99999) instead of producing a user-facing diagnostic. Other unsupported field types (opaque resources, CoopVec, CoopMat, String, class instances) correctly emit error 41014 ("type cannot be packed for dynamic dispatch").

## Reproducer Code

```hlsl
interface IFoo { int get(); }
export struct Impl : IFoo {
    Atomic<int> counter;
    int get() { return 1; }
}
export struct GoodImpl : IFoo {
    int v;
    int get() { return v; }
}
RWStructuredBuffer<int> out;
[numthreads(1,1,1)]
void computeMain() {
    IFoo f = createDynamicObject<IFoo>(0, 0);
    out[0] = f.get();
}
```

**Command:**
```bash
slangc -target spirv test.slang
```

## Expected Behavior

Error 41014: "type 'Impl' contains fields that cannot be packed into ordinary bytes for dynamic dispatch."

## Actual Behavior

```
error[E99999]: Slang compilation aborted due to an exception of N5Slang13InternalErrorE unimplemented: Unimplemented type packing
```

## Test to Enable

When fixed, enable the DISABLED test `tests/language-feature/dynamic-dispatch/diagnose-atomic-in-impl.slang`.



Discussion:

Patch:
diff --git a/source/slang/slang-ir-lower-dynamic-dispatch-insts.cpp b/source/slang/slang-ir-lower-dynamic-dispatch-insts.cpp
index e769fafa16e..ea201f9e078 100644
--- a/source/slang/slang-ir-lower-dynamic-dispatch-insts.cpp
+++ b/source/slang/slang-ir-lower-dynamic-dispatch-insts.cpp
@@ -882,6 +882,52 @@ struct UntaggedUnionLoweringContext : public InstPassBase
         return builder->getAnyValueType(size);
     }
 
+    // Check whether a type (or any of its nested fields) contains types that
+    // cannot be marshalled to/from an AnyValue. Types like Atomic<T> and
+    // unsized arrays would crash in emitMarshallingCode; reject them here
+    // so we emit error 41014 instead.
+    bool containsUnmarshalableType(IRType* type)
+    {
+        switch (type->getOp())
+        {
+        case kIROp_AtomicType:
+        case kIROp_UnsizedArrayType:
+            return true;
+
+        case kIROp_StructType:
+            {
+                auto structType = cast<IRStructType>(type);
+                for (auto field : structType->getFields())
+                {
+                    if (containsUnmarshalableType(field->getFieldType()))
+                        return true;
+                }
+                return false;
+            }
+
+        case kIROp_ArrayType:
+            {
+                auto arrayType = cast<IRArrayType>(type);
+                return containsUnmarshalableType((IRType*)arrayType->getElementType());
+            }
+
+        case kIROp_VectorType:
+            {
+                auto vectorType = cast<IRVectorType>(type);
+                return containsUnmarshalableType((IRType*)vectorType->getElementType());
+            }
+
+        case kIROp_MatrixType:
+            {
+                auto matrixType = cast<IRMatrixType>(type);
+                return containsUnmarshalableType((IRType*)matrixType->getElementType());
+            }
+
+        default:
+            return false;
+        }
+    }
+
     bool canTypeBeStored(IRType* concreteType)
     {
         if (!areResourceTypesBindlessOnTarget(targetProgram->getTargetReq()))
@@ -902,6 +948,9 @@ struct UntaggedUnionLoweringContext : public InstPassBase
         if (SLANG_FAILED(result))
             return false;
 
+        if (containsUnmarshalableType(concreteType))
+            return false;
+
         return true;
     }
 


Test patch:
diff --git a/tests/language-feature/dynamic-dispatch/diagnose-atomic-in-impl.slang b/tests/language-feature/dynamic-dispatch/diagnose-atomic-in-impl.slang
index 9eb6b144950..c6093adb206 100644
--- a/tests/language-feature/dynamic-dispatch/diagnose-atomic-in-impl.slang
+++ b/tests/language-feature/dynamic-dispatch/diagnose-atomic-in-impl.slang
@@ -6,8 +6,8 @@
 // a user-facing diagnostic (#10419). The compiler should reject this with
 // error 41014 like other unsupported types.
 
-//DISABLE_DIAGNOSTIC_TEST:SIMPLE(diag=CHECK): -target spirv -conformance "Impl:IFoo=0" -conformance "GoodImpl:IFoo=1"
-//DISABLE_DIAGNOSTIC_TEST:SIMPLE(diag=CHECK): -target hlsl -stage compute -entry computeMain -conformance "Impl:IFoo=0" -conformance "GoodImpl:IFoo=1"
+//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK): -target spirv -conformance "Impl:IFoo=0" -conformance "GoodImpl:IFoo=1"
+//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK): -target hlsl -stage compute -entry computeMain -conformance "Impl:IFoo=0" -conformance "GoodImpl:IFoo=1"
 
 interface IFoo
 {
diff --git a/tests/language-feature/dynamic-dispatch/diagnose-unsized-array-in-impl.slang b/tests/language-feature/dynamic-dispatch/diagnose-unsized-array-in-impl.slang
index 6b191728a50..63c6ef5c6de 100644
--- a/tests/language-feature/dynamic-dispatch/diagnose-unsized-array-in-impl.slang
+++ b/tests/language-feature/dynamic-dispatch/diagnose-unsized-array-in-impl.slang
@@ -7,8 +7,8 @@
 // a user-facing diagnostic (#10420). The compiler should reject this with
 // error 41014 like other unsupported types.
 
-//DISABLE_DIAGNOSTIC_TEST:SIMPLE(diag=CHECK): -target spirv -conformance "Impl:IFoo=0" -conformance "GoodImpl:IFoo=1"
-//DISABLE_DIAGNOSTIC_TEST:SIMPLE(diag=CHECK): -target hlsl -stage compute -entry computeMain -conformance "Impl:IFoo=0" -conformance "GoodImpl:IFoo=1"
+//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK): -target spirv -conformance "Impl:IFoo=0" -conformance "GoodImpl:IFoo=1"
+//DIAGNOSTIC_TEST:SIMPLE(diag=CHECK): -target hlsl -stage compute -entry computeMain -conformance "Impl:IFoo=0" -conformance "GoodImpl:IFoo=1"
 
 interface IFoo
 {