[clang] [HLSL] Allow arrays to copy-initialize (PR #127557)

via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 17 18:47:08 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Chris B (llvm-beanz)

<details>
<summary>Changes</summary>

This change allows array variables to copy-initialize from other arrays. It also corrects a small error in HLSL C-Style casting that did not error on casting to arrays if elementwise and splat conversions fail.

Fixes #<!-- -->127551

---
Full diff: https://github.com/llvm/llvm-project/pull/127557.diff


4 Files Affected:

- (modified) clang/lib/Sema/SemaCast.cpp (+39-31) 
- (modified) clang/lib/Sema/SemaInit.cpp (+12) 
- (added) clang/test/SemaHLSL/Language/AssignArray.hlsl (+34) 
- (modified) clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl (+1-1) 


``````````diff
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 8972957ded9f5..3ab8598e513c6 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -2778,37 +2778,45 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
                                   : CheckedConversionKind::CStyleCast;
 
   QualType SrcTy = SrcExpr.get()->getType();
-  // This case should not trigger on regular vector cast, vector truncation
-  if (Self.getLangOpts().HLSL &&
-      Self.HLSL().CanPerformElementwiseCast(SrcExpr.get(), DestType)) {
-    if (SrcTy->isConstantArrayType())
-      SrcExpr = Self.ImpCastExprToType(
-          SrcExpr.get(), Self.Context.getArrayParameterType(SrcTy),
-          CK_HLSLArrayRValue, VK_PRValue, nullptr, CCK);
-    Kind = CK_HLSLElementwiseCast;
-    return;
-  }
-
-  // This case should not trigger on regular vector splat
-  // If the relative order of this and the HLSLElementWise cast checks
-  // are changed, it might change which cast handles what in a few cases
-  if (Self.getLangOpts().HLSL &&
-      Self.HLSL().CanPerformAggregateSplatCast(SrcExpr.get(), DestType)) {
-    const VectorType *VT = SrcTy->getAs<VectorType>();
-    // change splat from vec1 case to splat from scalar
-    if (VT && VT->getNumElements() == 1)
-      SrcExpr = Self.ImpCastExprToType(
-          SrcExpr.get(), VT->getElementType(), CK_HLSLVectorTruncation,
-          SrcExpr.get()->getValueKind(), nullptr, CCK);
-    // Inserting a scalar cast here allows for a simplified codegen in
-    // the case the destTy is a vector
-    if (const VectorType *DVT = DestType->getAs<VectorType>())
-      SrcExpr = Self.ImpCastExprToType(
-          SrcExpr.get(), DVT->getElementType(),
-          Self.PrepareScalarCast(SrcExpr, DVT->getElementType()),
-          SrcExpr.get()->getValueKind(), nullptr, CCK);
-    Kind = CK_HLSLAggregateSplatCast;
-    return;
+  // HLSL has several unique forms of C-style casts which support aggregate to
+  // aggregate casting.
+  if (Self.getLangOpts().HLSL) {
+    // This case should not trigger on regular vector cast, vector truncation
+    if (Self.HLSL().CanPerformElementwiseCast(SrcExpr.get(), DestType)) {
+      if (SrcTy->isConstantArrayType())
+        SrcExpr = Self.ImpCastExprToType(
+            SrcExpr.get(), Self.Context.getArrayParameterType(SrcTy),
+            CK_HLSLArrayRValue, VK_PRValue, nullptr, CCK);
+      Kind = CK_HLSLElementwiseCast;
+      return;
+    }
+
+    // This case should not trigger on regular vector splat
+    // If the relative order of this and the HLSLElementWise cast checks
+    // are changed, it might change which cast handles what in a few cases
+    if (Self.HLSL().CanPerformAggregateSplatCast(SrcExpr.get(), DestType)) {
+      const VectorType *VT = SrcTy->getAs<VectorType>();
+      // change splat from vec1 case to splat from scalar
+      if (VT && VT->getNumElements() == 1)
+        SrcExpr = Self.ImpCastExprToType(
+            SrcExpr.get(), VT->getElementType(), CK_HLSLVectorTruncation,
+            SrcExpr.get()->getValueKind(), nullptr, CCK);
+      // Inserting a scalar cast here allows for a simplified codegen in
+      // the case the destTy is a vector
+      if (const VectorType *DVT = DestType->getAs<VectorType>())
+        SrcExpr = Self.ImpCastExprToType(
+            SrcExpr.get(), DVT->getElementType(),
+            Self.PrepareScalarCast(SrcExpr, DVT->getElementType()),
+            SrcExpr.get()->getValueKind(), nullptr, CCK);
+      Kind = CK_HLSLAggregateSplatCast;
+      return;
+    }
+    if (DestType->isArrayType()) {
+      Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
+          << 4 << SrcTy << DestType;
+      SrcExpr = ExprError();
+      return;
+    }
   }
 
   if (ValueKind == VK_PRValue && !DestType->isRecordType() &&
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 6a76e6d74a4b0..a34005bf376aa 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6585,6 +6585,18 @@ void InitializationSequence::InitializeFrom(Sema &S,
       }
     }
 
+    if (S.getLangOpts().HLSL && Initializer && isa<ConstantArrayType>(DestAT)) {
+      QualType SrcType = Entity.getType();
+      if (SrcType->isArrayParameterType())
+        SrcType =
+            cast<ArrayParameterType>(SrcType)->getConstantArrayType(Context);
+      if (S.Context.hasSameUnqualifiedType(DestType, SrcType)) {
+        TryArrayCopy(S, Kind, Entity, Initializer, DestType, *this,
+                     TreatUnavailableAsInvalid);
+        return;
+      }
+    }
+
     // Some kinds of initialization permit an array to be initialized from
     // another array of the same type, and perform elementwise initialization.
     if (Initializer && isa<ConstantArrayType>(DestAT) &&
diff --git a/clang/test/SemaHLSL/Language/AssignArray.hlsl b/clang/test/SemaHLSL/Language/AssignArray.hlsl
new file mode 100644
index 0000000000000..1f813e7a350b1
--- /dev/null
+++ b/clang/test/SemaHLSL/Language/AssignArray.hlsl
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -ast-dump | FileCheck %s
+
+typedef vector<int,4> int8[2];
+
+export void fn(int8 A) {
+  int8 a = {A};
+// CHECK-LABEL: VarDecl {{.*}} b 'int8':'vector<int, 4>[2]' cinit
+// CHECK-NEXT: ArrayInitLoopExpr {{.*}} 'int8':'vector<int, 4>[2]'
+// CHECK-NEXT: OpaqueValueExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue Var {{.*}} 'a' 'int8':'vector<int, 4>[2]'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'vector<int, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4> *' <ArrayToPointerDecay>
+// CHECK-NEXT: OpaqueValueExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue Var {{.*}} 'a' 'int8':'vector<int, 4>[2]'
+// CHECK-NEXT: ArrayInitIndexExpr {{.*}} 'unsigned long'
+  int8 b = a;
+
+// CHECK-LABEL: VarDecl {{.*}} c 'int8':'vector<int, 4>[2]' cinit
+// CHECK-NEXT: ArrayInitLoopExpr {{.*}} 'int8':'vector<int, 4>[2]'
+// CHECK-NEXT: OpaqueValueExpr {{.*}} 'vector<int, 4>[2]' lvalue
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 4>[2]' lvalue ParmVar {{.*}} 'A' 'vector<int, 4>[2]'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'vector<int, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4> *' <ArrayToPointerDecay>
+// CHECK-NEXT: OpaqueValueExpr {{.*}} 'vector<int, 4>[2]' lvalue
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 4>[2]' lvalue ParmVar {{.*}} 'A' 'vector<int, 4>[2]'
+// CHECK-NEXT: ArrayInitIndexExpr {{.*}} 'unsigned long'
+  int8 c = A;
+}
+
+
+
+
diff --git a/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl b/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl
index 9417249383469..30591507b3260 100644
--- a/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl
+++ b/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl
@@ -4,7 +4,7 @@ export void cantCast() {
   int A[3] = {1,2,3};
   int B[4] = {1,2,3,4};
   B = (int[4])A;
-  // expected-error at -1 {{C-style cast from 'int *' to 'int[4]' is not allowed}}
+  // expected-error at -1 {{C-style cast from 'int[3]' to 'int[4]' is not allowed}}
 }
 
 struct S {

``````````

</details>


https://github.com/llvm/llvm-project/pull/127557


More information about the cfe-commits mailing list