https://github.com/Nemi26 created
https://github.com/llvm/llvm-project/pull/233008
Both constant evaluators assumed that a matrix initializer list holds one
initializer per element, which only holds for HLSL. Outside HLSL, `m{}` is the
only initializer list a matrix accepts, and evaluating it crashed: when
constant-initializing a namespace-scope `m3 x{};` in any C++ mode, or in a
constexpr function in C++23.
This value-initializes the matrix to zero for an empty initializer list, in
ExprConstant and in the bytecode interpreter, using the matrix `APValue` added
in #178762. The bytecode interpreter now also value-initializes a matrix for
`m3()`, which ExprConstant already accepted.
Reading a matrix element in a constant expression is still unsupported and
diagnosed as before (#120167).
Fixes #232999
🤖 Generated with [Claude Code](https://claude.com/claude-code)
>From 7cf5be679cff4e54a88a6afe845498bc6caaadd1 Mon Sep 17 00:00:00 2001
From: Nemi26 <[email protected]>
Date: Sat, 17 Oct 2026 05:14:19 +0200
Subject: [PATCH] [clang] Zero-initialize matrix types from empty init lists in
constant evaluation
Both constant evaluators assumed that a matrix initializer list holds
one initializer per element, which only holds for HLSL. Outside HLSL,
`m{}` is the only initializer list a matrix accepts, and evaluating it
crashed, for example when constant-initializing a namespace-scope
`m3 x{};` or in a constexpr function in C++23.
Value-initialize the matrix to zero for an empty initializer list, in
ExprConstant and in the bytecode interpreter. The bytecode interpreter
now also value-initializes a matrix for `m3()`, as ExprConstant does.
Fixes #232999
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
clang/docs/ReleaseNotes.md | 2 ++
clang/lib/AST/ByteCode/Compiler.cpp | 16 ++++++++++---
clang/lib/AST/ExprConstant.cpp | 21 +++++++++++++++++
clang/test/SemaCXX/matrix-type-constexpr.cpp | 24 ++++++++++++++++++++
4 files changed, 60 insertions(+), 3 deletions(-)
create mode 100644 clang/test/SemaCXX/matrix-type-constexpr.cpp
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 7d3f0eb702553d..a90ff6ad8b6e68 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -1076,6 +1076,8 @@ features cannot lower the translation-unit ABI level;
Objective-C `@implementation` that was ended by a nested `@interface`,
`@protocol` or `@implementation` before its `@end`. (#GH209503)
- Fixed use-after-free with annotate attribute on a C++ class method with a
this-adjusting thunk.
+- Fixed a crash when the constant evaluator initialized a `matrix_type`
+ variable with an empty initializer list, such as `m{}`. (#GH232999)
### OpenACC Specific Changes
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp
b/clang/lib/AST/ByteCode/Compiler.cpp
index 40b36b4e715a10..7e0acd69c43c37 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -2661,7 +2661,9 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr
*> Inits,
if (const auto *MT = QT->getAs<ConstantMatrixType>()) {
unsigned NumElems = MT->getNumElementsFlattened();
- assert(Inits.size() == NumElems);
+ // An empty initializer list value-initializes the matrix. Outside of HLSL,
+ // this is the only initializer list a matrix accepts.
+ assert(Inits.empty() || Inits.size() == NumElems);
QualType ElemQT = MT->getElementType();
PrimType ElemT = classifyPrim(ElemQT);
@@ -2670,8 +2672,12 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const
Expr *> Inits,
// the matrix APValue convention and therefore no index remapping is
// required.
for (unsigned I = 0; I != NumElems; ++I) {
- if (!this->visit(Inits[I]))
+ if (Inits.empty()) {
+ if (!this->visitZeroInitializer(ElemT, ElemQT, E))
+ return false;
+ } else if (!this->visit(Inits[I])) {
return false;
+ }
if (!this->emitInitElem(ElemT, I, E))
return false;
}
@@ -4202,7 +4208,8 @@ bool Compiler<Emitter>::VisitCXXScalarValueInitExpr(
if (OptPrimType T = classify(Ty))
return this->visitZeroInitializer(*T, Ty, E);
- if (Ty->isAnyComplexType() || Ty->isVectorType()) {
+ if (Ty->isAnyComplexType() || Ty->isVectorType() ||
+ Ty->isConstantMatrixType()) {
if (!Initializing) {
UnsignedOrNone LocalIndex = allocateLocal(E);
if (!LocalIndex)
@@ -4216,6 +4223,9 @@ bool Compiler<Emitter>::VisitCXXScalarValueInitExpr(
if (const auto *CT = Ty->getAs<ComplexType>()) {
NumElems = 2;
ElemQT = CT->getElementType();
+ } else if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
+ NumElems = MT->getNumElementsFlattened();
+ ElemQT = MT->getElementType();
} else {
const auto *VT = Ty->castAs<VectorType>();
NumElems = VT->getNumElements();
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 6d390032e2c717..95a1f6cf824842 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -15582,6 +15582,8 @@ class MatrixExprEvaluator : public
ExprEvaluatorBase<MatrixExprEvaluator> {
return true;
}
+ bool ZeroInitialization(const Expr *E);
+
bool VisitCastExpr(const CastExpr *E);
bool VisitInitListExpr(const InitListExpr *E);
};
@@ -15593,6 +15595,20 @@ static bool EvaluateMatrix(const Expr *E, APValue
&Result, EvalInfo &Info) {
return MatrixExprEvaluator(Info, Result).Visit(E);
}
+bool MatrixExprEvaluator::ZeroInitialization(const Expr *E) {
+ const auto *MT = E->getType()->castAs<ConstantMatrixType>();
+ QualType EltTy = MT->getElementType();
+ APValue ZeroElement;
+ if (EltTy->isIntegerType())
+ ZeroElement = APValue(Info.Ctx.MakeIntValue(0, EltTy));
+ else
+ ZeroElement =
+ APValue(APFloat::getZero(Info.Ctx.getFloatTypeSemantics(EltTy)));
+
+ SmallVector<APValue, 16> Elements(MT->getNumElementsFlattened(),
ZeroElement);
+ return Success(Elements, E);
+}
+
bool MatrixExprEvaluator::VisitCastExpr(const CastExpr *E) {
const auto *MT = E->getType()->castAs<ConstantMatrixType>();
unsigned NumRows = MT->getNumRows();
@@ -15641,6 +15657,11 @@ bool MatrixExprEvaluator::VisitInitListExpr(const
InitListExpr *E) {
const auto *MT = E->getType()->castAs<ConstantMatrixType>();
QualType EltTy = MT->getElementType();
+ // An empty initializer list value-initializes the matrix. Outside of HLSL,
+ // this is the only initializer list a matrix accepts.
+ if (E->getNumInits() == 0)
+ return ZeroInitialization(E);
+
assert(E->getNumInits() == MT->getNumElementsFlattened() &&
"Expected number of elements in initializer list to match the number "
"of matrix elements");
diff --git a/clang/test/SemaCXX/matrix-type-constexpr.cpp
b/clang/test/SemaCXX/matrix-type-constexpr.cpp
new file mode 100644
index 00000000000000..d3b4a66c7b4c10
--- /dev/null
+++ b/clang/test/SemaCXX/matrix-type-constexpr.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -fenable-matrix -std=c++11 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fenable-matrix -std=c++11 -verify %s
-fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -fsyntax-only -fenable-matrix -std=c++23 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fenable-matrix -std=c++23 -verify %s
-fexperimental-new-constant-interpreter
+// expected-no-diagnostics
+
+// GH232999: an empty initializer list value-initializes a matrix in constant
+// evaluation.
+
+typedef float fx3x3_t __attribute__((matrix_type(3, 3)));
+typedef int ix2x4_t __attribute__((matrix_type(2, 4)));
+
+fx3x3_t GlobalFloat{};
+ix2x4_t GlobalInt{};
+
+#if __cplusplus >= 202302L
+constexpr bool f() {
+ fx3x3_t M{};
+ ix2x4_t N{};
+ fx3x3_t O = fx3x3_t();
+ return true;
+}
+static_assert(f());
+#endif
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits