// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t -- -- -fexceptions
namespace std
{
template <typename T>
struct is_nothrow_move_constructible
{
static constexpr bool value = __is_nothrow_constructible(T, __add_rvalue_reference(T));
};
} // namespace std
struct Empty
{};
struct IntWrapper {
int value;
};
template <typename T>
struct FalseT {
static constexpr bool value = false;
};
template <typename T>
struct TrueT {
static constexpr bool value = true;
};
struct ThrowOnAnything {
ThrowOnAnything() noexcept(false);
ThrowOnAnything(ThrowOnAnything&&) noexcept(false);
ThrowOnAnything& operator=(ThrowOnAnything &&) noexcept(false);
~ThrowOnAnything() noexcept(false);
};
class A {
A(A &&);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: A(A &&) noexcept ;
A &operator=(A &&);
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: A &operator=(A &&) noexcept ;
};
struct B {
static constexpr bool kFalse = false;
B(B &&) noexcept(kFalse);
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
B &operator=(B &&) noexcept(kFalse);
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
};
template <typename>
struct C {
C(C &&);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: C(C &&) noexcept ;
C& operator=(C &&);
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: C& operator=(C &&) noexcept ;
};
struct D {
static constexpr bool kFalse = false;
D(D &&) noexcept(kFalse) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
D& operator=(D &&) noexcept(kFalse) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
};
template <typename>
struct E {
static constexpr bool kFalse = false;
E(E &&) noexcept(kFalse);
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
E& operator=(E &&) noexcept(kFalse);
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false'
};
template <typename>
struct F {
static constexpr bool kFalse = false;
F(F &&) noexcept(kFalse) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
F& operator=(F &&) noexcept(kFalse) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
};
struct G {
G(G &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: G(G &&) noexcept = default;
G& operator=(G &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: G& operator=(G &&) noexcept = default;
ThrowOnAnything field;
};
void throwing_function() noexcept(false) {}
struct H {
H(H &&) noexcept(noexcept(throwing_function()));
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
H &operator=(H &&) noexcept(noexcept(throwing_function()));
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
};
template <typename>
struct I {
I(I &&) noexcept(noexcept(throwing_function()));
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
I &operator=(I &&) noexcept(noexcept(throwing_function()));
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
};
template <typename T> struct TemplatedType {
static void f() {}
};
template <> struct TemplatedType<int> {
static void f() noexcept {}
};
struct J {
J(J &&) noexcept(noexcept(TemplatedType<double>::f()));
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor]
J &operator=(J &&) noexcept(noexcept(TemplatedType<double>::f()));
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
};
struct K : public ThrowOnAnything {
K(K &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: K(K &&) noexcept = default;
K &operator=(K &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: K &operator=(K &&) noexcept = default;
};
struct InheritFromThrowOnAnything : public ThrowOnAnything
{};
struct L {
L(L &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: L(L &&) noexcept = default;
L &operator=(L &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: L &operator=(L &&) noexcept = default;
InheritFromThrowOnAnything IFF;
};
struct M : public InheritFromThrowOnAnything {
M(M &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: M(M &&) noexcept = default;
M &operator=(M &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: M &operator=(M &&) noexcept = default;
};
struct N : public IntWrapper, ThrowOnAnything {
N(N &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: N(N &&) noexcept = default;
N &operator=(N &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: N &operator=(N &&) noexcept = default;
};
struct O : virtual IntWrapper, ThrowOnAnything {
O(O &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: O(O &&) noexcept = default;
O &operator=(O &&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
// CHECK-FIXES: O &operator=(O &&) noexcept = default;
};
class OK {};
void f() {
OK a;
a = OK();
}
struct OK1 {
OK1(const OK1 &);
OK1(OK1 &&) noexcept;
OK1 &operator=(OK1 &&) noexcept;
void f();
void g() noexcept;
};
struct OK2 {
static constexpr bool kTrue = true;
OK2(OK2 &&) noexcept(true) {}
OK2 &operator=(OK2 &&) noexcept(kTrue) { return *this; }
};
struct OK4 {
OK4(OK4 &&) noexcept(false) {}
OK4 &operator=(OK4 &&) = delete;
};
struct OK3 {
OK3(OK3 &&) noexcept = default;
OK3 &operator=(OK3 &&) noexcept = default;
};
struct OK5 {
OK5(OK5 &&) noexcept(true) = default;
OK5 &operator=(OK5 &&) noexcept(true) = default;
};
struct OK6 {
OK6(OK6 &&) = default;
OK6& operator=(OK6 &&) = default;
};
template <typename>
struct OK7 {
OK7(OK7 &&) = default;
OK7& operator=(OK7 &&) = default;
};
template <typename>
struct OK8 {
OK8(OK8 &&) noexcept = default;
OK8& operator=(OK8 &&) noexcept = default;
};
template <typename>
struct OK9 {
OK9(OK9 &&) noexcept(true) = default;
OK9& operator=(OK9 &&) noexcept(true) = default;
};
template <typename>
struct OK10 {
OK10(OK10 &&) noexcept(false) = default;
OK10& operator=(OK10 &&) noexcept(false) = default;
};
template <typename>
struct OK11 {
OK11(OK11 &&) = delete;
OK11& operator=(OK11 &&) = delete;
};
void noexcept_function() noexcept {}
struct OK12 {
OK12(OK12 &&) noexcept(noexcept(noexcept_function()));
OK12 &operator=(OK12 &&) noexcept(noexcept(noexcept_function));
};
struct OK13 {
OK13(OK13 &&) noexcept(noexcept(noexcept_function)) = default;
OK13 &operator=(OK13 &&) noexcept(noexcept(noexcept_function)) = default;
};
template <typename>
struct OK14 {
OK14(OK14 &&) noexcept(noexcept(TemplatedType<int>::f()));
OK14 &operator=(OK14 &&) noexcept(noexcept(TemplatedType<int>::f()));
};
struct OK15 {
OK15(OK15 &&) = default;
OK15 &operator=(OK15 &&) = default;
int member;
};
template <typename>
struct OK16 {
OK16(OK16 &&) = default;
OK16 &operator=(OK16 &&) = default;
int member;
};
struct OK17 {
OK17(OK17 &&) = default;
OK17 &operator=(OK17 &&) = default;
OK empty_field;
};
template <typename>
struct OK18 {
OK18(OK18 &&) = default;
OK18 &operator=(OK18 &&) = default;
OK empty_field;
};
struct OK19 : public OK {
OK19(OK19 &&) = default;
OK19 &operator=(OK19 &&) = default;
};
struct OK20 : virtual OK {
OK20(OK20 &&) = default;
OK20 &operator=(OK20 &&) = default;
};
template <typename T>
struct OK21 : public T {
OK21() = default;
OK21(OK21 &&) = default;
OK21 &operator=(OK21 &&) = default;
};
template <typename T>
struct OK22 : virtual T {
OK22() = default;
OK22(OK22 &&) = default;
OK22 &operator=(OK22 &&) = default;
};
template <typename T>
struct OK23 {
OK23() = default;
OK23(OK23 &&) = default;
OK23 &operator=(OK23 &&) = default;
T member;
};
void testTemplates() {
OK21<Empty> value(OK21<Empty>{});
value = OK21<Empty>{};
OK22<Empty> value2{OK22<Empty>{}};
value2 = OK22<Empty>{};
OK23<Empty> value3{OK23<Empty>{}};
value3 =OK23<Empty>{};
}
struct OK24 : public Empty, OK1 {
OK24(OK24 &&) = default;
OK24 &operator=(OK24 &&) = default;
};
struct OK25 : virtual Empty, OK1 {
OK25(OK25 &&) = default;
OK25 &operator=(OK25 &&) = default;
};
struct OK26 : public Empty, IntWrapper {
OK26(OK26 &&) = default;
OK26 &operator=(OK26 &&) = default;
};
template <typename T>
struct OK27 : public T {
OK27(OK27 &&) = default;
OK27 &operator=(OK27 &&) = default;
};
template <typename T>
struct OK28 : virtual T {
OK28(OK28 &&) = default;
OK28 &operator=(OK28 &&) = default;
};
template <typename T>
struct OK29 {
OK29(OK29 &&) = default;
OK29 &operator=(OK29 &&) = default;
T member;
};
struct OK30 {
OK30(OK30 &&) noexcept(TrueT<OK30>::value) = default;
OK30& operator=(OK30 &&) noexcept(TrueT<OK30>::value) = default;
};
template <typename>
struct OK31 {
OK31(OK31 &&) noexcept(TrueT<int>::value) = default;
OK31& operator=(OK31 &&) noexcept(TrueT<int>::value) = default;
};
namespace gh68101
{
template <typename T>
class Container {
public:
Container(Container&&) noexcept(std::is_nothrow_move_constructible<T>::value);
};
} // namespace gh68101