Author: Sarah Spall Date: 2024-10-01T11:03:37-07:00 New Revision: d8df118545bf0aff3b03d923ca1aa205e7e74f43
URL: https://github.com/llvm/llvm-project/commit/d8df118545bf0aff3b03d923ca1aa205e7e74f43 DIFF: https://github.com/llvm/llvm-project/commit/d8df118545bf0aff3b03d923ca1aa205e7e74f43.diff LOG: [HLSL] Array by-value assignment (#109323) Make Constant Arrays in HLSL assignable. Closes #109043 Added: clang/test/AST/HLSL/ArrayAssignable.hlsl clang/test/CodeGenHLSL/ArrayAssignable.hlsl clang/test/SemaHLSL/ArrayAssignable_errors.hlsl Modified: clang/include/clang/AST/CanonicalType.h clang/lib/AST/ExprClassification.cpp clang/lib/CodeGen/CGExpr.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/Sema/SemaOverload.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h index dde08f0394c98d..6102eb01793530 100644 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -299,6 +299,7 @@ class CanProxyBase { LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDependentType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isOverloadableType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArrayType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantArrayType) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasPointerRepresentation) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasObjCPointerRepresentation) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasIntegerRepresentation) diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 5dde923312698f..9d97633309ada2 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -704,7 +704,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, return Cl::CM_ConstAddrSpace; // Arrays are not modifiable, only their elements are. - if (CT->isArrayType()) + if (CT->isArrayType() && + !(Ctx.getLangOpts().HLSL && CT->isConstantArrayType())) return Cl::CM_ArrayType; // Incomplete types are not modifiable. if (CT->isIncompleteType()) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index df4994ba9af6e1..aaaa4c7cbf2aec 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -5797,11 +5797,26 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { return EmitComplexAssignmentLValue(E); case TEK_Aggregate: + // If the lang opt is HLSL and the LHS is a constant array + // then we are performing a copy assignment and call a special + // function because EmitAggExprToLValue emits to a temporary LValue + if (getLangOpts().HLSL && E->getLHS()->getType()->isConstantArrayType()) + return EmitHLSLArrayAssignLValue(E); + return EmitAggExprToLValue(E); } llvm_unreachable("bad evaluation kind"); } +// This function implements trivial copy assignment for HLSL's +// assignable constant arrays. +LValue CodeGenFunction::EmitHLSLArrayAssignLValue(const BinaryOperator *E) { + LValue TrivialAssignmentRHS = EmitLValue(E->getRHS()); + LValue LHS = EmitLValue(E->getLHS()); + EmitAggregateAssign(LHS, TrivialAssignmentRHS, E->getLHS()->getType()); + return LHS; +} + LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E, llvm::CallBase **CallOrInvoke) { RValue RV = EmitCallExpr(E, ReturnValueSlot(), CallOrInvoke); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 3e2abbd9bc1094..9ba0ed02a564dd 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4296,6 +4296,7 @@ class CodeGenFunction : public CodeGenTypeCache { LValue EmitCastLValue(const CastExpr *E); LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e); + LValue EmitHLSLArrayAssignLValue(const BinaryOperator *E); void EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, CallArgList &Args, QualType Ty); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 0c1e054f7c30a4..2cde8131108fbe 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2232,16 +2232,21 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // just strip the qualifiers because they don't matter. FromType = FromType.getUnqualifiedType(); } else if (S.getLangOpts().HLSL && FromType->isConstantArrayType() && - ToType->isArrayParameterType()) { + ToType->isConstantArrayType()) { // HLSL constant array parameters do not decay, so if the argument is a // constant array and the parameter is an ArrayParameterType we have special // handling here. - FromType = S.Context.getArrayParameterType(FromType); + if (ToType->isArrayParameterType()) { + FromType = S.Context.getArrayParameterType(FromType); + SCS.First = ICK_HLSL_Array_RValue; + } else { + SCS.First = ICK_Identity; + } + if (S.Context.getCanonicalType(FromType) != S.Context.getCanonicalType(ToType)) return false; - SCS.First = ICK_HLSL_Array_RValue; SCS.setAllToTypes(ToType); return true; } else if (FromType->isArrayType()) { diff --git a/clang/test/AST/HLSL/ArrayAssignable.hlsl b/clang/test/AST/HLSL/ArrayAssignable.hlsl new file mode 100644 index 00000000000000..b32d478983edf1 --- /dev/null +++ b/clang/test/AST/HLSL/ArrayAssignable.hlsl @@ -0,0 +1,106 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump %s | FileCheck %s + +// CHECK-LABEL: arr_assign1 +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '=' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2]' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2]' +void arr_assign1() { + int Arr[2] = {0, 1}; + int Arr2[2] = {0, 0}; + Arr = Arr2; +} + +// CHECK-LABEL: arr_assign2 +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '=' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2]' +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '=' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2]' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr3' 'int[2]' +void arr_assign2() { + int Arr[2] = {0, 1}; + int Arr2[2] = {0, 0}; + int Arr3[2] = {2, 2}; + Arr = Arr2 = Arr3; +} + +// CHECK-LABEL: arr_assign3 +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue '=' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2][2]' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2][2]' +void arr_assign3() { + int Arr[2][2] = {{0, 1}, {2, 3}}; + int Arr2[2][2] = {{0, 0}, {1, 1}}; + Arr = Arr2; +} + +// CHECK-LABEL: arr_assign4 +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue '=' +// CHECK: ArraySubscriptExpr 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue +// CHECK: ImplicitCastExpr 0x{{[0-9a-f]+}} {{.*}} 'int *' <ArrayToPointerDecay> +// CHECK: ParenExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '=' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2]' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2]' +// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 0 +// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 6 +void arr_assign4() { + int Arr[2] = {0, 1}; + int Arr2[2] = {0, 0}; + (Arr = Arr2)[0] = 6; +} + +// CHECK-LABEL: arr_assign5 +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue '=' +// CHECK: ArraySubscriptExpr 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue +// CHECK: ImplicitCastExpr 0x{{[0-9a-f]+}} {{.*}} 'int *' <ArrayToPointerDecay> +// CHECK: ParenExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '=' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2]' +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '=' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2]' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr3' 'int[2]' +// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 0 +// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 6 +void arr_assign5() { + int Arr[2] = {0, 1}; + int Arr2[2] = {0, 0}; + int Arr3[2] = {3, 4}; + (Arr = Arr2 = Arr3)[0] = 6; +} + +// CHECK-LABEL: arr_assign6 +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue '=' +// CHECK: ArraySubscriptExpr 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue +// CHECK: ImplicitCastExpr 0x{{[0-9a-f]+}} {{.*}} 'int *' <ArrayToPointerDecay> +// CHECK: ArraySubscriptExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue +// CHECK: ImplicitCastExpr 0x{{[0-9a-f]+}} {{.*}} 'int (*)[2]' <ArrayToPointerDecay> +// CHECK: ParenExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue '=' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2][2]' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2][2]' +// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 0 +// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 0 +// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 6 +void arr_assign6() { + int Arr[2][2] = {{0, 1}, {2, 3}}; + int Arr2[2][2] = {{0, 0}, {1, 1}}; + (Arr = Arr2)[0][0] = 6; +} + +// CHECK-LABEL: arr_assign7 +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '=' +// CHECK: ArraySubscriptExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue +// CHECK: ImplicitCastExpr 0x{{[0-9a-f]+}} {{.*}} 'int (*)[2]' <ArrayToPointerDecay> +// CHECK: ParenExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue +// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue '=' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2][2]' +// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2][2]' +// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 0 +// CHECK: InitListExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' +// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 6 +// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 6 +void arr_assign7() { + int Arr[2][2] = {{0, 1}, {2, 3}}; + int Arr2[2][2] = {{0, 0}, {1, 1}}; + (Arr = Arr2)[0] = {6, 6}; +} diff --git a/clang/test/CodeGenHLSL/ArrayAssignable.hlsl b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl new file mode 100644 index 00000000000000..a0dfe26e5d147b --- /dev/null +++ b/clang/test/CodeGenHLSL/ArrayAssignable.hlsl @@ -0,0 +1,120 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --enable-var-scope + +// CHECK-LABEL: define void {{.*}}arr_assign1 +// CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4 +// CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4 +// CHECK-NOT: alloca +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{@.*}}, i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[Arr2]], i8 0, i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 [[Arr2]], i32 8, i1 false) +// CHECK-NEXT: ret void +void arr_assign1() { + int Arr[2] = {0, 1}; + int Arr2[2] = {0, 0}; + Arr = Arr2; +} + +// CHECK-LABEL: define void {{.*}}arr_assign2 +// CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4 +// CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4 +// CHECK-NEXT: [[Arr3:%.*]] = alloca [2 x i32], align 4 +// CHECK-NOT: alloca +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{@.*}}, i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[Arr2]], i8 0, i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 {{@.*}}, i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr2]], ptr align 4 [[Arr3]], i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 [[Arr2]], i32 8, i1 false) +// CHECK-NEXT: ret void +void arr_assign2() { + int Arr[2] = {0, 1}; + int Arr2[2] = {0, 0}; + int Arr3[2] = {3, 4}; + Arr = Arr2 = Arr3; +} + +// CHECK-LABEL: define void {{.*}}arr_assign3 +// CHECK: [[Arr3:%.*]] = alloca [2 x [2 x i32]], align 4 +// CHECK-NEXT: [[Arr4:%.*]] = alloca [2 x [2 x i32]], align 4 +// CHECK-NOT: alloca +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 {{@.*}}, i32 16, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr4]], ptr align 4 {{@.*}}, i32 16, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 [[Arr4]], i32 16, i1 false) +// CHECK-NEXT: ret void +void arr_assign3() { + int Arr2[2][2] = {{0, 0}, {1, 1}}; + int Arr3[2][2] = {{1, 1}, {0, 0}}; + Arr2 = Arr3; +} + +// CHECK-LABEL: define void {{.*}}arr_assign4 +// CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4 +// CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4 +// CHECK-NOT: alloca +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{@.*}}, i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[Arr2]], i8 0, i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 [[Arr2]], i32 8, i1 false) +// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[Arr]], i32 0, i32 0 +// CHECK-NEXT: store i32 6, ptr [[Idx]], align 4 +// CHECK-NEXT: ret void +void arr_assign4() { + int Arr[2] = {0, 1}; + int Arr2[2] = {0, 0}; + (Arr = Arr2)[0] = 6; +} + +// CHECK-LABEL: define void {{.*}}arr_assign5 +// CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4 +// CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4 +// CHECK-NEXT: [[Arr3:%.*]] = alloca [2 x i32], align 4 +// CHECK-NOT: alloca +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{@.*}}, i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[Arr2]], i8 0, i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 {{@.*}}, i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr2]], ptr align 4 [[Arr3]], i32 8, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 [[Arr2]], i32 8, i1 false) +// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[Arr]], i32 0, i32 0 +// CHECK-NEXT: store i32 6, ptr [[Idx]], align 4 +// CHECK-NEXT: ret void +void arr_assign5() { + int Arr[2] = {0, 1}; + int Arr2[2] = {0, 0}; + int Arr3[2] = {3, 4}; + (Arr = Arr2 = Arr3)[0] = 6; +} + +// CHECK-LABEL: define void {{.*}}arr_assign6 +// CHECK: [[Arr3:%.*]] = alloca [2 x [2 x i32]], align 4 +// CHECK-NEXT: [[Arr4:%.*]] = alloca [2 x [2 x i32]], align 4 +// CHECK-NOT: alloca +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 {{@.*}}, i32 16, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr4]], ptr align 4 {{@.*}}, i32 16, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 [[Arr4]], i32 16, i1 false) +// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[Arr3]], i32 0, i32 0 +// CHECK-NEXT: [[Idx2:%.*]] = getelementptr inbounds [2 x i32], ptr [[Idx]], i32 0, i32 0 +// CHECK-NEXT: store i32 6, ptr [[Idx2]], align 4 +// CHECK-NEXT: ret void +void arr_assign6() { + int Arr[2][2] = {{0, 0}, {1, 1}}; + int Arr2[2][2] = {{1, 1}, {0, 0}}; + (Arr = Arr2)[0][0] = 6; +} + +// CHECK-LABEL: define void {{.*}}arr_assign7 +// CHECK: [[Arr3:%.*]] = alloca [2 x [2 x i32]], align 4 +// CHECK-NEXT: [[Arr4:%.*]] = alloca [2 x [2 x i32]], align 4 +// CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4 +// CHECK-NOT: alloca +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 {{@.*}}, i32 16, i1 false) +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr4]], ptr align 4 {{@.*}}, i32 16, i1 false) +// CHECK-NEXT: store i32 6, ptr [[Tmp]], align 4 +// CHECK-NEXT: [[AIE:%.*]] = getelementptr inbounds i32, ptr [[Tmp]], i32 1 +// CHECK-NEXT: store i32 6, ptr [[AIE]], align 4 +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 [[Arr4]], i32 16, i1 false) +// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[Arr3]], i32 0, i32 0 +// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Idx]], ptr align 4 [[Tmp]], i32 8, i1 false) +// CHECK-NEXT: ret void +void arr_assign7() { + int Arr[2][2] = {{0, 1}, {2, 3}}; + int Arr2[2][2] = {{0, 0}, {1, 1}}; + (Arr = Arr2)[0] = {6, 6}; +} diff --git a/clang/test/SemaHLSL/ArrayAssignable_errors.hlsl b/clang/test/SemaHLSL/ArrayAssignable_errors.hlsl new file mode 100644 index 00000000000000..1925032a93d488 --- /dev/null +++ b/clang/test/SemaHLSL/ArrayAssignable_errors.hlsl @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -verify + +void test_wrong_size1() { + int Arr[2] = {0, 1}; + int Arr2[3] = {1, 2, 0}; + Arr = Arr2; + // expected-error@-1 {{assigning to 'int[2]' from incompatible type 'int[3]'}} +} + +void test_wrong_size2() { + int Arr[2] = {0, 1}; + int Arr2[3] = {1, 2, 0}; + Arr2 = Arr; + // expected-error@-1 {{assigning to 'int[3]' from incompatible type 'int[2]'}} +} + +void test_wrong_size3() { + int Arr[2][2] = {{0, 1}, {2, 3}}; + int Arr2[2] = {4, 5}; + Arr = Arr2; + // expected-error@-1 {{assigning to 'int[2][2]' from incompatible type 'int[2]'}} +} + +void test_wrong_size4() { + int Arr[2][2] = {{0, 1}, {2, 3}}; + int Arr2[2] = {4, 5}; + Arr2 = Arr; + // expected-error@-1 {{assigning to 'int[2]' from incompatible type 'int[2][2]'}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits