diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp @@ -8,6 +8,7 @@ #include "RvalueReferenceParamNotMovedCheck.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ExprConcepts.h" #include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang::ast_matchers; @@ -15,6 +16,23 @@ namespace clang::tidy::cppcoreguidelines { namespace { +AST_MATCHER(Expr, hasUnevaluatedContext) { + if (isa(Node) || isa(Node)) + return true; + if (const auto *UnaryExpr = dyn_cast(&Node)) { + switch (UnaryExpr->getKind()) { + case UETT_SizeOf: + case UETT_AlignOf: + return true; + default: + return false; + } + } + if (const auto *TypeIDExpr = dyn_cast(&Node)) + return !TypeIDExpr->isPotentiallyEvaluated(); + return false; +} + AST_MATCHER_P(LambdaExpr, valueCapturesVar, DeclarationMatcher, VarMatcher) { return std::find_if(Node.capture_begin(), Node.capture_end(), [&](const LambdaCapture &Capture) { @@ -39,16 +57,18 @@ StatementMatcher MoveCallMatcher = callExpr( + argumentCountIs(1), anyOf(callee(functionDecl(hasName("::std::move"))), callee(unresolvedLookupExpr(hasAnyDeclaration( namedDecl(hasUnderlyingDecl(hasName("::std::move"))))))), - argumentCountIs(1), hasArgument( 0, argumentOf( AllowPartialMove, declRefExpr(to(equalsBoundNode("param"))).bind("ref"))), unless(hasAncestor( - lambdaExpr(valueCapturesVar(equalsBoundNode("param")))))) + lambdaExpr(valueCapturesVar(equalsBoundNode("param"))))), + unless(anyOf(hasAncestor(typeLoc()), + hasAncestor(expr(hasUnevaluatedContext()))))) .bind("move-call"); Finder->addMatcher( diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/rvalue-reference-param-not-moved.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/rvalue-reference-param-not-moved.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/rvalue-reference-param-not-moved.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/rvalue-reference-param-not-moved.cpp @@ -156,6 +156,13 @@ Obj moved = std::move((o)); } +void does_not_move_in_evaluated(Obj&& o) { + // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: rvalue reference parameter 'o' is never moved from inside the function body [cppcoreguidelines-rvalue-reference-param-not-moved] + using result_t = decltype(std::move(o)); + unsigned size = sizeof(std::move(o)); + Obj moved = o; +} + template struct mypair { T1 first;