Author: Sarah Spall
Date: 2026-03-26T11:48:07-07:00
New Revision: 1eebbb066a3711330b535965a7701c6f6f52f332

URL: 
https://github.com/llvm/llvm-project/commit/1eebbb066a3711330b535965a7701c6f6f52f332
DIFF: 
https://github.com/llvm/llvm-project/commit/1eebbb066a3711330b535965a7701c6f6f52f332.diff

LOG: [HLSL] Create XValue in HLSL list initialization if record is a prvalue 
(#186233)

In the case where the record in an Init List expression is a prvalue
create an xvalue so member accesses will be xvalues. This is in line
with the C++ specification. The Clang code which generates the member
field access however does not create an xvalue if the record is a
prvalue, so we make the record an xvalue here.

https://en.cppreference.com/w/cpp/language/value_category.html
```
is an xvalue expression: a.m, the member of object expression, where a is an 
rvalue and m is a non-static data member of an object type;
```

Adds Constant expression evaluation tests for Init list expressions
which contain a cast. This test file is currently XFAILed on issue
#188577
Closes #185911

---------

Co-authored-by: Deric C. <[email protected]>

Added: 
    clang/test/SemaHLSL/Types/InitListConstantExpr.hlsl

Modified: 
    clang/lib/Sema/SemaHLSL.cpp
    clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
    clang/test/SemaHLSL/Language/InitListAST.hlsl

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index aebe284b2399a..3b7b12a884f43 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -5700,6 +5700,11 @@ class InitListTransformer {
     if (auto *RD = Ty->getAsCXXRecordDecl()) {
       llvm::SmallVector<CXXRecordDecl *> RecordDecls;
       RecordDecls.push_back(RD);
+      // If this is a prvalue create an xvalue so the member accesses
+      // will be xvalues.
+      if (E->isPRValue())
+        E = new (Ctx)
+            MaterializeTemporaryExpr(Ty, E, /*BoundToLvalueReference=*/false);
       while (RecordDecls.back()->getNumBases()) {
         CXXRecordDecl *D = RecordDecls.back();
         assert(D->getNumBases() == 1 &&

diff  --git a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl 
b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
index 3d7b8a906cdae..9c42da8962c2d 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
@@ -1146,6 +1146,169 @@ struct CustomResource {
 void case27(CustomResource a) {
   CustomResource b = {a};
 }
+
+// Check cases with explicit casts
+
+// CHECK-LABEL: define hidden void @_Z6case289TwoFloats(
+// CHECK-SAME: ptr noundef byval([[STRUCT_TWOFLOATS:%.*]]) align 1 [[TF:%.*]]) 
#[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TI:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_TWOINTS]], align 1
+// CHECK-NEXT:    [[AGG_TEMP:%.*]] = alloca [[STRUCT_TWOFLOATS]], align 1
+// CHECK-NEXT:    [[REF_TMP6:%.*]] = alloca [[STRUCT_TWOINTS]], align 1
+// CHECK-NEXT:    [[AGG_TEMP7:%.*]] = alloca [[STRUCT_TWOFLOATS]], align 1
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], 
ptr [[TI]], i32 0, i32 0
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AGG_TEMP]], 
ptr align 1 [[TF]], i32 8, i1 false)
+// CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], ptr 
[[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], 
ptr [[REF_TMP]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds [[STRUCT_TWOFLOATS]], 
ptr [[AGG_TEMP]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP3:%.*]] = getelementptr inbounds [[STRUCT_TWOFLOATS]], 
ptr [[AGG_TEMP]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[GEP2]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[TMP0]] to i32
+// CHECK-NEXT:    store i32 [[CONV]], ptr [[GEP]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load float, ptr [[GEP3]], align 4
+// CHECK-NEXT:    [[CONV4:%.*]] = fptosi float [[TMP1]] to i32
+// CHECK-NEXT:    store i32 [[CONV4]], ptr [[GEP1]], align 4
+// CHECK-NEXT:    [[Z5:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], 
ptr [[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[Z5]], align 1
+// CHECK-NEXT:    store i32 [[TMP2]], ptr [[Z]], align 1
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], 
ptr [[TI]], i32 0, i32 1
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AGG_TEMP7]], 
ptr align 1 [[TF]], i32 8, i1 false)
+// CHECK-NEXT:    [[GEP8:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], 
ptr [[REF_TMP6]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP9:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], 
ptr [[REF_TMP6]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP10:%.*]] = getelementptr inbounds [[STRUCT_TWOFLOATS]], 
ptr [[AGG_TEMP7]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP11:%.*]] = getelementptr inbounds [[STRUCT_TWOFLOATS]], 
ptr [[AGG_TEMP7]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP3:%.*]] = load float, ptr [[GEP10]], align 4
+// CHECK-NEXT:    [[CONV12:%.*]] = fptosi float [[TMP3]] to i32
+// CHECK-NEXT:    store i32 [[CONV12]], ptr [[GEP8]], align 4
+// CHECK-NEXT:    [[TMP4:%.*]] = load float, ptr [[GEP11]], align 4
+// CHECK-NEXT:    [[CONV13:%.*]] = fptosi float [[TMP4]] to i32
+// CHECK-NEXT:    store i32 [[CONV13]], ptr [[GEP9]], align 4
+// CHECK-NEXT:    [[W14:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], 
ptr [[REF_TMP6]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[W14]], align 1
+// CHECK-NEXT:    store i32 [[TMP5]], ptr [[W]], align 1
+// CHECK-NEXT:    ret void
+//
+void case28(TwoFloats TF) {
+  TwoInts TI = {(TwoInts)TF};
+}
+
+// CHECK-LABEL: define hidden void @_Z6case2910FourFloats(
+// CHECK-SAME: ptr noundef byval([[STRUCT_FOURFLOATS:%.*]]) align 1 
[[FF:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[INTS:%.*]] = alloca [2 x i32], align 4
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca [2 x i32], align 4
+// CHECK-NEXT:    [[AGG_TEMP:%.*]] = alloca [[STRUCT_FOURFLOATS]], align 1
+// CHECK-NEXT:    [[REF_TMP7:%.*]] = alloca [2 x i32], align 4
+// CHECK-NEXT:    [[AGG_TEMP8:%.*]] = alloca [[STRUCT_FOURFLOATS]], align 1
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AGG_TEMP]], 
ptr align 1 [[FF]], i32 16, i1 false)
+// CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x i32], ptr 
[[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds [2 x i32], ptr 
[[REF_TMP]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], 
ptr [[AGG_TEMP]], i32 0, i32 0, i32 0
+// CHECK-NEXT:    [[GEP3:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], 
ptr [[AGG_TEMP]], i32 0, i32 0, i32 1
+// CHECK-NEXT:    [[GEP4:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], 
ptr [[AGG_TEMP]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP5:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], 
ptr [[AGG_TEMP]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[GEP2]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[TMP0]] to i32
+// CHECK-NEXT:    store i32 [[CONV]], ptr [[GEP]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load float, ptr [[GEP3]], align 4
+// CHECK-NEXT:    [[CONV6:%.*]] = fptosi float [[TMP1]] to i32
+// CHECK-NEXT:    store i32 [[CONV6]], ptr [[GEP1]], align 4
+// CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [2 x i32], ptr 
[[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// CHECK-NEXT:    store i32 [[TMP2]], ptr [[INTS]], align 4
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds i32, ptr 
[[INTS]], i32 1
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AGG_TEMP8]], 
ptr align 1 [[FF]], i32 16, i1 false)
+// CHECK-NEXT:    [[GEP9:%.*]] = getelementptr inbounds [2 x i32], ptr 
[[REF_TMP7]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP10:%.*]] = getelementptr inbounds [2 x i32], ptr 
[[REF_TMP7]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP11:%.*]] = getelementptr inbounds 
[[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP8]], i32 0, i32 0, i32 0
+// CHECK-NEXT:    [[GEP12:%.*]] = getelementptr inbounds 
[[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP8]], i32 0, i32 0, i32 1
+// CHECK-NEXT:    [[GEP13:%.*]] = getelementptr inbounds 
[[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP8]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP14:%.*]] = getelementptr inbounds 
[[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP8]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP3:%.*]] = load float, ptr [[GEP11]], align 4
+// CHECK-NEXT:    [[CONV15:%.*]] = fptosi float [[TMP3]] to i32
+// CHECK-NEXT:    store i32 [[CONV15]], ptr [[GEP9]], align 4
+// CHECK-NEXT:    [[TMP4:%.*]] = load float, ptr [[GEP12]], align 4
+// CHECK-NEXT:    [[CONV16:%.*]] = fptosi float [[TMP4]] to i32
+// CHECK-NEXT:    store i32 [[CONV16]], ptr [[GEP10]], align 4
+// CHECK-NEXT:    [[ARRAYIDX17:%.*]] = getelementptr inbounds nuw [2 x i32], 
ptr [[REF_TMP7]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[ARRAYIDX17]], align 4
+// CHECK-NEXT:    store i32 [[TMP5]], ptr [[ARRAYINIT_ELEMENT]], align 4
+// CHECK-NEXT:    ret void
+//
+void case29(FourFloats FF) {
+  int Ints[2] = {(int[2])FF};
+}
+
+// CHECK-LABEL: define hidden void @_Z6case30v(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[ARR:%.*]] = alloca [4 x float], align 4
+// CHECK-NEXT:    [[TI:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_TWOINTS]], align 1
+// CHECK-NEXT:    [[AGG_TEMP:%.*]] = alloca [4 x float], align 4
+// CHECK-NEXT:    [[REF_TMP8:%.*]] = alloca [[STRUCT_TWOINTS]], align 1
+// CHECK-NEXT:    [[AGG_TEMP9:%.*]] = alloca [4 x float], align 4
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr 
align 4 @__const._Z6case30v.Arr, i32 16, i1 false)
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], 
ptr [[TI]], i32 0, i32 0
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AGG_TEMP]], 
ptr align 4 [[ARR]], i32 16, i1 false)
+// CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], ptr 
[[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], 
ptr [[REF_TMP]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds [4 x float], ptr 
[[AGG_TEMP]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP3:%.*]] = getelementptr inbounds [4 x float], ptr 
[[AGG_TEMP]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP4:%.*]] = getelementptr inbounds [4 x float], ptr 
[[AGG_TEMP]], i32 0, i32 2
+// CHECK-NEXT:    [[GEP5:%.*]] = getelementptr inbounds [4 x float], ptr 
[[AGG_TEMP]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[GEP2]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[TMP0]] to i32
+// CHECK-NEXT:    store i32 [[CONV]], ptr [[GEP]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load float, ptr [[GEP3]], align 4
+// CHECK-NEXT:    [[CONV6:%.*]] = fptosi float [[TMP1]] to i32
+// CHECK-NEXT:    store i32 [[CONV6]], ptr [[GEP1]], align 4
+// CHECK-NEXT:    [[Z7:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], 
ptr [[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[Z7]], align 1
+// CHECK-NEXT:    store i32 [[TMP2]], ptr [[Z]], align 1
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], 
ptr [[TI]], i32 0, i32 1
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AGG_TEMP9]], 
ptr align 4 [[ARR]], i32 16, i1 false)
+// CHECK-NEXT:    [[GEP10:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], 
ptr [[REF_TMP8]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP11:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], 
ptr [[REF_TMP8]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP12:%.*]] = getelementptr inbounds [4 x float], ptr 
[[AGG_TEMP9]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP13:%.*]] = getelementptr inbounds [4 x float], ptr 
[[AGG_TEMP9]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP14:%.*]] = getelementptr inbounds [4 x float], ptr 
[[AGG_TEMP9]], i32 0, i32 2
+// CHECK-NEXT:    [[GEP15:%.*]] = getelementptr inbounds [4 x float], ptr 
[[AGG_TEMP9]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP3:%.*]] = load float, ptr [[GEP12]], align 4
+// CHECK-NEXT:    [[CONV16:%.*]] = fptosi float [[TMP3]] to i32
+// CHECK-NEXT:    store i32 [[CONV16]], ptr [[GEP10]], align 4
+// CHECK-NEXT:    [[TMP4:%.*]] = load float, ptr [[GEP13]], align 4
+// CHECK-NEXT:    [[CONV17:%.*]] = fptosi float [[TMP4]] to i32
+// CHECK-NEXT:    store i32 [[CONV17]], ptr [[GEP11]], align 4
+// CHECK-NEXT:    [[W18:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], 
ptr [[REF_TMP8]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[W18]], align 1
+// CHECK-NEXT:    store i32 [[TMP5]], ptr [[W]], align 1
+// CHECK-NEXT:    ret void
+//
+void case30() {
+  float Arr[4] = {1.0,2.0,3.0,4.0};
+  TwoInts TI = {(TwoInts)Arr};
+}
+
+// CHECK-LABEL: define hidden void @_Z6case31v(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[F:%.*]] = alloca float, align 4
+// CHECK-NEXT:    [[SB:%.*]] = alloca [[STRUCT_SLICYBITS:%.*]], align 1
+// CHECK-NEXT:    store float 1.000000e+00, ptr [[F]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[F]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[TMP0]] to i32
+// CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[CONV]] to i8
+// CHECK-NEXT:    store i8 [[TMP1]], ptr [[SB]], align 1
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_SLICYBITS]], 
ptr [[SB]], i32 0, i32 1
+// CHECK-NEXT:    store i8 2, ptr [[W]], align 1
+// CHECK-NEXT:    ret void
+//
+void case31() {
+  float F = 1.0;
+  SlicyBits SB = {(int)F, 2};
+}
 //.
 // CHECK: [[META3]] = !{}
 // CHECK: [[META4]] = !{i64 4}

diff  --git a/clang/test/SemaHLSL/Language/InitListAST.hlsl 
b/clang/test/SemaHLSL/Language/InitListAST.hlsl
index 460ec38bb44af..63e6af61b124a 100644
--- a/clang/test/SemaHLSL/Language/InitListAST.hlsl
+++ b/clang/test/SemaHLSL/Language/InitListAST.hlsl
@@ -1059,3 +1059,120 @@ float case17() {
   float Floats[] = {Structs, Structs};
   return Floats[7];
 }
+
+// Tests which use explicit casts
+
+// CHECK-LABEL: Dumping case18
+// CHECK: VarDecl {{.*}} used TF 'TwoFloats' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 2.000000e+00
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} used TI 'TwoInts' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' xvalue .Z
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'TwoInts' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'TwoInts' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue Var {{.*}} 'TF' 
'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' xvalue .W
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'TwoInts' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'TwoInts' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue Var {{.*}} 'TF' 
'TwoFloats'
+int case18() {
+  TwoFloats TF = {1.0,2.0};
+  TwoInts TI = {(TwoInts)TF};
+  return TI.Z;
+}
+
+// CHECK-LABEL: Dumping case19
+// CHECK: VarDecl {{.*}} used FF 'FourFloats' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'FourFloats'
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 2.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 3.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 4.000000e+00
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} used Ints 'int[4]' cinit
+// CHECK-NEXT: ExprWithCleanups {{.*}} 'int[4]'
+// CHECK-NEXT: InitListExpr {{.*}} 'int[4]'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' xvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'int[4]' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'int[4]' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'FourFloats' lvalue Var {{.*}} 'FF' 
'FourFloats'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' xvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'int[4]' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'int[4]' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'FourFloats' lvalue Var {{.*}} 'FF' 
'FourFloats'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' xvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'int[4]' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'int[4]' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'FourFloats' lvalue Var {{.*}} 'FF' 
'FourFloats'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' xvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'int[4]' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'int[4]' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'FourFloats' lvalue Var {{.*}} 'FF' 
'FourFloats'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 3
+int case19() {
+  FourFloats FF = {1.0,2.0,3.0,4.0};
+  int Ints[4] = {(int[4])FF};
+  return Ints[0];
+}
+
+// CHECK-LABEL: Dumping case20
+// CHECK: VarDecl {{.*}} used Arr 'float[4]' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'float[4]'
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 2.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 3.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 4.000000e+00
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} used TI 'TwoInts' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' xvalue .Z
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'TwoInts' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'TwoInts' <HLSLElementwiseCast>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float[4]' <HLSLArrayRValue> 
part_of_explicit_cast
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float[4]' lvalue Var {{.*}} 'Arr' 'float[4]'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' xvalue .W
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'TwoInts' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'TwoInts' <HLSLElementwiseCast>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float[4]' <HLSLArrayRValue> 
part_of_explicit_cast
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float[4]' lvalue Var {{.*}} 'Arr' 'float[4]'
+int case20() {
+  float Arr[4] = {1.0,2.0,3.0,4.0};
+  TwoInts TI = {(TwoInts)Arr};
+  return TI.Z;
+}
+
+// CHECK-LABEL: Dumping case21
+// CHECK: VarDecl {{.*}} used F 'float' cinit
+// CHECK-NEXT: {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} used SB 'SlicyBits' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'SlicyBits'
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'int' <NoOp>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <FloatingToIntegral> 
part_of_explicit_cast
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue> 
part_of_explicit_cast
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue Var {{.*}} 'F' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
+int case21() {
+  float F = 1.0;
+  SlicyBits SB = {(int)F, 2};
+  return SB.Z;
+}

diff  --git a/clang/test/SemaHLSL/Types/InitListConstantExpr.hlsl 
b/clang/test/SemaHLSL/Types/InitListConstantExpr.hlsl
new file mode 100644
index 0000000000000..c2797f5c8d94e
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/InitListConstantExpr.hlsl
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library 
-finclude-default-header -fnative-half-type -fnative-int16-type -std=hlsl202x 
-verify %s
+
+// expected-no-diagnostics
+// XFAIL because of this issue: 
https://github.com/llvm/llvm-project/issues/188577
+// These tests hit an assert.
+// XFAIL: *
+
+struct Base {
+  double D;
+  uint64_t2 U;
+  int16_t I : 5;
+  uint16_t I2: 5;
+};
+
+struct B1 {
+  float A;
+  float B;
+};
+
+struct B2 : B1 {
+  int C;
+  int D;
+  bool BB;
+};
+
+export void fn() {
+
+  // splat from a vector of size 1 in an init list
+  constexpr int1 A1 = {1};
+  constexpr uint64_t2 A72[2] = {(uint64_t2[2])A1};
+  _Static_assert(A72[0][0] == 1, "Woo!");
+  _Static_assert(A72[0][1] == 1, "Woo!");
+  _Static_assert(A72[1][0] == 1, "Woo!");
+  _Static_assert(A72[1][1] == 1, "Woo!");
+
+  // splat from a scalar inside an init list
+  constexpr double D = 97.6789;
+  constexpr B1 SB0 = {(B1)(D + 3.0)};
+  _Static_assert(SB0.A == 100.6789, "Woo!");
+  _Static_assert(SB0.B == 100.6789, "Woo!");
+
+  // result type struct from struct in an init list
+  constexpr B2 SB2 = {5.5, 6.5, 1000, 5000, false};
+  constexpr Base SB3 = {(Base)SB2};
+  _Static_assert(SB3.D == 5.5, "Woo!");
+  _Static_assert(SB3.U[0] == 6, "Woo!");
+  _Static_assert(SB3.U[1] == 1000, "Woo!");
+  _Static_assert(SB3.I == 8, "Woo!");
+  _Static_assert(SB3.I2 == 0, "Woo!");
+}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to