Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2418,9 +2418,9 @@ def err_init_conversion_failed : Error<
"cannot initialize %select{a variable|a parameter|template parameter|"
"return object|statement expression result|an "
"exception object|a member subobject|an array element|a new value|a value|a "
"base class|a constructor delegation|a vector element|a block element|a "
"block element|a complex element|a lambda capture|a compound literal "
"initializer|a related result|a parameter of CF audited function|a "
"base class|a constructor delegation|a vector element|a matrix element|a "
"block element|a block element|a complex element|a lambda capture|a compound"
" literal initializer|a related result|a parameter of CF audited function|a "
"structured binding|a member subobject}0 "
"%diff{of type $ with an %select{rvalue|lvalue}2 of type $|"
"with an %select{rvalue|lvalue}2 of incompatible type}1,3"
Expand Down Expand Up @@ -6546,9 +6546,9 @@ def warn_extern_init : Warning<"'extern' variable has an initializer">,
def err_variable_object_no_init : Error<
"variable-sized object may not be initialized">;
def err_excess_initializers : Error<
"excess elements in %select{array|vector|scalar|union|struct}0 initializer">;
"excess elements in %select{array|vector|matrix|scalar|union|struct}0 initializer">;
def ext_excess_initializers : ExtWarn<
"excess elements in %select{array|vector|scalar|union|struct}0 initializer">,
"excess elements in %select{array|vector|matrix|scalar|union|struct}0 initializer">,
InGroup<ExcessInitializers>;
def err_excess_initializers_for_sizeless_type : Error<
"excess elements in initializer for indivisible sizeless type %0">;
Expand Down
12 changes: 8 additions & 4 deletions clang/include/clang/Sema/Initialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ class alignas(8) InitializedEntity {
/// or vector.
EK_VectorElement,

/// The entity being initialized is an element of a matrix.
/// or matrix.
EK_MatrixElement,

/// The entity being initialized is a field of block descriptor for
/// the copied-in c++ object.
EK_BlockElement,
Expand Down Expand Up @@ -205,8 +209,8 @@ class alignas(8) InitializedEntity {
/// virtual base.
llvm::PointerIntPair<const CXXBaseSpecifier *, 1> Base;

/// When Kind == EK_ArrayElement, EK_VectorElement, or
/// EK_ComplexElement, the index of the array or vector element being
/// When Kind == EK_ArrayElement, EK_VectorElement, EK_MatrixElement,
/// or EK_ComplexElement, the index of the array or vector element being
/// initialized.
unsigned Index;

Expand Down Expand Up @@ -536,15 +540,15 @@ class alignas(8) InitializedEntity {
/// element's index.
unsigned getElementIndex() const {
assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement ||
getKind() == EK_ComplexElement);
getKind() == EK_MatrixElement || getKind() == EK_ComplexElement);
return Index;
}

/// If this is already the initializer for an array or vector
/// element, sets the element index.
void setElementIndex(unsigned Index) {
assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement ||
getKind() == EK_ComplexElement);
getKind() == EK_MatrixElement || getKind() == EK_ComplexElement);
this->Index = Index;
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/CheckExprLifetime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ getEntityLifetime(const InitializedEntity *Entity,
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
case InitializedEntity::EK_LambdaCapture:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_MatrixElement:
case InitializedEntity::EK_ComplexElement:
return {nullptr, LK_FullExpression};

Expand Down
39 changes: 37 additions & 2 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/HLSLResource.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeBase.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticSema.h"
Expand Down Expand Up @@ -3351,6 +3352,11 @@ static void BuildFlattenedTypeList(QualType BaseTy,
List.insert(List.end(), VT->getNumElements(), VT->getElementType());
continue;
}
if (const auto *MT = dyn_cast<ConstantMatrixType>(T)) {
List.insert(List.end(), MT->getNumElementsFlattened(),
MT->getElementType());
continue;
}
if (const auto *RD = T->getAsCXXRecordDecl()) {
if (RD->isStandardLayout())
RD = RD->getStandardLayoutBaseWithFields();
Expand Down Expand Up @@ -4149,6 +4155,32 @@ class InitListTransformer {
}
return true;
}
if (auto *MTy = Ty->getAs<ConstantMatrixType>()) {
unsigned Rows = MTy->getNumRows();
unsigned Cols = MTy->getNumColumns();
QualType ElemTy = MTy->getElementType();

for (unsigned C = 0; C < Cols; ++C) {
for (unsigned R = 0; R < Rows; ++R) {
// row index literal
Expr *RowIdx = IntegerLiteral::Create(
Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), R), Ctx.IntTy,
E->getBeginLoc());
// column index literal
Expr *ColIdx = IntegerLiteral::Create(
Ctx, llvm::APInt(Ctx.getIntWidth(Ctx.IntTy), C), Ctx.IntTy,
E->getBeginLoc());
ExprResult ElExpr = S.CreateBuiltinMatrixSubscriptExpr(
E, RowIdx, ColIdx, E->getEndLoc());
if (ElExpr.isInvalid())
return false;
if (!castInitializer(ElExpr.get()))
return false;
ElExpr.get()->setType(ElemTy);
}
}
return true;
}

if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
uint64_t Size = ArrTy->getZExtSize();
Expand Down Expand Up @@ -4202,14 +4234,17 @@ class InitListTransformer {
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()) {
if (Ty->isVectorType() || Ty->isConstantArrayType() ||
Ty->isConstantMatrixType()) {
QualType ElTy;
uint64_t Size = 0;
if (auto *ATy = Ty->getAs<VectorType>()) {
ElTy = ATy->getElementType();
Size = ATy->getNumElements();
} else if (auto *CMTy = Ty->getAs<ConstantMatrixType>()) {
ElTy = CMTy->getElementType();
Size = CMTy->getNumElementsFlattened();
} else {
auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
ElTy = VTy->getElementType();
Expand Down
84 changes: 69 additions & 15 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/IgnoreExpr.h"
#include "clang/AST/TypeBase.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
Expand Down Expand Up @@ -403,6 +404,9 @@ class InitListChecker {
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex);
void CheckMatrixType(const InitializedEntity &Entity, InitListExpr *IList,
QualType DeclType, unsigned &Index,
InitListExpr *StructuredList, unsigned &StructuredIndex);
void CheckVectorType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType, unsigned &Index,
InitListExpr *StructuredList,
Expand Down Expand Up @@ -1003,7 +1007,8 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
return;

if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement ||
ElementEntity.getKind() == InitializedEntity::EK_VectorElement)
ElementEntity.getKind() == InitializedEntity::EK_VectorElement ||
ElementEntity.getKind() == InitializedEntity::EK_MatrixElement)
ElementEntity.setElementIndex(Init);

if (Init >= NumInits && (ILE->hasArrayFiller() || SkipEmptyInitChecks))
Expand Down Expand Up @@ -1273,6 +1278,7 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity,

switch (Entity.getKind()) {
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_MatrixElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_Parameter:
Expand Down Expand Up @@ -1372,11 +1378,12 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK)
<< T << IList->getInit(Index)->getSourceRange();
} else {
int initKind = T->isArrayType() ? 0 :
T->isVectorType() ? 1 :
T->isScalarType() ? 2 :
T->isUnionType() ? 3 :
4;
int initKind = T->isArrayType() ? 0
: T->isVectorType() ? 1
: T->isMatrixType() ? 2
: T->isScalarType() ? 3
: T->isUnionType() ? 4
: 5;

unsigned DK = ExtraInitsIsError ? diag::err_excess_initializers
: diag::ext_excess_initializers;
Expand Down Expand Up @@ -1430,6 +1437,9 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
} else if (DeclType->isVectorType()) {
CheckVectorType(Entity, IList, DeclType, Index,
StructuredList, StructuredIndex);
} else if (DeclType->isMatrixType()) {
CheckMatrixType(Entity, IList, DeclType, Index, StructuredList,
StructuredIndex);
} else if (const RecordDecl *RD = DeclType->getAsRecordDecl()) {
auto Bases =
CXXRecordDecl::base_class_const_range(CXXRecordDecl::base_class_const_iterator(),
Expand Down Expand Up @@ -1877,6 +1887,34 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
AggrDeductionCandidateParamTypes->push_back(DeclType);
}

void InitListChecker::CheckMatrixType(const InitializedEntity &Entity,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why we need to do this checking. Shouldn't this all be done in the SemaHLSL code that validates the initializer list and transforms it to per-element initializers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well three things First SemaHLSL is validating vectors and yet we still have CheckVectorType which even has HLSL copy initalization.

Second removing

} else if (DeclType->isMatrixType()) {
    CheckMatrixType(Entity, IList, DeclType, Index, StructuredList,
                    StructuredIndex);
  }

causes us to hit this else case:

} else {
if (!VerifyOnly)
SemaRef.Diag(IList->getBeginLoc(), diag::err_illegal_initializer_type)
<< DeclType;
hadError = true;
}

Third even if we do something like below to avoid the err_illegal_initializer_type diag message

} else if (DeclType->isMatrixType()) {
    return;
  }

we still error with excess elements in matrix initializer. So CheckMatrixType is necessary.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said the diagnostics in CheckMatrixType never trigger and are now preceded by the ones in SemaHLSL and the flatten mixed vector/matrix/scalar elements is also done in SemaHLSL so I will investigate to see if we can reduce the scope of what CheckMatrixType is doing.

Copy link
Member Author

@farzonl farzonl Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@llvm-beanz the initializer list work simplifies but does not make us remove CheckMatrixType. It simplifies it so that all we have to do is support the scalar case by looping over the number of inits and calling CheckSubElementType. So I deleted all the vector and matrix type handeling

InitListExpr *IList, QualType DeclType,
unsigned &Index,
InitListExpr *StructuredList,
unsigned &StructuredIndex) {
if (!SemaRef.getLangOpts().HLSL)
return;

const ConstantMatrixType *MT = DeclType->castAs<ConstantMatrixType>();
QualType ElemTy = MT->getElementType();
const unsigned MaxElts = MT->getNumElementsFlattened();

unsigned NumEltsInit = 0;
InitializedEntity ElemEnt =
InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity);

while (NumEltsInit < MaxElts && Index < IList->getNumInits()) {
// Not a sublist: just consume directly.
ElemEnt.setElementIndex(Index);
CheckSubElementType(ElemEnt, IList, ElemTy, Index, StructuredList,
StructuredIndex);
++NumEltsInit;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at this and I understand what is going on. We need the code up to here. We'll never get this far if we have the wrong number of initializers because this happens after initializer flattening. We should add an assert assert(NumEltsInit != MaxElts), and drop the rest of the function because that's unreachable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep did this already. Originally was thinking if CheckMatrixType was expanded for c++ we would need a fall back diagnostic since all of ours are in SemaHLSL.cpp for this case. But now I think it makes more sense to leave that to the c++ matrix constructor implementer to figure out.


// HLSL requires exactly NumEltsInit to equal Max initializers.
assert(NumEltsInit == MaxElts && "NumEltsInit must equal MaxElts");
}

void InitListChecker::CheckVectorType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
unsigned &Index,
Expand Down Expand Up @@ -3639,6 +3677,9 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index,
} else if (const VectorType *VT = Parent.getType()->getAs<VectorType>()) {
Kind = EK_VectorElement;
Type = VT->getElementType();
} else if (const MatrixType *MT = Parent.getType()->getAs<MatrixType>()) {
Kind = EK_MatrixElement;
Type = MT->getElementType();
} else {
const ComplexType *CT = Parent.getType()->getAs<ComplexType>();
assert(CT && "Unexpected type");
Expand Down Expand Up @@ -3687,6 +3728,7 @@ DeclarationName InitializedEntity::getName() const {
case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_MatrixElement:
case EK_ComplexElement:
case EK_BlockElement:
case EK_LambdaToBlockConversionBlockElement:
Expand Down Expand Up @@ -3720,6 +3762,7 @@ ValueDecl *InitializedEntity::getDecl() const {
case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_MatrixElement:
case EK_ComplexElement:
case EK_BlockElement:
case EK_LambdaToBlockConversionBlockElement:
Expand Down Expand Up @@ -3753,6 +3796,7 @@ bool InitializedEntity::allowsNRVO() const {
case EK_Delegating:
case EK_ArrayElement:
case EK_VectorElement:
case EK_MatrixElement:
case EK_ComplexElement:
case EK_BlockElement:
case EK_LambdaToBlockConversionBlockElement:
Expand Down Expand Up @@ -3792,6 +3836,9 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
case EK_Delegating: OS << "Delegating"; break;
case EK_ArrayElement: OS << "ArrayElement " << Index; break;
case EK_VectorElement: OS << "VectorElement " << Index; break;
case EK_MatrixElement:
OS << "MatrixElement " << Index;
break;
case EK_ComplexElement: OS << "ComplexElement " << Index; break;
case EK_BlockElement: OS << "Block"; break;
case EK_LambdaToBlockConversionBlockElement:
Expand Down Expand Up @@ -6029,7 +6076,7 @@ static void TryOrBuildParenListInitialization(
Sequence.SetFailed(InitializationSequence::FK_ParenthesizedListInitFailed);
if (!VerifyOnly) {
QualType T = Entity.getType();
int InitKind = T->isArrayType() ? 0 : T->isUnionType() ? 3 : 4;
int InitKind = T->isArrayType() ? 0 : T->isUnionType() ? 4 : 5;
SourceRange ExcessInitSR(Args[EntityIndexToProcess]->getBeginLoc(),
Args.back()->getEndLoc());
S.Diag(Kind.getLocation(), diag::err_excess_initializers)
Expand Down Expand Up @@ -6822,7 +6869,8 @@ void InitializationSequence::InitializeFrom(Sema &S,
// For HLSL ext vector types we allow list initialization behavior for C++
// functional cast expressions which look like constructor syntax. This is
// accomplished by converting initialization arguments to InitListExpr.
if (S.getLangOpts().HLSL && Args.size() > 1 && DestType->isExtVectorType() &&
if (S.getLangOpts().HLSL && Args.size() > 1 &&
(DestType->isExtVectorType() || DestType->isConstantMatrixType()) &&
(SourceType.isNull() ||
!Context.hasSameUnqualifiedType(SourceType, DestType))) {
InitListExpr *ILE = new (Context)
Expand Down Expand Up @@ -6987,6 +7035,7 @@ static AssignmentAction getAssignmentAction(const InitializedEntity &Entity,
case InitializedEntity::EK_Binding:
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_MatrixElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
Expand All @@ -7012,6 +7061,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_MatrixElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_BlockElement:
Expand Down Expand Up @@ -7042,6 +7092,7 @@ static bool shouldDestroyEntity(const InitializedEntity &Entity) {
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_MatrixElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
Expand Down Expand Up @@ -7095,6 +7146,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_MatrixElement:
case InitializedEntity::EK_ComplexElement:
case InitializedEntity::EK_BlockElement:
case InitializedEntity::EK_LambdaToBlockConversionBlockElement:
Expand Down Expand Up @@ -7844,11 +7896,13 @@ ExprResult InitializationSequence::Perform(Sema &S,
ExprResult CurInit((Expr *)nullptr);
SmallVector<Expr*, 4> ArrayLoopCommonExprs;

// HLSL allows vector initialization to function like list initialization, but
// use the syntax of a C++-like constructor.
bool IsHLSLVectorInit = S.getLangOpts().HLSL && DestType->isExtVectorType() &&
isa<InitListExpr>(Args[0]);
(void)IsHLSLVectorInit;
// HLSL allows vector/matrix initialization to function like list
// initialization, but use the syntax of a C++-like constructor.
bool IsHLSLVectorOrMatrixInit =
S.getLangOpts().HLSL &&
(DestType->isExtVectorType() || DestType->isConstantMatrixType()) &&
isa<InitListExpr>(Args[0]);
(void)IsHLSLVectorOrMatrixInit;

// For initialization steps that start with a single initializer,
// grab the only argument out the Args and place it into the "current"
Expand Down Expand Up @@ -7887,7 +7941,7 @@ ExprResult InitializationSequence::Perform(Sema &S,
case SK_StdInitializerList:
case SK_OCLSamplerInit:
case SK_OCLZeroOpaqueType: {
assert(Args.size() == 1 || IsHLSLVectorInit);
assert(Args.size() == 1 || IsHLSLVectorOrMatrixInit);
CurInit = Args[0];
if (!CurInit.get()) return ExprError();
break;
Expand Down Expand Up @@ -9104,7 +9158,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< R;
else
S.Diag(Kind.getLocation(), diag::err_excess_initializers)
<< /*scalar=*/2 << R;
<< /*scalar=*/3 << R;
break;
}

Expand Down
Loading