AMS21 created this revision.
AMS21 added reviewers: PiotrZSL, njames93.
Herald added subscribers: carlosgalvezp, kbarton, xazax.hun, nemanjai.
Herald added a project: All.
AMS21 requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Renamed `performance-noexcept-move-constructor` -> 
`performance-noexcept-special-functions`
to reflect that it now also handles default constructors, destructors and swap 
functions.
Add check alias `cppcoreguidelines-noexcept-special-functions`.

This fixes llvm#62154


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D148697

Files:
  clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp
  clang-tools-extra/clang-tidy/performance/CMakeLists.txt
  clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
  clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h
  clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.cpp
  clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.h
  clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
  clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-special-functions.rst
  clang-tools-extra/docs/clang-tidy/checks/hicpp/noexcept-move.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-move-constructor.rst
  
clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-special-functions.rst
  
clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor-fix.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions-fix.cpp
  
clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions.cpp
@@ -0,0 +1,601 @@
+// RUN: %check_clang_tidy %s performance-noexcept-special-functions %t -- -- -fexceptions
+
+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();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: A() noexcept ;
+  A(A &&);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: A(A &&) noexcept ;
+  A &operator=(A &&);
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: A &operator=(A &&) noexcept ;
+  void swap(A &);
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: swap function should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: void swap(A &) noexcept ;
+};
+
+void swap(A &, A &);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap function should be marked noexcept [performance-noexcept-special-functions]
+// CHECK-FIXES: void swap(A &, A &) noexcept ;
+
+struct B {
+  static constexpr bool kFalse = false;
+  B() noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions]
+  B(B &&) noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions]
+  B &operator=(B &&) noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-special-functions]
+  ~B() noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions]
+  void swap(B &) noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions]
+};
+
+void swap(B &, B &);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap function should be marked noexcept [performance-noexcept-special-functions]
+// CHECK-FIXES: void swap(B &, B &) noexcept ;
+
+template <typename>
+struct C {
+  C();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: C() noexcept ;
+  C(C &&);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: C(C &&) noexcept ;
+  C& operator=(C &&);
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: C& operator=(C &&) noexcept ;
+  void swap(C&);
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: swap function should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: void swap(C&) noexcept ;
+};
+
+template <typename T>
+void swap(C<T>&, C<T>&);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap function should be marked noexcept [performance-noexcept-special-functions]
+// CHECK-FIXES: void swap(C<T>&, C<T>&) noexcept ;
+void swap(C<int>&, C<int>&);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap function should be marked noexcept [performance-noexcept-special-functions]
+// CHECK-FIXES: void swap(C<int>&, C<int>&) noexcept ;
+
+struct D {
+  static constexpr bool kFalse = false;
+  D() noexcept(kFalse) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions]
+  D(D &&) noexcept(kFalse) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions]
+  D& operator=(D &&) noexcept(kFalse) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-special-functions]
+  ~D() noexcept(kFalse) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions]
+};
+
+template <typename>
+struct E {
+  static constexpr bool kFalse = false;
+  E() noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions]
+  E(E &&) noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions]
+  E& operator=(E &&) noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false'
+  ~E() noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false'
+  void swap(E &) noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions]
+};
+
+template <typename T>
+void swap(E<T> &, E<T> &) noexcept(E<T>::kFalse);
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions]
+void swap(E<int> &, E<int> &) noexcept(E<int>::kFalse);
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions]
+
+template <typename>
+struct F {
+  static constexpr bool kFalse = false;
+  F() noexcept(kFalse) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions]
+  F(F &&) noexcept(kFalse) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions]
+  F& operator=(F &&) noexcept(kFalse) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-special-functions]
+  ~F() noexcept(kFalse) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions]
+};
+
+struct G {
+  G() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: G() noexcept  = default;
+  G(G &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: G(G &&)  noexcept = default;
+  G& operator=(G &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: G& operator=(G &&)  noexcept = default;
+  ~G() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: ~G() noexcept  = default;
+
+  ThrowOnAnything field;
+};
+
+void throwing_function() noexcept(false) {}
+
+struct H {
+  H() noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions]
+  H(H &&) noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions]
+  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-special-functions]
+  ~H() noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions]
+  void swap(H &) noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions]
+};
+
+void swap(H &, H &) noexcept(noexcept(throwing_function()));
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions]
+
+template <typename>
+struct I {
+  I() noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions]
+  I(I &&) noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions]
+  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-special-functions]
+  ~I() noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions]
+  void swap(I &) noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions]
+};
+
+template <typename T>
+void swap(I<T> &, I<T> &) noexcept(noexcept(throwing_function()));
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions]
+void swap(I<int> &, I<int> &) noexcept(noexcept(throwing_function()));
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions]
+
+template <typename T> struct TemplatedType {
+  static void f() {}
+};
+
+template <> struct TemplatedType<int> {
+  static void f() noexcept {}
+};
+
+struct J {
+  J() noexcept(noexcept(TemplatedType<double>::f()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: noexcept specifier on the default constructor evaluates to 'false' [performance-noexcept-special-functions]
+  J(J &&) noexcept(noexcept(TemplatedType<double>::f()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: noexcept specifier on the move constructor evaluates to 'false' [performance-noexcept-special-functions]
+  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-special-functions]
+  ~J() noexcept(noexcept(TemplatedType<double>::f()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-special-functions]
+  void swap(J &) noexcept(noexcept(TemplatedType<double>::f()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions]
+};
+
+void swap(J &, J &) noexcept(noexcept(TemplatedType<double>::f()));
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: noexcept specifier on the swap function evaluates to 'false' [performance-noexcept-special-functions]
+
+struct K : public ThrowOnAnything {
+  K() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: K() noexcept  = default;
+  K(K &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: K(K &&)  noexcept = default;
+  K &operator=(K &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: K &operator=(K &&)  noexcept = default;
+  ~K() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: ~K() noexcept  = default;
+};
+
+struct InheritFromThrowOnAnything : public ThrowOnAnything
+{};
+
+struct L {
+  L() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: L() noexcept  = default;
+  L(L &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: L(L &&)  noexcept = default;
+  L &operator=(L &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: L &operator=(L &&)  noexcept = default;
+  ~L() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: ~L() noexcept  = default;
+
+  InheritFromThrowOnAnything IFF;
+};
+
+struct M : public InheritFromThrowOnAnything {
+  M() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: M() noexcept  = default;
+  M(M &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: M(M &&)  noexcept = default;
+  M &operator=(M &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: M &operator=(M &&)  noexcept = default;
+  ~M() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: ~M() noexcept  = default;
+};
+
+struct N : public IntWrapper, ThrowOnAnything {
+  N() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: N() noexcept  = default;
+  N(N &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: N(N &&)  noexcept = default;
+  N &operator=(N &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: N &operator=(N &&)  noexcept = default;
+  ~N() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: ~N() noexcept  = default;
+};
+
+struct O : virtual IntWrapper, ThrowOnAnything {
+  O() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: default constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: O() noexcept  = default;
+  O(O &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: O(O &&)  noexcept = default;
+  O &operator=(O &&) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operator should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: O &operator=(O &&)  noexcept = default;
+  ~O() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructor should be marked noexcept [performance-noexcept-special-functions]
+  // CHECK-FIXES: ~O() noexcept  = default;
+};
+
+class OK {};
+
+void f() {
+  OK a;
+  a = OK();
+}
+
+struct OK1 {
+  OK1() noexcept;
+  OK1(const OK1 &);
+  OK1(OK1 &&) noexcept;
+  OK1 &operator=(OK1 &&) noexcept;
+  ~OK1() noexcept;
+  void f();
+  void g() noexcept;
+  void swap(OK1 &) noexcept;
+};
+
+void swap(OK1 &, OK1 &) noexcept;
+
+struct OK2 {
+  static constexpr bool kTrue = true;
+
+  OK2() noexcept(true) {}
+  OK2(OK2 &&) noexcept(true) {}
+  OK2 &operator=(OK2 &&) noexcept(kTrue) { return *this; }
+  ~OK2() noexcept(true) {}
+  void swap(OK2 &) noexcept(kTrue) {}
+};
+
+void swap(OK2 &, OK2 &) = delete;
+
+struct OK3 {
+  OK3() = delete;
+  OK3(OK3 &&) noexcept(false) {}
+  OK3 &operator=(OK3 &&) = delete;
+  ~OK3() noexcept(false) {}
+  void swap(OK3 &) noexcept(false) {}
+};
+
+void swap(OK3 &, OK3 &)noexcept(false) {}
+
+struct OK4 {
+  OK4() = default;
+  OK4(OK4 &&) noexcept = default;
+  OK4 &operator=(OK4 &&) noexcept = default;
+  ~OK4() = default;
+};
+
+struct OK5 {
+  OK5() noexcept(true) = default;
+  OK5(OK5 &&) noexcept(true) = default;
+  OK5 &operator=(OK5 &&) noexcept(true) = default;
+  ~OK5() noexcept(true) = default;
+};
+
+struct OK6 {
+  OK6() = default;
+  OK6(OK6 &&) = default;
+  OK6& operator=(OK6 &&) = default;
+  ~OK6() = default;
+};
+
+template <typename>
+struct OK7 {
+  OK7() = default;
+  OK7(OK7 &&) = default;
+  OK7& operator=(OK7 &&) = default;
+  ~OK7() = default;
+};
+
+template <typename>
+struct OK8 {
+  OK8() noexcept = default;
+  OK8(OK8 &&) noexcept = default;
+  OK8& operator=(OK8 &&) noexcept = default;
+  ~OK8() noexcept = default;
+};
+
+template <typename>
+struct OK9 {
+  OK9() noexcept(true) = default;
+  OK9(OK9 &&) noexcept(true) = default;
+  OK9& operator=(OK9 &&) noexcept(true) = default;
+  ~OK9() noexcept(true) = default;
+};
+
+template <typename>
+struct OK10 {
+  OK10() noexcept(false) = default;
+  OK10(OK10 &&) noexcept(false) = default;
+  OK10& operator=(OK10 &&) noexcept(false) = default;
+  ~OK10() noexcept(false) = default;
+};
+
+template <typename>
+struct OK11 {
+  OK11() = delete;
+  OK11(OK11 &&) = delete;
+  OK11& operator=(OK11 &&) = delete;
+  ~OK11() = delete;
+};
+
+void noexcept_function() noexcept {}
+
+struct OK12 {
+  OK12() noexcept(noexcept(noexcept_function()));
+  OK12(OK12 &&) noexcept(noexcept(noexcept_function()));
+  OK12 &operator=(OK12 &&) noexcept(noexcept(noexcept_function));
+  ~OK12() noexcept(noexcept(noexcept_function()));
+  void swap(OK12 &) noexcept(noexcept(noexcept_function()));
+};
+
+void swap(OK12 &, OK12 &) noexcept(noexcept(noexcept_function())) {}
+
+struct OK13 {
+  OK13() noexcept(noexcept(noexcept_function())) = default;
+  OK13(OK13 &&) noexcept(noexcept(noexcept_function)) = default;
+  OK13 &operator=(OK13 &&) noexcept(noexcept(noexcept_function)) = default;
+  ~OK13() noexcept(noexcept(noexcept_function())) = default;
+};
+
+template <typename>
+struct OK14 {
+  OK14() noexcept(noexcept(TemplatedType<int>::f()));
+  OK14(OK14 &&) noexcept(noexcept(TemplatedType<int>::f()));
+  OK14 &operator=(OK14 &&) noexcept(noexcept(TemplatedType<int>::f()));
+  ~OK14() noexcept(noexcept(TemplatedType<int>::f()));
+  void swap(OK14 &) noexcept(noexcept(TemplatedType<int>::f()));
+};
+
+template <typename T>
+void swap(OK14<T> &, OK14<T> &) noexcept(noexcept(TemplatedType<int>::f()));
+void swap(OK14<int> &, OK14<int> &) noexcept(noexcept(TemplatedType<int>::f()));
+
+struct OK15 {
+  OK15() = default;
+  OK15(OK15 &&) = default;
+  OK15 &operator=(OK15 &&) = default;
+  ~OK15() = default;
+
+  int member;
+};
+
+template <typename>
+struct OK16 {
+  OK16() = default;
+  OK16(OK16 &&) = default;
+  OK16 &operator=(OK16 &&) = default;
+  ~OK16() = default;
+
+  int member;
+};
+
+struct OK17
+{
+  OK17() = default;
+  OK17(OK17 &&) = default;
+  OK17 &operator=(OK17 &&) = default;
+  ~OK17() = default;
+
+  OK empty_field;
+};
+
+template <typename>
+struct OK18
+{
+  OK18() = default;
+  OK18(OK18 &&) = default;
+  OK18 &operator=(OK18 &&) = default;
+  ~OK18() = default;
+
+  OK empty_field;
+};
+
+struct OK19 : public OK
+{
+  OK19() = default;
+  OK19(OK19 &&) = default;
+  OK19 &operator=(OK19 &&) = default;
+  ~OK19() = default;
+};
+
+struct OK20 : virtual OK
+{
+  OK20() = default;
+  OK20(OK20 &&) = default;
+  OK20 &operator=(OK20 &&) = default;
+  ~OK20() = default;
+};
+
+template <typename T>
+struct OK21 : public T
+{
+  OK21() = default;
+  OK21(OK21 &&) = default;
+  OK21 &operator=(OK21 &&) = default;
+  ~OK21() = default;
+};
+
+template <typename T>
+struct OK22 : virtual T
+{
+  OK22() = default;
+  OK22(OK22 &&) = default;
+  OK22 &operator=(OK22 &&) = default;
+  ~OK22() = default;
+};
+
+template <typename T>
+struct OK23 {
+  OK23()= default;
+  OK23(OK23 &&) = default;
+  OK23 &operator=(OK23 &&) = default;
+  ~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() = default;
+  OK24(OK24 &&) = default;
+  OK24 &operator=(OK24 &&) = default;
+  ~OK24() = default;
+};
+
+struct OK25 : virtual Empty, OK1 {
+  OK25() = default;
+  OK25(OK25 &&) = default;
+  OK25 &operator=(OK25 &&) = default;
+  ~OK25() = default;
+};
+
+struct OK26 : public Empty, IntWrapper {
+  OK26() = default;
+  OK26(OK26 &&) = default;
+  OK26 &operator=(OK26 &&) = default;
+  ~OK26() = default;
+};
+
+template <typename T>
+struct OK27 : public T {
+  OK27() = default;
+  OK27(OK27 &&) = default;
+  OK27 &operator=(OK27 &&) = default;
+  ~OK27() = default;
+};
+
+template <typename T>
+struct OK28 : virtual T {
+  OK28() = default;
+  OK28(OK28 &&) = default;
+  OK28 &operator=(OK28 &&) = default;
+  ~OK28() = default;
+};
+
+template <typename T>
+struct OK29 {
+  OK29() = default;
+  OK29(OK29 &&) = default;
+  OK29 &operator=(OK29 &&) = default;
+  ~OK29() = default;
+
+  T member;
+};
+
+struct OK30 {
+  OK30() noexcept(TrueT<OK30>::value) = default;
+  OK30(OK30 &&) noexcept(TrueT<OK30>::value) = default;
+  OK30& operator=(OK30 &&) noexcept(TrueT<OK30>::value) = default;
+  ~OK30() noexcept(TrueT<OK30>::value) = default;
+};
+
+template <typename>
+struct OK31 {
+  OK31() noexcept(TrueT<int>::value) = default;
+  OK31(OK31 &&) noexcept(TrueT<int>::value) = default;
+  OK31& operator=(OK31 &&) noexcept(TrueT<int>::value) = default;
+  ~OK31() noexcept(TrueT<int>::value) = default;
+};
+
+struct OK32 {
+  ~OK32();
+};
+
+template <typename>
+struct OK33 {
+  ~OK33();
+};
+
+struct OK34 {
+  ~OK34() {}
+};
+
+template <typename>
+struct OK35 {
+  ~OK35() {}
+};
Index: clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions-fix.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions-fix.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-special-functions-fix.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t -- -- -fexceptions
+// RUN: %check_clang_tidy %s performance-noexcept-special-functions %t -- -- -fexceptions
 
 struct C_1 {
  ~C_1() {}
Index: clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-// RUN: %check_clang_tidy %s performance-noexcept-move-constructor %t -- -- -fexceptions
-
-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 ThrowingMoveConstructor
-{
-  ThrowingMoveConstructor() = default;
-  ThrowingMoveConstructor(ThrowingMoveConstructor&&) noexcept(false) {
-  }
-  ThrowingMoveConstructor& operator=(ThrowingMoveConstructor &&) noexcept(false) {
-    return *this;
-  }
-};
-
-class A {
-  A(A &&);
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
-  A &operator=(A &&);
-  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
-};
-
-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]
-};
-
-template <typename>
-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 <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'
-};
-
-struct G {
-  G(G &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
-  G& operator=(G &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
-
-  ThrowingMoveConstructor 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'
-};
-
-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'
-};
-
-template <typename TemplateType> 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 ThrowingMoveConstructor {
-  K(K &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
-  K &operator=(K &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
-};
-
-struct InheritFromThrowingMoveConstrcutor : public ThrowingMoveConstructor
-{};
-
-struct L {
-  L(L &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
-  L &operator=(L &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
-
-  InheritFromThrowingMoveConstrcutor IFF;
-};
-
-struct M : public InheritFromThrowingMoveConstrcutor {
-  M(M &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
-  M &operator=(M &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
-};
-
-struct N : public IntWrapper, ThrowingMoveConstructor {
-  N(N &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
-  N &operator=(N &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
-};
-
-struct O : virtual IntWrapper, ThrowingMoveConstructor {
-  O(O &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: move constructors should be marked noexcept [performance-noexcept-move-constructor]
-  O &operator=(O &&) = default;
-  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: move assignment operators should be marked noexcept [performance-noexcept-move-constructor]
-};
-
-class OK {};
-
-void f() {
-  OK a;
-  a = OK();
-}
-
-class OK1 {
-public:
-  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 OK3 {
-  OK3(OK3 &&) noexcept(false) {}
-  OK3 &operator=(OK3 &&) = delete;
-};
-
-struct OK4 {
-  OK4(OK4 &&) noexcept = default;
-  OK4 &operator=(OK4 &&) 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;
-};
Index: clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-special-functions.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-special-functions.rst
+++ clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-special-functions.rst
@@ -1,10 +1,11 @@
-.. title:: clang-tidy - performance-noexcept-move-constructor
+.. title:: clang-tidy - performance-noexcept-special-functions
 
-performance-noexcept-move-constructor
-=====================================
+performance-noexcept-special-functions
+======================================
 
 
-The check flags user-defined move constructors and assignment operators not
+The check flags user-defined default constructors, move constructors,
+assignment operators, destructors and swap functions not
 marked with ``noexcept`` or marked with ``noexcept(expr)`` where ``expr``
 evaluates to ``false`` (but is not a ``false`` literal itself).
 
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -192,6 +192,7 @@
    `cppcoreguidelines-misleading-capture-default-by-value <cppcoreguidelines/misleading-capture-default-by-value.html>`_, "Yes"
    `cppcoreguidelines-narrowing-conversions <cppcoreguidelines/narrowing-conversions.html>`_,
    `cppcoreguidelines-no-malloc <cppcoreguidelines/no-malloc.html>`_,
+   `cppcoreguidelines-noexcept-special-functions <cppcoreguidelines/noexcept-special-functions.html>`_, "Yes"
    `cppcoreguidelines-owning-memory <cppcoreguidelines/owning-memory.html>`_,
    `cppcoreguidelines-prefer-member-initializer <cppcoreguidelines/prefer-member-initializer.html>`_, "Yes"
    `cppcoreguidelines-pro-bounds-array-to-pointer-decay <cppcoreguidelines/pro-bounds-array-to-pointer-decay.html>`_,
@@ -324,7 +325,7 @@
    `performance-move-constructor-init <performance/move-constructor-init.html>`_,
    `performance-no-automatic-move <performance/no-automatic-move.html>`_,
    `performance-no-int-to-ptr <performance/no-int-to-ptr.html>`_,
-   `performance-noexcept-move-constructor <performance/noexcept-move-constructor.html>`_, "Yes"
+   `performance-noexcept-special-functions <performance/noexcept-special-functions.html>`_, "Yes"
    `performance-trivially-destructible <performance/trivially-destructible.html>`_, "Yes"
    `performance-type-promotion-in-math-fn <performance/type-promotion-in-math-fn.html>`_, "Yes"
    `performance-unnecessary-copy-initialization <performance/unnecessary-copy-initialization.html>`_, "Yes"
@@ -494,7 +495,7 @@
    `hicpp-new-delete-operators <hicpp/new-delete-operators.html>`_, `misc-new-delete-overloads <misc/new-delete-overloads.html>`_,
    `hicpp-no-array-decay <hicpp/no-array-decay.html>`_, `cppcoreguidelines-pro-bounds-array-to-pointer-decay <cppcoreguidelines/pro-bounds-array-to-pointer-decay.html>`_,
    `hicpp-no-malloc <hicpp/no-malloc.html>`_, `cppcoreguidelines-no-malloc <cppcoreguidelines/no-malloc.html>`_,
-   `hicpp-noexcept-move <hicpp/noexcept-move.html>`_, `performance-noexcept-move-constructor <performance/noexcept-move-constructor.html>`_, "Yes"
+   `hicpp-noexcept-move <hicpp/noexcept-move.html>`_, `performance-noexcept-special-functions <performance/noexcept-special-functions.html>`_, "Yes"
    `hicpp-special-member-functions <hicpp/special-member-functions.html>`_, `cppcoreguidelines-special-member-functions <cppcoreguidelines/special-member-functions.html>`_,
    `hicpp-static-assert <hicpp/static-assert.html>`_, `misc-static-assert <misc/static-assert.html>`_, "Yes"
    `hicpp-undelegated-constructor <hicpp/undelegated-constructor.html>`_, `bugprone-undelegated-constructor <bugprone/undelegated-constructor.html>`_,
Index: clang-tools-extra/docs/clang-tidy/checks/hicpp/noexcept-move.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/hicpp/noexcept-move.rst
+++ clang-tools-extra/docs/clang-tidy/checks/hicpp/noexcept-move.rst
@@ -1,9 +1,9 @@
 .. title:: clang-tidy - hicpp-noexcept-move
 .. meta::
-   :http-equiv=refresh: 5;URL=../performance/noexcept-move-constructor.html
+   :http-equiv=refresh: 5;URL=../performance/noexcept-special-functions.html
 
 hicpp-noexcept-move
 ===================
 
-This check is an alias for `performance-noexcept-move-constructor <../performance/noexcept-move-constructor.html>`_.
+This check is an alias for `performance-noexcept-special-functions <../performance/noexcept-special-functions.html>`_.
 Checks `rule 12.5.4 <http://www.codingstandard.com/rule/12-5-4-declare-noexcept-the-move-constructor-and-move-assignment-operator>`_ to mark move assignment and move construction `noexcept`.
Index: clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-special-functions.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-special-functions.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cppcoreguidelines-noexcept-special-functions
+.. meta::
+   :http-equiv=refresh: 5;URL=../performance/noexcept-special-functions.html
+
+cppcoreguidelines-noexcept-special-functions
+============================================
+
+The cppcoreguidelines-noexcept-special-functions check is an alias, please see
+`performance-noexcept-special-functions <../performance/noexcept-special-functions.html>`_
+for more information.
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -174,6 +174,12 @@
   <clang-tidy/checks/cert/msc33-c>` to :doc:`bugprone-unsafe-functions
   <clang-tidy/checks/bugprone/unsafe-functions>` was added.
 
+- New alias :doc:`cppcoreguidelines-noexcept-special-functions
+  <clang-tidy/checks/cppcoreguidelines/noexcept-special-functions>` to
+  :doc:`performance-noexcept-special-functions
+  <clang-tidy/checks/performance/noexcept-special-functions>`
+  was added.
+
 - New alias :doc:`cppcoreguidelines-use-default-member-init
   <clang-tidy/checks/cppcoreguidelines/use-default-member-init>` to
   :doc:`modernize-use-default-member-init
@@ -334,10 +340,14 @@
   <clang-tidy/checks/bugprone/use-after-move>` to understand that there is a
   sequence point between designated initializers.
 
-- Fixed an issue in the :doc:`performance-noexcept-move-constructor
-  <clang-tidy/checks/performance/noexcept-move-constructor>` checker that was causing
+- Fixed an issue in the :doc:`performance-noexcept-special-functions
+  <clang-tidy/checks/performance/noexcept-special-functions>` checker that was causing
   false-positives when the move constructor or move assign operator were defaulted.
 
+- Improved :doc:`performance-noexcept-special-functions
+  <clang-tidy/checks/performance/noexcept-special-functions>` to also handle
+  default constructors, destructors and swap functions.
+
 - Fixed an issue in :doc:`readability-identifier-naming
   <clang-tidy/checks/readability/identifier-naming>` when specifying an empty
   string for ``Prefix`` or ``Suffix`` options could result in the style not
Index: clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
===================================================================
--- clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
+++ clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
@@ -134,6 +134,11 @@
   if (isUnresolvedExceptionSpec(FuncProto->getExceptionSpecType()))
     return State::Unknown;
 
+  // A non defaulted destructor without the noexcept specifier is still noexcept
+  if (isa<CXXDestructorDecl>(FuncDecl) &&
+      FuncDecl->getExceptionSpecType() == EST_None)
+    return State::NotThrowing;
+
   switch (FuncProto->canThrow()) {
   case CT_Cannot:
     return State::NotThrowing;
Index: clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
+++ clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
@@ -19,7 +19,7 @@
 #include "MoveConstructorInitCheck.h"
 #include "NoAutomaticMoveCheck.h"
 #include "NoIntToPtrCheck.h"
-#include "NoexceptMoveConstructorCheck.h"
+#include "NoexceptSpecialFunctionsCheck.h"
 #include "TriviallyDestructibleCheck.h"
 #include "TypePromotionInMathFnCheck.h"
 #include "UnnecessaryCopyInitialization.h"
@@ -50,8 +50,8 @@
     CheckFactories.registerCheck<NoAutomaticMoveCheck>(
         "performance-no-automatic-move");
     CheckFactories.registerCheck<NoIntToPtrCheck>("performance-no-int-to-ptr");
-    CheckFactories.registerCheck<NoexceptMoveConstructorCheck>(
-        "performance-noexcept-move-constructor");
+    CheckFactories.registerCheck<NoexceptSpecialFunctionsCheck>(
+        "performance-noexcept-special-functions");
     CheckFactories.registerCheck<TriviallyDestructibleCheck>(
         "performance-trivially-destructible");
     CheckFactories.registerCheck<TypePromotionInMathFnCheck>(
Index: clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.h
===================================================================
--- clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.h
+++ clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.h
@@ -1,4 +1,4 @@
-//===--- NoexceptMoveConstructorCheck.h - clang-tidy-------------*- C++ -*-===//
+//===--- NoexceptSpecialFunctionsCheck.h - clang-tidy------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTSPECIALFUNCTIONSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTSPECIALFUNCTIONSCHECK_H
 
 #include "../ClangTidyCheck.h"
 #include "../utils/ExceptionSpecAnalyzer.h"
@@ -21,9 +21,9 @@
 /// Move constructors of all the types used with STL containers, for example,
 /// need to be declared `noexcept`. Otherwise STL will choose copy constructors
 /// instead. The same is valid for move assignment operations.
-class NoexceptMoveConstructorCheck : public ClangTidyCheck {
+class NoexceptSpecialFunctionsCheck : public ClangTidyCheck {
 public:
-  NoexceptMoveConstructorCheck(StringRef Name, ClangTidyContext *Context)
+  NoexceptSpecialFunctionsCheck(StringRef Name, ClangTidyContext *Context)
       : ClangTidyCheck(Name, Context) {}
   bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
     return LangOpts.CPlusPlus11 && LangOpts.CXXExceptions;
@@ -37,4 +37,4 @@
 
 } // namespace clang::tidy::performance
 
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTMOVECONSTRUCTORCHECK_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTSPECIALFUNCTIONSCHECK_H
Index: clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/performance/NoexceptSpecialFunctionsCheck.cpp
@@ -0,0 +1,125 @@
+//===--- NoexceptSpecialFunctionsCheck.cpp - clang-tidy--------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "NoexceptSpecialFunctionsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Tooling/FixIt.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::performance {
+
+namespace {
+StringRef getSpecialFunctionName(const FunctionDecl *FuncDecl) {
+  assert(FuncDecl);
+
+  if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl)) {
+    if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(FuncDecl)) {
+      if (Ctor->isDefaultConstructor())
+        return "default constructor";
+
+      if (Ctor->isMoveConstructor())
+        return "move constructor";
+    }
+
+    if (MethodDecl->isMoveAssignmentOperator())
+      return "move assignment operator";
+
+    if (isa<CXXDestructorDecl>(FuncDecl))
+      return "destructor";
+  }
+
+  assert(FuncDecl->getName() == "swap");
+  return "swap function";
+}
+
+SourceLocation getNoexceptLoc(const FunctionDecl *FuncDecl,
+                              const SourceManager &SM) {
+  assert(FuncDecl);
+
+  const LangOptions &LangOpts = FuncDecl->getLangOpts();
+
+  if (FuncDecl->getNumParams() == 0) {
+    // Start at the beginning of the function declaration, and find the closing
+    // parenthesis after which we would place the noexcept specifier.
+    Token CurrentToken;
+    SourceLocation CurrentLocation = FuncDecl->getBeginLoc();
+    while (!Lexer::getRawToken(CurrentLocation, CurrentToken, SM, LangOpts,
+                               true)) {
+      if (CurrentToken.is(tok::r_paren))
+        return CurrentLocation.getLocWithOffset(1);
+
+      CurrentLocation = CurrentToken.getEndLoc();
+    }
+
+    // Failed to find the closing parenthesis, so just return an invalid
+    // SourceLocation.
+    return {};
+  }
+
+  // FunctionDecl with parameters
+  SourceLocation NoexceptLoc =
+      FuncDecl->getParamDecl(FuncDecl->getNumParams() - 1)->getEndLoc();
+  if (NoexceptLoc.isValid())
+    return Lexer::findLocationAfterToken(NoexceptLoc, tok::r_paren, SM,
+                                         LangOpts, true);
+
+  return {};
+}
+} // namespace
+
+void NoexceptSpecialFunctionsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      functionDecl(unless(isImplicit()), unless(isDeleted()),
+                   anyOf(cxxDestructorDecl(),
+                         cxxConstructorDecl(anyOf(isMoveConstructor(),
+                                                  isDefaultConstructor())),
+                         cxxMethodDecl(isMoveAssignmentOperator()),
+                         hasName("swap")))
+          .bind("decl"),
+      this);
+}
+
+void NoexceptSpecialFunctionsCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *FuncDecl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
+  assert(FuncDecl);
+
+  if (SpecAnalyzer.analyze(FuncDecl) !=
+      utils::ExceptionSpecAnalyzer::State::Throwing)
+    return;
+
+  // Don't complain about nothrow(false), but complain on nothrow(expr)
+  // where expr evaluates to false.
+  const auto *ProtoType = FuncDecl->getType()->castAs<FunctionProtoType>();
+  const Expr *NoexceptExpr = ProtoType->getNoexceptExpr();
+  if (NoexceptExpr) {
+    NoexceptExpr = NoexceptExpr->IgnoreImplicit();
+    if (!isa<CXXBoolLiteralExpr>(NoexceptExpr)) {
+      diag(NoexceptExpr->getExprLoc(),
+           "noexcept specifier on the %0 evaluates to 'false'")
+          << getSpecialFunctionName(FuncDecl);
+    }
+    return;
+  }
+
+  auto Diag = diag(FuncDecl->getLocation(), "%0 should "
+                                            "be marked noexcept")
+              << getSpecialFunctionName(FuncDecl);
+
+  // Add FixIt hints.
+  const SourceManager &SM = *Result.SourceManager;
+
+  const SourceLocation NoexceptLoc = getNoexceptLoc(FuncDecl, SM);
+  if (NoexceptLoc.isValid())
+    Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept ");
+}
+
+} // namespace clang::tidy::performance
Index: clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
===================================================================
--- clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//===--- NoexceptMoveConstructorCheck.cpp - clang-tidy---------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "NoexceptMoveConstructorCheck.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Tooling/FixIt.h"
-
-using namespace clang::ast_matchers;
-
-namespace clang::tidy::performance {
-
-void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) {
-  Finder->addMatcher(
-      cxxMethodDecl(unless(isImplicit()), unless(isDeleted()),
-                    anyOf(cxxConstructorDecl(isMoveConstructor()),
-                          isMoveAssignmentOperator()))
-          .bind("decl"),
-      this);
-}
-
-void NoexceptMoveConstructorCheck::check(
-    const MatchFinder::MatchResult &Result) {
-  const auto *Decl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl");
-  if (!Decl)
-    return;
-
-  if (SpecAnalyzer.analyze(Decl) !=
-      utils::ExceptionSpecAnalyzer::State::Throwing)
-    return;
-
-  const bool IsConstructor = CXXConstructorDecl::classof(Decl);
-
-  // Don't complain about nothrow(false), but complain on nothrow(expr)
-  // where expr evaluates to false.
-  const auto *ProtoType = Decl->getType()->castAs<FunctionProtoType>();
-  const Expr *NoexceptExpr = ProtoType->getNoexceptExpr();
-  if (NoexceptExpr) {
-    NoexceptExpr = NoexceptExpr->IgnoreImplicit();
-    if (!isa<CXXBoolLiteralExpr>(NoexceptExpr)) {
-      diag(NoexceptExpr->getExprLoc(),
-           "noexcept specifier on the move %select{assignment "
-           "operator|constructor}0 evaluates to 'false'")
-          << IsConstructor;
-    }
-    return;
-  }
-
-  auto Diag = diag(Decl->getLocation(),
-                   "move %select{assignment operator|constructor}0s should "
-                   "be marked noexcept")
-              << IsConstructor;
-  // Add FixIt hints.
-  const SourceManager &SM = *Result.SourceManager;
-  assert(Decl->getNumParams() > 0);
-  SourceLocation NoexceptLoc =
-      Decl->getParamDecl(Decl->getNumParams() - 1)->getSourceRange().getEnd();
-  if (NoexceptLoc.isValid())
-    NoexceptLoc = Lexer::findLocationAfterToken(
-        NoexceptLoc, tok::r_paren, SM, Result.Context->getLangOpts(), true);
-  if (NoexceptLoc.isValid())
-    Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept ");
-  return;
-}
-
-} // namespace clang::tidy::performance
Index: clang-tools-extra/clang-tidy/performance/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/performance/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/performance/CMakeLists.txt
@@ -14,7 +14,7 @@
   MoveConstructorInitCheck.cpp
   NoAutomaticMoveCheck.cpp
   NoIntToPtrCheck.cpp
-  NoexceptMoveConstructorCheck.cpp
+  NoexceptSpecialFunctionsCheck.cpp
   PerformanceTidyModule.cpp
   TriviallyDestructibleCheck.cpp
   TypePromotionInMathFnCheck.cpp
Index: clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp
+++ clang-tools-extra/clang-tidy/hicpp/HICPPTidyModule.cpp
@@ -31,7 +31,7 @@
 #include "../modernize/UseNullptrCheck.h"
 #include "../modernize/UseOverrideCheck.h"
 #include "../performance/MoveConstArgCheck.h"
-#include "../performance/NoexceptMoveConstructorCheck.h"
+#include "../performance/NoexceptSpecialFunctionsCheck.h"
 #include "../readability/BracesAroundStatementsCheck.h"
 #include "../readability/FunctionSizeCheck.h"
 #include "../readability/NamedParameterCheck.h"
@@ -74,7 +74,7 @@
         "hicpp-move-const-arg");
     CheckFactories.registerCheck<misc::NewDeleteOverloadsCheck>(
         "hicpp-new-delete-operators");
-    CheckFactories.registerCheck<performance::NoexceptMoveConstructorCheck>(
+    CheckFactories.registerCheck<performance::NoexceptSpecialFunctionsCheck>(
         "hicpp-noexcept-move");
     CheckFactories
         .registerCheck<cppcoreguidelines::ProBoundsArrayToPointerDecayCheck>(
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
@@ -14,6 +14,7 @@
 #include "../modernize/AvoidCArraysCheck.h"
 #include "../modernize/UseDefaultMemberInitCheck.h"
 #include "../modernize/UseOverrideCheck.h"
+#include "../performance/NoexceptSpecialFunctionsCheck.h"
 #include "../readability/MagicNumbersCheck.h"
 #include "AvoidCapturingLambdaCoroutinesCheck.h"
 #include "AvoidConstOrRefDataMembersCheck.h"
@@ -80,6 +81,8 @@
     CheckFactories.registerCheck<NarrowingConversionsCheck>(
         "cppcoreguidelines-narrowing-conversions");
     CheckFactories.registerCheck<NoMallocCheck>("cppcoreguidelines-no-malloc");
+    CheckFactories.registerCheck<performance::NoexceptSpecialFunctionsCheck>(
+        "cppcoreguidelines-noexcept-special-functions");
     CheckFactories.registerCheck<misc::NonPrivateMemberVariablesInClassesCheck>(
         "cppcoreguidelines-non-private-member-variables-in-classes");
     CheckFactories.registerCheck<OwningMemoryCheck>(
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to