diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 697b514ae1572a..a23483e6df6d20 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -450,7 +450,8 @@ Changes in existing checks ` check detecting more cases for template functions including lambdas with ``auto``. E.g., ``std::sort(a.begin(), a.end(), [](auto x, auto y) { return a > b; });`` - will be detected for expensive to copy types. + will be detected for expensive to copy types. Fixed false positives for + dependent call expressions. - Improved :doc:`readability-avoid-return-with-void-value ` check by adding diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param.cpp index 0dffaefa213a45..7c7ae436989294 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/unnecessary-value-param.cpp @@ -2,6 +2,31 @@ // CHECK-FIXES: #include +namespace std { +template +struct remove_reference; + +template +struct remove_reference { + typedef _Tp type; +}; + +template +struct remove_reference<_Tp &> { + typedef _Tp type; +}; + +template +struct remove_reference<_Tp &&> { + typedef _Tp type; +}; + +template +constexpr typename std::remove_reference<_Tp>::type &&move(_Tp &&__t) { + return static_cast::type &&>(__t); +} +} // namespace std + struct ExpensiveToCopyType { const ExpensiveToCopyType & constReference() const { return *this; @@ -357,3 +382,12 @@ void fun() { ExpensiveToCopyType E; NegativeUsingConstructor S(E); } + +struct B { + static void bar(ExpensiveMovableType a, ExpensiveMovableType b); +}; + +template +void NegativeCallWithDependentAndNondependentArgs(ExpensiveMovableType a, T b) { + B::bar(std::move(a), b); +} diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp index 3b3782fa1db9a0..6d726ae44104ed 100644 --- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -404,25 +404,24 @@ ExprMutationAnalyzer::Analyzer::findDirectMutation(const Expr *Exp) { memberExpr(hasObjectExpression(canResolveToExpr(Exp)))), nonConstReferenceType()); const auto NotInstantiated = unless(hasDeclaration(isInstantiated())); - const auto TypeDependentCallee = - callee(expr(anyOf(unresolvedLookupExpr(), unresolvedMemberExpr(), - cxxDependentScopeMemberExpr(), - hasType(templateTypeParmType()), isTypeDependent()))); - - const auto AsNonConstRefArg = anyOf( - callExpr(NonConstRefParam, NotInstantiated), - cxxConstructExpr(NonConstRefParam, NotInstantiated), - callExpr(TypeDependentCallee, hasAnyArgument(canResolveToExpr(Exp))), - cxxUnresolvedConstructExpr(hasAnyArgument(canResolveToExpr(Exp))), - // Previous False Positive in the following Code: - // `template void f() { int i = 42; new Type(i); }` - // Where the constructor of `Type` takes its argument as reference. - // The AST does not resolve in a `cxxConstructExpr` because it is - // type-dependent. - parenListExpr(hasDescendant(expr(canResolveToExpr(Exp)))), - // If the initializer is for a reference type, there is no cast for - // the variable. Values are cast to RValue first. - initListExpr(hasAnyInit(expr(canResolveToExpr(Exp))))); + + const auto AsNonConstRefArg = + anyOf(callExpr(NonConstRefParam, NotInstantiated), + cxxConstructExpr(NonConstRefParam, NotInstantiated), + // If the call is type-dependent, we can't properly process any + // argument because required type conversions and implicit casts + // will be inserted only after specialization. + callExpr(isTypeDependent(), hasAnyArgument(canResolveToExpr(Exp))), + cxxUnresolvedConstructExpr(hasAnyArgument(canResolveToExpr(Exp))), + // Previous False Positive in the following Code: + // `template void f() { int i = 42; new Type(i); }` + // Where the constructor of `Type` takes its argument as reference. + // The AST does not resolve in a `cxxConstructExpr` because it is + // type-dependent. + parenListExpr(hasDescendant(expr(canResolveToExpr(Exp)))), + // If the initializer is for a reference type, there is no cast for + // the variable. Values are cast to RValue first. + initListExpr(hasAnyInit(expr(canResolveToExpr(Exp))))); // Captured by a lambda by reference. // If we're initializing a capture with 'Exp' directly then we're initializing