[clang] f99f2a5 - [analyzer] Implement LifetimeModeling checker and refactor UseAfterLifetimeEnd (#205951)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jul 12 05:58:57 PDT 2026
Author: Benedek Kaibas
Date: 2026-07-12T13:58:52+01:00
New Revision: f99f2a582e947af3f20580fa2674ca0c6bde1b2c
URL: https://github.com/llvm/llvm-project/commit/f99f2a582e947af3f20580fa2674ca0c6bde1b2c
DIFF: https://github.com/llvm/llvm-project/commit/f99f2a582e947af3f20580fa2674ca0c6bde1b2c.diff
LOG: [analyzer] Implement LifetimeModeling checker and refactor UseAfterLifetimeEnd (#205951)
Added:
clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h
Modified:
clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp
clang/test/Analysis/debug-lifetime-bound.cpp
clang/test/Analysis/lifetime-bound.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 949e20d1fb98d..0f8b3bb1e1d18 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -795,9 +795,15 @@ def SmartPtrChecker: Checker<"SmartPtr">,
Dependencies<[SmartPtrModeling]>,
Documentation<HasDocumentation>;
+def LifetimeModeling : Checker<"LifetimeModeling">,
+ HelpText<"Model lifetime annotations for other checkers">,
+ Documentation<NotDocumented>,
+ Hidden;
+
def UseAfterLifetimeEnd : Checker<"UseAfterLifetimeEnd">,
HelpText<"Check for uses of references or pointers that "
"outlive their bound object">,
+ Dependencies<[LifetimeModeling]>,
Documentation<NotDocumented>;
} // end: "alpha.cplusplus"
@@ -1588,10 +1594,9 @@ def CheckerDocumentationChecker : Checker<"CheckerDocumentation">,
HelpText<"Defines an empty checker callback for all possible handlers.">,
Documentation<NotDocumented>;
-def DebugUseAfterLifetimeEnd : Checker<"DebugUseAfterLifetimeEnd">,
- HelpText<"Prints the bindings recorded by the UseAfterLifetimeEnd checker. "
- "Use with clang_analyzer_dumpLifetimeOriginsOf().">,
- WeakDependencies<[UseAfterLifetimeEnd]>,
+def DebugLifetimeModeling : Checker<"DebugLifetimeModeling">,
+ HelpText<"Dump the set of regions the bound variable originates from">,
+ Dependencies<[LifetimeModeling]>,
Documentation<NotDocumented>;
} // end "debug"
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 46c0c36fda736..8f61b7d88e8d2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -55,6 +55,7 @@ add_clang_library(clangStaticAnalyzerCheckers
IteratorModeling.cpp
IteratorRangeChecker.cpp
IvarInvalidationChecker.cpp
+ LifetimeModeling.cpp
LLVMConventionsChecker.cpp
LocalizationChecker.cpp
MacOSKeychainAPIChecker.cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
new file mode 100644
index 0000000000000..a2f58e0710801
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp
@@ -0,0 +1,214 @@
+#include "LifetimeModeling.h"
+#include "clang/AST/Attr.h"
+#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(LifetimeSourceSet, const MemRegion *)
+REGISTER_MAP_WITH_PROGRAMSTATE(LifetimeBoundMap, SVal, LifetimeSourceSet)
+
+namespace {
+
+class LifetimeModeling : public Checker<check::PostCall, check::DeadSymbols> {
+public:
+ void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
+ const char *Sep) const override;
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+};
+
+} // namespace
+
+static bool isDanglingStackSource(const MemRegion *Source,
+ ProgramStateRef State, CheckerContext &C) {
+ // FIXME: The checker currently handles stack-region sources. Other
+ // region kinds require separate methodology. For example, heap
+ // regions do not go out of scope at the end of a stack frame, so
+ // in order to detect those type of dangling sources the function
+ // needs to be expanded to an event-driven approach as well.
+ if (const auto *StackSpace =
+ Source->getMemorySpaceAs<StackSpaceRegion>(State)) {
+ const StackFrame *SF = StackSpace->getStackFrame();
+ const StackFrame *CurrentSF = C.getStackFrame();
+ if (SF == CurrentSF || !SF->isParentOf(CurrentSF))
+ return true;
+ }
+ return false;
+}
+
+std::vector<const MemRegion *> lifetime_modeling::getDanglingRegionsAfterReturn(
+ SVal Val, ProgramStateRef State, CheckerContext &C) {
+ std::vector<const MemRegion *> Regions;
+ if (auto *SourceSet = State->get<LifetimeBoundMap>(Val)) {
+ for (const MemRegion *Region : *SourceSet) {
+ if (isDanglingStackSource(Region, State, C))
+ Regions.push_back(Region);
+ }
+ }
+ return Regions;
+}
+
+static ProgramStateRef bindSource(ProgramStateRef State, SVal RetVal,
+ const MemRegion *Source) {
+ LifetimeSourceSet::Factory &F = State->get_context<LifetimeSourceSet>();
+ const LifetimeSourceSet *LSet = State->get<LifetimeBoundMap>(RetVal);
+
+ LifetimeSourceSet Set = LSet ? *LSet : F.getEmptySet();
+ Set = F.add(Set, Source);
+ State = State->set<LifetimeBoundMap>(RetVal, Set);
+ return State;
+}
+
+void LifetimeModeling::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ const auto *FC = dyn_cast<AnyFunctionCall>(&Call);
+ if (!FC)
+ return;
+
+ const FunctionDecl *FD = FC->getDecl();
+ if (!FD)
+ return;
+
+ SVal RetVal = Call.getReturnValue();
+
+ for (const ParmVarDecl *PVD : FD->parameters()) {
+ if (PVD->hasAttr<LifetimeBoundAttr>()) {
+ unsigned Idx = PVD->getFunctionScopeIndex();
+ SVal Arg = Call.getArgSVal(Idx);
+ if (const MemRegion *ArgValRegion = Arg.getAsRegion())
+ State = bindSource(State, RetVal, ArgValRegion);
+ }
+ }
+
+ const auto *IC = dyn_cast<CXXInstanceCall>(&Call);
+ if (IC && lifetimes::implicitObjectParamIsLifetimeBound(FD)) {
+ if (const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion())
+ State = bindSource(State, RetVal, ThisRegion);
+ }
+ C.addTransition(State);
+}
+
+void LifetimeModeling::checkDeadSymbols(SymbolReaper &SymReaper,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ LifetimeBoundMapTy LBMap = State->get<LifetimeBoundMap>();
+
+ for (SVal Val : llvm::make_first_range(LBMap)) {
+ if (const auto *R = Val.getAsRegion(); R && SymReaper.isLiveRegion(R))
+ continue;
+
+ if (SymbolRef S = Val.getAsSymbol(/*IncludeBaseRegions=*/true);
+ S && SymReaper.isLive(S))
+ continue;
+
+ State = State->remove<LifetimeBoundMap>(Val);
+ }
+ C.addTransition(State);
+}
+
+void LifetimeModeling::printState(raw_ostream &Out, ProgramStateRef State,
+ const char *NL, const char *Sep) const {
+ auto LBMap = State->get<LifetimeBoundMap>();
+
+ if (LBMap.isEmpty())
+ return;
+
+ Out << Sep << "LifetimeBound bindings:" << NL;
+ for (auto &&[OriginSym, SourceSet] : LBMap) {
+ for (const auto *Region : SourceSet)
+ Out << " Origin " << OriginSym << " contains Loan " << Region << NL;
+ }
+}
+
+// FIXME: Eventually move the debug checker to its own source file once
+// it has more functionality.
+namespace {
+class DebugLifetimeModeling : public Checker<eval::Call> {
+public:
+ bool evalCall(const CallEvent &Call, CheckerContext &C) const;
+ void analyzerDumpLifetimeOriginsOf(const CallEvent &Call,
+ CheckerContext &C) const;
+ const BugType BugMsg{this, "DebugLifetimeModeling", "DebugLifetimeModeling"};
+ using FnCheck = void (DebugLifetimeModeling::*)(const CallEvent &Call,
+ CheckerContext &C) const;
+
+ const CallDescriptionMap<FnCheck> Callbacks = {
+ {{CDM::SimpleFunc, {"clang_analyzer_dumpLifetimeOriginsOf"}},
+ &DebugLifetimeModeling::analyzerDumpLifetimeOriginsOf},
+ };
+};
+
+} // namespace
+
+bool DebugLifetimeModeling::evalCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ if (!isa_and_nonnull<CallExpr>(Call.getOriginExpr()))
+ return false;
+
+ const FnCheck *Handler = Callbacks.lookup(Call);
+ if (!Handler)
+ return false;
+
+ (this->*(*Handler))(Call, C);
+ return true;
+}
+
+void DebugLifetimeModeling::analyzerDumpLifetimeOriginsOf(
+ const CallEvent &Call, CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ if (Call.getNumArgs() != 1) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+ auto BR = std::make_unique<PathSensitiveBugReport>(
+ BugMsg,
+ "clang_analyzer_dumpLifetimeOriginsOf requires exactly 1 argument",
+ N);
+ C.emitReport(std::move(BR));
+ }
+ return;
+ }
+
+ SVal ArgSVal = Call.getArgSVal(0);
+ const LifetimeSourceSet *SourceSet = State->get<LifetimeBoundMap>(ArgSVal);
+
+ if (!SourceSet)
+ return;
+
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+ llvm::SmallVector<std::string> RegionNames =
+ to_vector(map_range(llvm::make_pointee_range(*SourceSet),
+ std::mem_fn(&MemRegion::getString)));
+ llvm::sort(RegionNames);
+
+ llvm::SmallString<128> Str;
+ llvm::raw_svector_ostream OS(Str);
+ OS << " Origin " << ArgSVal << " bound to ";
+ llvm::interleaveComma(RegionNames, OS);
+ C.emitReport(std::make_unique<PathSensitiveBugReport>(BugMsg, OS.str(), N));
+ }
+}
+
+void ento::registerLifetimeModeling(CheckerManager &Mgr) {
+ Mgr.registerChecker<LifetimeModeling>();
+}
+
+bool ento::shouldRegisterLifetimeModeling(const CheckerManager &Mgr) {
+ return true;
+}
+
+void ento::registerDebugLifetimeModeling(CheckerManager &Mgr) {
+ Mgr.registerChecker<DebugLifetimeModeling>();
+}
+
+bool ento::shouldRegisterDebugLifetimeModeling(const CheckerManager &Mgr) {
+ return true;
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h
new file mode 100644
index 0000000000000..e13942eb1856b
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.h
@@ -0,0 +1,18 @@
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_LIFETIMEMODELING_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_LIFETIMEMODELING_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include <vector>
+
+namespace clang::ento::lifetime_modeling {
+/// Returns the set of lifetime sources bound to \p Source that are dangling
+/// stack regions.
+std::vector<const MemRegion *>
+getDanglingRegionsAfterReturn(SVal Source, ProgramStateRef State,
+ CheckerContext &C);
+
+} // namespace clang::ento::lifetime_modeling
+
+#endif // LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_LIFETIMEMODELING_H
diff --git a/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp b/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp
index db776f1c1c49d..6a2933900c01f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UseAfterLifetimeEnd.cpp
@@ -1,123 +1,27 @@
-#include "clang/AST/Attr.h"
-#include "clang/Analysis/Analyses/LifetimeSafety/LifetimeAnnotations.h"
+#include "LifetimeModeling.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
-REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(LifetimeSourceSet, const MemRegion *)
-REGISTER_MAP_WITH_PROGRAMSTATE(LifetimeBoundMap, SVal, LifetimeSourceSet)
-
namespace {
-class UseAfterLifetimeEnd
- : public Checker<check::PostCall, check::EndFunction, check::DeadSymbols> {
+class UseAfterLifetimeEnd : public Checker<check::EndFunction> {
public:
- void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
- void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
- const char *Sep) const override;
- void reportDanglingSource(const MemRegion *Region, ExplodedNode *N,
+ void reportDanglingSource(const MemRegion *Source, ExplodedNode *N,
CheckerContext &C) const;
- void checkReturnedBorrower(SVal Val, ProgramStateRef State,
- CheckerContext &C) const;
void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
- void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
const BugType BugMsg{this, "UseAfterLifetimeEnd", "LifetimeBound"};
};
} // namespace
-static ProgramStateRef bindValues(ProgramStateRef State, SVal RetVal,
- const MemRegion *Source) {
- LifetimeSourceSet::Factory &F = State->get_context<LifetimeSourceSet>();
-
- const LifetimeSourceSet *LSet = State->get<LifetimeBoundMap>(RetVal);
- LifetimeSourceSet Set = LSet ? *LSet : F.getEmptySet();
- Set = F.add(Set, Source);
- State = State->set<LifetimeBoundMap>(RetVal, Set);
- return State;
-}
-
-void UseAfterLifetimeEnd::checkPostCall(const CallEvent &Call,
- CheckerContext &C) const {
- ProgramStateRef State = C.getState();
-
- const auto *FC = dyn_cast<AnyFunctionCall>(&Call);
- if (!FC)
- return;
-
- const FunctionDecl *FD = FC->getDecl();
- if (!FD)
- return;
-
- SVal RetVal = Call.getReturnValue();
-
- for (const ParmVarDecl *PVD : FD->parameters()) {
- if (PVD->hasAttr<LifetimeBoundAttr>()) {
- unsigned Idx = PVD->getFunctionScopeIndex();
- SVal Arg = Call.getArgSVal(Idx);
- if (const MemRegion *ArgValRegion = Arg.getAsRegion())
- State = bindValues(State, RetVal, ArgValRegion);
- }
- }
-
- if (const auto *IC = dyn_cast<CXXInstanceCall>(&Call)) {
- if (lifetimes::implicitObjectParamIsLifetimeBound(FD)) {
- if (const MemRegion *AttrRegion = IC->getCXXThisVal().getAsRegion()) {
- State = bindValues(State, RetVal, AttrRegion);
- }
- }
- }
- C.addTransition(State);
-}
-
-static bool hasDanglingSource(const MemRegion *Source, ProgramStateRef State,
- CheckerContext &C) {
- // FIXME: The checker currently handles stack-region sources. Other
- // region kinds require separate methodology. For example, heap
- // regions do not go out of scope at the end of a stack frame, so
- // in order to detect those type of dangling sources the function
- // needs to be expanded to an event-driven approach as well.
- if (const auto *StackSpace =
- Source->getMemorySpaceAs<StackSpaceRegion>(State)) {
- const StackFrame *SF = StackSpace->getStackFrame();
- const StackFrame *CurrentSF = C.getStackFrame();
- if (SF == CurrentSF || !SF->isParentOf(CurrentSF))
- return true;
- }
- return false;
-}
-
-void UseAfterLifetimeEnd::checkReturnedBorrower(SVal Val, ProgramStateRef State,
- CheckerContext &C) const {
- if (auto *SourceSet = State->get<LifetimeBoundMap>(Val)) {
- ExplodedNode *N = nullptr;
- for (const MemRegion *Region : *SourceSet) {
- if (hasDanglingSource(Region, State, C)) {
- if (!N)
- N = C.generateNonFatalErrorNode();
- if (!N)
- return;
- reportDanglingSource(Region, N, C);
- }
- }
- }
-}
-
void UseAfterLifetimeEnd::checkEndFunction(const ReturnStmt *RS,
CheckerContext &C) const {
if (!RS)
return;
ProgramStateRef State = C.getState();
- auto LBMap = State->get<LifetimeBoundMap>();
-
- if (LBMap.isEmpty())
- return;
const Expr *RetExpr = RS->getRetValue();
if (!RetExpr)
@@ -125,122 +29,30 @@ void UseAfterLifetimeEnd::checkEndFunction(const ReturnStmt *RS,
RetExpr = RetExpr->IgnoreParens();
SVal RetVal = C.getSVal(RetExpr);
- checkReturnedBorrower(RetVal, State, C);
+
+ std::vector<const MemRegion *> RetValRegion =
+ lifetime_modeling::getDanglingRegionsAfterReturn(RetVal, State, C);
+ if (RetValRegion.empty())
+ return;
+
+ if (ExplodedNode *N =
+ C.generateNonFatalErrorNode(State, C.getPredecessor())) {
+ for (const MemRegion *R : RetValRegion)
+ reportDanglingSource(R, N, C);
+ }
}
-void UseAfterLifetimeEnd::reportDanglingSource(const MemRegion *Region,
+void UseAfterLifetimeEnd::reportDanglingSource(const MemRegion *Source,
ExplodedNode *N,
CheckerContext &C) const {
auto BR = std::make_unique<PathSensitiveBugReport>(
BugMsg,
- (llvm::Twine("Returning value bound to '") + Region->getString() +
+ (llvm::Twine("Returning value bound to '") + Source->getString() +
"' that will go out of scope"),
N);
C.emitReport(std::move(BR));
}
-void UseAfterLifetimeEnd::checkDeadSymbols(SymbolReaper &SymReaper,
- CheckerContext &C) const {
- ProgramStateRef State = C.getState();
- LifetimeBoundMapTy LBMap = State->get<LifetimeBoundMap>();
-
- for (SVal Val : llvm::make_first_range(LBMap)) {
- if (const MemRegion *ValRegion = Val.getAsRegion()) {
- if (!SymReaper.isLiveRegion(ValRegion))
- State = State->remove<LifetimeBoundMap>(Val);
- } else if (SymbolRef ValRef =
- Val.getAsSymbol(/*IncludeBaseRegions=*/true)) {
- if (!SymReaper.isLive(ValRef))
- State = State->remove<LifetimeBoundMap>(Val);
- }
- }
-
- C.addTransition(State);
-}
-
-void UseAfterLifetimeEnd::printState(raw_ostream &Out, ProgramStateRef State,
- const char *NL, const char *Sep) const {
- auto LBMap = State->get<LifetimeBoundMap>();
-
- if (LBMap.isEmpty())
- return;
-
- Out << Sep << "LifetimeBound bindings:" << NL;
- for (auto &&[OriginSym, SourceSet] : LBMap) {
- for (const auto *Region : SourceSet)
- Out << " Origin " << OriginSym << " contains Loan " << Region << NL;
- }
-}
-
-namespace {
-class DebugUseAfterLifetimeEnd : public Checker<eval::Call> {
-public:
- bool evalCall(const CallEvent &Call, CheckerContext &C) const;
- void analyzerDumpLifetimeOriginsOf(const CallEvent &Call,
- CheckerContext &C) const;
-
- const BugType BugMsg{this, "DebugUseAfterLifetimeEnd",
- "DebugUseAfterLifetimeEnd"};
- using FnCheck = void (DebugUseAfterLifetimeEnd::*)(const CallEvent &Call,
- CheckerContext &C) const;
-
- const CallDescriptionMap<FnCheck> Callbacks = {
- {{CDM::SimpleFunc, {"clang_analyzer_dumpLifetimeOriginsOf"}},
- &DebugUseAfterLifetimeEnd::analyzerDumpLifetimeOriginsOf},
- };
-};
-
-} // namespace
-
-bool DebugUseAfterLifetimeEnd::evalCall(const CallEvent &Call,
- CheckerContext &C) const {
- const auto *CE = dyn_cast_if_present<CallExpr>(Call.getOriginExpr());
- if (!CE)
- return false;
-
- const FnCheck *Handler = Callbacks.lookup(Call);
- if (!Handler)
- return false;
-
- (this->*(*Handler))(Call, C);
- return true;
-}
-
-void DebugUseAfterLifetimeEnd::analyzerDumpLifetimeOriginsOf(
- const CallEvent &Call, CheckerContext &C) const {
- ProgramStateRef State = C.getState();
-
- if (Call.getNumArgs() != 1) {
- if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
- auto BR = std::make_unique<PathSensitiveBugReport>(
- BugMsg,
- "clang_analyzer_dumpLifetimeOriginsOf requires exactly 1 argument",
- N);
- C.emitReport(std::move(BR));
- }
- return;
- }
-
- SVal ArgSVal = Call.getArgSVal(0);
- const LifetimeSourceSet *SourceSet = State->get<LifetimeBoundMap>(ArgSVal);
-
- if (!SourceSet)
- return;
-
- if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
- llvm::SmallVector<std::string> RegionNames =
- to_vector(map_range(llvm::make_pointee_range(*SourceSet),
- std::mem_fn(&MemRegion::getString)));
- llvm::sort(RegionNames);
-
- llvm::SmallString<128> Str;
- llvm::raw_svector_ostream OS(Str);
- OS << " Origin " << ArgSVal << " bound to ";
- llvm::interleaveComma(RegionNames, OS);
- C.emitReport(std::make_unique<PathSensitiveBugReport>(BugMsg, OS.str(), N));
- }
-}
-
void ento::registerUseAfterLifetimeEnd(CheckerManager &Mgr) {
Mgr.registerChecker<UseAfterLifetimeEnd>();
}
@@ -248,11 +60,3 @@ void ento::registerUseAfterLifetimeEnd(CheckerManager &Mgr) {
bool ento::shouldRegisterUseAfterLifetimeEnd(const CheckerManager &Mgr) {
return true;
}
-
-void ento::registerDebugUseAfterLifetimeEnd(CheckerManager &Mgr) {
- Mgr.registerChecker<DebugUseAfterLifetimeEnd>();
-}
-
-bool ento::shouldRegisterDebugUseAfterLifetimeEnd(const CheckerManager &Mgr) {
- return true;
-}
diff --git a/clang/test/Analysis/debug-lifetime-bound.cpp b/clang/test/Analysis/debug-lifetime-bound.cpp
index 8ef704195dcc6..b52d23c88071d 100644
--- a/clang/test/Analysis/debug-lifetime-bound.cpp
+++ b/clang/test/Analysis/debug-lifetime-bound.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugUseAfterLifetimeEnd -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugLifetimeModeling -verify %s
// expected-no-diagnostics
diff --git a/clang/test/Analysis/lifetime-bound.cpp b/clang/test/Analysis/lifetime-bound.cpp
index e99299b5d03bf..f8519b76798fd 100644
--- a/clang/test/Analysis/lifetime-bound.cpp
+++ b/clang/test/Analysis/lifetime-bound.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugUseAfterLifetimeEnd \
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugLifetimeModeling \
// RUN: -analyzer-config cfg-lifetime=true -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugUseAfterLifetimeEnd \
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UseAfterLifetimeEnd,debug.DebugLifetimeModeling \
// RUN: -analyzer-config c++-container-inlining=false -analyzer-config cfg-lifetime=true -verify %s
struct A {};
More information about the cfe-commits
mailing list