diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 8972957ded9f5..89e8082ee80e7 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -104,6 +104,7 @@ namespace { void CheckStaticCast(); void CheckDynamicCast(); void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization); + bool CheckHLSLCStyleCast(CheckedConversionKind CCK); void CheckCStyleCast(); void CheckBuiltinBitCast(); void CheckAddrspaceCast(); @@ -2776,39 +2777,9 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, CheckedConversionKind CCK = FunctionalStyle ? CheckedConversionKind::FunctionalCast : 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(); - // 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()) - SrcExpr = Self.ImpCastExprToType( - SrcExpr.get(), DVT->getElementType(), - Self.PrepareScalarCast(SrcExpr, DVT->getElementType()), - SrcExpr.get()->getValueKind(), nullptr, CCK); - Kind = CK_HLSLAggregateSplatCast; - return; + if (Self.getLangOpts().HLSL) { + if (CheckHLSLCStyleCast(CCK)) + return; } if (ValueKind == VK_PRValue && !DestType->isRecordType() && @@ -2927,6 +2898,56 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, } } +// CheckHLSLCStyleCast - Returns `true` ihe cast is handled or errored as an +// HLSL-specific cast. Returns false if the cast should be checked as a CXX +// C-Style cast. +bool CastOperation::CheckHLSLCStyleCast(CheckedConversionKind CCK) { + assert(Self.getLangOpts().HLSL && "Must be HLSL!"); + QualType SrcTy = SrcExpr.get()->getType(); + // HLSL has several unique forms of C-style casts which support aggregate to + // aggregate casting. + // 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 true; + } + + // 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(); + // 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()) + SrcExpr = Self.ImpCastExprToType( + SrcExpr.get(), DVT->getElementType(), + Self.PrepareScalarCast(SrcExpr, DVT->getElementType()), + SrcExpr.get()->getValueKind(), nullptr, CCK); + Kind = CK_HLSLAggregateSplatCast; + return true; + } + + // If the destination is an array, we've exhausted the valid HLSL casts, so we + // should emit a dignostic and stop processing. + if (DestType->isArrayType()) { + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic) + << 4 << SrcTy << DestType; + SrcExpr = ExprError(); + return true; + } + return false; +} + /// DiagnoseBadFunctionCast - Warn whenever a function call is cast to a /// non-matching type. Such as enum function call to int, int call to /// pointer; etc. Cast to 'void' is an exception. 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(DestAT)) { + QualType SrcType = Entity.getType(); + if (SrcType->isArrayParameterType()) + SrcType = + cast(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(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 int8[2]; + +export void fn(int8 A) { + int8 a = {A}; +// CHECK-LABEL: VarDecl {{.*}} b 'int8':'vector[2]' cinit +// CHECK-NEXT: ArrayInitLoopExpr {{.*}} 'int8':'vector[2]' +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'int8':'vector[2]' lvalue +// CHECK-NEXT: DeclRefExpr {{.*}} 'int8':'vector[2]' lvalue Var {{.*}} 'a' 'int8':'vector[2]' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'vector' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector *' +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'int8':'vector[2]' lvalue +// CHECK-NEXT: DeclRefExpr {{.*}} 'int8':'vector[2]' lvalue Var {{.*}} 'a' 'int8':'vector[2]' +// CHECK-NEXT: ArrayInitIndexExpr {{.*}} 'unsigned long' + int8 b = a; + +// CHECK-LABEL: VarDecl {{.*}} c 'int8':'vector[2]' cinit +// CHECK-NEXT: ArrayInitLoopExpr {{.*}} 'int8':'vector[2]' +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'vector[2]' lvalue +// CHECK-NEXT: DeclRefExpr {{.*}} 'vector[2]' lvalue ParmVar {{.*}} 'A' 'vector[2]' +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector' +// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'vector' lvalue +// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector *' +// CHECK-NEXT: OpaqueValueExpr {{.*}} 'vector[2]' lvalue +// CHECK-NEXT: DeclRefExpr {{.*}} 'vector[2]' lvalue ParmVar {{.*}} 'A' 'vector[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@-1 {{C-style cast from 'int *' to 'int[4]' is not allowed}} + // expected-error@-1 {{C-style cast from 'int[3]' to 'int[4]' is not allowed}} } struct S {