[HLSL] Handle incomplete array types (#133508)
This refactors the initialization list transformation code to handle incomplete array types. Fixes #132958
This commit is contained in:
@@ -151,8 +151,7 @@ public:
|
||||
|
||||
QualType getInoutParameterType(QualType Ty);
|
||||
|
||||
bool TransformInitList(const InitializedEntity &Entity,
|
||||
const InitializationKind &Kind, InitListExpr *Init);
|
||||
bool transformInitList(const InitializedEntity &Entity, InitListExpr *Init);
|
||||
|
||||
void deduceAddressSpace(VarDecl *Decl);
|
||||
|
||||
|
||||
@@ -3294,164 +3294,210 @@ void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
|
||||
if (!HasBinding && isResourceRecordTypeOrArrayOf(VD))
|
||||
SemaRef.Diag(VD->getLocation(), diag::warn_hlsl_implicit_binding);
|
||||
}
|
||||
namespace {
|
||||
class InitListTransformer {
|
||||
Sema &S;
|
||||
ASTContext &Ctx;
|
||||
QualType InitTy;
|
||||
QualType *DstIt = nullptr;
|
||||
Expr **ArgIt = nullptr;
|
||||
// Is wrapping the destination type iterator required? This is only used for
|
||||
// incomplete array types where we loop over the destination type since we
|
||||
// don't know the full number of elements from the declaration.
|
||||
bool Wrap;
|
||||
|
||||
static bool CastInitializer(Sema &S, ASTContext &Ctx, Expr *E,
|
||||
llvm::SmallVectorImpl<Expr *> &List,
|
||||
llvm::SmallVectorImpl<QualType> &DestTypes) {
|
||||
if (List.size() >= DestTypes.size()) {
|
||||
List.push_back(E);
|
||||
// This is odd, but it isn't technically a failure due to conversion, we
|
||||
// handle mismatched counts of arguments differently.
|
||||
return true;
|
||||
}
|
||||
InitializedEntity Entity = InitializedEntity::InitializeParameter(
|
||||
Ctx, DestTypes[List.size()], false);
|
||||
ExprResult Res = S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
|
||||
if (Res.isInvalid())
|
||||
return false;
|
||||
Expr *Init = Res.get();
|
||||
List.push_back(Init);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
|
||||
llvm::SmallVectorImpl<Expr *> &List,
|
||||
llvm::SmallVectorImpl<QualType> &DestTypes) {
|
||||
// If this is an initialization list, traverse the sub initializers.
|
||||
if (auto *Init = dyn_cast<InitListExpr>(E)) {
|
||||
for (auto *SubInit : Init->inits())
|
||||
if (!BuildInitializerList(S, Ctx, SubInit, List, DestTypes))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this is a scalar type, just enqueue the expression.
|
||||
QualType Ty = E->getType();
|
||||
|
||||
if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
|
||||
return CastInitializer(S, Ctx, E, List, DestTypes);
|
||||
|
||||
if (auto *VecTy = Ty->getAs<VectorType>()) {
|
||||
uint64_t Size = VecTy->getNumElements();
|
||||
|
||||
QualType SizeTy = Ctx.getSizeType();
|
||||
uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
|
||||
for (uint64_t I = 0; I < Size; ++I) {
|
||||
auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
|
||||
SizeTy, SourceLocation());
|
||||
|
||||
ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
|
||||
E, E->getBeginLoc(), Idx, E->getEndLoc());
|
||||
if (ElExpr.isInvalid())
|
||||
return false;
|
||||
if (!CastInitializer(S, Ctx, ElExpr.get(), List, DestTypes))
|
||||
return false;
|
||||
bool castInitializer(Expr *E) {
|
||||
assert(DstIt && "This should always be something!");
|
||||
if (DstIt == DestTypes.end()) {
|
||||
if (!Wrap) {
|
||||
ArgExprs.push_back(E);
|
||||
// This is odd, but it isn't technically a failure due to conversion, we
|
||||
// handle mismatched counts of arguments differently.
|
||||
return true;
|
||||
}
|
||||
DstIt = DestTypes.begin();
|
||||
}
|
||||
InitializedEntity Entity = InitializedEntity::InitializeParameter(
|
||||
Ctx, *DstIt, /* Consumed (ObjC) */ false);
|
||||
ExprResult Res = S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
|
||||
if (Res.isInvalid())
|
||||
return false;
|
||||
Expr *Init = Res.get();
|
||||
ArgExprs.push_back(Init);
|
||||
DstIt++;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
|
||||
uint64_t Size = ArrTy->getZExtSize();
|
||||
QualType SizeTy = Ctx.getSizeType();
|
||||
uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
|
||||
for (uint64_t I = 0; I < Size; ++I) {
|
||||
auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
|
||||
SizeTy, SourceLocation());
|
||||
ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
|
||||
E, E->getBeginLoc(), Idx, E->getEndLoc());
|
||||
if (ElExpr.isInvalid())
|
||||
return false;
|
||||
if (!BuildInitializerList(S, Ctx, ElExpr.get(), List, DestTypes))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (auto *RTy = Ty->getAs<RecordType>()) {
|
||||
llvm::SmallVector<const RecordType *> RecordTypes;
|
||||
RecordTypes.push_back(RTy);
|
||||
while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
|
||||
CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
|
||||
assert(D->getNumBases() == 1 &&
|
||||
"HLSL doesn't support multiple inheritance");
|
||||
RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
|
||||
}
|
||||
while (!RecordTypes.empty()) {
|
||||
const RecordType *RT = RecordTypes.pop_back_val();
|
||||
for (auto *FD : RT->getDecl()->fields()) {
|
||||
DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
|
||||
DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
|
||||
ExprResult Res = S.BuildFieldReferenceExpr(
|
||||
E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
|
||||
if (Res.isInvalid())
|
||||
bool buildInitializerListImpl(Expr *E) {
|
||||
// If this is an initialization list, traverse the sub initializers.
|
||||
if (auto *Init = dyn_cast<InitListExpr>(E)) {
|
||||
for (auto *SubInit : Init->inits())
|
||||
if (!buildInitializerListImpl(SubInit))
|
||||
return false;
|
||||
if (!BuildInitializerList(S, Ctx, Res.get(), List, DestTypes))
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this is a scalar type, just enqueue the expression.
|
||||
QualType Ty = E->getType();
|
||||
|
||||
if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
|
||||
return castInitializer(E);
|
||||
|
||||
if (auto *VecTy = Ty->getAs<VectorType>()) {
|
||||
uint64_t Size = VecTy->getNumElements();
|
||||
|
||||
QualType SizeTy = Ctx.getSizeType();
|
||||
uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
|
||||
for (uint64_t I = 0; I < Size; ++I) {
|
||||
auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
|
||||
SizeTy, SourceLocation());
|
||||
|
||||
ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
|
||||
E, E->getBeginLoc(), Idx, E->getEndLoc());
|
||||
if (ElExpr.isInvalid())
|
||||
return false;
|
||||
if (!castInitializer(ElExpr.get()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static Expr *GenerateInitLists(ASTContext &Ctx, QualType Ty,
|
||||
llvm::SmallVectorImpl<Expr *>::iterator &It) {
|
||||
if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType())) {
|
||||
return *(It++);
|
||||
}
|
||||
llvm::SmallVector<Expr *> Inits;
|
||||
assert(!isa<MatrixType>(Ty) && "Matrix types not yet supported in HLSL");
|
||||
Ty = Ty.getDesugaredType(Ctx);
|
||||
if (Ty->isVectorType() || Ty->isConstantArrayType()) {
|
||||
QualType ElTy;
|
||||
uint64_t Size = 0;
|
||||
if (auto *ATy = Ty->getAs<VectorType>()) {
|
||||
ElTy = ATy->getElementType();
|
||||
Size = ATy->getNumElements();
|
||||
} else {
|
||||
auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
|
||||
ElTy = VTy->getElementType();
|
||||
Size = VTy->getZExtSize();
|
||||
if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
|
||||
uint64_t Size = ArrTy->getZExtSize();
|
||||
QualType SizeTy = Ctx.getSizeType();
|
||||
uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
|
||||
for (uint64_t I = 0; I < Size; ++I) {
|
||||
auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
|
||||
SizeTy, SourceLocation());
|
||||
ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
|
||||
E, E->getBeginLoc(), Idx, E->getEndLoc());
|
||||
if (ElExpr.isInvalid())
|
||||
return false;
|
||||
if (!buildInitializerListImpl(ElExpr.get()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
for (uint64_t I = 0; I < Size; ++I)
|
||||
Inits.push_back(GenerateInitLists(Ctx, ElTy, It));
|
||||
}
|
||||
if (auto *RTy = Ty->getAs<RecordType>()) {
|
||||
llvm::SmallVector<const RecordType *> RecordTypes;
|
||||
RecordTypes.push_back(RTy);
|
||||
while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
|
||||
CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
|
||||
assert(D->getNumBases() == 1 &&
|
||||
"HLSL doesn't support multiple inheritance");
|
||||
RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
|
||||
}
|
||||
while (!RecordTypes.empty()) {
|
||||
const RecordType *RT = RecordTypes.pop_back_val();
|
||||
for (auto *FD : RT->getDecl()->fields()) {
|
||||
Inits.push_back(GenerateInitLists(Ctx, FD->getType(), It));
|
||||
|
||||
if (auto *RTy = Ty->getAs<RecordType>()) {
|
||||
llvm::SmallVector<const RecordType *> RecordTypes;
|
||||
RecordTypes.push_back(RTy);
|
||||
while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
|
||||
CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
|
||||
assert(D->getNumBases() == 1 &&
|
||||
"HLSL doesn't support multiple inheritance");
|
||||
RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
|
||||
}
|
||||
while (!RecordTypes.empty()) {
|
||||
const RecordType *RT = RecordTypes.pop_back_val();
|
||||
for (auto *FD : RT->getDecl()->fields()) {
|
||||
DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
|
||||
DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
|
||||
ExprResult Res = S.BuildFieldReferenceExpr(
|
||||
E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
|
||||
if (Res.isInvalid())
|
||||
return false;
|
||||
if (!buildInitializerListImpl(Res.get()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
|
||||
Inits, Inits.back()->getEndLoc());
|
||||
NewInit->setType(Ty);
|
||||
return NewInit;
|
||||
}
|
||||
|
||||
bool SemaHLSL::TransformInitList(const InitializedEntity &Entity,
|
||||
const InitializationKind &Kind,
|
||||
Expr *generateInitListsImpl(QualType Ty) {
|
||||
assert(ArgIt != ArgExprs.end() && "Something is off in iteration!");
|
||||
if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
|
||||
return *(ArgIt++);
|
||||
|
||||
llvm::SmallVector<Expr *> Inits;
|
||||
assert(!isa<MatrixType>(Ty) && "Matrix types not yet supported in HLSL");
|
||||
Ty = Ty.getDesugaredType(Ctx);
|
||||
if (Ty->isVectorType() || Ty->isConstantArrayType()) {
|
||||
QualType ElTy;
|
||||
uint64_t Size = 0;
|
||||
if (auto *ATy = Ty->getAs<VectorType>()) {
|
||||
ElTy = ATy->getElementType();
|
||||
Size = ATy->getNumElements();
|
||||
} else {
|
||||
auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
|
||||
ElTy = VTy->getElementType();
|
||||
Size = VTy->getZExtSize();
|
||||
}
|
||||
for (uint64_t I = 0; I < Size; ++I)
|
||||
Inits.push_back(generateInitListsImpl(ElTy));
|
||||
}
|
||||
if (auto *RTy = Ty->getAs<RecordType>()) {
|
||||
llvm::SmallVector<const RecordType *> RecordTypes;
|
||||
RecordTypes.push_back(RTy);
|
||||
while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
|
||||
CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
|
||||
assert(D->getNumBases() == 1 &&
|
||||
"HLSL doesn't support multiple inheritance");
|
||||
RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
|
||||
}
|
||||
while (!RecordTypes.empty()) {
|
||||
const RecordType *RT = RecordTypes.pop_back_val();
|
||||
for (auto *FD : RT->getDecl()->fields()) {
|
||||
Inits.push_back(generateInitListsImpl(FD->getType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
|
||||
Inits, Inits.back()->getEndLoc());
|
||||
NewInit->setType(Ty);
|
||||
return NewInit;
|
||||
}
|
||||
|
||||
public:
|
||||
llvm::SmallVector<QualType, 16> DestTypes;
|
||||
llvm::SmallVector<Expr *, 16> ArgExprs;
|
||||
InitListTransformer(Sema &SemaRef, const InitializedEntity &Entity)
|
||||
: S(SemaRef), Ctx(SemaRef.getASTContext()),
|
||||
Wrap(Entity.getType()->isIncompleteArrayType()) {
|
||||
InitTy = Entity.getType().getNonReferenceType();
|
||||
// When we're generating initializer lists for incomplete array types we
|
||||
// need to wrap around both when building the initializers and when
|
||||
// generating the final initializer lists.
|
||||
if (Wrap) {
|
||||
assert(InitTy->isIncompleteArrayType());
|
||||
const IncompleteArrayType *IAT = Ctx.getAsIncompleteArrayType(InitTy);
|
||||
InitTy = IAT->getElementType();
|
||||
}
|
||||
BuildFlattenedTypeList(InitTy, DestTypes);
|
||||
DstIt = DestTypes.begin();
|
||||
}
|
||||
|
||||
bool buildInitializerList(Expr *E) { return buildInitializerListImpl(E); }
|
||||
|
||||
Expr *generateInitLists() {
|
||||
assert(!ArgExprs.empty() &&
|
||||
"Call buildInitializerList to generate argument expressions.");
|
||||
ArgIt = ArgExprs.begin();
|
||||
if (!Wrap)
|
||||
return generateInitListsImpl(InitTy);
|
||||
llvm::SmallVector<Expr *> Inits;
|
||||
while (ArgIt != ArgExprs.end())
|
||||
Inits.push_back(generateInitListsImpl(InitTy));
|
||||
|
||||
auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
|
||||
Inits, Inits.back()->getEndLoc());
|
||||
llvm::APInt ArySize(64, Inits.size());
|
||||
NewInit->setType(Ctx.getConstantArrayType(InitTy, ArySize, nullptr,
|
||||
ArraySizeModifier::Normal, 0));
|
||||
return NewInit;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
bool SemaHLSL::transformInitList(const InitializedEntity &Entity,
|
||||
InitListExpr *Init) {
|
||||
// If the initializer is a scalar, just return it.
|
||||
if (Init->getType()->isScalarType())
|
||||
return true;
|
||||
ASTContext &Ctx = SemaRef.getASTContext();
|
||||
llvm::SmallVector<QualType, 16> DestTypes;
|
||||
// An initializer list might be attempting to initialize a reference or
|
||||
// rvalue-reference. When checking the initializer we should look through the
|
||||
// reference.
|
||||
QualType InitTy = Entity.getType().getNonReferenceType();
|
||||
BuildFlattenedTypeList(InitTy, DestTypes);
|
||||
InitListTransformer ILT(SemaRef, Entity);
|
||||
|
||||
llvm::SmallVector<Expr *, 16> ArgExprs;
|
||||
for (unsigned I = 0; I < Init->getNumInits(); ++I) {
|
||||
Expr *E = Init->getInit(I);
|
||||
if (E->HasSideEffects(Ctx)) {
|
||||
@@ -3462,21 +3508,35 @@ bool SemaHLSL::TransformInitList(const InitializedEntity &Entity,
|
||||
E->getObjectKind(), E);
|
||||
Init->setInit(I, E);
|
||||
}
|
||||
if (!BuildInitializerList(SemaRef, Ctx, E, ArgExprs, DestTypes))
|
||||
if (!ILT.buildInitializerList(E))
|
||||
return false;
|
||||
}
|
||||
size_t ExpectedSize = ILT.DestTypes.size();
|
||||
size_t ActualSize = ILT.ArgExprs.size();
|
||||
// For incomplete arrays it is completely arbitrary to choose whether we think
|
||||
// the user intended fewer or more elements. This implementation assumes that
|
||||
// the user intended more, and errors that there are too few initializers to
|
||||
// complete the final element.
|
||||
if (Entity.getType()->isIncompleteArrayType())
|
||||
ExpectedSize =
|
||||
((ActualSize + ExpectedSize - 1) / ExpectedSize) * ExpectedSize;
|
||||
|
||||
if (DestTypes.size() != ArgExprs.size()) {
|
||||
int TooManyOrFew = ArgExprs.size() > DestTypes.size() ? 1 : 0;
|
||||
// An initializer list might be attempting to initialize a reference or
|
||||
// rvalue-reference. When checking the initializer we should look through
|
||||
// the reference.
|
||||
QualType InitTy = Entity.getType().getNonReferenceType();
|
||||
if (InitTy.hasAddressSpace())
|
||||
InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
|
||||
if (ExpectedSize != ActualSize) {
|
||||
int TooManyOrFew = ActualSize > ExpectedSize ? 1 : 0;
|
||||
SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
|
||||
<< TooManyOrFew << InitTy << DestTypes.size() << ArgExprs.size();
|
||||
<< TooManyOrFew << InitTy << ExpectedSize << ActualSize;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto It = ArgExprs.begin();
|
||||
// GenerateInitLists will always return an InitListExpr here, because the
|
||||
// generateInitListsImpl will always return an InitListExpr here, because the
|
||||
// scalar case is handled above.
|
||||
auto *NewInit = cast<InitListExpr>(GenerateInitLists(Ctx, InitTy, It));
|
||||
auto *NewInit = cast<InitListExpr>(ILT.generateInitLists());
|
||||
Init->resizeInits(Ctx, NewInit->getNumInits());
|
||||
for (unsigned I = 0; I < NewInit->getNumInits(); ++I)
|
||||
Init->updateInit(Ctx, I, NewInit->getInit(I));
|
||||
|
||||
@@ -4844,8 +4844,7 @@ static void TryListInitialization(Sema &S,
|
||||
bool TreatUnavailableAsInvalid) {
|
||||
QualType DestType = Entity.getType();
|
||||
|
||||
if (S.getLangOpts().HLSL &&
|
||||
!S.HLSL().TransformInitList(Entity, Kind, InitList))
|
||||
if (S.getLangOpts().HLSL && !S.HLSL().transformInitList(Entity, InitList))
|
||||
return;
|
||||
|
||||
// C++ doesn't allow scalar initialization with more than one argument.
|
||||
|
||||
68
clang/test/SemaHLSL/Language/InitIncompleteArrays.hlsl
Normal file
68
clang/test/SemaHLSL/Language/InitIncompleteArrays.hlsl
Normal file
@@ -0,0 +1,68 @@
|
||||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -finclude-default-header -verify -Wdouble-promotion -Wconversion %s
|
||||
|
||||
// Some helpers!
|
||||
template <typename T, typename U>
|
||||
struct is_same {
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct is_same<T, T> {
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct remove_addrspace {
|
||||
using type = __decltype((T)0);
|
||||
};
|
||||
|
||||
template <typename T, typename V>
|
||||
using is_same_ignore_addrspace = is_same<typename remove_addrspace<T>::type, typename remove_addrspace<V>::type>;
|
||||
|
||||
struct SomeVals {
|
||||
int2 X;
|
||||
float2 Y;
|
||||
double2 D;
|
||||
};
|
||||
|
||||
static SomeVals V = {1,2,3,4,5,6};
|
||||
|
||||
static int2 SomeArr[] = {V}; // #SomeArr
|
||||
// expected-warning@#SomeArr 2 {{implicit conversion turns floating-point number into integer: 'double' to 'int'}}
|
||||
// expected-warning@#SomeArr 2 {{implicit conversion turns floating-point number into integer: 'float' to 'int'}}
|
||||
|
||||
_Static_assert(is_same_ignore_addrspace<__decltype(SomeArr), int2[3]>::value, "What is this even?");
|
||||
|
||||
static int2 VecArr[] = {
|
||||
int2(0,1),
|
||||
int2(2,3),
|
||||
int4(4,5,6,7),
|
||||
};
|
||||
|
||||
_Static_assert(is_same_ignore_addrspace<__decltype(VecArr), int2[4]>::value, "One vec, two vec, three vecs, FOUR!");
|
||||
|
||||
static int4 V4Arr[] = {
|
||||
int2(0,1),
|
||||
int2(2,3),
|
||||
};
|
||||
|
||||
_Static_assert(is_same_ignore_addrspace<__decltype(V4Arr), int4[1]>::value, "One!");
|
||||
|
||||
static int ArrOfArr[][4] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
||||
|
||||
_Static_assert(is_same_ignore_addrspace<__decltype(ArrOfArr), int[2][4]>::value, "Two arrays of four!");
|
||||
|
||||
// expected-error@+1{{too few initializers in list for type 'int4[]' (aka 'vector<int, 4>[]') (expected 4 but found 2)}}
|
||||
static int4 V4ArrTooSmall[] = {
|
||||
int2(0,1),
|
||||
};
|
||||
|
||||
// expected-error@+1{{too few initializers in list for type 'int4[]' (aka 'vector<int, 4>[]') (expected 8 but found 7)}}
|
||||
static int4 V4ArrAlsoTooSmall[] = {
|
||||
int2(0,1),
|
||||
int2(2,3),
|
||||
int3(4,5,6),
|
||||
};
|
||||
|
||||
// expected-error@+1{{too few initializers in list for type 'int[][2]' (expected 6 but found 5)}}
|
||||
static int ArrOfArrTooSmall[][2] = { 1, 2, 3, 4, 5 };
|
||||
@@ -8,6 +8,11 @@ struct TwoInts {
|
||||
int Z, W;
|
||||
};
|
||||
|
||||
struct IntAndFloat {
|
||||
int A;
|
||||
float B;
|
||||
};
|
||||
|
||||
struct Doggo {
|
||||
int4 LegState;
|
||||
int TailState;
|
||||
@@ -981,3 +986,76 @@ FourFloats case16() {
|
||||
FourFloats FF = {0, makeTwo(X), 3};
|
||||
return FF;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: Dumping case17
|
||||
// CHECK: VarDecl {{.*}} col:15 used Structs 'IntAndFloat[2]' cinit
|
||||
// CHECK-NEXT: InitListExpr {{.*}} 'IntAndFloat[2]'
|
||||
// CHECK-NEXT: InitListExpr {{.*}} 'IntAndFloat'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
|
||||
// CHECK-NEXT: InitListExpr {{.*}} 'IntAndFloat'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 4
|
||||
|
||||
|
||||
// CHECK: VarDecl {{.*}} col:9 used Floats 'float[8]' cinit
|
||||
// CHECK-NEXT: InitListExpr {{.*}} 'float[8]'
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
|
||||
// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .A {{.*}}
|
||||
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'IntAndFloat' lvalue
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'IntAndFloat *' <ArrayToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'IntAndFloat[2]' lvalue Var {{.*}} 'Structs' 'IntAndFloat[2]'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
|
||||
// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .B {{.*}}
|
||||
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'IntAndFloat' lvalue
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'IntAndFloat *' <ArrayToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'IntAndFloat[2]' lvalue Var {{.*}} 'Structs' 'IntAndFloat[2]'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
|
||||
// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .A {{.*}}
|
||||
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'IntAndFloat' lvalue
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'IntAndFloat *' <ArrayToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'IntAndFloat[2]' lvalue Var {{.*}} 'Structs' 'IntAndFloat[2]'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
|
||||
// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .B {{.*}}
|
||||
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'IntAndFloat' lvalue
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'IntAndFloat *' <ArrayToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'IntAndFloat[2]' lvalue Var {{.*}} 'Structs' 'IntAndFloat[2]'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
|
||||
// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .A {{.*}}
|
||||
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'IntAndFloat' lvalue
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'IntAndFloat *' <ArrayToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'IntAndFloat[2]' lvalue Var {{.*}} 'Structs' 'IntAndFloat[2]'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
|
||||
// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .B {{.*}}
|
||||
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'IntAndFloat' lvalue
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'IntAndFloat *' <ArrayToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'IntAndFloat[2]' lvalue Var {{.*}} 'Structs' 'IntAndFloat[2]'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
|
||||
// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .A {{.*}}
|
||||
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'IntAndFloat' lvalue
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'IntAndFloat *' <ArrayToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'IntAndFloat[2]' lvalue Var {{.*}} 'Structs' 'IntAndFloat[2]'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
|
||||
// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .B {{.*}}
|
||||
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'IntAndFloat' lvalue
|
||||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'IntAndFloat *' <ArrayToPointerDecay>
|
||||
// CHECK-NEXT: DeclRefExpr {{.*}} 'IntAndFloat[2]' lvalue Var {{.*}} 'Structs' 'IntAndFloat[2]'
|
||||
// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
|
||||
float case17() {
|
||||
IntAndFloat Structs[] = {1,2,3,4};
|
||||
float Floats[] = {Structs, Structs};
|
||||
return Floats[7];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user