Skip to content

Commit e1952dc

Browse files
authored
Fix a bug in default ctor synthesizing (#6527)
* Fix a bug in default ctor synthesizing - This is fix for the implementation bug, when a struct has explicit ctor we should not synthesize the default ctor anymore. - When invoke the synthesized ctor converted from initializer list, we should check if the struct is a c-style type if it struct has no synthesized ctor. In this case we should report error because it's invalid to use initializer list here. - The only exception is the unsized array, we still have to fall back to use the legacy initializer list logic to initialize the unsized array until we formalize a proper solution. - update test.
1 parent 9d7d943 commit e1952dc

6 files changed

+89
-30
lines changed

source/slang/slang-check-conversion.cpp

+25-4
Original file line numberDiff line numberDiff line change
@@ -396,14 +396,35 @@ bool SemanticsVisitor::createInvokeExprForSynthesizedCtor(
396396
{
397397
StructDecl* structDecl = isDeclRefTypeOf<StructDecl>(toType).getDecl();
398398

399-
if (!structDecl || !_getSynthesizedConstructor(
400-
structDecl,
401-
ConstructorDecl::ConstructorFlavor::SynthesizedDefault))
399+
if (!structDecl)
402400
return false;
403401

404402
HashSet<Type*> isVisit;
405-
bool isCStyle = isCStyleType(toType, isVisit);
403+
bool isCStyle = false;
404+
if (!_getSynthesizedConstructor(
405+
structDecl,
406+
ConstructorDecl::ConstructorFlavor::SynthesizedDefault))
407+
{
408+
// When a struct has no constructor and it's not a C-style type, the initializer list is
409+
// invalid.
410+
isCStyle = isCStyleType(toType, isVisit);
411+
412+
// WAR: We currently still has to allow legacy initializer list for array type until we have
413+
// more proper solution for array initialization, so if the right hand side is an array
414+
// type, we will not report error and fall-back to legacy initializer list logic.
415+
bool isArrayType = as<ArrayExpressionType>(toType) != nullptr;
416+
if (!isCStyle && !isArrayType)
417+
{
418+
getSink()->diagnose(
419+
fromInitializerListExpr->loc,
420+
Diagnostics::cannotUseInitializerListForType,
421+
toType);
422+
}
423+
424+
return false;
425+
}
406426

427+
isCStyle = isCStyleType(toType, isVisit);
407428
// TODO: This is just a special case for a backwards-compatibility feature
408429
// for HLSL, this flag will imply that the initializer list is synthesized
409430
// for a type cast from a literal zero to a 'struct'. In this case, we will fall

source/slang/slang-check-decl.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -12412,7 +12412,7 @@ bool SemanticsDeclAttributesVisitor::_synthesizeCtorSignature(StructDecl* struct
1241212412
// any constructors. see:
1241312413
// https://github.com/shader-slang/slang/blob/master/docs/proposals/004-initialization.md#inheritance-initialization
1241412414
if (_hasExplicitConstructor(structDecl, true))
12415-
return false;
12415+
return true;
1241612416

1241712417
// synthesize the signature first.
1241812418
// The constructor's visibility level is the same as the struct itself.

tests/initializer-list/explicit-ctor-diagnostic.slang

+3
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ void test()
1616
{
1717
// CHECK: error 39999: too many arguments to call (got 2, expected 1)
1818
ExplicitCtor e = {1, 2}; // error, no ctor matches initializer list.
19+
20+
// CHECK: error 39999: not enough arguments to call (got 0, expected 1)
21+
ExplicitCtor e1 = {};
1922
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
2+
3+
struct DefaultStruct_base
4+
{
5+
int data0;
6+
__init()
7+
{
8+
data0 = 2;
9+
}
10+
};
11+
12+
struct DefaultStruct1 : DefaultStruct_base
13+
{
14+
int data1 = 1;
15+
};
16+
17+
struct DefaultStruct2 : DefaultStruct_base
18+
{
19+
20+
};
21+
22+
[numthreads(1, 1, 1)]
23+
void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
24+
{
25+
//CHECK: error 30504: cannot use initializer list for type 'DefaultStruct1'
26+
DefaultStruct1 s1 = {};
27+
28+
//CHECK: error 30504: cannot use initializer list for type 'DefaultStruct1'
29+
DefaultStruct1 s2 = {1};
30+
31+
//CHECK: error 30504: cannot use initializer list for type 'DefaultStruct1'
32+
DefaultStruct1 s3 = {1, 2};
33+
34+
//CHECK: error 30504: cannot use initializer list for type 'DefaultStruct2'
35+
DefaultStruct2 s4 = {};
36+
37+
//CHECK: error 30504: cannot use initializer list for type 'DefaultStruct2'
38+
DefaultStruct2 s5 = {1};
39+
}
+15-24
Original file line numberDiff line numberDiff line change
@@ -16,51 +16,42 @@ struct DefaultStruct_base
1616

1717
__init()
1818
{
19-
data1 = 1;
19+
data0 = 2;
20+
data1 = 3;
2021
}
2122
};
23+
2224
struct DefaultStruct1 : DefaultStruct_base
23-
{
24-
int data2 = 1;
25-
};
26-
struct DefaultStruct2 : DefaultStruct_base
2725
{
2826
int data2 = 1;
2927
__init()
3028
{
31-
if (data0 != 1)
29+
if (data0 == 2)
3230
{
33-
data2 = 0;
31+
data2 = 4;
3432
}
3533
}
3634
};
37-
struct DefaultStruct3 : DefaultStruct_base
35+
36+
struct DefaultStruct2 : DefaultStruct_base
3837
{
3938
__init()
4039
{
4140
}
4241
};
43-
struct DefaultStruct4 : DefaultStruct_base
44-
{
45-
};
42+
4643
[numthreads(1, 1, 1)]
4744
void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
4845
{
49-
DefaultStruct1 s1 = {};
46+
DefaultStruct1 s1;
5047
DefaultStruct2 s2;
51-
DefaultStruct3 s3;
52-
DefaultStruct4 s4 = {};
48+
5349
// BUF: 1
5450
outputBuffer[0] = true
55-
&& s1.data0 == 1
56-
&& s1.data1 == 1
57-
&& s1.data2 == 1
58-
&& s2.data0 == 1
59-
&& s2.data1 == 1
60-
&& s2.data2 == 1
61-
&& s3.data0 == 1
62-
&& s3.data1 == 1
63-
&& s4.data0 == 1
64-
&& s4.data1 == 1
51+
&& s1.data0 == 2
52+
&& s1.data1 == 3
53+
&& s1.data2 == 4
54+
&& s2.data0 == 2
55+
&& s2.data1 == 3
6556
;
6657
}

tests/language-feature/interfaces/default-construct-conformance.slang

+6-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ struct TestAny : ITest
3333
value = v;
3434
}
3535

36+
__init()
37+
{
38+
value = 0;
39+
}
40+
3641
uint getValue() { return value; }
3742
}
3843

@@ -183,4 +188,4 @@ void testMain(uint3 threadID: SV_DispatchThreadID)
183188
}
184189

185190
expected[outputIdx++] = uint(-1);
186-
}
191+
}

0 commit comments

Comments
 (0)