diff --git a/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp @@ -46,8 +46,9 @@ } } // namespace -static TypeMatcher constRefType() { - return lValueReferenceType(pointee(isConstQualified())); +static TypeMatcher notTemplateSpecConstRefType() { + return lValueReferenceType( + pointee(unless(templateSpecializationType()), isConstQualified())); } static TypeMatcher nonConstValueType() { @@ -145,16 +146,18 @@ // ParenListExpr is generated instead of a CXXConstructExpr, // filtering out templates automatically for us. withInitializer(cxxConstructExpr( - has(ignoringParenImpCasts(declRefExpr(to( - parmVarDecl( - hasType(qualType( - // Match only const-ref or a non-const value - // parameters. Rvalues and const-values - // shouldn't be modified. - ValuesOnly ? nonConstValueType() - : anyOf(constRefType(), - nonConstValueType())))) - .bind("Param"))))), + has(ignoringParenImpCasts(declRefExpr( + to(parmVarDecl( + hasType(qualType( + // Match only const-ref or a non-const + // value parameters. Rvalues, + // TemplateSpecializationValues and + // const-values shouldn't be modified. + ValuesOnly + ? nonConstValueType() + : anyOf(notTemplateSpecConstRefType(), + nonConstValueType())))) + .bind("Param"))))), hasDeclaration(cxxConstructorDecl( isCopyConstructor(), unless(isDeleted()), hasDeclContext( diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-pass-by-value.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-pass-by-value.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/modernize-pass-by-value.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-pass-by-value.cpp @@ -118,6 +118,26 @@ J j1(Movable()); J j2(NotMovable()); +template +struct MovableTemplateT +{ + MovableTemplateT() {} + MovableTemplateT(const MovableTemplateT& o) { } + MovableTemplateT(MovableTemplateT&& o) { } +}; + +template +struct J2 { + J2(const MovableTemplateT& A); + // CHECK-FIXES: J2(const MovableTemplateT& A); + MovableTemplateT M; +}; + +template +J2::J2(const MovableTemplateT& A) : M(A) {} +// CHECK-FIXES: J2::J2(const MovableTemplateT& A) : M(A) {} +J2 j3(MovableTemplateT{}); + struct K_Movable { K_Movable() = default; K_Movable(const K_Movable &) = default;