summaryrefslogtreecommitdiffstats
path: root/tests/initializer-list
diff options
context:
space:
mode:
authorkaizhangNV <149626564+kaizhangNV@users.noreply.github.com>2025-02-05 12:37:03 -0600
committerGitHub <noreply@github.com>2025-02-05 10:37:03 -0800
commit9ec6b91686b651d959fd9ffbec283845bd725dd6 (patch)
tree2c48202cb04b76e5ddcb274be35529378ddf8f31 /tests/initializer-list
parent4b350645042b8e8fbdad19784ee745d11c7bc616 (diff)
Feature/initialize list side branch (#6058)
* SP004: implement initialize list translation to ctor - We synthesize a member-wise constructor for each struct follow the rules described in SP004. - Add logic to translate the initialize list to constructor invoke - Add cuda-host decoration for the synthesized constructor - Remove the default constructor when we have a valid member init constructor - Disable -zero-initialize option, will re-implement it in followup (#6109). - Fix the overload lookup issue When creating invoke expression for ctor, we need to call ResolveInvoke() to find us the best candidates, however the existing lookup logic could find us the base constructor for child struct, we should eliminate this case by providing the LookupOptions::IgnoreInheritance to lookup, this requires us to create a subcontext on SemanticsVisitor to indicate that we only want to use this option on looking the constructor. - Do not implicit initialize a struct that doesn't have explicit default constructor. Co-authored-by: slangbot <186143334+slangbot@users.noreply.github.com>
Diffstat (limited to 'tests/initializer-list')
-rw-r--r--tests/initializer-list/c-style-type.slang44
-rw-r--r--tests/initializer-list/default-member.slang35
-rw-r--r--tests/initializer-list/explicit-ctor-diagnostic.slang19
-rw-r--r--tests/initializer-list/explicit-ctor.slang41
-rw-r--r--tests/initializer-list/extension-overload-1.slang49
-rw-r--r--tests/initializer-list/extension-overload-2.slang28
-rw-r--r--tests/initializer-list/modulea.slang5
-rw-r--r--tests/initializer-list/partial-init-diagnostic.slang19
-rw-r--r--tests/initializer-list/partial-init.slang47
-rw-r--r--tests/initializer-list/struct-visibility-1.slang105
-rw-r--r--tests/initializer-list/struct-visibility-diagnostic-1.slang21
-rw-r--r--tests/initializer-list/struct-visibility-diagnostic-2.slang21
-rw-r--r--tests/initializer-list/struct-visibility-diagnostic-3.slang21
-rw-r--r--tests/initializer-list/struct-visibility-diagnostic-4.slang16
-rw-r--r--tests/initializer-list/unintialize-warning.slang85
15 files changed, 556 insertions, 0 deletions
diff --git a/tests/initializer-list/c-style-type.slang b/tests/initializer-list/c-style-type.slang
new file mode 100644
index 000000000..500bf37bb
--- /dev/null
+++ b/tests/initializer-list/c-style-type.slang
@@ -0,0 +1,44 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+struct CLike
+{
+ int x;
+ int y;
+ // compiler synthesizes:
+ // __init(int x, int y);
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+void test()
+{
+ // case 1: initialized with synthesized ctor call using legacy logic to form arguments,
+ // and `c1` is now `{0,0}`.
+ CLike c1 = {};
+
+ // case 2: initialized with legacy initializaer list logic, `c1` is now `{1,0}`:
+ CLike c2 = {1};
+
+ // case 3: initilaized with ctor call `CLike(1,2)`, `c3` is now `{1,2}`:
+ CLike c3 = {1, 2};
+
+ // BUFFER: 0
+ outputBuffer[0] = c1.x;
+ // BUFFER-NEXT: 0
+ outputBuffer[1] = c1.y;
+ // BUFFER-NEXT: 1
+ outputBuffer[2] = c2.x;
+ // BUFFER-NEXT: 0
+ outputBuffer[3] = c2.y;
+ // BUFFER-NEXT: 1
+ outputBuffer[4] = c3.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[5] = c3.y;
+}
+
+[shader("compute")]
+void computeMain()
+{
+ test();
+}
diff --git a/tests/initializer-list/default-member.slang b/tests/initializer-list/default-member.slang
new file mode 100644
index 000000000..8a6a0dc7f
--- /dev/null
+++ b/tests/initializer-list/default-member.slang
@@ -0,0 +1,35 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+struct DefaultMember {
+ int x = 0;
+ int y = 1;
+ // compiler synthesizes:
+ // __init(int x = 0, int y = 1);
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+void test()
+{
+ DefaultMember m1 = {1}; // calls `__init(1)`, initialized to `{1,1}`.
+
+ // BUFFER: 1
+ outputBuffer[0] = m1.x;
+
+ // BUFFER-NEXT: 1
+ outputBuffer[1] = m1.y;
+
+ DefaultMember m2 = {1,2}; // calls `__init(1,2)`, initialized to `{1,2}`.
+
+ // BUFFER-NEXT: 1
+ outputBuffer[2] = m2.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[3] = m2.y;
+}
+
+[shader("compute")]
+void computeMain()
+{
+ test();
+}
diff --git a/tests/initializer-list/explicit-ctor-diagnostic.slang b/tests/initializer-list/explicit-ctor-diagnostic.slang
new file mode 100644
index 000000000..a9d0e9858
--- /dev/null
+++ b/tests/initializer-list/explicit-ctor-diagnostic.slang
@@ -0,0 +1,19 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+struct ExplicitCtor
+{
+ int x;
+ int y;
+ __init(int x)
+ {
+ this.x = x;
+ this.y = 0;
+ }
+ // compiler does not synthesize any ctors.
+}
+
+void test()
+{
+ // CHECK: error 39999: too many arguments to call (got 2, expected 1)
+ ExplicitCtor e = {1, 2}; // error, no ctor matches initializer list.
+}
diff --git a/tests/initializer-list/explicit-ctor.slang b/tests/initializer-list/explicit-ctor.slang
new file mode 100644
index 000000000..c587bcce4
--- /dev/null
+++ b/tests/initializer-list/explicit-ctor.slang
@@ -0,0 +1,41 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+struct ExplicitCtor
+{
+ int x;
+ int y;
+ __init(int x)
+ {
+ this.x = x;
+ this.y = x + 5;
+ }
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+void test()
+{
+ // case 1: initialized with synthesized ctor call using legacy logic to form arguments,
+ // and `c1` is now `{0,0}`.
+ ExplicitCtor c1 = {4};
+
+ // BUFFER: 4
+ outputBuffer[0] = c1.x;
+ // BUFFER-NEXT: 9
+ outputBuffer[1] = c1.y;
+
+
+ ExplicitCtor c2 = ExplicitCtor(10);
+
+ // BUFFER: A
+ outputBuffer[2] = c2.x;
+ // BUFFER-NEXT: F
+ outputBuffer[3] = c2.y;
+}
+
+[shader("compute")]
+void computeMain()
+{
+ test();
+}
diff --git a/tests/initializer-list/extension-overload-1.slang b/tests/initializer-list/extension-overload-1.slang
new file mode 100644
index 000000000..1c3189f84
--- /dev/null
+++ b/tests/initializer-list/extension-overload-1.slang
@@ -0,0 +1,49 @@
+
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+import modulea;
+
+// Definition of the Foo struct
+// struct Foo
+// {
+// int a;
+// int b;
+// }
+
+// This test demonstrates that whether struct is a C-Style type only depends on the definition of the struct, not the extension.
+// Even we have an explicit constructor defined in extension of Foo, it is still a C-Style type.
+
+extension Foo
+{
+ __init(int a)
+ {
+ this.a = a + 5;
+ this.b = 3;
+ }
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+[shader("compute")]
+[numthreads(1, 1, 1)]
+void computeMain()
+{
+
+ // This will miss both synthesized constructor and explicit constructor in extension, but it will still fall back
+ // to legacy initializer list because Foo is a C-Style type.
+ Foo foo = {};
+ //CHECK: BUFFER: 0
+ //CHECK: BUFFER-NEXT: 0
+ outputBuffer[0] = foo.a;
+ outputBuffer[1] = foo.b;
+
+
+ // When providing 1 parameter, it will lookup for the explicit constructor in extension.
+ Foo foo1 = {1};
+ //CHECK: BUFFER: 6
+ //CHECK: BUFFER-NEXT: 3
+ outputBuffer[2] = foo1.a;
+ outputBuffer[3] = foo1.b;
+}
diff --git a/tests/initializer-list/extension-overload-2.slang b/tests/initializer-list/extension-overload-2.slang
new file mode 100644
index 000000000..3937127f4
--- /dev/null
+++ b/tests/initializer-list/extension-overload-2.slang
@@ -0,0 +1,28 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+struct Foo
+{
+ int a;
+}
+
+extension Foo
+{
+ __init(int a)
+ {
+ this.a = a + 5;
+ }
+}
+
+//TEST_INPUT:ubuffer(data=[0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+[shader("compute")]
+[numthreads(1, 1, 1)]
+void computeMain()
+{
+ // it will prefer the explicit constructor defined in the extension instead of the synthesized one in the struct
+ Foo foo = {1.0f};
+ //CHECK: BUFFER: 6
+ outputBuffer[0] = foo.a;
+}
diff --git a/tests/initializer-list/modulea.slang b/tests/initializer-list/modulea.slang
new file mode 100644
index 000000000..48a4a5d6a
--- /dev/null
+++ b/tests/initializer-list/modulea.slang
@@ -0,0 +1,5 @@
+export struct Foo
+{
+ int a;
+ int b;
+}
diff --git a/tests/initializer-list/partial-init-diagnostic.slang b/tests/initializer-list/partial-init-diagnostic.slang
new file mode 100644
index 000000000..ea3acb2c7
--- /dev/null
+++ b/tests/initializer-list/partial-init-diagnostic.slang
@@ -0,0 +1,19 @@
+//DISABLE_DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+struct PartialInit
+{
+ int x = 1;
+ int y;
+ // compiler synthesizes:
+ // __init(int x, int y);
+}
+
+void test()
+{
+ // TODO: Because we have a legacy logic that will always convert the one arugment ctor call to
+ // initializer list, and that initializer list will fall back to the legacy C-Style initialization.
+ // We need to remove that logic.
+
+ // CHECK: error 33070: expected a function, got 'typeof(PartialInit)'
+ PartialInit p = PartialInit(2); // error, no ctor match.
+}
diff --git a/tests/initializer-list/partial-init.slang b/tests/initializer-list/partial-init.slang
new file mode 100644
index 000000000..55f3816fb
--- /dev/null
+++ b/tests/initializer-list/partial-init.slang
@@ -0,0 +1,47 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+struct PartialInit {
+ // warning: not all members are initialized.
+ // members should either be all-uninitialized or all-initialized with
+ // default expr.
+ int x;
+ int y = 1;
+ // compiler synthesizes:
+ // __init(int x, int y = 1);
+}
+
+struct PartialInit2 {
+ int x = 1;
+ int y;
+ // __init(int x, int y);
+}
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+void test()
+{
+ PartialInit p1 = {2}; // calls `__init`, result is `{2,1}`.
+ // BUFFER: 2
+ outputBuffer[0] = p1.x;
+ // BUFFER-NEXT: 1
+ outputBuffer[1] = p1.y;
+
+
+ PartialInit p2 = {2, 3}; // calls `__init`, result is {2, 3}
+ // BUFFER-NEXT: 2
+ outputBuffer[2] = p2.x;
+ // BUFFER-NEXT: 3
+ outputBuffer[3] = p2.y;
+
+ PartialInit2 p3 = {4, 5}; // calls `__init`, result is {4, 5}
+ // BUFFER-NEXT: 4
+ outputBuffer[4] = p3.x;
+ // BUFFER-NEXT: 5
+ outputBuffer[5] = p3.y;
+}
+
+[shader("compute")]
+void computeMain()
+{
+ test();
+}
diff --git a/tests/initializer-list/struct-visibility-1.slang b/tests/initializer-list/struct-visibility-1.slang
new file mode 100644
index 000000000..691e8c991
--- /dev/null
+++ b/tests/initializer-list/struct-visibility-1.slang
@@ -0,0 +1,105 @@
+
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj -vk
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUFFER):-shaderobj
+
+public struct Visibility
+{
+ internal int x = 1;
+ public int y = 5;
+
+ int getX() { return x; }
+}
+
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+void test(inout uint index)
+{
+ Visibility t1 = {}; // OK, initialized to {1,5} via ctor call.
+ // BUFFER: 1
+ outputBuffer[index++] = t1.getX();
+ // BUFFER-NEXT: 5
+ outputBuffer[index++] = t1.y;
+
+ Visibility t2 = {1}; // OK, initialized to {1,1} via ctor call.
+ // BUFFER-NEXT: 1
+ outputBuffer[index++] = t2.getX();
+ // BUFFER-NEXT: 1
+ outputBuffer[index++] = t2.y;
+}
+
+internal struct Visibility2
+{
+ // Visibility3 type is considered as C-style struct.
+ // Because all members have the same visibility as the type.
+ // Therefore we will attempt the legacy fallback logic for
+ // initializer-list syntax.
+ // Note that c-style structs can still have init exprs on members.
+ internal int x;
+ internal int y = 2;
+ // compiler synthesizes:
+ // internal __init(int x, int y = 2);
+}
+
+internal void test2(inout uint index)
+{
+ Visibility2 t = {3, 4}; // OK, initialized to {3,4} via ctor call.
+ // BUFFER-NEXT: 3
+ outputBuffer[index++] = t.x;
+ // BUFFER-NEXT: 4
+ outputBuffer[index++] = t.y;
+
+ Visibility2 t1 = {1}; // OK, initialized to {1,2} via ctor call.
+ // BUFFER-NEXT: 1
+ outputBuffer[index++] = t1.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[index++] = t1.y;
+
+ Visibility2 t2 = {}; // OK, initialized to {0, 2} via legacy logic.
+ // BUFFER-NEXT: 0
+ outputBuffer[index++] = t2.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[index++] = t2.y;
+}
+
+internal struct Visibility3
+{
+ // Visibility4 type is considered as C-style struct.
+ // And we still synthesize a ctor for member initialization.
+ // Because Visibility4 has no public members, the synthesized
+ // ctor will take 0 arguments.
+ internal int x = 1;
+ internal int y = 2;
+ // compiler synthesizes:
+ // internal __init(int x = 1, int y = 2);
+}
+
+internal void test3(inout uint index)
+{
+ Visibility3 t = {0, 0}; // OK, initialized to {0,0} via ctor call.
+ // BUFFER-NEXT: 0
+ outputBuffer[index++] = t.x;
+ // BUFFER-NEXT: 0
+ outputBuffer[index++] = t.y;
+
+ Visibility3 t1 = {3}; // OK, initialized to {3,2} via ctor call.
+ // BUFFER-NEXT: 3
+ outputBuffer[index++] = t1.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[index++] = t1.y;
+
+ Visibility3 t2 = {}; // OK, initialized to {1,2} via ctor call.
+ // BUFFER-NEXT: 1
+ outputBuffer[index++] = t2.x;
+ // BUFFER-NEXT: 2
+ outputBuffer[index++] = t2.y;
+}
+
+[shader("compute")]
+void computeMain()
+{
+ uint index = 0;
+ test(index);
+ test2(index);
+ test3(index);
+}
diff --git a/tests/initializer-list/struct-visibility-diagnostic-1.slang b/tests/initializer-list/struct-visibility-diagnostic-1.slang
new file mode 100644
index 000000000..ab11933ae
--- /dev/null
+++ b/tests/initializer-list/struct-visibility-diagnostic-1.slang
@@ -0,0 +1,21 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+public struct Visibility
+{
+ internal int x;
+ public int y = 0;
+ // the compiler does not synthesize any ctor.
+ // the compiler will try to synthesize:
+ // public __init(int y);
+ // but then it will find that `x` cannot be initialized.
+ // so this synthesis will fail and no ctor will be added
+ // to the type.
+}
+
+void test()
+{
+ // CHECK: error 39999: too many arguments to call (got 2, expected 1)
+ Visibility t1 = {1, 2}; // error, no matching ctor
+}
+
+
diff --git a/tests/initializer-list/struct-visibility-diagnostic-2.slang b/tests/initializer-list/struct-visibility-diagnostic-2.slang
new file mode 100644
index 000000000..a3255de5e
--- /dev/null
+++ b/tests/initializer-list/struct-visibility-diagnostic-2.slang
@@ -0,0 +1,21 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+public struct Visibility
+{
+ internal int x;
+ public int y = 5;
+ // the compiler does not synthesize any ctor.
+ // the compiler will try to synthesize:
+ // public __init(int y);
+ // but then it will find that `x` cannot be initialized.
+ // so this synthesis will fail and no ctor will be added
+ // to the type.
+}
+
+void test()
+{
+ // CHECK: warning 41021: default initializer for 'Visibility' will not initialize field 'x'
+ Visibility t1 = {};
+}
+
+
diff --git a/tests/initializer-list/struct-visibility-diagnostic-3.slang b/tests/initializer-list/struct-visibility-diagnostic-3.slang
new file mode 100644
index 000000000..75ac5919d
--- /dev/null
+++ b/tests/initializer-list/struct-visibility-diagnostic-3.slang
@@ -0,0 +1,21 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+public struct Visibility
+{
+ internal int x;
+ public int y;
+ // the compiler does not synthesize any ctor.
+ // the compiler will try to synthesize:
+ // public __init(int y);
+ // but then it will find that `x` cannot be initialized.
+ // so this synthesis will fail and no ctor will be added
+ // to the type.
+}
+
+void test()
+{
+ //CHECK: error 39999: not enough arguments to call (got 0, expected 1)
+ Visibility t1 = {};
+}
+
+
diff --git a/tests/initializer-list/struct-visibility-diagnostic-4.slang b/tests/initializer-list/struct-visibility-diagnostic-4.slang
new file mode 100644
index 000000000..9bc3a76f0
--- /dev/null
+++ b/tests/initializer-list/struct-visibility-diagnostic-4.slang
@@ -0,0 +1,16 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+public struct Visibility
+{
+ internal int x = 1;
+ public int y = 5;
+ // compiler synthesizes:
+ // public __init(int y = 0);
+}
+
+void test()
+{
+ //CHECK: error 39999: too many arguments to call (got 2, expected 1)
+ Visibility t1 = {1, 2};
+}
+
diff --git a/tests/initializer-list/unintialize-warning.slang b/tests/initializer-list/unintialize-warning.slang
new file mode 100644
index 000000000..b8f2867ee
--- /dev/null
+++ b/tests/initializer-list/unintialize-warning.slang
@@ -0,0 +1,85 @@
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
+
+struct CLike
+{
+ int x;
+ int y;
+ // compiler synthesizes:
+ // __init(int x, int y);
+}
+
+struct ExplicitCtor
+{
+ int x;
+ int y;
+ __init(int x)
+ {
+ this.x = x;
+ this.y = 0;
+ }
+ // compiler does not synthesize any ctors.
+}
+
+struct DefaultMember {
+ int x = 0;
+ int y = 1;
+ // compiler synthesizes:
+ // __init(int x = 0, int y = 1);
+}
+
+struct PartialInit1 {
+ int x;
+ int y = 1;
+ // compiler synthesizes:
+ // __init(int x, int y = 1);
+}
+
+struct PartialInit2 {
+ int x = 1;
+ int y; // warning: not all members are initialized.
+ // compiler synthesizes:
+ // __init(int x, int y);
+}
+
+void func1(CLike c)
+{
+}
+
+void func2(ExplicitCtor e)
+{
+}
+
+void func3(DefaultMember d)
+{
+}
+
+void func4(PartialInit1 p)
+{
+}
+
+void func5(PartialInit2 p)
+{
+}
+
+void test()
+{
+ CLike c; // `c` is uninitialized.
+ // CHECK: warning 41016: use of uninitialized variable 'c'
+ func1(c);
+
+ ExplicitCtor e; // `e` is uninitialized.
+ // CHECK: warning 41016: use of uninitialized variable 'e'
+ func2(e);
+
+ DefaultMember d; // `d` is uninitialized.
+ // CHECK: warning 41016: use of uninitialized variable 'd'
+ func3(d);
+
+ PartialInit1 p1; // `p` is uninitialized.
+ // CHECK: warning 41016: use of uninitialized variable 'p1'
+ func4(p1);
+
+ PartialInit2 p2; // `p` is uninitialized.
+ // CHECK: warning 41016: use of uninitialized variable 'p2'
+ func5(p2);
+}