[clang] 083acc3 - [clang][bytecode] Fix uninitialized diagnostics (#209702)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 15 03:59:34 PDT 2026
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}}
+}
More information about the cfe-commits
mailing list