https://github.com/Serosh-commits updated 
https://github.com/llvm/llvm-project/pull/180261

>From 9e3a16f024b3d1160264c3eee87b979a763207e1 Mon Sep 17 00:00:00 2001
From: Serosh-commits <[email protected]>
Date: Fri, 13 Feb 2026 21:51:25 +0530
Subject: [PATCH] Fix crash when constexpr variables have invalid initializers

---
 clang/lib/AST/ByteCode/Pointer.cpp | 104 +++++++++++++++++++----------
 clang/lib/AST/ByteCode/Pointer.h   |  22 +++++-
 clang/lib/Sema/SemaDecl.cpp        |   9 ++-
 test-invalid-constexpr.cpp         |   2 +
 4 files changed, 98 insertions(+), 39 deletions(-)
 create mode 100644 test-invalid-constexpr.cpp

diff --git a/clang/lib/AST/ByteCode/Pointer.cpp 
b/clang/lib/AST/ByteCode/Pointer.cpp
index fb9202c6d66c8..bef0f6cacadf9 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -385,14 +385,17 @@ size_t Pointer::computeOffsetForComparison(const 
ASTContext &ASTCtx) const {
   Pointer P = *this;
   while (true) {
     if (P.isVirtualBaseClass()) {
-      Result += getInlineDesc()->Offset;
+      if (InlineDescriptor *ID = getInlineDesc())
+        Result += ID->Offset;
       P = P.getBase();
       continue;
     }
 
     if (P.isBaseClass()) {
-      if (P.getRecord()->getNumVirtualBases() > 0)
-        Result += P.getInlineDesc()->Offset;
+      if (P.getRecord()->getNumVirtualBases() > 0) {
+        if (InlineDescriptor *ID = P.getInlineDesc())
+          Result += ID->Offset;
+      }
       P = P.getBase();
       continue;
     }
@@ -444,26 +447,31 @@ std::string Pointer::toDiagnosticString(const ASTContext 
&Ctx) const {
   return toAPValue(Ctx).getAsString(Ctx, getType());
 }
 
+bool Pointer::isGlobalInitialized() const {
+  assert(isBlockPointer());
+  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+    if (Block *B = block()) {
+      const auto &GD = B->getBlockDesc<GlobalInlineDescriptor>();
+      return GD.InitState == GlobalInitState::Initialized;
+    }
+  }
+  return false;
+}
+
 bool Pointer::isInitialized() const {
   if (!isBlockPointer())
     return true;
 
-  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
-      Offset == BS.Base) {
-    const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
-    return GD.InitState == GlobalInitState::Initialized;
-  }
-
   assert(BS.Pointee && "Cannot check if null pointer was initialized");
   const Descriptor *Desc = getFieldDesc();
   assert(Desc);
   if (Desc->isPrimitiveArray())
     return isElementInitialized(getIndex());
 
-  if (asBlockPointer().Base == 0)
-    return true;
-  // Field has its bit in an inline descriptor.
-  return getInlineDesc()->IsInitialized;
+  if (InlineDescriptor *D = getInlineDesc())
+    return D->IsInitialized;
+
+  return isGlobalInitialized();
 }
 
 bool Pointer::isElementInitialized(unsigned Index) const {
@@ -476,11 +484,8 @@ bool Pointer::isElementInitialized(unsigned Index) const {
   if (isStatic() && BS.Base == 0)
     return true;
 
-  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
-      Offset == BS.Base) {
-    const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
-    return GD.InitState == GlobalInitState::Initialized;
-  }
+  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor))
+    return isGlobalInitialized();
 
   if (Desc->isPrimitiveArray()) {
     InitMapPtr IM = getInitMap();
@@ -525,7 +530,8 @@ void Pointer::startLifetime() const {
     return;
   }
 
-  getInlineDesc()->LifeState = Lifetime::Started;
+  if (InlineDescriptor *ID = getInlineDesc())
+    ID->LifeState = Lifetime::Started;
 }
 
 void Pointer::endLifetime() const {
@@ -545,7 +551,8 @@ void Pointer::endLifetime() const {
     return;
   }
 
-  getInlineDesc()->LifeState = Lifetime::Ended;
+  if (InlineDescriptor *ID = getInlineDesc())
+    ID->LifeState = Lifetime::Ended;
 }
 
 void Pointer::initialize() const {
@@ -556,8 +563,10 @@ void Pointer::initialize() const {
 
   if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
       Offset == BS.Base) {
-    auto &GD = BS.Pointee->getBlockDesc<GlobalInlineDescriptor>();
-    GD.InitState = GlobalInitState::Initialized;
+    if (Block *B = block()) {
+      auto &GD = B->getBlockDesc<GlobalInlineDescriptor>();
+      GD.InitState = GlobalInitState::Initialized;
+    }
     return;
   }
 
@@ -571,7 +580,16 @@ void Pointer::initialize() const {
 
   // Field has its bit in an inline descriptor.
   assert(BS.Base != 0 && "Only composite fields can be initialised");
-  getInlineDesc()->IsInitialized = true;
+  if (InlineDescriptor *D = getInlineDesc()) {
+    D->IsInitialized = true;
+    return;
+  }
+
+  assert(isRoot() && BS.Base == sizeof(GlobalInlineDescriptor));
+  if (Block *B = block()) {
+    auto &GD = B->getBlockDesc<GlobalInlineDescriptor>();
+    GD.InitState = GlobalInitState::Initialized;
+  }
 }
 
 void Pointer::initializeElement(unsigned Index) const {
@@ -611,8 +629,11 @@ bool Pointer::allElementsInitialized() const {
 
   if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
       Offset == BS.Base) {
-    const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
-    return GD.InitState == GlobalInitState::Initialized;
+    if (Block *B = block()) {
+      const auto &GD = B->getBlockDesc<GlobalInlineDescriptor>();
+      return GD.InitState == GlobalInitState::Initialized;
+    }
+    return false;
   }
 
   InitMapPtr IM = getInitMap();
@@ -628,8 +649,11 @@ bool Pointer::allElementsAlive() const {
 
   if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
       Offset == BS.Base) {
-    const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
-    return GD.InitState == GlobalInitState::Initialized;
+    if (Block *B = block()) {
+      const auto &GD = B->getBlockDesc<GlobalInlineDescriptor>();
+      return GD.InitState == GlobalInitState::Initialized;
+    }
+    return false;
   }
 
   InitMapPtr &IM = getInitMap();
@@ -642,17 +666,26 @@ void Pointer::activate() const {
 
   if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor))
     return;
-  if (!getInlineDesc()->InUnion)
+
+  if (InlineDescriptor *ID = getInlineDesc()) {
+    if (!ID->InUnion)
+      return;
+  } else {
     return;
+  }
 
   std::function<void(Pointer &)> activate;
   activate = [&activate](Pointer &P) -> void {
-    P.getInlineDesc()->IsActive = true;
+    if (InlineDescriptor *ID = P.getInlineDesc())
+      ID->IsActive = true;
+
     if (const Record *R = P.getRecord(); R && !R->isUnion()) {
       for (const Record::Field &F : R->fields()) {
         Pointer FieldPtr = P.atField(F.Offset);
-        if (!FieldPtr.getInlineDesc()->IsActive)
-          activate(FieldPtr);
+        if (InlineDescriptor *ID = FieldPtr.getInlineDesc()) {
+          if (!ID->IsActive)
+            activate(FieldPtr);
+        }
       }
       // FIXME: Bases?
     }
@@ -660,13 +693,16 @@ void Pointer::activate() const {
 
   std::function<void(Pointer &)> deactivate;
   deactivate = [&deactivate](Pointer &P) -> void {
-    P.getInlineDesc()->IsActive = false;
+    if (InlineDescriptor *ID = P.getInlineDesc())
+      ID->IsActive = false;
 
     if (const Record *R = P.getRecord()) {
       for (const Record::Field &F : R->fields()) {
         Pointer FieldPtr = P.atField(F.Offset);
-        if (FieldPtr.getInlineDesc()->IsActive)
-          deactivate(FieldPtr);
+        if (InlineDescriptor *ID = FieldPtr.getInlineDesc()) {
+          if (ID->IsActive)
+            deactivate(FieldPtr);
+        }
       }
       // FIXME: Bases?
     }
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 2515b2fe56ab9..fc2d815f33fac 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -246,7 +246,11 @@ class Pointer {
       return Pointer(Pointee, BS.Base, BS.Base);
 
     // Step into the containing array, if inside one.
-    unsigned Next = BS.Base - getInlineDesc()->Offset;
+    InlineDescriptor *ID = getInlineDesc();
+    if (!ID)
+      return *this;
+
+    unsigned Next = BS.Base - ID->Offset;
     const Descriptor *Desc =
         (Next == Pointee->getDescriptor()->getMetadataSize())
             ? getDeclDesc()
@@ -315,7 +319,14 @@ class Pointer {
       assert(Offset == PastEndMark && "cannot get base of a block");
       return Pointer(BS.Pointee, BS.Base, 0);
     }
-    unsigned NewBase = BS.Base - getInlineDesc()->Offset;
+    if (isRoot())
+      return *this;
+
+    InlineDescriptor *ID = getInlineDesc();
+    if (!ID)
+      return *this;
+
+    unsigned NewBase = BS.Base - ID->Offset;
     return Pointer(BS.Pointee, NewBase, NewBase);
   }
   /// Returns the parent array.
@@ -829,12 +840,17 @@ class Pointer {
   /// Returns the embedded descriptor preceding a field.
   InlineDescriptor *getInlineDesc() const {
     assert(isBlockPointer());
-    assert(BS.Base != sizeof(GlobalInlineDescriptor));
+    if (BS.Base == sizeof(GlobalInlineDescriptor))
+      return nullptr;
+
     assert(BS.Base <= BS.Pointee->getSize());
     assert(BS.Base >= sizeof(InlineDescriptor));
     return getDescriptor(BS.Base);
   }
 
+  /// Returns whether the pointer is a global root and is initialized.
+  bool isGlobalInitialized() const;
+
   /// Returns a descriptor at a given offset.
   InlineDescriptor *getDescriptor(unsigned Offset) const {
     assert(Offset != 0 && "Not a nested pointer");
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 3b2c93b9fe7b5..06fa33e5615e8 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14337,7 +14337,9 @@ void Sema::ActOnInitializerError(Decl *D) {
       BD->setInvalidDecl();
 
   // Auto types are meaningless if we can't make sense of the initializer.
-  if (VD->getType()->isUndeducedType()) {
+  // Similarly, constexpr variables require a valid constant initializer;
+  // if the initializer is erroneous, the variable is unusable.
+  if (VD->getType()->isUndeducedType() || VD->isConstexpr()) {
     D->setInvalidDecl();
     return;
   }
@@ -14949,9 +14951,11 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl 
*var) {
   QualType baseType = Context.getBaseElementType(type);
   bool HasConstInit = true;
 
-  if (getLangOpts().C23 && var->isConstexpr() && !Init)
+  if (getLangOpts().C23 && var->isConstexpr() && !Init) {
     Diag(var->getLocation(), diag::err_constexpr_var_requires_const_init)
         << var;
+    var->setInvalidDecl();
+  }
 
   // Check whether the initializer is sufficiently constant.
   if ((getLangOpts().CPlusPlus || (getLangOpts().C23 && var->isConstexpr())) &&
@@ -15012,6 +15016,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl 
*var) {
           << var << Init->getSourceRange();
       for (unsigned I = 0, N = Notes.size(); I != N; ++I)
         Diag(Notes[I].first, Notes[I].second);
+      var->setInvalidDecl();
     } else if (GlobalStorage && var->hasAttr<ConstInitAttr>()) {
       auto *Attr = var->getAttr<ConstInitAttr>();
       Diag(var->getLocation(), diag::err_require_constant_init_failed)
diff --git a/test-invalid-constexpr.cpp b/test-invalid-constexpr.cpp
new file mode 100644
index 0000000000000..2dd10750e66ef
--- /dev/null
+++ b/test-invalid-constexpr.cpp
@@ -0,0 +1,2 @@
+constexpr const int *foo[][2] = { {nullptr, int}, };
+static_assert(foo[0][0] == nullptr, "");

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to