[clang] 83a0866 - [HLSL] Mark vector and matrix constructor-turned-InitListExprs as ListInitializations (#192151)

via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 15 10:43:08 PDT 2026


Author: Deric C.
Date: 2026-04-15T10:43:04-07:00
New Revision: 83a0866d0faf96fd1e4bf2526acd9afdcb231a69

URL: https://github.com/llvm/llvm-project/commit/83a0866d0faf96fd1e4bf2526acd9afdcb231a69
DIFF: https://github.com/llvm/llvm-project/commit/83a0866d0faf96fd1e4bf2526acd9afdcb231a69.diff

LOG: [HLSL] Mark vector and matrix constructor-turned-InitListExprs as ListInitializations (#192151)

Fixes #189086

This PR fixes a bug for HLSL where vector and matrix constructors that
have been turned into initializer lists via
https://github.com/llvm/llvm-project/blob/18519f34650db7fc8e1885ac0293c1e9a5f1b071/clang/lib/Sema/SemaInit.cpp#L6993-L7000
were not marked with ListInitialization = true, which causes template
re-instantiation to fail because the initialization with a InitListExpr
gets classified as a InitializationKind::IK_Direct instead of a
InitializationKind::IK_DirectList when ListInitialization is false.

Assisted-by: Claude Opus 4.6

Added: 
    clang/test/AST/HLSL/hlsl-constructors-template.hlsl

Modified: 
    clang/lib/Sema/SemaExprCXX.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 39c5e3b0671bb..e60d5d7748b44 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1674,7 +1674,15 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
     // CXXTemporaryObjectExpr. It's also weird that the functional cast
     // is sometimes handled by initialization and sometimes not.
     QualType ResultType = Result.get()->getType();
-    SourceRange Locs = ListInitialization
+    // In HLSL, vector/matrix constructors have their arguments wrapped into an
+    // InitListExpr during initialization sequencing. Mark the resulting
+    // CXXFunctionalCastExpr as list-initialization so that during template
+    // re-instantiation, TreeTransform correctly passes the InitListExpr back
+    // through BuildCXXTypeConstructExpr with ListInitialization=true as opposed
+    // to false.
+    bool IsListInit = ListInitialization ||
+                      (getLangOpts().HLSL && isa<InitListExpr>(Result.get()));
+    SourceRange Locs = IsListInit
                            ? SourceRange()
                            : SourceRange(LParenOrBraceLoc, RParenOrBraceLoc);
     Result = CXXFunctionalCastExpr::Create(

diff  --git a/clang/test/AST/HLSL/hlsl-constructors-template.hlsl b/clang/test/AST/HLSL/hlsl-constructors-template.hlsl
new file mode 100644
index 0000000000000..3dbbdb5e16a68
--- /dev/null
+++ b/clang/test/AST/HLSL/hlsl-constructors-template.hlsl
@@ -0,0 +1,169 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-compute -x hlsl -ast-dump -o - %s | FileCheck %s
+
+// Verify that HLSL vector/matrix paren-syntax constructors inside template
+// functions produce the correct AST after template instantiation. The key
+// property is that the CXXFunctionalCastExpr wrapping an InitListExpr survives
+// re-instantiation intact.
+
+typedef int int2 __attribute__((ext_vector_type(2)));
+typedef float float2 __attribute__((ext_vector_type(2)));
+typedef float float3 __attribute__((ext_vector_type(3)));
+typedef float float4 __attribute__((ext_vector_type(4)));
+typedef float float2x2 __attribute__((matrix_type(2, 2)));
+typedef float float2x3 __attribute__((matrix_type(2, 3)));
+
+// Basic vector constructors in a template.
+template<typename T>
+void vector_constructors() {
+// CHECK-LABEL: FunctionDecl {{.*}} used vector_constructors 'void ()' implicit_instantiation
+// CHECK: VarDecl {{.*}} a 'int2':'vector<int, 2>' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'int2':'vector<int, 2>' functional cast to int2 <NoOp>
+// CHECK-NEXT: InitListExpr {{.*}} 'int2':'vector<int, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+// CHECK: VarDecl {{.*}} b 'float3':'vector<float, 3>' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float3':'vector<float, 3>' functional cast to float3 <NoOp>
+// CHECK-NEXT: InitListExpr {{.*}} 'float3':'vector<float, 3>'
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 2.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 3.000000e+00
+  int2 a = int2(0, 0);
+  float3 b = float3(1.0f, 2.0f, 3.0f);
+}
+
+
+// Nested vector constructor: float4 built from a float2 + two scalars.
+template<typename T>
+void vector_constructors_nested() {
+// CHECK-LABEL: FunctionDecl {{.*}} used vector_constructors_nested 'void ()' implicit_instantiation
+// CHECK: VarDecl {{.*}} used v 'float2':'vector<float, 2>' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float2':'vector<float, 2>' functional cast to float2 <NoOp>
+// CHECK-NEXT: InitListExpr {{.*}} 'float2':'vector<float, 2>'
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 2.000000e+00
+// CHECK: VarDecl {{.*}} w 'float4':'vector<float, 4>' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float4':'vector<float, 4>' functional cast to float4 <NoOp>
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector<float, 2>' lvalue Var {{.*}} 'v' 'float2':'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector<float, 2>' lvalue Var {{.*}} 'v' 'float2':'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 1
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 3.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 4.000000e+00
+  float2 v = float2(1.0f, 2.0f);
+  float4 w = float4(v, 3.0f, 4.0f);
+}
+
+// Matrix constructor in a template.
+template<typename T>
+void matrix_constructors() {
+// CHECK-LABEL: FunctionDecl {{.*}} used matrix_constructors 'void ()' implicit_instantiation
+// CHECK: VarDecl {{.*}} m 'float2x2':'matrix<float, 2, 2>' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float2x2':'matrix<float, 2, 2>' functional cast to float2x2 <NoOp>
+// CHECK-NEXT: InitListExpr {{.*}} 'float2x2':'matrix<float, 2, 2>'
+// 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
+  float2x2 m = float2x2(1.0f, 2.0f, 3.0f, 4.0f);
+}
+
+// Nested matrix constructor: float2x2 built from a float2 + two scalars.
+template<typename T>
+void matrix_constructors_nested() {
+// CHECK-LABEL: FunctionDecl {{.*}} used matrix_constructors_nested 'void ()' implicit_instantiation
+// CHECK: VarDecl {{.*}} used v 'float2':'vector<float, 2>' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float2':'vector<float, 2>' functional cast to float2 <NoOp>
+// CHECK-NEXT: InitListExpr {{.*}} 'float2':'vector<float, 2>'
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 2.000000e+00
+// CHECK: VarDecl {{.*}} m 'float2x2':'matrix<float, 2, 2>' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float2x2':'matrix<float, 2, 2>' functional cast to float2x2 <NoOp>
+// CHECK-NEXT: InitListExpr {{.*}} 'float2x2':'matrix<float, 2, 2>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector<float, 2>' lvalue Var {{.*}} 'v' 'float2':'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector<float, 2>' lvalue Var {{.*}} 'v' 'float2':'vector<float, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 1
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 3.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 4.000000e+00
+  float2 v = float2(1.0f, 2.0f);
+  float2x2 m = float2x2(v, 3.0f, 4.0f);
+}
+
+// Vector from matrix: float4 built from a float2x2 (elementwise cast).
+template<typename T>
+void vector_from_matrix() {
+// CHECK-LABEL: FunctionDecl {{.*}} used vector_from_matrix 'void ()' implicit_instantiation
+// CHECK: VarDecl {{.*}} used m 'float2x2':'matrix<float, 2, 2>' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float2x2':'matrix<float, 2, 2>' functional cast to float2x2 <NoOp>
+// CHECK-NEXT: InitListExpr {{.*}} 'float2x2':'matrix<float, 2, 2>'
+// 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: VarDecl {{.*}} v 'float4':'vector<float, 4>' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float4':'vector<float, 4>' functional cast to float4 <HLSLElementwiseCast>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float2x2':'matrix<float, 2, 2>' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float2x2':'matrix<float, 2, 2>' lvalue Var {{.*}} 'm' 'float2x2':'matrix<float, 2, 2>'
+  float2x2 m = float2x2(1.0f, 2.0f, 3.0f, 4.0f);
+  float4 v = float4(m);
+}
+
+// Matrix from matrix: float2x3 built from a float2x2 + two scalars.
+template<typename T>
+void matrix_from_matrix() {
+// CHECK-LABEL: FunctionDecl {{.*}} used matrix_from_matrix 'void ()' implicit_instantiation
+// CHECK: VarDecl {{.*}} used m 'float2x2':'matrix<float, 2, 2>' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float2x2':'matrix<float, 2, 2>' functional cast to float2x2 <NoOp>
+// CHECK-NEXT: InitListExpr {{.*}} 'float2x2':'matrix<float, 2, 2>'
+// 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: VarDecl {{.*}} n 'float2x3':'matrix<float, 2, 3>' cinit
+// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float2x3':'matrix<float, 2, 3>' functional cast to float2x3 <NoOp>
+// CHECK-NEXT: InitListExpr {{.*}} 'float2x3':'matrix<float, 2, 3>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MatrixSubscriptExpr {{.*}} 'float' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float2x2':'matrix<float, 2, 2>' lvalue Var {{.*}} 'm' 'float2x2':'matrix<float, 2, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MatrixSubscriptExpr {{.*}} 'float' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float2x2':'matrix<float, 2, 2>' lvalue Var {{.*}} 'm' 'float2x2':'matrix<float, 2, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MatrixSubscriptExpr {{.*}} 'float' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float2x2':'matrix<float, 2, 2>' lvalue Var {{.*}} 'm' 'float2x2':'matrix<float, 2, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MatrixSubscriptExpr {{.*}} 'float' lvalue matrixcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float2x2':'matrix<float, 2, 2>' lvalue Var {{.*}} 'm' 'float2x2':'matrix<float, 2, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 5.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 6.000000e+00
+  float2x2 m = float2x2(1.0f, 2.0f, 3.0f, 4.0f);
+  float2x3 n = float2x3(m, 5.0f, 6.0f);
+}
+
+// Instantiate the templates from a compute shader entry point.
+[numthreads(1,1,1)]
+void main() {
+  vector_constructors<int>();
+  vector_constructors_nested<float>();
+  matrix_constructors<int>();
+  matrix_constructors_nested<int>();
+  vector_from_matrix<int>();
+  matrix_from_matrix<int>();
+}


        


More information about the cfe-commits mailing list