Author: Timm Baeder Date: 2026-07-15T12:59:30+02:00 New Revision: 083acc3c31fd4696bbc6d4b1c647c63ac976a7ec
URL: https://github.com/llvm/llvm-project/commit/083acc3c31fd4696bbc6d4b1c647c63ac976a7ec DIFF: https://github.com/llvm/llvm-project/commit/083acc3c31fd4696bbc6d4b1c647c63ac976a7ec.diff LOG: [clang][bytecode] Fix uninitialized diagnostics (#209702) ... if the pointer is also outside its lifetime. In that case, prefer to diagnose it as outside its lifetime. Added: Modified: clang/lib/AST/ByteCode/Interp.cpp clang/lib/AST/ByteCode/Interp.h clang/lib/AST/ByteCode/Pointer.h clang/test/AST/ByteCode/cxx2a.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index f4a5ddc99d95d..1163ec07ecd1e 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -731,15 +731,16 @@ static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return false; } -bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, +bool diagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK) { assert(Ptr.isLive()); assert(!Ptr.isInitialized()); - return DiagnoseUninitialized(S, OpPC, Ptr.isExtern(), Ptr.block(), AK); + return diagnoseUninitialized(S, OpPC, Ptr.isExtern(), Ptr.block(), + Ptr.getLifetime(), AK); } -bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern, - const Block *B, AccessKinds AK) { +bool diagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern, + const Block *B, Lifetime LT, AccessKinds AK) { if (S.checkingPotentialConstantExpression()) { // Extern and static member declarations might be initialized later. if (Extern) @@ -782,7 +783,8 @@ bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern, if (!S.checkingPotentialConstantExpression()) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit) - << AK << /*uninitialized=*/true << S.Current->getRange(OpPC); + << AK << /*uninitialized=*/(LT == Lifetime::Started) + << S.Current->getRange(OpPC); noteValueLocation(S, B); } return false; @@ -835,7 +837,7 @@ bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B) { if (!CheckConstant(S, OpPC, B->getDescriptor())) return false; if (Desc.InitState != GlobalInitState::Initialized) - return DiagnoseUninitialized(S, OpPC, B->isExtern(), B, AK_Read); + return diagnoseUninitialized(S, OpPC, B->isExtern(), B); if (!CheckTemporary(S, OpPC, B, AK_Read)) return false; if (B->getDescriptor()->IsVolatile) { @@ -857,10 +859,10 @@ bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) { assert(!B->isExtern()); const auto &Desc = *reinterpret_cast<const InlineDescriptor *>(B->rawData()); const Descriptor *BlockDesc = B->getDescriptor(); + if (!Desc.IsInitialized) + return diagnoseUninitialized(S, OpPC, /*Extern=*/false, B, Desc.LifeState); if (!CheckLifetime(S, OpPC, Desc.LifeState, B, AK_Read)) return false; - if (!Desc.IsInitialized) - return DiagnoseUninitialized(S, OpPC, /*Extern=*/false, B, AK_Read); if (BlockDesc->IsVolatile) { if (!S.getLangOpts().CPlusPlus) return Invalid(S, OpPC); @@ -916,7 +918,7 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, if (!CheckActive(S, OpPC, Ptr, AK)) return false; if (!Ptr.isInitialized()) - return DiagnoseUninitialized(S, OpPC, Ptr, AK); + return diagnoseUninitialized(S, OpPC, Ptr, AK); if (!CheckLifetime(S, OpPC, Ptr, AK)) return false; if (!CheckTemporary(S, OpPC, Ptr.block(), AK)) @@ -984,7 +986,7 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!CheckLifetime(S, OpPC, Ptr, AK_Read)) return false; if (!Ptr.isInitialized()) - return DiagnoseUninitialized(S, OpPC, Ptr, AK_Read); + return diagnoseUninitialized(S, OpPC, Ptr, AK_Read); if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Read)) return false; if (!CheckMutable(S, OpPC, Ptr)) @@ -2121,7 +2123,7 @@ bool DynamicCast(InterpState &S, CodePtr OpPC, const Type *DestTypePtr, return false; if (!Ptr.isInitialized()) - return DiagnoseUninitialized(S, OpPC, Ptr, AK_Read); + return diagnoseUninitialized(S, OpPC, Ptr, AK_Read); // Our given pointer, limited by the base that's currently being initialized, // if any. diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 201679017c98b..b676e7ab43750 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -81,10 +81,11 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc, bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); -bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, +bool diagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK); -bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern, - const Block *B, AccessKinds AK); +bool diagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern, + const Block *B, Lifetime LT = Lifetime::Started, + AccessKinds AK = AK_Read); /// Checks a direct load of a primitive value from a global or local variable. bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B); @@ -1764,7 +1765,7 @@ bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) { const Block *B = S.P.getGlobal(I); const auto &Desc = B->getBlockDesc<GlobalInlineDescriptor>(); if (Desc.InitState != GlobalInitState::Initialized) - return DiagnoseUninitialized(S, OpPC, B->isExtern(), B, AK_Read); + return diagnoseUninitialized(S, OpPC, B->isExtern(), B); S.Stk.push<T>(B->deref<T>()); return true; @@ -2076,7 +2077,7 @@ inline bool GetRefGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { const auto &Desc = B->getBlockDesc<GlobalInlineDescriptor>(); if (Desc.InitState != GlobalInitState::Initialized) - return DiagnoseUninitialized(S, OpPC, B->isExtern(), B, AK_Read); + return diagnoseUninitialized(S, OpPC, B->isExtern(), B); S.Stk.push<Pointer>(B->deref<Pointer>()); return true; @@ -2693,7 +2694,7 @@ static inline bool IncPtr(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop<Pointer>(); if (!Ptr.isInitialized()) - return DiagnoseUninitialized(S, OpPC, Ptr, AK_Increment); + return diagnoseUninitialized(S, OpPC, Ptr, AK_Increment); return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr); } @@ -2702,7 +2703,7 @@ static inline bool DecPtr(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop<Pointer>(); if (!Ptr.isInitialized()) - return DiagnoseUninitialized(S, OpPC, Ptr, AK_Decrement); + return diagnoseUninitialized(S, OpPC, Ptr, AK_Decrement); return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr); } diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index dda5ac61ef126..417c28b46875a 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -957,23 +957,7 @@ class Pointer { Lifetime getLifetime() const { if (!isBlockPointer()) return Lifetime::Started; - if (BS.Base < sizeof(InlineDescriptor)) - return Lifetime::Started; - - if (inArray() && !isArrayRoot()) { - InitMapPtr &IM = getInitMap(); - - if (!IM.hasInitMap()) { - if (IM.allInitialized()) - return Lifetime::Started; - return getArray().getLifetime(); - } - - return IM->isElementAlive(getIndex()) ? Lifetime::Started - : Lifetime::Ended; - } - - return getInlineDesc()->LifeState; + return view().getLifetime(); } /// Start the lifetime of this pointer. This works for pointer with an diff --git a/clang/test/AST/ByteCode/cxx2a.cpp b/clang/test/AST/ByteCode/cxx2a.cpp index 2f2f2b95745b3..e2cf74aa4ec57 100644 --- a/clang/test/AST/ByteCode/cxx2a.cpp +++ b/clang/test/AST/ByteCode/cxx2a.cpp @@ -302,3 +302,15 @@ namespace PseudoDtorOnGlobal { a.m.~T(); // both-note {{cannot modify an object that is visible outside}} } } + +namespace UninitializedAndLifetime { + struct A { int n; }; + constexpr void use_after_destroy() { + A a; // both-note {{declared here}} + a.~A(); + A b = a; // both-note {{in call}} \ + // both-note {{read of object outside its lifetime}} + } + static_assert((use_after_destroy(), true)); // both-error {{not an integral constant expression}} \ + // both-note {{in call}} +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
