summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-07-11 16:12:41 -0700
committerGitHub <noreply@github.com>2024-07-11 16:12:41 -0700
commit24f8999c892a9c4d108616c08d714e8dea562707 (patch)
treec3632963f8a940503b46ae2d82b70fedaaf0e1db
parent977e4b21d69406b0b68c5963f50489d7433db830 (diff)
Fix incorrect codegen when returning initializer list as existential value. (#4618)
* Add `dev` cmake preset. * Fix incorrect codegen when returning initializer list as existential value. * Fix cmake. * Fixup.
-rw-r--r--CMakePresets.json9
-rw-r--r--docs/building.md4
-rw-r--r--source/slang/slang-check-conversion.cpp41
-rw-r--r--tests/language-feature/interfaces/default-construct-conformance.slang190
4 files changed, 224 insertions, 20 deletions
diff --git a/CMakePresets.json b/CMakePresets.json
index 08f85a37f..cd516c8ea 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -38,6 +38,15 @@
"generator": "Visual Studio 17 2022"
},
{
+ "name": "vs2022-dev",
+ "inherits": "msvc-base",
+ "description": "Visual Studio 2022 project with debug assisting features",
+ "generator": "Visual Studio 17 2022",
+ "cacheVariables": {
+ "SLANG_ENABLE_IR_BREAK_ALLOC": "TRUE"
+ }
+ },
+ {
"name": "slang-llvm",
"inherits": "default",
"description": "Build slang-llvm from the system LLVM",
diff --git a/docs/building.md b/docs/building.md
index a42f4cde6..2b2435302 100644
--- a/docs/building.md
+++ b/docs/building.md
@@ -40,11 +40,13 @@ cmake --build --preset release # or --preset debug
For Visual Studio run:
```bash
-cmake --preset vs2022 # or --preset vs2019
+cmake --preset vs2022 # or 'vs2019' or `vs2022-dev`
start devenv ./build/slang.sln # to optionally open the project in Visual Studio
cmake --build --preset release # to build from the CLI
```
+The `vs2022-dev` preset turns on features that makes debugging easy.
+
## Testing
```bash
diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp
index 16f413055..111f4e465 100644
--- a/source/slang/slang-check-conversion.cpp
+++ b/source/slang/slang-check-conversion.cpp
@@ -842,29 +842,32 @@ namespace Slang
// Coercion from an initializer list is allowed for many types,
// so we will farm that out to its own subroutine.
//
- if( auto fromInitializerListExpr = as<InitializerListExpr>(fromExpr))
+ if (fromExpr && as<InitializerListType>(fromExpr->type.type))
{
- if( !_coerceInitializerList(
- toType,
- outToExpr,
- fromInitializerListExpr) )
+ if (auto fromInitializerListExpr = as<InitializerListExpr>(fromExpr))
{
- return false;
- }
+ if (!_coerceInitializerList(
+ toType,
+ outToExpr,
+ fromInitializerListExpr))
+ {
+ return false;
+ }
- // For now, we treat coercion from an initializer list
- // as having no cost, so that all conversions from initializer
- // lists are equally valid. This is fine given where initializer
- // lists are allowed to appear now, but might need to be made
- // more strict if we allow for initializer lists in more
- // places in the language (e.g., as function arguments).
- //
- if(outCost)
- {
- *outCost = kConversionCost_None;
- }
+ // For now, we treat coercion from an initializer list
+ // as having no cost, so that all conversions from initializer
+ // lists are equally valid. This is fine given where initializer
+ // lists are allowed to appear now, but might need to be made
+ // more strict if we allow for initializer lists in more
+ // places in the language (e.g., as function arguments).
+ //
+ if (outCost)
+ {
+ *outCost = kConversionCost_None;
+ }
- return true;
+ return true;
+ }
}
// nullptr_t can be cast into any pointer type.
diff --git a/tests/language-feature/interfaces/default-construct-conformance.slang b/tests/language-feature/interfaces/default-construct-conformance.slang
new file mode 100644
index 000000000..00778a9f6
--- /dev/null
+++ b/tests/language-feature/interfaces/default-construct-conformance.slang
@@ -0,0 +1,190 @@
+//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry testMain -profile cs_6_0
+
+// Test that invoking the default constructor of a type then use the result as an existential value
+// works correctly.
+
+RWStructuredBuffer<uint> output;
+RWStructuredBuffer<uint> expected;
+
+interface ITest
+{
+ uint getValue();
+};
+
+
+//TEST_INPUT:type_conformance Test0:ITest = 0
+struct Test0 : ITest
+{
+ uint getValue() { return 0; }
+};
+
+//TEST_INPUT:type_conformance Test1:ITest = 1
+struct Test1 : ITest
+{
+ uint getValue() { return 1; }
+};
+
+//TEST_INPUT:type_conformance TestAny:ITest = 2
+struct TestAny : ITest
+{
+ uint value = 5;
+ __init(uint v)
+ {
+ value = v;
+ }
+
+ uint getValue() { return value; }
+}
+
+// CHECK: Tuple{{.*}} makeTest0{{.*}}()
+// CHECK: Tuple{{.*}} = { uint2(0U, 0U), uint2(0U, 0U), packAnyValue4{{.*}} };
+ITest makeTest0()
+{
+ return Test0();
+}
+
+// CHECK: Tuple{{.*}} makeTest1{{.*}}()
+// CHECK: Tuple{{.*}} = { uint2(0U, 0U), uint2(1U, 0U), packAnyValue4{{.*}} };
+ITest makeTest1()
+{
+ return Test1();
+}
+
+// CHECK: Tuple{{.*}} makeTestAny{{.*}}()
+// CHECK: Tuple{{.*}} = { uint2(0U, 0U), uint2(2U, 0U), packAnyValue4{{.*}} };
+ITest makeTestAny()
+{
+ return TestAny();
+}
+
+ITest makeTestAny(uint v)
+{
+ return TestAny(v);
+}
+
+
+[numthreads(16, 1, 1)]
+void testMain(uint3 threadID: SV_DispatchThreadID)
+{
+ if (threadID.x != 0)
+ return;
+
+ int outputIdx = 0;
+
+ /// Test0
+ {
+ Test0 test;
+ output[outputIdx] = test.getValue();
+ expected[outputIdx++] = 0;
+ }
+
+ {
+ ITest test = Test0();
+ output[outputIdx] = test.getValue();
+ expected[outputIdx++] = 0;
+ }
+
+ {
+ output[outputIdx] = Test0().getValue();
+ expected[outputIdx++] = 0;
+ }
+
+ {
+ ITest test = makeTest0();
+ output[outputIdx] = test.getValue();
+ expected[outputIdx++] = 0;
+ }
+
+ {
+ output[outputIdx] = makeTest0().getValue();
+ expected[outputIdx++] = 0;
+ }
+
+ output[outputIdx] = 1000;
+ expected[outputIdx++] = 1000;
+
+ /// Test1
+ {
+ Test1 test;
+ output[outputIdx] = test.getValue();
+ expected[outputIdx++] = 1;
+ }
+
+ {
+ ITest test = Test1();
+ output[outputIdx] = test.getValue();
+ expected[outputIdx++] = 1;
+ }
+
+ {
+ output[outputIdx] = Test1().getValue();
+ expected[outputIdx++] = 1;
+ }
+
+ {
+ ITest test = makeTest1();
+ output[outputIdx] = test.getValue();
+ expected[outputIdx++] = 1;
+ }
+
+ {
+ output[outputIdx] = makeTest1().getValue();
+ expected[outputIdx++] = 1;
+ }
+
+ output[outputIdx] = 2000;
+ expected[outputIdx++] = 2000;
+
+ /// TestAny
+ {
+ TestAny test;
+ output[outputIdx] = test.getValue();
+ expected[outputIdx++] = 5;
+ }
+
+ {
+ ITest test = TestAny();
+ output[outputIdx] = test.getValue();
+ expected[outputIdx++] = 5;
+ }
+
+ {
+ ITest test = TestAny(2);
+ output[outputIdx] = test.getValue();
+ expected[outputIdx++] = 2;
+ }
+
+ {
+ output[outputIdx] = TestAny().getValue();
+ expected[outputIdx++] = 5;
+ }
+
+ {
+ output[outputIdx] = TestAny(2).getValue();
+ expected[outputIdx++] = 2;
+ }
+
+ {
+ ITest test = makeTestAny();
+ output[outputIdx] = test.getValue();
+ expected[outputIdx++] = 5;
+ }
+
+ {
+ ITest test = makeTestAny(2);
+ output[outputIdx] = test.getValue();
+ expected[outputIdx++] = 2;
+ }
+
+ {
+ output[outputIdx] = makeTestAny().getValue();
+ expected[outputIdx++] = 5;
+ }
+
+ {
+ output[outputIdx] = makeTestAny(2).getValue();
+ expected[outputIdx++] = 2;
+ }
+
+ expected[outputIdx++] = uint(-1);
+} \ No newline at end of file