[clang] [clang][bytecode] Fix uninitialized diagnostics (PR #209702)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 15 02:02:59 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
... if the pointer is also outside its lifetime. In that case, prefer to diagnose it as outside its lifetime.
---
Full diff: https://github.com/llvm/llvm-project/pull/209702.diff
4 Files Affected:
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+13-11)
- (modified) clang/lib/AST/ByteCode/Interp.h (+8-7)
- (modified) clang/lib/AST/ByteCode/Pointer.h (+1-17)
- (modified) clang/test/AST/ByteCode/cxx2a.cpp (+12)
``````````diff
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 58bbf4aaf5f89..1310500ca871e 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)
@@ -783,7 +784,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;
@@ -836,7 +838,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) {
@@ -858,10 +860,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);
@@ -917,7 +919,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))
@@ -985,7 +987,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))
@@ -2122,7 +2124,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}}
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/209702
More information about the cfe-commits
mailing list