================
@@ -1737,22 +1733,95 @@ class BuildLockset : public
ConstStmtVisitor<BuildLockset> {
FactSet FSet;
// The fact set for the function on exit.
const FactSet &FunctionExitFSet;
- LocalVariableMap::Context LVarCtx;
- unsigned CtxIndex;
+
+ /// A `LocalVariableMap::Context` wrapper that groups a context 'Q' with its
+ /// immediate predecessor 'P' for a program point. If the program point is
+ /// right after a Stmt 'S', 'P' is the pre-context of 'S' and 'Q' is the
+ /// post-context of 'S'. Otherwise, 'P' == 'Q'.
+ ///
+ /// A DualLocalVarContext sets the global context for VarDefinition lookup to
+ /// the post-context 'Q', once CREATED or UPDATED to the next program
+ /// point. One can temporarily switch the global context to either 'P' or
'Q'
+ /// using `switchToContextForScope`. The lifetime of the global context
+ /// switching is bound to the enclosing scope. The global context will be set
+ /// back to the prior state by the end of the scope. This is done by the
+ /// returned ContextSwitchScope object.
+ ///
+ /// Note: The pre- and post-context of a Stmt are distinct only in Beta mode
+ /// (i.e., `Analyzer.Handler.issueBetaWarnings()`) because of the
+ /// out-parameter validation. If not in Beta mode, the global context for
+ /// VarDefinition lookup is invisible, thus this wrapper has no impact on the
+ /// analysis.
+ class DualLocalVarContext {
+ public:
+ enum Point : char { Pre = 0, Post = 1 };
+
+ struct [[nodiscard]] ContextSwitchScope {
+ DualLocalVarContext &DC;
+ enum Point LastPoint;
+ ~ContextSwitchScope() { DC.switchContextTo(LastPoint); }
+ };
+
+ /// Temporarily switch context to \p P as long as the returned object
lives.
+ [[nodiscard]] ContextSwitchScope switchToContextForScope(Point P) {
+ enum Point PriorPoint = CurrPoint;
+ switchContextTo(P);
+ return ContextSwitchScope{*this, PriorPoint};
+ }
+
+ /// Update the pre- and post-contexts to be associated with the next Stmt
\p
+ /// S. Set the global context to the post-context of \p S upon returning.
+ ///
+ /// If \p S is null, the behavior is as if the Stmt is a no-op--the
+ /// post-context will shift to be the pre-context and the new post-context
+ /// is the same as the old one, resulting in identical pre- and
+ /// post-contexts.
+ void moveToNextContext(const Stmt *S) {
+ PrePost[Pre] = PrePost[Post];
+
+ const LocalVariableMap::Context &NewPostCtx =
+ S ? Analyzer.LocalVarMap.getNextContext(CtxIndex, S, *PrePost[Post])
+ : *PrePost[Pre];
+
+ PrePost[Post] = &NewPostCtx;
+ switchContextTo(Post);
+ }
+
+ /// Constructs a DualLocalVarContext for the entry program point, where
pre-
+ /// and post-contexts are both equal to the \p EntryContext.
+ DualLocalVarContext(ThreadSafetyAnalyzer &Analyzer, unsigned EntryIdx,
+ const LocalVariableMap::Context *EntryContext)
+ : Analyzer(Analyzer), PrePost{EntryContext, EntryContext},
+ CurrPoint(Post), CtxIndex(EntryIdx) {
+ assert(EntryContext);
+ switchContextTo(Post);
+ }
+
+ private:
+ ThreadSafetyAnalyzer &Analyzer;
+ // PrePost[0] points to the pre-context and
+ // PrePost[1] points to the post-context:
+ std::array<const LocalVariableMap::Context *, 2> PrePost;
+ enum Point CurrPoint;
----------------
melver wrote:
Just `Point CurrPoint` (C-style `enum Point...` redundant). Here and in other
places.
https://github.com/llvm/llvm-project/pull/210219
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits