diff --git a/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp index e182df75b1d9..deb17880aaf8 100644 --- a/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp @@ -13,6 +13,14 @@ using namespace clang::ast_matchers; namespace clang::tidy::bugprone { +namespace { + +AST_MATCHER(DeclRefExpr, refersToEnclosingVariableOrCapture) { + return Node.refersToEnclosingVariableOrCapture(); +} + +} // namespace + static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee, const ParmVarDecl *ParmVar, const TemplateTypeParmDecl *TypeParmDecl, @@ -80,13 +88,15 @@ void MoveForwardingReferenceCheck::registerMatchers(MatchFinder *Finder) { .bind("parm-var"); Finder->addMatcher( - callExpr(callee(unresolvedLookupExpr( - hasAnyDeclaration(namedDecl( - hasUnderlyingDecl(hasName("::std::move"))))) - .bind("lookup")), - argumentCountIs(1), - hasArgument(0, ignoringParenImpCasts(declRefExpr( - to(ForwardingReferenceParmMatcher))))) + callExpr( + callee(unresolvedLookupExpr( + hasAnyDeclaration( + namedDecl(hasUnderlyingDecl(hasName("::std::move"))))) + .bind("lookup")), + argumentCountIs(1), + hasArgument(0, ignoringParenImpCasts(declRefExpr( + to(ForwardingReferenceParmMatcher), + unless(refersToEnclosingVariableOrCapture()))))) .bind("call-move"), this); } diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 52aaa2d0df55..241991777818 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -272,6 +272,10 @@ Changes in existing checks ` check by printing the macro definition in the warning message if the macro is defined on command line. +- Improved :doc:`bugprone-move-forwarding-reference + ` check by fixing some + false positives in the context of moved lambda captures. + - Improved :doc:`bugprone-narrowing-conversions ` check by fixing a false positive when converting a ``bool`` to a signed integer type. diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/move-forwarding-reference.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/move-forwarding-reference.cpp index c9f40668f449..4661bdccbf11 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/move-forwarding-reference.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/move-forwarding-reference.cpp @@ -111,3 +111,25 @@ template void f12() { // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: forwarding reference passed to // CHECK-FIXES: [] (auto&& x) { T SomeT(std::forward(x)); }; } + +// Ignore the case of captured variables where an implicit copy already +// happened. Explicit capture version. +template void f13(U&& SomeU) { + [SomeU] () { T SomeT(std::move(SomeU)); }; +} + +// Ignore the case of captured variables where an implicit copy already +// happened. Implicit capture version. +template void f14(U&& SomeU) { + [=] () { T SomeT(std::move(SomeU)); }; +} + +// FIXME: Do not ignore the case of captured variables by reference. Explicit capture version. +template void f15(U&& SomeU) { + [&SomeU] () { T SomeT(std::move(SomeU)); }; +} + +// FIXME: Do not ignore the case of captured variables by reference. Implicit capture version. +template void f16(U&& SomeU) { + [&] () { T SomeT(std::move(SomeU)); }; +}