diff --git a/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp --- a/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp @@ -48,15 +48,23 @@ hasParameter(0, hasType(rValueReferenceType( pointee(type(equalsBoundNode("SrcT"))))))))))); + // A matcher for `DstT::DstT(const Src&&)`, which typically comes from an + // instantiation of `template DstT::DstT(U&&)`. + const auto ConstRefRefCtor = cxxConstructorDecl( + parameterCountIs(1), + hasParameter(0, + hasType(rValueReferenceType(pointee(isConstQualified()))))); + Finder->addMatcher( - traverse(TK_AsIs, - returnStmt(hasReturnValue( - ignoringElidableConstructorCall(ignoringParenImpCasts( - cxxConstructExpr( - hasDeclaration(LValueRefCtor), - hasArgument(0, ignoringParenImpCasts(declRefExpr( - to(NonNrvoConstLocalVariable))))) - .bind("ctor_call")))))), + traverse( + TK_AsIs, + returnStmt(hasReturnValue( + ignoringElidableConstructorCall(ignoringParenImpCasts( + cxxConstructExpr( + hasDeclaration(anyOf(LValueRefCtor, ConstRefRefCtor)), + hasArgument(0, ignoringParenImpCasts(declRefExpr( + to(NonNrvoConstLocalVariable))))) + .bind("ctor_call")))))), this); } diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -381,6 +381,10 @@ ` when warning would be emitted for a const local variable to which NRVO is applied. +- Improved :doc:`performance-no-automatic-move + `: warn on ``const &&`` + constructors. + Removed checks ^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/no-automatic-move.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/no-automatic-move.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/performance/no-automatic-move.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/no-automatic-move.cpp @@ -7,30 +7,42 @@ virtual ~Obj(); }; -template -struct StatusOr { - StatusOr(const T &); - StatusOr(T &&); -}; - struct NonTemplate { NonTemplate(const Obj &); NonTemplate(Obj &&); }; +template struct TemplateCtorPair { + TemplateCtorPair(const T &); + TemplateCtorPair(T &&value); +}; + +template struct UrefCtor { + template UrefCtor(U &&value); +}; + template T Make(); -StatusOr PositiveStatusOrConstValue() { +NonTemplate PositiveNonTemplate() { const Obj obj = Make(); - return obj; - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: constness of 'obj' prevents automatic move [performance-no-automatic-move] + return obj; // selects `NonTemplate(const Obj&)` + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: constness of 'obj' prevents + // automatic move [performance-no-automatic-move] } -NonTemplate PositiveNonTemplateConstValue() { +TemplateCtorPair PositiveTemplateCtorPair() { const Obj obj = Make(); - return obj; - // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: constness of 'obj' prevents automatic move [performance-no-automatic-move] + return obj; // selects `TemplateCtorPair(const T&)` + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: constness of 'obj' prevents + // automatic move [performance-no-automatic-move] +} + +UrefCtor PositiveUrefCtor() { + const Obj obj = Make(); + return obj; // selects `UrefCtor(const T&&)` + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: constness of 'obj' prevents + // automatic move [performance-no-automatic-move] } Obj PositiveCantNrvo(bool b) { @@ -51,22 +63,18 @@ } // FIXME: Ideally we would warn here too. -StatusOr PositiveStatusOrLifetimeExtension() { +UrefCtor PositiveUrefCtorLifetimeExtension() { const Obj &obj = Make(); return obj; } // Negatives. -StatusOr Temporary() { - return Make(); -} +UrefCtor Temporary() { return Make(); } -StatusOr ConstTemporary() { - return Make(); -} +UrefCtor ConstTemporary() { return Make(); } -StatusOr ConvertingMoveConstructor() { +UrefCtor ConvertingMoveConstructor() { Obj obj = Make(); return obj; } @@ -85,21 +93,19 @@ return obj2; } -StatusOr Ref() { +UrefCtor Ref() { Obj &obj = Make(); return obj; } -StatusOr ConstRef() { +UrefCtor ConstRef() { const Obj &obj = Make(); return obj; } const Obj global; -StatusOr Global() { - return global; -} +UrefCtor Global() { return global; } struct FromConstRefOnly { FromConstRefOnly(const Obj &);