Index: cfe/trunk/lib/StaticAnalyzer/Checkers/MoveChecker.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/MoveChecker.cpp +++ cfe/trunk/lib/StaticAnalyzer/Checkers/MoveChecker.cpp @@ -43,7 +43,7 @@ }; class MoveChecker - : public Checker { public: void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const; @@ -217,42 +217,6 @@ return nullptr; } -// Removing the function parameters' MemRegion from the state. This is needed -// for PODs where the trivial destructor does not even created nor executed. -void MoveChecker::checkEndFunction(const ReturnStmt *RS, - CheckerContext &C) const { - auto State = C.getState(); - TrackedRegionMapTy Objects = State->get(); - if (Objects.isEmpty()) - return; - - auto LC = C.getLocationContext(); - - const auto LD = dyn_cast_or_null(LC->getDecl()); - if (!LD) - return; - llvm::SmallSet InvalidRegions; - - for (auto Param : LD->parameters()) { - auto Type = Param->getType().getTypePtrOrNull(); - if (!Type) - continue; - if (!Type->isPointerType() && !Type->isReferenceType()) { - InvalidRegions.insert(State->getLValue(Param, LC).getAsRegion()); - } - } - - if (InvalidRegions.empty()) - return; - - for (const auto &E : State->get()) { - if (InvalidRegions.count(E.first->getBaseRegion())) - State = State->remove(E.first); - } - - C.addTransition(State); -} - void MoveChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { const auto *AFC = dyn_cast(&Call); @@ -382,20 +346,19 @@ const auto IC = dyn_cast(&Call); if (!IC) return; - // In case of destructor call we do not track the object anymore. - const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion(); - if (!ThisRegion) + + // Calling a destructor on a moved object is fine. + if (isa(IC)) return; - if (dyn_cast_or_null(Call.getDecl())) { - State = removeFromState(State, ThisRegion); - C.addTransition(State); + const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion(); + if (!ThisRegion) return; - } const auto MethodDecl = dyn_cast_or_null(IC->getDecl()); if (!MethodDecl) return; + // Checking assignment operators. bool OperatorEq = MethodDecl->isOverloadedOperator() && MethodDecl->getOverloadedOperator() == OO_Equal; Index: cfe/trunk/test/Analysis/use-after-move.cpp =================================================================== --- cfe/trunk/test/Analysis/use-after-move.cpp +++ cfe/trunk/test/Analysis/use-after-move.cpp @@ -714,3 +714,15 @@ Empty f = std::move(e); // no-warning } } + +struct MoveOnlyWithDestructor { + MoveOnlyWithDestructor(); + ~MoveOnlyWithDestructor(); + MoveOnlyWithDestructor(const MoveOnlyWithDestructor &m) = delete; + MoveOnlyWithDestructor(MoveOnlyWithDestructor &&m); +}; + +MoveOnlyWithDestructor foo() { + MoveOnlyWithDestructor m; + return m; +}