From ad91a2f036820e210b669926cf0982b0c8d2da99 Mon Sep 17 00:00:00 2001 From: Baranov Victor Date: Sat, 28 Mar 2026 10:44:46 +0300 Subject: [PATCH] [clang-tidy] Fix rvalue-reference-param-not-moved FP on implicit functions (#189113) Fixes https://github.com/llvm/llvm-project/issues/187716. --- .../RvalueReferenceParamNotMovedCheck.cpp | 1 + clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../rvalue-reference-param-not-moved.cpp | 61 +++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp index a5fdd211efd2..5aa6cbeff53d 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/RvalueReferenceParamNotMovedCheck.cpp @@ -64,6 +64,7 @@ void RvalueReferenceParamNotMovedCheck::registerMatchers(MatchFinder *Finder) { hasDeclContext( functionDecl( isDefinition(), unless(isDeleted()), unless(isDefaulted()), + unless(isImplicit()), unless(cxxConstructorDecl(isMoveConstructor())), unless(cxxMethodDecl(isMoveAssignmentOperator())), ToParam, anyOf(cxxConstructorDecl( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 97b2ffdd9557..637edaece2a9 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -272,6 +272,11 @@ Changes in existing checks like ``__builtin_clzg``) that use variadic declarations as an implementation detail. +- Improved :doc:`cppcoreguidelines-rvalue-reference-param-not-moved + ` check + by fixing a false positive on implicitly generated functions such as + inherited constructors. + - Improved :doc:`llvm-use-ranges ` check by adding support for the following algorithms: ``std::accumulate``, ``std::replace_copy``, and 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 index ce8b7e44f8ea..5663e90082dd 100644 --- 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 @@ -350,3 +350,64 @@ namespace gh69412 { void foo(int&&) = delete; }; } // namespace gh69412 + +namespace gh187716 { + struct Base { + Obj o; + Base(Obj&& o) : o(std::move(o)) {} + }; + + struct Inherit : Base { + using Base::Base; + }; + + void test_inheriting_ctor() { + Inherit x(Obj{}); + } + + struct BaseFailing { + Obj o; + BaseFailing(Obj&& o) : o(o) {} + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: rvalue reference parameter 'o' is never moved + }; + + struct InheritingFailing : BaseFailing { + using BaseFailing::BaseFailing; + }; + + void test_inheriting_ctor2() { + Inherit x(Obj{}); + } + + struct Derived : Base { + using Base::Base; + }; + + struct Derived2 : Derived { + using Derived::Derived; + }; + + void test_multi_level() { + Derived2 x(Obj{}); + } + + struct MixedDerived : Base { + using Base::Base; + MixedDerived(Obj&& a, Obj&& b) : Base(std::move(a)) {} + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: rvalue reference parameter 'b' is never moved + }; + + template + struct TemplateBase { + T val; + TemplateBase(T&& v) : val(std::move(v)) {} + }; + + struct InheritingFromTemplate : TemplateBase { + using TemplateBase::TemplateBase; + }; + + void test_template_base() { + InheritingFromTemplate x(Obj{}); + } +} // namespace gh187716