https://github.com/steakhal created https://github.com/llvm/llvm-project/pull/210938
Walking a StackFrame's parent chain was open-coded across the Analysis library and Static Analyzer as hand-rolled loops of the form `for (const StackFrame *SF = X; SF; SF = SF->getParent())`. Add range-based traversal helpers and convert the applicable loops: * StackFrame::parents() - strict ancestors (excludes *this) * StackFrame::parentsIncludingSelf() - *this then all ancestors Both are built on a small forward `parent_iterator` that dereferences to `const StackFrame &` and advances via getParent(), with a null past-the-end sentinel. For the common case of obtaining the current frame from an ExplodedNode or CheckerContext, add a self-inclusive `stackframes()` convenience on each that delegates to `getStackFrame()->parentsIncludingSelf()`. Converted call-sites additionally adopt llvm::any_of / llvm::enumerate / make_pointer_range where it makes the traversal more declarative. Loops that stop at a target frame or advance conditionally (i.e. not "walk until null") are intentionally left as-is. From c79cc42619fa9b6d9e933503dc6ae19b902a6214 Mon Sep 17 00:00:00 2001 From: Balazs Benics <[email protected]> Date: Tue, 21 Jul 2026 09:14:28 +0100 Subject: [PATCH] [analyzer][NFC] Add StackFrame parent-chain range helpers Walking a StackFrame's parent chain was open-coded across the Analysis library and Static Analyzer as hand-rolled loops of the form `for (const StackFrame *SF = X; SF; SF = SF->getParent())`. Add range-based traversal helpers and convert the applicable loops: * StackFrame::parents() - strict ancestors (excludes *this) * StackFrame::parentsIncludingSelf() - *this then all ancestors Both are built on a small forward `parent_iterator` that dereferences to `const StackFrame &` and advances via getParent(), with a null past-the-end sentinel. For the common case of obtaining the current frame from an ExplodedNode or CheckerContext, add a self-inclusive `stackframes()` convenience on each that delegates to `getStackFrame()->parentsIncludingSelf()`. Converted call-sites additionally adopt llvm::any_of / llvm::enumerate / make_pointer_range where it makes the traversal more declarative. Loops that stop at a target frame or advance conditionally (i.e. not "walk until null") are intentionally left as-is. This is NFC. --- .../clang/Analysis/AnalysisDeclContext.h | 48 +++++++++++++++++++ .../Core/PathSensitive/CheckerContext.h | 5 ++ .../Core/PathSensitive/ExplodedGraph.h | 5 ++ .../Core/PathSensitive/ExprEngine.h | 6 ++- clang/lib/Analysis/AnalysisDeclContext.cpp | 38 ++++++--------- .../Checkers/CheckObjCDealloc.cpp | 14 ++---- .../StaticAnalyzer/Checkers/MallocChecker.cpp | 6 +-- .../StaticAnalyzer/Checkers/MoveChecker.cpp | 24 +++++----- .../Checkers/TraversalChecker.cpp | 13 ++--- .../UninitializedObjectChecker.cpp | 32 +++++-------- .../Core/BugReporterVisitors.cpp | 4 +- clang/lib/StaticAnalyzer/Core/Environment.cpp | 5 +- .../Core/ExprEngineCallAndReturn.cpp | 13 +++-- clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 27 +++++------ 14 files changed, 136 insertions(+), 104 deletions(-) diff --git a/clang/include/clang/Analysis/AnalysisDeclContext.h b/clang/include/clang/Analysis/AnalysisDeclContext.h index 84877136f842b..83e2cbce6118b 100644 --- a/clang/include/clang/Analysis/AnalysisDeclContext.h +++ b/clang/include/clang/Analysis/AnalysisDeclContext.h @@ -29,6 +29,7 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Allocator.h" #include <functional> +#include <iterator> #include <memory> namespace clang { @@ -247,6 +248,53 @@ class StackFrame final : public llvm::FoldingSetNode { /// It might return null. const StackFrame *getParent() const { return Parent; } + /// Forward iterator over a chain of \c StackFrame parents. Advancing follows + /// \c getParent(); the past-the-end iterator holds a null frame. + class parent_iterator { + const StackFrame *Current = nullptr; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = const StackFrame; + using difference_type = std::ptrdiff_t; + using pointer = const StackFrame *; + using reference = const StackFrame &; + + parent_iterator() = default; + explicit parent_iterator(const StackFrame *SF) : Current(SF) {} + + reference operator*() const { return *Current; } + pointer operator->() const { return Current; } + parent_iterator &operator++() { + assert(Current && "Cannot call ++ on the end iterator"); + Current = Current->getParent(); + return *this; + } + parent_iterator operator++(int) { + parent_iterator Tmp = *this; + ++*this; + return Tmp; + } + bool operator==(const parent_iterator &Other) const { + return Current == Other.Current; + } + bool operator!=(const parent_iterator &Other) const { + return !(*this == Other); + } + }; + + /// Iterates over the strict ancestors of this frame, i.e. \c getParent(), + /// \c getParent()->getParent(), ... up to (but excluding) the null frame. + /// Does not include \c *this. + llvm::iterator_range<parent_iterator> parents() const { + return {parent_iterator(getParent()), parent_iterator()}; + } + + /// Iterates over this frame followed by all of its ancestors. + llvm::iterator_range<parent_iterator> parentsIncludingSelf() const { + return {parent_iterator(this), parent_iterator()}; + } + int64_t getID() const { return ID; } bool isParentOf(const StackFrame *SF) const; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index b853769148625..18e55862bc855 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -103,6 +103,11 @@ class CheckerContext { const StackFrame *getStackFrame() const { return Pred->getStackFrame(); } + /// Iterates over the current stack frame and all of its ancestors. + llvm::iterator_range<StackFrame::parent_iterator> stackframes() const { + return getStackFrame()->parentsIncludingSelf(); + } + /// Return true if the current StackFrame has no caller context. bool inTopFrame() const { return getStackFrame()->inTopFrame(); } diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index f5bb5ad81d680..9e48dfe2297e8 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -144,6 +144,11 @@ class ExplodedNode : public llvm::FoldingSetNode { return getLocation().getStackFrame(); } + /// Iterates over the current stack frame and all of its ancestors. + llvm::iterator_range<StackFrame::parent_iterator> stackframes() const { + return getStackFrame()->parentsIncludingSelf(); + } + const Decl &getCodeDecl() const { return *getStackFrame()->getDecl(); } CFG &getCFG() const { return *getStackFrame()->getCFG(); } diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 327d5858e9c6b..b50b7f2b05747 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -843,8 +843,10 @@ class ExprEngine { bool isLoad); /// Count the stack depth and determine if the call is recursive. - void examineStackFrames(const Decl *D, const StackFrame *SF, - bool &IsRecursive, unsigned &StackDepth); + void + examineStackFrames(const Decl *D, + llvm::iterator_range<StackFrame::parent_iterator> Frames, + bool &IsRecursive, unsigned &StackDepth); enum CallInlinePolicy { CIP_Allowed, diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp index 437360a775275..649035c46d019 100644 --- a/clang/lib/Analysis/AnalysisDeclContext.cpp +++ b/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -36,6 +36,7 @@ #include "clang/Basic/SourceManager.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Allocator.h" @@ -424,15 +425,8 @@ const StackFrame *StackFrameManager::getStackFrame( //===----------------------------------------------------------------------===// bool StackFrame::isParentOf(const StackFrame *SF) const { - do { - const StackFrame *Parent = SF->getParent(); - if (Parent == this) - return true; - else - SF = Parent; - } while (SF); - - return false; + return llvm::any_of(SF->parents(), + [this](const StackFrame &A) { return &A == this; }); } static void printLocation(raw_ostream &Out, const SourceManager &SM, @@ -451,15 +445,13 @@ void StackFrame::dumpStack(raw_ostream &Out) const { const SourceManager &SM = getAnalysisDeclContext()->getASTContext().getSourceManager(); - unsigned Frame = 0; - for (const StackFrame *SF = this; SF; SF = SF->getParent()) { - Out << "\t#" << Frame << ' '; - ++Frame; - if (const auto *D = dyn_cast<NamedDecl>(SF->getDecl())) + for (auto [Idx, SF] : llvm::enumerate(parentsIncludingSelf())) { + Out << "\t#" << Idx << ' '; + if (const auto *D = dyn_cast<NamedDecl>(SF.getDecl())) Out << "Calling " << AnalysisDeclContext::getFunctionName(D); else Out << "Calling anonymous code"; - if (const Expr *E = SF->getCallSite()) { + if (const Expr *E = SF.getCallSite()) { Out << " at line "; printLocation(Out, SM, E->getBeginLoc()); } @@ -477,19 +469,17 @@ void StackFrame::printJson( const SourceManager &SM = getAnalysisDeclContext()->getASTContext().getSourceManager(); - unsigned Frame = 0; - for (const StackFrame *SF = this; SF; SF = SF->getParent()) { + for (auto [Idx, SF] : llvm::enumerate(parentsIncludingSelf())) { Indent(Out, Space, IsDot) - << "{ \"lctx_id\": " << SF->getID() << ", \"location_context\": \""; - Out << '#' << Frame << " Call\", \"calling\": \""; - ++Frame; - if (const auto *D = dyn_cast<NamedDecl>(SF->getDecl())) + << "{ \"lctx_id\": " << SF.getID() << ", \"location_context\": \""; + Out << '#' << Idx << " Call\", \"calling\": \""; + if (const auto *D = dyn_cast<NamedDecl>(SF.getDecl())) Out << D->getQualifiedNameAsString(); else Out << "anonymous code"; Out << "\", \"location\": "; - if (const Expr *E = SF->getCallSite()) { + if (const Expr *E = SF.getCallSite()) { printSourceLocationAsJson(Out, E->getBeginLoc(), SM); } else { Out << "null"; @@ -497,10 +487,10 @@ void StackFrame::printJson( Out << ", \"items\": "; - printMoreInfoPerStackFrame(SF); + printMoreInfoPerStackFrame(&SF); Out << '}'; - if (SF->getParent()) + if (SF.getParent()) Out << ','; Out << NL; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index 9006a6a19ca90..042e19fa20218 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -44,6 +44,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" #include <optional> @@ -983,16 +984,9 @@ bool ObjCDeallocChecker::isInInstanceDealloc(const CheckerContext &C, /// 'self' in the frame for -dealloc. bool ObjCDeallocChecker::instanceDeallocIsOnStack(const CheckerContext &C, SVal &InstanceValOut) const { - const StackFrame *SF = C.getStackFrame(); - - while (SF) { - if (isInInstanceDealloc(C, SF, InstanceValOut)) - return true; - - SF = SF->getParent(); - } - - return false; + return llvm::any_of(C.stackframes(), [&](const StackFrame &SF) { + return isInInstanceDealloc(C, &SF, InstanceValOut); + }); } /// Returns true if the ID is a class in which is known to have diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 287824984623c..df911f3ce3d0e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -4112,8 +4112,8 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N, ReleaseFunctionSF = CurrentSF; // ...but if the stack contains a destructor call, then we say that the // outermost destructor stack frame is the _responsible_ one: - for (const StackFrame *SF = CurrentSF; SF; SF = SF->getParent()) { - if (const auto *DD = dyn_cast<CXXDestructorDecl>(SF->getDecl())) { + for (const StackFrame &SF : N->stackframes()) { + if (const auto *DD = dyn_cast<CXXDestructorDecl>(SF.getDecl())) { if (isReferenceCountingPointerDestructor(DD)) { // This immediately looks like a reference-counting destructor. // We're bad at guessing the original reference count of the @@ -4149,7 +4149,7 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N, // if (refPut(data)) // doFree(data); // } - ReleaseFunctionSF = SF; + ReleaseFunctionSF = &SF; } } diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp index d6787ae517f6c..9c616a2d17783 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp @@ -24,6 +24,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSet.h" using namespace clang; @@ -227,7 +228,7 @@ class MoveChecker ExplodedNode *tryToReportBug(const MemRegion *Region, const CXXRecordDecl *RD, CheckerContext &C, MisuseKind MK) const; - bool isInMoveSafeStackFrame(const StackFrame *SF) const; + bool isInMoveSafeStackFrame(const CheckerContext &C) const; bool isStateResetMethod(const CXXMethodDecl *MethodDec) const; bool isMoveSafeMethod(const CXXMethodDecl *MethodDec) const; const ExplodedNode *getMoveLocation(const ExplodedNode *N, @@ -374,8 +375,7 @@ void MoveChecker::modelUse(ProgramStateRef State, const MemRegion *Region, if (MK == MK_Dereference && OK.StdKind != SK_SmartPtr) MK = MK_FunCall; - if (!RS || !shouldWarnAbout(OK, MK) || - isInMoveSafeStackFrame(C.getStackFrame())) { + if (!RS || !shouldWarnAbout(OK, MK) || isInMoveSafeStackFrame(C)) { // Finalize changes made by the caller. C.addTransition(State); return; @@ -615,19 +615,17 @@ bool MoveChecker::isStateResetMethod(const CXXMethodDecl *MethodDec) const { // Don't report an error inside a move related operation. // We assume that the programmer knows what she does. -bool MoveChecker::isInMoveSafeStackFrame(const StackFrame *SF) const { - do { - const auto *SFDec = SF->getDecl(); +bool MoveChecker::isInMoveSafeStackFrame(const CheckerContext &C) const { + return llvm::any_of(C.stackframes(), [this](const StackFrame &Frame) { + const auto *SFDec = Frame.getDecl(); auto *CtorDec = dyn_cast_or_null<CXXConstructorDecl>(SFDec); auto *DtorDec = dyn_cast_or_null<CXXDestructorDecl>(SFDec); auto *MethodDec = dyn_cast_or_null<CXXMethodDecl>(SFDec); - if (DtorDec || (CtorDec && CtorDec->isCopyOrMoveConstructor()) || - (MethodDec && MethodDec->isOverloadedOperator() && - MethodDec->getOverloadedOperator() == OO_Equal) || - isStateResetMethod(MethodDec) || isMoveSafeMethod(MethodDec)) - return true; - } while ((SF = SF->getParent())); - return false; + return DtorDec || (CtorDec && CtorDec->isCopyOrMoveConstructor()) || + (MethodDec && MethodDec->isOverloadedOperator() && + MethodDec->getOverloadedOperator() == OO_Equal) || + isStateResetMethod(MethodDec) || isMoveSafeMethod(MethodDec); + }); } bool MoveChecker::belongsTo(const CXXRecordDecl *RD, diff --git a/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp index 95e03d1e4947f..2b3befb099e06 100644 --- a/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp @@ -18,6 +18,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "llvm/Support/raw_ostream.h" +#include <iterator> using namespace clang; using namespace ento; @@ -66,10 +67,8 @@ class CallDumper : public Checker< check::PreCall, } void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const { - unsigned Indentation = 0; - for (const StackFrame *SF = C.getStackFrame()->getParent(); SF != nullptr; - SF = SF->getParent()) - ++Indentation; + auto Parents = C.getStackFrame()->parents(); + unsigned Indentation = std::distance(Parents.begin(), Parents.end()); // It is mildly evil to print directly to llvm::outs() rather than emitting // warnings, but this ensures things do not get filtered out by the rest of @@ -83,10 +82,8 @@ void CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const { if (!CallE) return; - unsigned Indentation = 0; - for (const StackFrame *SF = C.getStackFrame()->getParent(); SF != nullptr; - SF = SF->getParent()) - ++Indentation; + auto Parents = C.getStackFrame()->parents(); + unsigned Indentation = std::distance(Parents.begin(), Parents.end()); // It is mildly evil to print directly to llvm::outs() rather than emitting // warnings, but this ensures things do not get filtered out by the rest of diff --git a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp index 19f170cc0ae4a..7105276d46053 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp @@ -25,6 +25,7 @@ #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" +#include "llvm/ADT/STLExtras.h" using namespace clang; using namespace clang::ento; @@ -492,25 +493,18 @@ static bool willObjectBeAnalyzedLater(const CXXConstructorDecl *Ctor, if (!CurrRegion) return false; - const StackFrame *SF = Context.getStackFrame(); - while ((SF = SF->getParent())) { - - // If \p Ctor was called by another constructor. - const auto *OtherCtor = dyn_cast<CXXConstructorDecl>(SF->getDecl()); - if (!OtherCtor) - continue; - - const SubRegion *OtherRegion = getConstructedSubRegion(OtherCtor, Context); - if (!OtherRegion) - continue; - - // If the CurrRegion is a subregion of OtherRegion, it will be analyzed - // during the analysis of OtherRegion. - if (CurrRegion->isSubRegionOf(OtherRegion)) - return true; - } - - return false; + // Returns true if \p Ctor was called by another constructor whose region + // contains CurrRegion, so CurrRegion will be analyzed during that analysis. + return llvm::any_of( + Context.getStackFrame()->parents(), [&](const StackFrame &SF) { + const auto *OtherCtor = dyn_cast<CXXConstructorDecl>(SF.getDecl()); + if (!OtherCtor) + return false; + + const SubRegion *OtherRegion = + getConstructedSubRegion(OtherCtor, Context); + return OtherRegion && CurrRegion->isSubRegionOf(OtherRegion); + }); } static bool shouldIgnoreRecord(const RecordDecl *RD, StringRef Pattern) { diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index f3c7f3a25b716..8ab375b32af89 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -3292,8 +3292,8 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor( } } - for (const auto *SF = N->getStackFrame(); SF; SF = SF->getParent()) { - const auto *MD = dyn_cast<CXXMethodDecl>(SF->getDecl()); + for (const StackFrame &SF : N->stackframes()) { + const auto *MD = dyn_cast<CXXMethodDecl>(SF.getDecl()); if (!MD) continue; diff --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp index 8494f7600ebbe..12f61c0416a13 100644 --- a/clang/lib/StaticAnalyzer/Core/Environment.cpp +++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp @@ -26,6 +26,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/iterator.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include <cassert> @@ -206,8 +207,8 @@ void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx, if (FoundStackFrames.count(CurrentSF) == 0) { // This stack frame is fresher than all other stack frames so far. SF = CurrentSF; - for (const StackFrame *SFI = CurrentSF; SFI; SFI = SFI->getParent()) - FoundStackFrames.insert(SFI); + FoundStackFrames.insert_range( + llvm::make_pointer_range(CurrentSF->parentsIncludingSelf())); } } } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index b66b5c5e358e4..e0139484b2b48 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -450,20 +450,20 @@ bool ExprEngine::isHuge(AnalysisDeclContext *ADC) const { return Cfg->getNumBlockIDs() > AMgr.options.MaxInlinableSize; } -void ExprEngine::examineStackFrames(const Decl *D, const StackFrame *SF, - bool &IsRecursive, unsigned &StackDepth) { +void ExprEngine::examineStackFrames( + const Decl *D, llvm::iterator_range<StackFrame::parent_iterator> Frames, + bool &IsRecursive, unsigned &StackDepth) { IsRecursive = false; StackDepth = 0; - while (SF) { - const Decl *DI = SF->getDecl(); + for (const StackFrame &Frame : Frames) { + const Decl *DI = Frame.getDecl(); // Mark recursive (and mutually recursive) functions and always count // them when measuring the stack depth. if (DI == D) { IsRecursive = true; ++StackDepth; - SF = SF->getParent(); continue; } @@ -471,7 +471,6 @@ void ExprEngine::examineStackFrames(const Decl *D, const StackFrame *SF, AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(DI); if (!isSmall(CalleeADC)) ++StackDepth; - SF = SF->getParent(); } } @@ -1123,7 +1122,7 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D, // Do not inline if recursive or we've reached max stack frame count. bool IsRecursive = false; unsigned StackDepth = 0; - examineStackFrames(D, Pred->getStackFrame(), IsRecursive, StackDepth); + examineStackFrames(D, Pred->stackframes(), IsRecursive, StackDepth); if ((StackDepth >= Opts.InlineMaxStackDepth) && (!isSmall(CalleeADC) || IsRecursive)) return false; diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index f3fe21101792c..b26c63f50ef06 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -998,23 +998,22 @@ static llvm::PointerUnion<const StackFrame *, const VarRegion *> getStackOrCaptureRegionForDeclContext(const StackFrame *SF, const DeclContext *DC, const VarDecl *VD) { - while (SF) { - if (cast<DeclContext>(SF->getDecl()) == DC) - return SF; - if (SF->getData()) { - // FIXME: This can be made more efficient. - for (auto Var : static_cast<const BlockDataRegion *>(SF->getData()) - ->referenced_vars()) { - const TypedValueRegion *OrigR = Var.getOriginalRegion(); - if (const auto *VR = dyn_cast<VarRegion>(OrigR)) { - if (VR->getDecl() == VD) - return cast<VarRegion>(Var.getCapturedRegion()); + if (SF) + for (const StackFrame &Frame : SF->parentsIncludingSelf()) { + if (cast<DeclContext>(Frame.getDecl()) == DC) + return &Frame; + if (Frame.getData()) { + // FIXME: This can be made more efficient. + for (auto Var : static_cast<const BlockDataRegion *>(Frame.getData()) + ->referenced_vars()) { + const TypedValueRegion *OrigR = Var.getOriginalRegion(); + if (const auto *VR = dyn_cast<VarRegion>(OrigR)) { + if (VR->getDecl() == VD) + return cast<VarRegion>(Var.getCapturedRegion()); + } } } } - - SF = SF->getParent(); - } return (const StackFrame *)nullptr; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
