https://github.com/SekaiArendelle updated https://github.com/llvm/llvm-project/pull/218303
>From 24dfc21213e8e98d829ee8b73fa141973a8421cc Mon Sep 17 00:00:00 2001 From: Arendelle <[email protected]> Date: Mon, 24 Aug 2026 09:50:41 +0800 Subject: [PATCH 1/2] [clang][analyzer] Handle explicit-object move assignment Model the explicit object parameter as the assignment target and the following parameter as the moved-from source in the cplusplus.Move checker. --- .../StaticAnalyzer/Checkers/MoveChecker.cpp | 39 +++++++++++++-- clang/test/Analysis/use-after-move-cxx23.cpp | 47 +++++++++++++++++++ 2 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 clang/test/Analysis/use-after-move-cxx23.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp index 9c616a2d17783..47e808afca3a0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp @@ -473,7 +473,12 @@ void MoveChecker::checkPostCall(const CallEvent &Call, if (!ConstructorDecl && !MethodDecl->isMoveAssignmentOperator()) return; - const auto ArgRegion = AFC->getArgSVal(0).getAsRegion(); + // For an explicit-object member function, the object parameter is part of + // the function's parameter list. In that case, the object being moved from + // is the second argument rather than the first one. + const unsigned MoveArgIndex = + MethodDecl->isExplicitObjectMemberFunction() ? 1 : 0; + const auto ArgRegion = AFC->getArgSVal(MoveArgIndex).getAsRegion(); if (!ArgRegion) return; @@ -482,14 +487,17 @@ void MoveChecker::checkPostCall(const CallEvent &Call, if (CC && CC->getCXXThisVal().getAsRegion() == ArgRegion) return; - if (const auto *IC = dyn_cast<CXXInstanceCall>(AFC)) + if (MethodDecl->isExplicitObjectMemberFunction()) { + if (AFC->getArgSVal(0).getAsRegion() == ArgRegion) + return; + } else if (const auto *IC = dyn_cast<CXXInstanceCall>(AFC)) if (IC->getCXXThisVal().getAsRegion() == ArgRegion) return; const MemRegion *BaseRegion = ArgRegion->getBaseRegion(); // Skip temp objects because of their short lifetime. if (BaseRegion->getAs<CXXTempObjectRegion>() || - AFC->getArgExpr(0)->isPRValue()) + AFC->getArgExpr(MoveArgIndex)->isPRValue()) return; // If it has already been reported do not need to modify the state. @@ -705,6 +713,31 @@ void MoveChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { } } + // Calls to explicit-object member functions are represented as ordinary + // function calls because they have no implicit 'this' argument. Model an + // explicit-object assignment here before handling instance calls below. + const auto *ExplicitObjectMethod = + dyn_cast_or_null<CXXMethodDecl>(Call.getDecl()); + if (ExplicitObjectMethod && + ExplicitObjectMethod->isExplicitObjectMemberFunction() && + ExplicitObjectMethod->getOverloadedOperator() == OO_Equal) { + const MemRegion *ThisRegion = Call.getArgSVal(0).getAsRegion(); + State = removeFromState(State, ThisRegion); + + if (ExplicitObjectMethod->isCopyAssignmentOperator() || + ExplicitObjectMethod->isMoveAssignmentOperator()) { + const MemRegion *ArgRegion = Call.getArgSVal(1).getAsRegion(); + const CXXRecordDecl *RD = ExplicitObjectMethod->getParent(); + MisuseKind MK = ExplicitObjectMethod->isMoveAssignmentOperator() + ? MK_Move + : MK_Copy; + modelUse(State, ArgRegion, RD, MK, C); + return; + } + C.addTransition(State); + return; + } + const auto IC = dyn_cast<CXXInstanceCall>(&Call); if (!IC) return; diff --git a/clang/test/Analysis/use-after-move-cxx23.cpp b/clang/test/Analysis/use-after-move-cxx23.cpp new file mode 100644 index 0000000000000..ff989f43d17d3 --- /dev/null +++ b/clang/test/Analysis/use-after-move-cxx23.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_analyze_cc1 -std=c++23 -analyzer-checker=cplusplus.Move \ +// RUN: -analyzer-output=text -verify %s + +#include "Inputs/system-header-simulator-cxx.h" + +struct Owner { + Owner() = default; + Owner(Owner &&) {} + + Owner &operator=(this Owner &self, Owner &&other) { + return self; + } + + void use() const {} +}; + +void moveAssignmentMarksTheSource() { + Owner target; + Owner source; + target = std::move(source); // expected-note {{Object 'source' is moved}} + target.use(); + source.use(); // expected-warning {{Method called on moved-from object 'source'}} + // expected-note@-1 {{Method called on moved-from object 'source'}} +} + +void moveAssignmentResetsTheTarget() { + Owner movedFrom; + Owner target = std::move(movedFrom); + Owner source; + target = std::move(source); + target.use(); +} + +void movingFromTheSourceTwiceWarns() { + Owner firstTarget; + Owner secondTarget; + Owner source; + firstTarget = std::move(source); // expected-note {{Object 'source' is moved}} + secondTarget = std::move(source); // expected-warning {{Moved-from object 'source' is moved}} + // expected-note@-1 {{Moved-from object 'source' is moved}} +} + +void selfMoveAssignmentDoesNotMarkTheObject() { + Owner object; + object = std::move(object); + object.use(); +} >From 9d81aed2f462eb38d29e6e5f0b868be3c7d600a1 Mon Sep 17 00:00:00 2001 From: Arendelle <[email protected]> Date: Mon, 24 Aug 2026 10:11:33 +0800 Subject: [PATCH 2/2] [clang][analyzer] Fix formatting in MoveChecker --- clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp index 47e808afca3a0..5614ccf0a2c62 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp @@ -728,9 +728,8 @@ void MoveChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { ExplicitObjectMethod->isMoveAssignmentOperator()) { const MemRegion *ArgRegion = Call.getArgSVal(1).getAsRegion(); const CXXRecordDecl *RD = ExplicitObjectMethod->getParent(); - MisuseKind MK = ExplicitObjectMethod->isMoveAssignmentOperator() - ? MK_Move - : MK_Copy; + MisuseKind MK = + ExplicitObjectMethod->isMoveAssignmentOperator() ? MK_Move : MK_Copy; modelUse(State, ArgRegion, RD, MK, C); return; } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
