Skip to content

Commit bd1c29e

Browse files
committed
Update to support classes with base classes
Also added tests for bitfield members to verify correct code generation for initializing bitfield members or initializing new objects from bitfields. ../clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
1 parent 74f5004 commit bd1c29e

File tree

4 files changed

+250
-11
lines changed

4 files changed

+250
-11
lines changed

clang/lib/AST/DeclCXX.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,14 @@ void CXXRecordDecl::addedMember(Decl *D) {
14621462
if (Using->getDeclName().getCXXOverloadedOperator() == OO_Equal)
14631463
data().HasInheritedAssignment = true;
14641464
}
1465+
1466+
// HLSL: All user-defined data types are aggregates and use aggregate
1467+
// initialization. This _needs_ to change in the future. There are two
1468+
// relevant HLSL feature proposals that will depend on this changing:
1469+
// * 0005-strict-initializer-lists.md
1470+
// * https://github.com/microsoft/hlsl-specs/pull/325
1471+
if (getLangOpts().HLSL && !isImplicit())
1472+
data().Aggregate = true;
14651473
}
14661474

14671475
bool CXXRecordDecl::isLiteral() const {

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3132,14 +3132,25 @@ static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
31323132
}
31333133

31343134
if (auto *RTy = Ty->getAs<RecordType>()) {
3135-
for (auto *FD : RTy->getDecl()->fields()) {
3136-
DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
3137-
DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
3138-
ExprResult Res = S.BuildFieldReferenceExpr(
3139-
E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
3140-
if (Res.isInvalid())
3141-
return;
3142-
BuildInitializerList(S, Ctx, Res.get(), List, DestTypes, ExcessInits);
3135+
llvm::SmallVector<const RecordType*> RecordTypes;
3136+
RecordTypes.push_back(RTy);
3137+
while(RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
3138+
CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
3139+
assert(D->getNumBases() == 1 && "HLSL doesn't support multiple inheritance");
3140+
RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
3141+
}
3142+
while (!RecordTypes.empty()) {
3143+
const RecordType* RT = RecordTypes.back();
3144+
RecordTypes.pop_back();
3145+
for (auto *FD : RT->getDecl()->fields()) {
3146+
DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
3147+
DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
3148+
ExprResult Res = S.BuildFieldReferenceExpr(
3149+
E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
3150+
if (Res.isInvalid())
3151+
return;
3152+
BuildInitializerList(S, Ctx, Res.get(), List, DestTypes, ExcessInits);
3153+
}
31433154
}
31443155
}
31453156
}
@@ -3166,9 +3177,20 @@ static Expr *GenerateInitLists(ASTContext &Ctx, QualType Ty,
31663177
for (uint64_t I = 0; I < Size; ++I)
31673178
Inits.push_back(GenerateInitLists(Ctx, ElTy, It));
31683179
}
3169-
if (const RecordDecl *RD = Ty->getAsRecordDecl()) {
3170-
for (auto *FD : RD->fields()) {
3171-
Inits.push_back(GenerateInitLists(Ctx, FD->getType(), It));
3180+
if (auto *RTy = Ty->getAs<RecordType>()) {
3181+
llvm::SmallVector<const RecordType*> RecordTypes;
3182+
RecordTypes.push_back(RTy);
3183+
while(RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
3184+
CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
3185+
assert(D->getNumBases() == 1 && "HLSL doesn't support multiple inheritance");
3186+
RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
3187+
}
3188+
while (!RecordTypes.empty()) {
3189+
const RecordType* RT = RecordTypes.back();
3190+
RecordTypes.pop_back();
3191+
for (auto *FD : RT->getDecl()->fields()) {
3192+
Inits.push_back(GenerateInitLists(Ctx, FD->getType(), It));
3193+
}
31723194
}
31733195
}
31743196
auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),

clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ struct Zoo {
3636
Kitteh Cats[4];
3737
};
3838

39+
struct FourFloats : TwoFloats {
40+
float Z, W;
41+
};
42+
43+
struct SlicyBits {
44+
int Z : 8;
45+
int W : 8;
46+
};
47+
3948
// Case 1: Extraneous braces get ignored in literal instantiation.
4049
// CHECK-LABEL: define void @_Z5case1v(
4150
// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]]) #[[ATTR0:[0-9]+]] {
@@ -712,3 +721,183 @@ Zoo case9(Doggo D1, AnimalBits A1) {
712721
Zoo Z1 = {D1, A1, D1, A1, D1, A1};
713722
return Z1;
714723
}
724+
725+
// Case 10: Initialize an object with a base class from two objects.
726+
// CHECK-LABEL: define void @_Z6case109TwoFloatsS_(
727+
// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_FOURFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS:%.*]]) align 4 [[TF1:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 4 [[TF2:%.*]]) #[[ATTR0]] {
728+
// CHECK-NEXT: [[ENTRY:.*:]]
729+
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 0
730+
// CHECK-NEXT: [[X1:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF1]], i32 0, i32 0
731+
// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X1]], align 4
732+
// CHECK-NEXT: store float [[TMP0]], ptr [[X]], align 4
733+
// CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
734+
// CHECK-NEXT: [[Y2:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF1]], i32 0, i32 1
735+
// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[Y2]], align 4
736+
// CHECK-NEXT: store float [[TMP1]], ptr [[Y]], align 4
737+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_FOURFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
738+
// CHECK-NEXT: [[X3:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF2]], i32 0, i32 0
739+
// CHECK-NEXT: [[TMP2:%.*]] = load float, ptr [[X3]], align 4
740+
// CHECK-NEXT: store float [[TMP2]], ptr [[Z]], align 4
741+
// CHECK-NEXT: [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_FOURFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 2
742+
// CHECK-NEXT: [[Y4:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF2]], i32 0, i32 1
743+
// CHECK-NEXT: [[TMP3:%.*]] = load float, ptr [[Y4]], align 4
744+
// CHECK-NEXT: store float [[TMP3]], ptr [[W]], align 4
745+
// CHECK-NEXT: ret void
746+
//
747+
FourFloats case10(TwoFloats TF1, TwoFloats TF2) {
748+
FourFloats FF1 = {TF1, TF2};
749+
return FF1;
750+
}
751+
752+
// Case 11: Initialize an object with a base class from a vector splat.
753+
// CHECK-LABEL: define void @_Z6case11f(
754+
// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_FOURFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]], float noundef nofpclass(nan inf) [[F:%.*]]) #[[ATTR0]] {
755+
// CHECK-NEXT: [[ENTRY:.*:]]
756+
// CHECK-NEXT: [[F_ADDR:%.*]] = alloca float, align 4
757+
// CHECK-NEXT: [[REF_TMP:%.*]] = alloca <4 x float>, align 16
758+
// CHECK-NEXT: [[REF_TMP1:%.*]] = alloca <4 x float>, align 16
759+
// CHECK-NEXT: [[REF_TMP4:%.*]] = alloca <4 x float>, align 16
760+
// CHECK-NEXT: [[REF_TMP7:%.*]] = alloca <4 x float>, align 16
761+
// CHECK-NEXT: store float [[F]], ptr [[F_ADDR]], align 4
762+
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS:%.*]], ptr [[AGG_RESULT]], i32 0, i32 0
763+
// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[F_ADDR]], align 4
764+
// CHECK-NEXT: [[CAST_SPLAT:%.*]] = insertelement <1 x float> poison, float [[TMP0]], i64 0
765+
// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <1 x float> [[CAST_SPLAT]], <1 x float> poison, <4 x i32> zeroinitializer
766+
// CHECK-NEXT: store <4 x float> [[TMP1]], ptr [[REF_TMP]], align 16
767+
// CHECK-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[REF_TMP]], align 16
768+
// CHECK-NEXT: [[VECEXT:%.*]] = extractelement <4 x float> [[TMP2]], i64 0
769+
// CHECK-NEXT: store float [[VECEXT]], ptr [[X]], align 4
770+
// CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
771+
// CHECK-NEXT: [[TMP3:%.*]] = load float, ptr [[F_ADDR]], align 4
772+
// CHECK-NEXT: [[CAST_SPLAT2:%.*]] = insertelement <1 x float> poison, float [[TMP3]], i64 0
773+
// CHECK-NEXT: [[TMP4:%.*]] = shufflevector <1 x float> [[CAST_SPLAT2]], <1 x float> poison, <4 x i32> zeroinitializer
774+
// CHECK-NEXT: store <4 x float> [[TMP4]], ptr [[REF_TMP1]], align 16
775+
// CHECK-NEXT: [[TMP5:%.*]] = load <4 x float>, ptr [[REF_TMP1]], align 16
776+
// CHECK-NEXT: [[VECEXT3:%.*]] = extractelement <4 x float> [[TMP5]], i64 1
777+
// CHECK-NEXT: store float [[VECEXT3]], ptr [[Y]], align 4
778+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_FOURFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
779+
// CHECK-NEXT: [[TMP6:%.*]] = load float, ptr [[F_ADDR]], align 4
780+
// CHECK-NEXT: [[CAST_SPLAT5:%.*]] = insertelement <1 x float> poison, float [[TMP6]], i64 0
781+
// CHECK-NEXT: [[TMP7:%.*]] = shufflevector <1 x float> [[CAST_SPLAT5]], <1 x float> poison, <4 x i32> zeroinitializer
782+
// CHECK-NEXT: store <4 x float> [[TMP7]], ptr [[REF_TMP4]], align 16
783+
// CHECK-NEXT: [[TMP8:%.*]] = load <4 x float>, ptr [[REF_TMP4]], align 16
784+
// CHECK-NEXT: [[VECEXT6:%.*]] = extractelement <4 x float> [[TMP8]], i64 2
785+
// CHECK-NEXT: store float [[VECEXT6]], ptr [[Z]], align 4
786+
// CHECK-NEXT: [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_FOURFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 2
787+
// CHECK-NEXT: [[TMP9:%.*]] = load float, ptr [[F_ADDR]], align 4
788+
// CHECK-NEXT: [[CAST_SPLAT8:%.*]] = insertelement <1 x float> poison, float [[TMP9]], i64 0
789+
// CHECK-NEXT: [[TMP10:%.*]] = shufflevector <1 x float> [[CAST_SPLAT8]], <1 x float> poison, <4 x i32> zeroinitializer
790+
// CHECK-NEXT: store <4 x float> [[TMP10]], ptr [[REF_TMP7]], align 16
791+
// CHECK-NEXT: [[TMP11:%.*]] = load <4 x float>, ptr [[REF_TMP7]], align 16
792+
// CHECK-NEXT: [[VECEXT9:%.*]] = extractelement <4 x float> [[TMP11]], i64 3
793+
// CHECK-NEXT: store float [[VECEXT9]], ptr [[W]], align 4
794+
// CHECK-NEXT: ret void
795+
//
796+
FourFloats case11(float F) {
797+
FourFloats FF1 = {F.xxxx};
798+
return FF1;
799+
}
800+
801+
// Case 12: Initialize bitfield from two integers.
802+
// CHECK-LABEL: define void @_Z6case12ii(
803+
// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_SLICYBITS:%.*]]) align 4 [[AGG_RESULT:%.*]], i32 noundef [[I:%.*]], i32 noundef [[J:%.*]]) #[[ATTR0]] {
804+
// CHECK-NEXT: [[ENTRY:.*:]]
805+
// CHECK-NEXT: [[I_ADDR:%.*]] = alloca i32, align 4
806+
// CHECK-NEXT: [[J_ADDR:%.*]] = alloca i32, align 4
807+
// CHECK-NEXT: store i32 [[I]], ptr [[I_ADDR]], align 4
808+
// CHECK-NEXT: store i32 [[J]], ptr [[J_ADDR]], align 4
809+
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
810+
// CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i16
811+
// CHECK-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[AGG_RESULT]], align 4
812+
// CHECK-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP1]], 255
813+
// CHECK-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD]], -256
814+
// CHECK-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_VALUE]]
815+
// CHECK-NEXT: store i16 [[BF_SET]], ptr [[AGG_RESULT]], align 4
816+
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[J_ADDR]], align 4
817+
// CHECK-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP2]] to i16
818+
// CHECK-NEXT: [[BF_LOAD1:%.*]] = load i16, ptr [[AGG_RESULT]], align 4
819+
// CHECK-NEXT: [[BF_VALUE2:%.*]] = and i16 [[TMP3]], 255
820+
// CHECK-NEXT: [[BF_SHL:%.*]] = shl i16 [[BF_VALUE2]], 8
821+
// CHECK-NEXT: [[BF_CLEAR3:%.*]] = and i16 [[BF_LOAD1]], 255
822+
// CHECK-NEXT: [[BF_SET4:%.*]] = or i16 [[BF_CLEAR3]], [[BF_SHL]]
823+
// CHECK-NEXT: store i16 [[BF_SET4]], ptr [[AGG_RESULT]], align 4
824+
// CHECK-NEXT: ret void
825+
//
826+
SlicyBits case12(int I, int J) {
827+
SlicyBits SB = {I, J};
828+
return SB;
829+
}
830+
831+
// Case 13: Initialize bitfield from a struct of two ints.
832+
// CHECK-LABEL: define void @_Z6case137TwoInts(
833+
// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_SLICYBITS:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_TWOINTS:%.*]]) align 4 [[TI:%.*]]) #[[ATTR0]] {
834+
// CHECK-NEXT: [[ENTRY:.*:]]
835+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 0
836+
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[Z]], align 4
837+
// CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i16
838+
// CHECK-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[AGG_RESULT]], align 4
839+
// CHECK-NEXT: [[BF_VALUE:%.*]] = and i16 [[TMP1]], 255
840+
// CHECK-NEXT: [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD]], -256
841+
// CHECK-NEXT: [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_VALUE]]
842+
// CHECK-NEXT: store i16 [[BF_SET]], ptr [[AGG_RESULT]], align 4
843+
// CHECK-NEXT: [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 1
844+
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[W]], align 4
845+
// CHECK-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP2]] to i16
846+
// CHECK-NEXT: [[BF_LOAD1:%.*]] = load i16, ptr [[AGG_RESULT]], align 4
847+
// CHECK-NEXT: [[BF_VALUE2:%.*]] = and i16 [[TMP3]], 255
848+
// CHECK-NEXT: [[BF_SHL:%.*]] = shl i16 [[BF_VALUE2]], 8
849+
// CHECK-NEXT: [[BF_CLEAR3:%.*]] = and i16 [[BF_LOAD1]], 255
850+
// CHECK-NEXT: [[BF_SET4:%.*]] = or i16 [[BF_CLEAR3]], [[BF_SHL]]
851+
// CHECK-NEXT: store i16 [[BF_SET4]], ptr [[AGG_RESULT]], align 4
852+
// CHECK-NEXT: ret void
853+
//
854+
SlicyBits case13(TwoInts TI) {
855+
SlicyBits SB = {TI};
856+
return SB;
857+
}
858+
859+
// Case 14: Initialize struct of ints from struct with bitfields.
860+
// CHECK-LABEL: define void @_Z6case149SlicyBits(
861+
// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOINTS:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_SLICYBITS:%.*]]) align 4 [[SB:%.*]]) #[[ATTR0]] {
862+
// CHECK-NEXT: [[ENTRY:.*:]]
863+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[AGG_RESULT]], i32 0, i32 0
864+
// CHECK-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[SB]], align 4
865+
// CHECK-NEXT: [[BF_SHL:%.*]] = shl i16 [[BF_LOAD]], 8
866+
// CHECK-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 8
867+
// CHECK-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32
868+
// CHECK-NEXT: store i32 [[BF_CAST]], ptr [[Z]], align 4
869+
// CHECK-NEXT: [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[AGG_RESULT]], i32 0, i32 1
870+
// CHECK-NEXT: [[BF_LOAD1:%.*]] = load i16, ptr [[SB]], align 4
871+
// CHECK-NEXT: [[BF_ASHR2:%.*]] = ashr i16 [[BF_LOAD1]], 8
872+
// CHECK-NEXT: [[BF_CAST3:%.*]] = sext i16 [[BF_ASHR2]] to i32
873+
// CHECK-NEXT: store i32 [[BF_CAST3]], ptr [[W]], align 4
874+
// CHECK-NEXT: ret void
875+
//
876+
TwoInts case14(SlicyBits SB) {
877+
TwoInts TI = {SB};
878+
return TI;
879+
}
880+
881+
// Case 15: Initialize struct of floats from struct with bitfields.
882+
// CHECK-LABEL: define void @_Z6case159SlicyBits(
883+
// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_SLICYBITS:%.*]]) align 4 [[SB:%.*]]) #[[ATTR0]] {
884+
// CHECK-NEXT: [[ENTRY:.*:]]
885+
// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 0
886+
// CHECK-NEXT: [[BF_LOAD:%.*]] = load i16, ptr [[SB]], align 4
887+
// CHECK-NEXT: [[BF_SHL:%.*]] = shl i16 [[BF_LOAD]], 8
888+
// CHECK-NEXT: [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 8
889+
// CHECK-NEXT: [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32
890+
// CHECK-NEXT: [[CONV:%.*]] = sitofp i32 [[BF_CAST]] to float
891+
// CHECK-NEXT: store float [[CONV]], ptr [[X]], align 4
892+
// CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
893+
// CHECK-NEXT: [[BF_LOAD1:%.*]] = load i16, ptr [[SB]], align 4
894+
// CHECK-NEXT: [[BF_ASHR2:%.*]] = ashr i16 [[BF_LOAD1]], 8
895+
// CHECK-NEXT: [[BF_CAST3:%.*]] = sext i16 [[BF_ASHR2]] to i32
896+
// CHECK-NEXT: [[CONV4:%.*]] = sitofp i32 [[BF_CAST3]] to float
897+
// CHECK-NEXT: store float [[CONV4]], ptr [[Y]], align 4
898+
// CHECK-NEXT: ret void
899+
//
900+
TwoFloats case15(SlicyBits SB) {
901+
TwoFloats TI = {SB};
902+
return TI;
903+
}

clang/test/SemaHLSL/Language/InitLists.hlsl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,15 @@ struct Zoo {
3535
Kitteh Cats[4];
3636
};
3737

38+
struct FourFloats : TwoFloats {
39+
float Z, W;
40+
};
41+
42+
struct SlicyBits {
43+
int Z : 8;
44+
int W : 8;
45+
};
46+
3847
void fn() {
3948
TwoFloats TF1 = {{{1.0, 2}}};
4049
TwoFloats TF2 = {1,2};
@@ -60,6 +69,17 @@ void fn() {
6069
// expected-warning@#insanity{{implicit conversion changes signedness: 'uint' (aka 'unsigned int') to 'int'}}
6170
}
6271

72+
void fn2() {
73+
TwoFloats TF2 = {1,2};
74+
FourFloats FF1 = {TF2, TF2};
75+
FourFloats FF2 = {1,2,3,4};
76+
FourFloats FF3 = {1.xxx, 2};
77+
78+
SlicyBits SB1 = {1,2};
79+
TwoInts TI1 = {SB1};
80+
SlicyBits SB2 = {TI1};
81+
}
82+
6383
void Errs() {
6484
TwoFloats F1 = {}; // expected-error{{too few initializers in list for type 'TwoFloats' (expected 2 but found 0)}}
6585
TwoFloats F2 = {1}; // expected-error{{too few initializers in list for type 'TwoFloats' (expected 2 but found 1)}}

0 commit comments

Comments
 (0)