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
