189a1d03eSRichard // RUN: %check_clang_tidy %s performance-move-constructor-init,modernize-pass-by-value %t -- \ 289a1d03eSRichard // RUN: -config='{CheckOptions: \ 3*e8a3ddafSNathan James // RUN: {modernize-pass-by-value.ValuesOnly: true}}' \ 489a1d03eSRichard // RUN: -- -isystem %clang_tidy_headers 589a1d03eSRichard 689a1d03eSRichard #include <s.h> 789a1d03eSRichard 889a1d03eSRichard // CHECK-FIXES: #include <utility> 989a1d03eSRichard 1089a1d03eSRichard template <class T> struct remove_reference {typedef T type;}; 1189a1d03eSRichard template <class T> struct remove_reference<T&> {typedef T type;}; 1289a1d03eSRichard template <class T> struct remove_reference<T&&> {typedef T type;}; 1389a1d03eSRichard 1489a1d03eSRichard template <typename T> move(T && arg)1589a1d03eSRichardtypename remove_reference<T>::type&& move(T&& arg) { 1689a1d03eSRichard return static_cast<typename remove_reference<T>::type&&>(arg); 1789a1d03eSRichard } 1889a1d03eSRichard 1989a1d03eSRichard struct C { 2089a1d03eSRichard C() = default; 2189a1d03eSRichard C(const C&) = default; 2289a1d03eSRichard }; 2389a1d03eSRichard 2489a1d03eSRichard struct B { BB2589a1d03eSRichard B() {} BB2689a1d03eSRichard B(const B&) {} BB2789a1d03eSRichard B(B &&) {} 2889a1d03eSRichard }; 2989a1d03eSRichard 3089a1d03eSRichard struct D : B { DD3189a1d03eSRichard D() : B() {} DD3289a1d03eSRichard D(const D &RHS) : B(RHS) {} 3389a1d03eSRichard // CHECK-NOTES: :[[@LINE+3]]:16: warning: move constructor initializes base class by calling a copy constructor [performance-move-constructor-init] 3489a1d03eSRichard // CHECK-NOTES: 26:3: note: copy constructor being called 3589a1d03eSRichard // CHECK-NOTES: 27:3: note: candidate move constructor here DD3689a1d03eSRichard D(D &&RHS) : B(RHS) {} 3789a1d03eSRichard }; 3889a1d03eSRichard 3989a1d03eSRichard struct E : B { EE4089a1d03eSRichard E() : B() {} EE4189a1d03eSRichard E(const E &RHS) : B(RHS) {} EE4289a1d03eSRichard E(E &&RHS) : B(move(RHS)) {} // ok 4389a1d03eSRichard }; 4489a1d03eSRichard 4589a1d03eSRichard struct F { 4689a1d03eSRichard C M; 4789a1d03eSRichard FF4889a1d03eSRichard F(F &&) : M(C()) {} // ok 4989a1d03eSRichard }; 5089a1d03eSRichard 5189a1d03eSRichard struct G { 5289a1d03eSRichard G() = default; 5389a1d03eSRichard G(const G&) = default; 5489a1d03eSRichard G(G&&) = delete; 5589a1d03eSRichard }; 5689a1d03eSRichard 5789a1d03eSRichard struct H : G { 5889a1d03eSRichard H() = default; 5989a1d03eSRichard H(const H&) = default; HH6089a1d03eSRichard H(H &&RHS) : G(RHS) {} // ok 6189a1d03eSRichard }; 6289a1d03eSRichard 6389a1d03eSRichard struct I { 6489a1d03eSRichard I(const I &) = default; // suppresses move constructor creation 6589a1d03eSRichard }; 6689a1d03eSRichard 6789a1d03eSRichard struct J : I { JJ6889a1d03eSRichard J(J &&RHS) : I(RHS) {} // ok 6989a1d03eSRichard }; 7089a1d03eSRichard 7189a1d03eSRichard struct K {}; // Has implicit copy and move constructors, is trivially copyable 7289a1d03eSRichard struct L : K { LL7389a1d03eSRichard L(L &&RHS) : K(RHS) {} // ok 7489a1d03eSRichard }; 7589a1d03eSRichard 7689a1d03eSRichard struct M { 7789a1d03eSRichard B Mem; 7889a1d03eSRichard // CHECK-NOTES: :[[@LINE+1]]:16: warning: move constructor initializes class member by calling a copy constructor [performance-move-constructor-init] MM7989a1d03eSRichard M(M &&RHS) : Mem(RHS.Mem) {} 8089a1d03eSRichard // CHECK-NOTES: 26:3: note: copy constructor being called 8189a1d03eSRichard // CHECK-NOTES: 27:3: note: candidate move constructor here 8289a1d03eSRichard }; 8389a1d03eSRichard 8489a1d03eSRichard struct N { 8589a1d03eSRichard B Mem; NN8689a1d03eSRichard N(N &&RHS) : Mem(move(RHS.Mem)) {} 8789a1d03eSRichard }; 8889a1d03eSRichard 8989a1d03eSRichard struct O { OO9089a1d03eSRichard O(O&& other) : b(other.b) {} // ok 9189a1d03eSRichard const B b; 9289a1d03eSRichard }; 9389a1d03eSRichard 9489a1d03eSRichard struct P { PP9589a1d03eSRichard P(O&& other) : b(other.b) {} // ok 9689a1d03eSRichard B b; 9789a1d03eSRichard }; 9889a1d03eSRichard 9989a1d03eSRichard struct Movable { 10089a1d03eSRichard Movable(Movable &&) = default; 10189a1d03eSRichard Movable(const Movable &) = default; 10289a1d03eSRichard Movable &operator=(const Movable &) = default; ~MovableMovable10389a1d03eSRichard ~Movable() {} 10489a1d03eSRichard }; 10589a1d03eSRichard 10689a1d03eSRichard struct TriviallyCopyable { 10789a1d03eSRichard TriviallyCopyable() = default; 10889a1d03eSRichard TriviallyCopyable(TriviallyCopyable &&) = default; 10989a1d03eSRichard TriviallyCopyable(const TriviallyCopyable &) = default; 11089a1d03eSRichard }; 11189a1d03eSRichard 11289a1d03eSRichard struct Positive { PositivePositive11389a1d03eSRichard Positive(Movable M) : M_(M) {} 11489a1d03eSRichard // CHECK-NOTES: [[@LINE-1]]:12: warning: pass by value and use std::move [modernize-pass-by-value] 11589a1d03eSRichard // CHECK-FIXES: Positive(Movable M) : M_(std::move(M)) {} 11689a1d03eSRichard Movable M_; 11789a1d03eSRichard }; 11889a1d03eSRichard 11989a1d03eSRichard struct NegativeMultipleInitializerReferences { NegativeMultipleInitializerReferencesNegativeMultipleInitializerReferences12089a1d03eSRichard NegativeMultipleInitializerReferences(Movable M) : M_(M), n_(M) {} 12189a1d03eSRichard Movable M_; 12289a1d03eSRichard Movable n_; 12389a1d03eSRichard }; 12489a1d03eSRichard 12589a1d03eSRichard struct NegativeReferencedInConstructorBody { NegativeReferencedInConstructorBodyNegativeReferencedInConstructorBody12689a1d03eSRichard NegativeReferencedInConstructorBody(Movable M) : M_(M) { M_ = M; } 12789a1d03eSRichard Movable M_; 12889a1d03eSRichard }; 12989a1d03eSRichard 13089a1d03eSRichard struct NegativeParamTriviallyCopyable { NegativeParamTriviallyCopyableNegativeParamTriviallyCopyable13189a1d03eSRichard NegativeParamTriviallyCopyable(TriviallyCopyable T) : T_(T) {} NegativeParamTriviallyCopyableNegativeParamTriviallyCopyable13289a1d03eSRichard NegativeParamTriviallyCopyable(int I) : I_(I) {} 13389a1d03eSRichard 13489a1d03eSRichard TriviallyCopyable T_; 13589a1d03eSRichard int I_; 13689a1d03eSRichard }; 13789a1d03eSRichard 13889a1d03eSRichard struct NegativeNotPassedByValue { 13989a1d03eSRichard // This const ref constructor isn't warned about because the ValuesOnly option is set. NegativeNotPassedByValueNegativeNotPassedByValue14089a1d03eSRichard NegativeNotPassedByValue(const Movable &M) : M_(M) {} NegativeNotPassedByValueNegativeNotPassedByValue14189a1d03eSRichard NegativeNotPassedByValue(const Movable M) : M_(M) {} NegativeNotPassedByValueNegativeNotPassedByValue14289a1d03eSRichard NegativeNotPassedByValue(Movable &M) : M_(M) {} NegativeNotPassedByValueNegativeNotPassedByValue14389a1d03eSRichard NegativeNotPassedByValue(Movable *M) : M_(*M) {} NegativeNotPassedByValueNegativeNotPassedByValue14489a1d03eSRichard NegativeNotPassedByValue(const Movable *M) : M_(*M) {} 14589a1d03eSRichard Movable M_; 14689a1d03eSRichard }; 14789a1d03eSRichard 14889a1d03eSRichard struct Immovable { 14989a1d03eSRichard Immovable(const Immovable &) = default; 15089a1d03eSRichard Immovable(Immovable &&) = delete; 15189a1d03eSRichard }; 15289a1d03eSRichard 15389a1d03eSRichard struct NegativeImmovableParameter { NegativeImmovableParameterNegativeImmovableParameter15489a1d03eSRichard NegativeImmovableParameter(Immovable I) : I_(I) {} 15589a1d03eSRichard Immovable I_; 15689a1d03eSRichard }; 157