diff --git a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp --- a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp @@ -41,6 +41,11 @@ if (isUnresolvedExceptionSpec(ProtoType->getExceptionSpecType())) return; + // Defaulted move constructors are noexcept even without a noexcept + // specifier + if (Decl->isDefaulted() && ProtoType->getExceptionSpecType() == EST_None) + return; + if (!isNoexceptExceptionSpec(ProtoType->getExceptionSpecType())) { auto Diag = diag(Decl->getLocation(), "move %select{assignment operator|constructor}0s should " diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor-fix.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor-fix.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor-fix.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor-fix.cpp @@ -31,9 +31,7 @@ }; C_3::C_3(C_3&& a) = default; -// CHECK-FIXES: ){{.*}}noexcept{{.*}} = default; C_3& C_3::operator=(C_3&& a) = default; -// CHECK-FIXES: ){{.*}}noexcept{{.*}} = default; template struct C_4 { @@ -41,7 +39,6 @@ // CHECK-FIXES: ){{.*}}noexcept{{.*}} {} ~C_4() {} C_4& operator=(C_4&& a) = default; -// CHECK-FIXES: ){{.*}}noexcept{{.*}} = default; }; template @@ -50,7 +47,6 @@ // CHECK-FIXES:){{.*}}noexcept{{.*}} {} ~C_5() {} auto operator=(C_5&& a)->C_5 = default; -// CHECK-FIXES:){{.*}}noexcept{{.*}} = default; }; template diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp @@ -13,6 +13,44 @@ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-move-constructor] }; +template +struct C +{ + C(C &&); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor] + C& operator=(C &&); + // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor] +}; + +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' +}; + +template +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 +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' +}; + class OK {}; void f() { @@ -52,3 +90,38 @@ OK5(OK5 &&) noexcept(true) = default; OK5 &operator=(OK5 &&) noexcept(true) = default; }; + +struct OK6 { + OK6(OK6 &&) = default; + OK6& operator=(OK6 &&) = default; +}; + +template +struct OK7 { + OK7(OK7 &&) = default; + OK7& operator=(OK7 &&) = default; +}; + +template +struct OK8 { + OK8(OK8 &&) noexcept = default; + OK8& operator=(OK8 &&) noexcept = default; +}; + +template +struct OK9 { + OK9(OK9 &&) noexcept(true) = default; + OK9& operator=(OK9 &&) noexcept(true) = default; +}; + +template +struct OK10 { + OK10(OK10 &&) noexcept(false) = default; + OK10& operator=(OK10 &&) noexcept(false) = default; +}; + +template +struct OK11 { + OK11(OK11 &&) = delete; + OK11& operator=(OK11 &&) = delete; +};