Skip to content

Commit 31b38d6

Browse files
authored
[HLSL] Handle incomplete array types (llvm#133508)
This refactors the initialization list transformation code to handle incomplete array types. Fixes llvm#132958
1 parent 70e303f commit 31b38d6

File tree

5 files changed

+347
-143
lines changed

5 files changed

+347
-143
lines changed

clang/include/clang/Sema/SemaHLSL.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,7 @@ class SemaHLSL : public SemaBase {
151151

152152
QualType getInoutParameterType(QualType Ty);
153153

154-
bool TransformInitList(const InitializedEntity &Entity,
155-
const InitializationKind &Kind, InitListExpr *Init);
154+
bool transformInitList(const InitializedEntity &Entity, InitListExpr *Init);
156155

157156
void deduceAddressSpace(VarDecl *Decl);
158157

clang/lib/Sema/SemaHLSL.cpp

+199-139
Original file line numberDiff line numberDiff line change
@@ -3294,164 +3294,210 @@ void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
32943294
if (!HasBinding && isResourceRecordTypeOrArrayOf(VD))
32953295
SemaRef.Diag(VD->getLocation(), diag::warn_hlsl_implicit_binding);
32963296
}
3297-
3298-
static bool CastInitializer(Sema &S, ASTContext &Ctx, Expr *E,
3299-
llvm::SmallVectorImpl<Expr *> &List,
3300-
llvm::SmallVectorImpl<QualType> &DestTypes) {
3301-
if (List.size() >= DestTypes.size()) {
3302-
List.push_back(E);
3303-
// This is odd, but it isn't technically a failure due to conversion, we
3304-
// handle mismatched counts of arguments differently.
3297+
namespace {
3298+
class InitListTransformer {
3299+
Sema &S;
3300+
ASTContext &Ctx;
3301+
QualType InitTy;
3302+
QualType *DstIt = nullptr;
3303+
Expr **ArgIt = nullptr;
3304+
// Is wrapping the destination type iterator required? This is only used for
3305+
// incomplete array types where we loop over the destination type since we
3306+
// don't know the full number of elements from the declaration.
3307+
bool Wrap;
3308+
3309+
bool castInitializer(Expr *E) {
3310+
assert(DstIt && "This should always be something!");
3311+
if (DstIt == DestTypes.end()) {
3312+
if (!Wrap) {
3313+
ArgExprs.push_back(E);
3314+
// This is odd, but it isn't technically a failure due to conversion, we
3315+
// handle mismatched counts of arguments differently.
3316+
return true;
3317+
}
3318+
DstIt = DestTypes.begin();
3319+
}
3320+
InitializedEntity Entity = InitializedEntity::InitializeParameter(
3321+
Ctx, *DstIt, /* Consumed (ObjC) */ false);
3322+
ExprResult Res = S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
3323+
if (Res.isInvalid())
3324+
return false;
3325+
Expr *Init = Res.get();
3326+
ArgExprs.push_back(Init);
3327+
DstIt++;
33053328
return true;
33063329
}
3307-
InitializedEntity Entity = InitializedEntity::InitializeParameter(
3308-
Ctx, DestTypes[List.size()], false);
3309-
ExprResult Res = S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
3310-
if (Res.isInvalid())
3311-
return false;
3312-
Expr *Init = Res.get();
3313-
List.push_back(Init);
3314-
return true;
3315-
}
33163330

3317-
static bool BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
3318-
llvm::SmallVectorImpl<Expr *> &List,
3319-
llvm::SmallVectorImpl<QualType> &DestTypes) {
3320-
// If this is an initialization list, traverse the sub initializers.
3321-
if (auto *Init = dyn_cast<InitListExpr>(E)) {
3322-
for (auto *SubInit : Init->inits())
3323-
if (!BuildInitializerList(S, Ctx, SubInit, List, DestTypes))
3324-
return false;
3325-
return true;
3326-
}
3331+
bool buildInitializerListImpl(Expr *E) {
3332+
// If this is an initialization list, traverse the sub initializers.
3333+
if (auto *Init = dyn_cast<InitListExpr>(E)) {
3334+
for (auto *SubInit : Init->inits())
3335+
if (!buildInitializerListImpl(SubInit))
3336+
return false;
3337+
return true;
3338+
}
33273339

3328-
// If this is a scalar type, just enqueue the expression.
3329-
QualType Ty = E->getType();
3340+
// If this is a scalar type, just enqueue the expression.
3341+
QualType Ty = E->getType();
33303342

3331-
if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
3332-
return CastInitializer(S, Ctx, E, List, DestTypes);
3343+
if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
3344+
return castInitializer(E);
33333345

3334-
if (auto *VecTy = Ty->getAs<VectorType>()) {
3335-
uint64_t Size = VecTy->getNumElements();
3346+
if (auto *VecTy = Ty->getAs<VectorType>()) {
3347+
uint64_t Size = VecTy->getNumElements();
33363348

3337-
QualType SizeTy = Ctx.getSizeType();
3338-
uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
3339-
for (uint64_t I = 0; I < Size; ++I) {
3340-
auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
3341-
SizeTy, SourceLocation());
3349+
QualType SizeTy = Ctx.getSizeType();
3350+
uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
3351+
for (uint64_t I = 0; I < Size; ++I) {
3352+
auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
3353+
SizeTy, SourceLocation());
33423354

3343-
ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
3344-
E, E->getBeginLoc(), Idx, E->getEndLoc());
3345-
if (ElExpr.isInvalid())
3346-
return false;
3347-
if (!CastInitializer(S, Ctx, ElExpr.get(), List, DestTypes))
3348-
return false;
3355+
ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
3356+
E, E->getBeginLoc(), Idx, E->getEndLoc());
3357+
if (ElExpr.isInvalid())
3358+
return false;
3359+
if (!castInitializer(ElExpr.get()))
3360+
return false;
3361+
}
3362+
return true;
33493363
}
3350-
return true;
3351-
}
33523364

3353-
if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
3354-
uint64_t Size = ArrTy->getZExtSize();
3355-
QualType SizeTy = Ctx.getSizeType();
3356-
uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
3357-
for (uint64_t I = 0; I < Size; ++I) {
3358-
auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
3359-
SizeTy, SourceLocation());
3360-
ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
3361-
E, E->getBeginLoc(), Idx, E->getEndLoc());
3362-
if (ElExpr.isInvalid())
3363-
return false;
3364-
if (!BuildInitializerList(S, Ctx, ElExpr.get(), List, DestTypes))
3365-
return false;
3366-
}
3367-
return true;
3368-
}
3369-
3370-
if (auto *RTy = Ty->getAs<RecordType>()) {
3371-
llvm::SmallVector<const RecordType *> RecordTypes;
3372-
RecordTypes.push_back(RTy);
3373-
while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
3374-
CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
3375-
assert(D->getNumBases() == 1 &&
3376-
"HLSL doesn't support multiple inheritance");
3377-
RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
3378-
}
3379-
while (!RecordTypes.empty()) {
3380-
const RecordType *RT = RecordTypes.pop_back_val();
3381-
for (auto *FD : RT->getDecl()->fields()) {
3382-
DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
3383-
DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
3384-
ExprResult Res = S.BuildFieldReferenceExpr(
3385-
E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
3386-
if (Res.isInvalid())
3365+
if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
3366+
uint64_t Size = ArrTy->getZExtSize();
3367+
QualType SizeTy = Ctx.getSizeType();
3368+
uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
3369+
for (uint64_t I = 0; I < Size; ++I) {
3370+
auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
3371+
SizeTy, SourceLocation());
3372+
ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
3373+
E, E->getBeginLoc(), Idx, E->getEndLoc());
3374+
if (ElExpr.isInvalid())
33873375
return false;
3388-
if (!BuildInitializerList(S, Ctx, Res.get(), List, DestTypes))
3376+
if (!buildInitializerListImpl(ElExpr.get()))
33893377
return false;
33903378
}
3379+
return true;
3380+
}
3381+
3382+
if (auto *RTy = Ty->getAs<RecordType>()) {
3383+
llvm::SmallVector<const RecordType *> RecordTypes;
3384+
RecordTypes.push_back(RTy);
3385+
while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
3386+
CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
3387+
assert(D->getNumBases() == 1 &&
3388+
"HLSL doesn't support multiple inheritance");
3389+
RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
3390+
}
3391+
while (!RecordTypes.empty()) {
3392+
const RecordType *RT = RecordTypes.pop_back_val();
3393+
for (auto *FD : RT->getDecl()->fields()) {
3394+
DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
3395+
DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
3396+
ExprResult Res = S.BuildFieldReferenceExpr(
3397+
E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
3398+
if (Res.isInvalid())
3399+
return false;
3400+
if (!buildInitializerListImpl(Res.get()))
3401+
return false;
3402+
}
3403+
}
33913404
}
3405+
return true;
33923406
}
3393-
return true;
3394-
}
33953407

3396-
static Expr *GenerateInitLists(ASTContext &Ctx, QualType Ty,
3397-
llvm::SmallVectorImpl<Expr *>::iterator &It) {
3398-
if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType())) {
3399-
return *(It++);
3400-
}
3401-
llvm::SmallVector<Expr *> Inits;
3402-
assert(!isa<MatrixType>(Ty) && "Matrix types not yet supported in HLSL");
3403-
Ty = Ty.getDesugaredType(Ctx);
3404-
if (Ty->isVectorType() || Ty->isConstantArrayType()) {
3405-
QualType ElTy;
3406-
uint64_t Size = 0;
3407-
if (auto *ATy = Ty->getAs<VectorType>()) {
3408-
ElTy = ATy->getElementType();
3409-
Size = ATy->getNumElements();
3410-
} else {
3411-
auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
3412-
ElTy = VTy->getElementType();
3413-
Size = VTy->getZExtSize();
3414-
}
3415-
for (uint64_t I = 0; I < Size; ++I)
3416-
Inits.push_back(GenerateInitLists(Ctx, ElTy, It));
3417-
}
3418-
if (auto *RTy = Ty->getAs<RecordType>()) {
3419-
llvm::SmallVector<const RecordType *> RecordTypes;
3420-
RecordTypes.push_back(RTy);
3421-
while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
3422-
CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
3423-
assert(D->getNumBases() == 1 &&
3424-
"HLSL doesn't support multiple inheritance");
3425-
RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
3426-
}
3427-
while (!RecordTypes.empty()) {
3428-
const RecordType *RT = RecordTypes.pop_back_val();
3429-
for (auto *FD : RT->getDecl()->fields()) {
3430-
Inits.push_back(GenerateInitLists(Ctx, FD->getType(), It));
3408+
Expr *generateInitListsImpl(QualType Ty) {
3409+
assert(ArgIt != ArgExprs.end() && "Something is off in iteration!");
3410+
if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
3411+
return *(ArgIt++);
3412+
3413+
llvm::SmallVector<Expr *> Inits;
3414+
assert(!isa<MatrixType>(Ty) && "Matrix types not yet supported in HLSL");
3415+
Ty = Ty.getDesugaredType(Ctx);
3416+
if (Ty->isVectorType() || Ty->isConstantArrayType()) {
3417+
QualType ElTy;
3418+
uint64_t Size = 0;
3419+
if (auto *ATy = Ty->getAs<VectorType>()) {
3420+
ElTy = ATy->getElementType();
3421+
Size = ATy->getNumElements();
3422+
} else {
3423+
auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
3424+
ElTy = VTy->getElementType();
3425+
Size = VTy->getZExtSize();
3426+
}
3427+
for (uint64_t I = 0; I < Size; ++I)
3428+
Inits.push_back(generateInitListsImpl(ElTy));
3429+
}
3430+
if (auto *RTy = Ty->getAs<RecordType>()) {
3431+
llvm::SmallVector<const RecordType *> RecordTypes;
3432+
RecordTypes.push_back(RTy);
3433+
while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
3434+
CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
3435+
assert(D->getNumBases() == 1 &&
3436+
"HLSL doesn't support multiple inheritance");
3437+
RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
3438+
}
3439+
while (!RecordTypes.empty()) {
3440+
const RecordType *RT = RecordTypes.pop_back_val();
3441+
for (auto *FD : RT->getDecl()->fields()) {
3442+
Inits.push_back(generateInitListsImpl(FD->getType()));
3443+
}
34313444
}
34323445
}
3446+
auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
3447+
Inits, Inits.back()->getEndLoc());
3448+
NewInit->setType(Ty);
3449+
return NewInit;
34333450
}
3434-
auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
3435-
Inits, Inits.back()->getEndLoc());
3436-
NewInit->setType(Ty);
3437-
return NewInit;
3438-
}
34393451

3440-
bool SemaHLSL::TransformInitList(const InitializedEntity &Entity,
3441-
const InitializationKind &Kind,
3452+
public:
3453+
llvm::SmallVector<QualType, 16> DestTypes;
3454+
llvm::SmallVector<Expr *, 16> ArgExprs;
3455+
InitListTransformer(Sema &SemaRef, const InitializedEntity &Entity)
3456+
: S(SemaRef), Ctx(SemaRef.getASTContext()),
3457+
Wrap(Entity.getType()->isIncompleteArrayType()) {
3458+
InitTy = Entity.getType().getNonReferenceType();
3459+
// When we're generating initializer lists for incomplete array types we
3460+
// need to wrap around both when building the initializers and when
3461+
// generating the final initializer lists.
3462+
if (Wrap) {
3463+
assert(InitTy->isIncompleteArrayType());
3464+
const IncompleteArrayType *IAT = Ctx.getAsIncompleteArrayType(InitTy);
3465+
InitTy = IAT->getElementType();
3466+
}
3467+
BuildFlattenedTypeList(InitTy, DestTypes);
3468+
DstIt = DestTypes.begin();
3469+
}
3470+
3471+
bool buildInitializerList(Expr *E) { return buildInitializerListImpl(E); }
3472+
3473+
Expr *generateInitLists() {
3474+
assert(!ArgExprs.empty() &&
3475+
"Call buildInitializerList to generate argument expressions.");
3476+
ArgIt = ArgExprs.begin();
3477+
if (!Wrap)
3478+
return generateInitListsImpl(InitTy);
3479+
llvm::SmallVector<Expr *> Inits;
3480+
while (ArgIt != ArgExprs.end())
3481+
Inits.push_back(generateInitListsImpl(InitTy));
3482+
3483+
auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
3484+
Inits, Inits.back()->getEndLoc());
3485+
llvm::APInt ArySize(64, Inits.size());
3486+
NewInit->setType(Ctx.getConstantArrayType(InitTy, ArySize, nullptr,
3487+
ArraySizeModifier::Normal, 0));
3488+
return NewInit;
3489+
}
3490+
};
3491+
} // namespace
3492+
3493+
bool SemaHLSL::transformInitList(const InitializedEntity &Entity,
34423494
InitListExpr *Init) {
34433495
// If the initializer is a scalar, just return it.
34443496
if (Init->getType()->isScalarType())
34453497
return true;
34463498
ASTContext &Ctx = SemaRef.getASTContext();
3447-
llvm::SmallVector<QualType, 16> DestTypes;
3448-
// An initializer list might be attempting to initialize a reference or
3449-
// rvalue-reference. When checking the initializer we should look through the
3450-
// reference.
3451-
QualType InitTy = Entity.getType().getNonReferenceType();
3452-
BuildFlattenedTypeList(InitTy, DestTypes);
3499+
InitListTransformer ILT(SemaRef, Entity);
34533500

3454-
llvm::SmallVector<Expr *, 16> ArgExprs;
34553501
for (unsigned I = 0; I < Init->getNumInits(); ++I) {
34563502
Expr *E = Init->getInit(I);
34573503
if (E->HasSideEffects(Ctx)) {
@@ -3462,21 +3508,35 @@ bool SemaHLSL::TransformInitList(const InitializedEntity &Entity,
34623508
E->getObjectKind(), E);
34633509
Init->setInit(I, E);
34643510
}
3465-
if (!BuildInitializerList(SemaRef, Ctx, E, ArgExprs, DestTypes))
3511+
if (!ILT.buildInitializerList(E))
34663512
return false;
34673513
}
3514+
size_t ExpectedSize = ILT.DestTypes.size();
3515+
size_t ActualSize = ILT.ArgExprs.size();
3516+
// For incomplete arrays it is completely arbitrary to choose whether we think
3517+
// the user intended fewer or more elements. This implementation assumes that
3518+
// the user intended more, and errors that there are too few initializers to
3519+
// complete the final element.
3520+
if (Entity.getType()->isIncompleteArrayType())
3521+
ExpectedSize =
3522+
((ActualSize + ExpectedSize - 1) / ExpectedSize) * ExpectedSize;
34683523

3469-
if (DestTypes.size() != ArgExprs.size()) {
3470-
int TooManyOrFew = ArgExprs.size() > DestTypes.size() ? 1 : 0;
3524+
// An initializer list might be attempting to initialize a reference or
3525+
// rvalue-reference. When checking the initializer we should look through
3526+
// the reference.
3527+
QualType InitTy = Entity.getType().getNonReferenceType();
3528+
if (InitTy.hasAddressSpace())
3529+
InitTy = SemaRef.getASTContext().removeAddrSpaceQualType(InitTy);
3530+
if (ExpectedSize != ActualSize) {
3531+
int TooManyOrFew = ActualSize > ExpectedSize ? 1 : 0;
34713532
SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
3472-
<< TooManyOrFew << InitTy << DestTypes.size() << ArgExprs.size();
3533+
<< TooManyOrFew << InitTy << ExpectedSize << ActualSize;
34733534
return false;
34743535
}
34753536

3476-
auto It = ArgExprs.begin();
3477-
// GenerateInitLists will always return an InitListExpr here, because the
3537+
// generateInitListsImpl will always return an InitListExpr here, because the
34783538
// scalar case is handled above.
3479-
auto *NewInit = cast<InitListExpr>(GenerateInitLists(Ctx, InitTy, It));
3539+
auto *NewInit = cast<InitListExpr>(ILT.generateInitLists());
34803540
Init->resizeInits(Ctx, NewInit->getNumInits());
34813541
for (unsigned I = 0; I < NewInit->getNumInits(); ++I)
34823542
Init->updateInit(Ctx, I, NewInit->getInit(I));

0 commit comments

Comments
 (0)