diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp --- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp @@ -397,11 +397,13 @@ } void UseAfterMoveCheck::registerMatchers(MatchFinder *Finder) { - auto CallMoveMatcher = + auto AncestorMatcher = + anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")), + hasAncestor(functionDecl().bind("containing-func"))); + + auto BaseMoveMatcher = callExpr(callee(functionDecl(hasName("::std::move"))), argumentCountIs(1), hasArgument(0, declRefExpr().bind("arg")), - anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")), - hasAncestor(functionDecl().bind("containing-func"))), unless(inDecltypeOrTemplateArg()), // try_emplace is a common maybe-moving function that returns a // bool to tell callers whether it moved. Ignore std::move inside @@ -411,6 +413,16 @@ callee(cxxMethodDecl(hasName("try_emplace"))))))) .bind("call-move"); + auto CallMoveMatcherLambda = lambdaExpr( + forEachLambdaCapture(lambdaCapture(capturesVar(varDecl( + hasInitializer(expr(ignoringParenImpCasts(BaseMoveMatcher))))))), + AncestorMatcher); + + Finder->addMatcher(CallMoveMatcherLambda, this); + + auto CallMoveMatcherNoLambda = + expr(ignoringParenImpCasts(BaseMoveMatcher), AncestorMatcher); + Finder->addMatcher( traverse( TK_AsIs, @@ -418,7 +430,7 @@ // for the direct ancestor of the std::move() that isn't one of the // node types ignored by ignoringParenImpCasts(). stmt( - forEach(expr(ignoringParenImpCasts(CallMoveMatcher))), + forEach(CallMoveMatcherNoLambda), // Don't allow an InitListExpr to be the moving call. An // InitListExpr has both a syntactic and a semantic form, and the // parent-child relationships are different between the two. This diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-use-after-move.cpp @@ -1350,3 +1350,18 @@ private: std::string val_; }; + +// Check std::move usage inside lambda captures +int lambdaCaptures() { + int a = 0; + int b = 0; + int c = 0; + auto foo = [aa = std::move(a), bb = std::move(b), cc = c] { + // CHECK-NOTES: [[@LINE+6]]:10: warning: 'a' used after it was moved + // CHECK-NOTES: [[@LINE-2]]:20: note: move occurred here + // CHECK-NOTES: [[@LINE+4]]:14: warning: 'b' used after it was moved + // CHECK-NOTES: [[@LINE-4]]:39: note: move occurred here + return aa + bb + cc; + }; + return a + b + c; +};