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

Reply via email to