[clang-tools-extra] 474a2b9 - [clang-tidy] Add more checks for functions which should be noexcept

Piotr Zegar via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 13 12:05:55 PDT 2023


Author: AMS21
Date: 2023-06-13T18:56:57Z
New Revision: 474a2b9367ad36213ad8575dc349350fdd8fc8f3

URL: https://github.com/llvm/llvm-project/commit/474a2b9367ad36213ad8575dc349350fdd8fc8f3
DIFF: https://github.com/llvm/llvm-project/commit/474a2b9367ad36213ad8575dc349350fdd8fc8f3.diff

LOG: [clang-tidy] Add more checks for functions which should be noexcept

Added new checks
- `performance-noexcept-destructor`
- `performance-noexcept-swap`

Also added cppcoreguidlines aliases for the 2 new checks as well as `performance-noexcept-move-constructor`

This fixes llvm#62154

Reviewed By: PiotrZSL

Differential Revision: https://reviews.llvm.org/D148697

Added: 
    clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.cpp
    clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.h
    clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.cpp
    clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.h
    clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-destructor.rst
    clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-move-operations.rst
    clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-swap.rst
    clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-destructor.rst
    clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-swap.rst
    clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-destructor.cpp
    clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp

Modified: 
    clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.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/PerformanceTidyModule.cpp
    clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
    clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
    clang-tools-extra/clang-tidy/utils/LexerUtils.h
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/docs/clang-tidy/checks/list.rst
    clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-move-constructor.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
index 264d771f44491..a535e7d0c14fb 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
@@ -14,6 +14,9 @@
 #include "../modernize/AvoidCArraysCheck.h"
 #include "../modernize/UseDefaultMemberInitCheck.h"
 #include "../modernize/UseOverrideCheck.h"
+#include "../performance/NoexceptDestructorCheck.h"
+#include "../performance/NoexceptMoveConstructorCheck.h"
+#include "../performance/NoexceptSwapCheck.h"
 #include "../readability/MagicNumbersCheck.h"
 #include "AvoidCapturingLambdaCoroutinesCheck.h"
 #include "AvoidConstOrRefDataMembersCheck.h"
@@ -83,6 +86,12 @@ class CppCoreGuidelinesModule : public ClangTidyModule {
     CheckFactories.registerCheck<NarrowingConversionsCheck>(
         "cppcoreguidelines-narrowing-conversions");
     CheckFactories.registerCheck<NoMallocCheck>("cppcoreguidelines-no-malloc");
+    CheckFactories.registerCheck<performance::NoexceptDestructorCheck>(
+        "cppcoreguidelines-noexcept-destructor");
+    CheckFactories.registerCheck<performance::NoexceptMoveConstructorCheck>(
+        "cppcoreguidelines-noexcept-move-operations");
+    CheckFactories.registerCheck<performance::NoexceptSwapCheck>(
+        "cppcoreguidelines-noexcept-swap");
     CheckFactories.registerCheck<misc::NonPrivateMemberVariablesInClassesCheck>(
         "cppcoreguidelines-non-private-member-variables-in-classes");
     CheckFactories.registerCheck<OwningMemoryCheck>(

diff  --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
index f6676bcf4be43..74a2cac092f86 100644
--- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt
@@ -15,7 +15,9 @@ add_clang_library(clangTidyPerformanceModule
   MoveConstructorInitCheck.cpp
   NoAutomaticMoveCheck.cpp
   NoIntToPtrCheck.cpp
+  NoexceptDestructorCheck.cpp
   NoexceptMoveConstructorCheck.cpp
+  NoexceptSwapCheck.cpp
   PerformanceTidyModule.cpp
   TriviallyDestructibleCheck.cpp
   TypePromotionInMathFnCheck.cpp

diff  --git a/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.cpp
new file mode 100644
index 0000000000000..a21451dd232df
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.cpp
@@ -0,0 +1,57 @@
+//===--- NoexceptDestructorCheck.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 "NoexceptDestructorCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::performance {
+
+void NoexceptDestructorCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      functionDecl(unless(isDeleted()), cxxDestructorDecl()).bind("decl"),
+      this);
+}
+
+void NoexceptDestructorCheck::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 destructor evaluates to 'false'");
+    }
+    return;
+  }
+
+  auto Diag = diag(FuncDecl->getLocation(), "destructors should "
+                                            "be marked noexcept");
+
+  // Add FixIt hints.
+  const SourceManager &SM = *Result.SourceManager;
+
+  const SourceLocation NoexceptLoc =
+      utils::lexer::getLocationForNoexceptSpecifier(FuncDecl, SM);
+  if (NoexceptLoc.isValid())
+    Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept ");
+}
+
+} // namespace clang::tidy::performance

diff  --git a/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.h b/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.h
new file mode 100644
index 0000000000000..38ae9272b7de7
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/performance/NoexceptDestructorCheck.h
@@ -0,0 +1,42 @@
+//===--- NoexceptDestructorCheck.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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTDESTRUCTORCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTDESTRUCTORCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "../utils/ExceptionSpecAnalyzer.h"
+
+namespace clang::tidy::performance {
+
+/// The check flags destructors not marked with `noexcept` or marked
+/// with `noexcept(expr)` where `expr` evaluates to `false`
+/// (but is not a `false` literal itself).
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/performance/noexcept-destructor.html
+class NoexceptDestructorCheck : public ClangTidyCheck {
+public:
+  NoexceptDestructorCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus11 && LangOpts.CXXExceptions;
+  }
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+
+private:
+  utils::ExceptionSpecAnalyzer SpecAnalyzer;
+};
+
+} // namespace clang::tidy::performance
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTDESTRUCTORCHECK_H

diff  --git a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
index bf659ad14eed4..b56a99a8f3491 100644
--- a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "NoexceptMoveConstructorCheck.h"
+#include "../utils/LexerUtils.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
@@ -18,7 +19,7 @@ namespace clang::tidy::performance {
 
 void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
-      cxxMethodDecl(unless(isImplicit()), unless(isDeleted()),
+      cxxMethodDecl(unless(isDeleted()),
                     anyOf(cxxConstructorDecl(isMoveConstructor()),
                           isMoveAssignmentOperator()))
           .bind("decl"),
@@ -27,19 +28,18 @@ void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) {
 
 void NoexceptMoveConstructorCheck::check(
     const MatchFinder::MatchResult &Result) {
-  const auto *Decl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl");
-  if (!Decl)
-    return;
+  const auto *FuncDecl = Result.Nodes.getNodeAs<CXXMethodDecl>("decl");
+  assert(FuncDecl);
 
-  if (SpecAnalyzer.analyze(Decl) !=
+  if (SpecAnalyzer.analyze(FuncDecl) !=
       utils::ExceptionSpecAnalyzer::State::Throwing)
     return;
 
-  const bool IsConstructor = CXXConstructorDecl::classof(Decl);
+  const bool IsConstructor = CXXConstructorDecl::classof(FuncDecl);
 
   // Don't complain about nothrow(false), but complain on nothrow(expr)
   // where expr evaluates to false.
-  const auto *ProtoType = Decl->getType()->castAs<FunctionProtoType>();
+  const auto *ProtoType = FuncDecl->getType()->castAs<FunctionProtoType>();
   const Expr *NoexceptExpr = ProtoType->getNoexceptExpr();
   if (NoexceptExpr) {
     NoexceptExpr = NoexceptExpr->IgnoreImplicit();
@@ -52,21 +52,18 @@ void NoexceptMoveConstructorCheck::check(
     return;
   }
 
-  auto Diag = diag(Decl->getLocation(),
+  auto Diag = diag(FuncDecl->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);
+
+  const SourceLocation NoexceptLoc =
+      utils::lexer::getLocationForNoexceptSpecifier(FuncDecl, SM);
   if (NoexceptLoc.isValid())
     Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept ");
-  return;
 }
 
 } // namespace clang::tidy::performance

diff  --git a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h b/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h
index 149aa24c1707b..053e6d992eeef 100644
--- a/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h
+++ b/clang-tools-extra/clang-tidy/performance/NoexceptMoveConstructorCheck.h
@@ -21,6 +21,9 @@ namespace clang::tidy::performance {
 /// 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.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/performance/noexcept-move-constructor.html
 class NoexceptMoveConstructorCheck : public ClangTidyCheck {
 public:
   NoexceptMoveConstructorCheck(StringRef Name, ClangTidyContext *Context)
@@ -30,6 +33,9 @@ class NoexceptMoveConstructorCheck : public ClangTidyCheck {
   }
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
 
 private:
   utils::ExceptionSpecAnalyzer SpecAnalyzer;

diff  --git a/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.cpp
new file mode 100644
index 0000000000000..170a918b3e575
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.cpp
@@ -0,0 +1,57 @@
+//===--- NoexceptSwapCheck.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 "NoexceptSwapCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::performance {
+
+void NoexceptSwapCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      functionDecl(unless(isDeleted()), hasName("swap")).bind("decl"), this);
+}
+
+void NoexceptSwapCheck::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 swap function evaluates to 'false'");
+    }
+    return;
+  }
+
+  auto Diag = diag(FuncDecl->getLocation(), "swap functions should "
+                                            "be marked noexcept");
+
+  // Add FixIt hints.
+  const SourceManager &SM = *Result.SourceManager;
+
+  const SourceLocation NoexceptLoc =
+      utils::lexer::getLocationForNoexceptSpecifier(FuncDecl, SM);
+  if (NoexceptLoc.isValid())
+    Diag << FixItHint::CreateInsertion(NoexceptLoc, " noexcept ");
+}
+
+} // namespace clang::tidy::performance

diff  --git a/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.h b/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.h
new file mode 100644
index 0000000000000..5578aec986d2b
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/performance/NoexceptSwapCheck.h
@@ -0,0 +1,42 @@
+//===--- NoexceptSwapCheck.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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTSWAPCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTSWAPCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "../utils/ExceptionSpecAnalyzer.h"
+
+namespace clang::tidy::performance {
+
+/// The check flags swap functions not marked with `noexcept` or marked
+/// with `noexcept(expr)` where `expr` evaluates to `false`
+/// (but is not a `false` literal itself).
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/performance/noexcept-swap.html
+class NoexceptSwapCheck : public ClangTidyCheck {
+public:
+  NoexceptSwapCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus11 && LangOpts.CXXExceptions;
+  }
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+
+private:
+  utils::ExceptionSpecAnalyzer SpecAnalyzer;
+};
+
+} // namespace clang::tidy::performance
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_NOEXCEPTSWAPCHECK_H

diff  --git a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
index b5151a1cc8939..54bf14fae8ca7 100644
--- a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
@@ -20,7 +20,9 @@
 #include "MoveConstructorInitCheck.h"
 #include "NoAutomaticMoveCheck.h"
 #include "NoIntToPtrCheck.h"
+#include "NoexceptDestructorCheck.h"
 #include "NoexceptMoveConstructorCheck.h"
+#include "NoexceptSwapCheck.h"
 #include "TriviallyDestructibleCheck.h"
 #include "TypePromotionInMathFnCheck.h"
 #include "UnnecessaryCopyInitialization.h"
@@ -52,8 +54,12 @@ class PerformanceModule : public ClangTidyModule {
     CheckFactories.registerCheck<NoAutomaticMoveCheck>(
         "performance-no-automatic-move");
     CheckFactories.registerCheck<NoIntToPtrCheck>("performance-no-int-to-ptr");
+    CheckFactories.registerCheck<NoexceptDestructorCheck>(
+        "performance-noexcept-destructor");
     CheckFactories.registerCheck<NoexceptMoveConstructorCheck>(
         "performance-noexcept-move-constructor");
+    CheckFactories.registerCheck<NoexceptSwapCheck>(
+        "performance-noexcept-swap");
     CheckFactories.registerCheck<TriviallyDestructibleCheck>(
         "performance-trivially-destructible");
     CheckFactories.registerCheck<TypePromotionInMathFnCheck>(

diff  --git a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
index 8795d9e99f391..40a3916fde478 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
@@ -134,6 +134,11 @@ ExceptionSpecAnalyzer::analyzeFunctionEST(const FunctionDecl *FuncDecl,
   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;

diff  --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
index eb4d174e7f5ac..218cf2f08a20d 100644
--- a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
@@ -20,7 +20,7 @@ Token getPreviousToken(SourceLocation Location, const SourceManager &SM,
 
   Location = Location.getLocWithOffset(-1);
   if (Location.isInvalid())
-      return Token;
+    return Token;
 
   auto StartOfFile = SM.getLocForStartOfFile(SM.getFileID(Location));
   while (Location != StartOfFile) {
@@ -181,7 +181,8 @@ static bool breakAndReturnEnd(const Stmt &S) {
 }
 
 static bool breakAndReturnEndPlus1Token(const Stmt &S) {
-  return isa<Expr, DoStmt, ReturnStmt, BreakStmt, ContinueStmt, GotoStmt, SEHLeaveStmt>(S);
+  return isa<Expr, DoStmt, ReturnStmt, BreakStmt, ContinueStmt, GotoStmt,
+             SEHLeaveStmt>(S);
 }
 
 // Given a Stmt which does not include it's semicolon this method returns the
@@ -233,11 +234,45 @@ SourceLocation getUnifiedEndLoc(const Stmt &S, const SourceManager &SM,
       LastChild = Child;
   }
 
-  if (!breakAndReturnEnd(*LastChild) &&
-      breakAndReturnEndPlus1Token(*LastChild))
+  if (!breakAndReturnEnd(*LastChild) && breakAndReturnEndPlus1Token(*LastChild))
     return getSemicolonAfterStmtEndLoc(S.getEndLoc(), SM, LangOpts);
 
   return S.getEndLoc();
 }
 
+SourceLocation getLocationForNoexceptSpecifier(const FunctionDecl *FuncDecl,
+                                               const SourceManager &SM) {
+  if (!FuncDecl)
+    return {};
+
+  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
+  const SourceLocation NoexceptLoc =
+      FuncDecl->getParamDecl(FuncDecl->getNumParams() - 1)->getEndLoc();
+  if (NoexceptLoc.isValid())
+    return Lexer::findLocationAfterToken(NoexceptLoc, tok::r_paren, SM,
+                                         LangOpts, true);
+
+  return {};
+}
+
 } // namespace clang::tidy::utils::lexer

diff  --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.h b/clang-tools-extra/clang-tidy/utils/LexerUtils.h
index 2dd31e5cb0994..cd5c76ee67e03 100644
--- a/clang-tools-extra/clang-tidy/utils/LexerUtils.h
+++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.h
@@ -116,6 +116,11 @@ std::optional<Token> getQualifyingToken(tok::TokenKind TK,
 SourceLocation getUnifiedEndLoc(const Stmt &S, const SourceManager &SM,
                                 const LangOptions &LangOpts);
 
+/// For a given FunctionDecl returns the location where you would need to place
+/// the noexcept specifier.
+SourceLocation getLocationForNoexceptSpecifier(const FunctionDecl *FuncDecl,
+                                               const SourceManager &SM);
+
 } // namespace tidy::utils::lexer
 } // namespace clang
 

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a0b996f51109d..aadda7efac690 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -181,6 +181,16 @@ New checks
 
   Finds uses of ``std::endl`` on streams and replaces them with ``'\n'``.
 
+- New :doc:`performance-noexcept-destructor
+  <clang-tidy/checks/performance/noexcept-destructor>` check.
+
+  Finds user declared destructors which are not ``noexcept``.
+
+- New :doc:`performance-noexcept-swap
+  <clang-tidy/checks/performance/noexcept-swap>` check.
+
+  Finds user declared swap functions which are not ``noexcept``.
+
 - New :doc:`readability-avoid-unconditional-preprocessor-if
   <clang-tidy/checks/readability/avoid-unconditional-preprocessor-if>` check.
 
@@ -205,6 +215,21 @@ New check aliases
   <clang-tidy/checks/cert/msc33-c>` to :doc:`bugprone-unsafe-functions
   <clang-tidy/checks/bugprone/unsafe-functions>` was added.
 
+- New alias :doc:`cppcoreguidelines-noexcept-destructor
+  <clang-tidy/checks/cppcoreguidelines/noexcept-destructor>` to
+  :doc`performance-noexcept-destructor
+  <clang-tidy/checks/performance/noexcept-destructor>` was added.
+
+- New alias :doc:`cppcoreguidelines-noexcept-move-operations
+  <clang-tidy/checks/cppcoreguidelines/noexcept-move-operations>` to
+  :doc`performance-noexcept-move-constructor
+  <clang-tidy/checks/performance/noexcept-move-constructor>` was added.
+
+- New alias :doc:`cppcoreguidelines-noexcept-swap
+  <clang-tidy/checks/cppcoreguidelines/noexcept-swap>` to
+  :doc`performance-noexcept-swap
+  <clang-tidy/checks/performance/noexcept-swap>` 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

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-destructor.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-destructor.rst
new file mode 100644
index 0000000000000..356c9efe929cf
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-destructor.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - cppcoreguidelines-noexcept-destructor
+.. meta::
+   :http-equiv=refresh: 5;URL=../performance/noexcept-destructor.html
+
+cppcoreguidelines-noexcept-destructor
+=====================================
+
+This check implements `C.37 <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c37-make-destructors-noexcept>`_
+from the CppCoreGuidelines.
+
+The cppcoreguidelines-noexcept-destructor check is an alias, please see
+`performance-noexcept-destructor <../performance/noexcept-destructor.html>`_
+for more information.

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-move-operations.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-move-operations.rst
new file mode 100644
index 0000000000000..eace9b8109b77
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-move-operations.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - cppcoreguidelines-noexcept-move-operations
+.. meta::
+   :http-equiv=refresh: 5;URL=../performance/noexcept-move-constructor.html
+
+cppcoreguidelines-noexcept-move-operations
+==========================================
+
+This check implements `C.66 <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c66-make-move-operations-noexcept>`_
+from the CppCoreGuidelines.
+
+The cppcoreguidelines-noexcept-move-operations check is an alias, please see
+`performance-noexcept-move-constructor <../performance/noexcept-move-constructor.html>`_
+for more information.

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-swap.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-swap.rst
new file mode 100644
index 0000000000000..3a6cb2b2ab8a3
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/noexcept-swap.rst
@@ -0,0 +1,15 @@
+.. title:: clang-tidy - cppcoreguidelines-noexcept-swap
+.. meta::
+   :http-equiv=refresh: 5;URL=../performance/noexcept-swap.html
+
+cppcoreguidelines-noexcept-swap
+===============================
+
+This check implements `C.83 <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c83-for-value-like-types-consider-providing-a-noexcept-swap-function>`_
+, `C.84 <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c84-a-swap-function-must-not-fail>`_
+and `C.85 <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c85-make-swap-noexcept>`_
+from the CppCoreGuidelines.
+
+The cppcoreguidelines-noexcept-swap check is an alias, please see
+`performance-noexcept-swap <../performance/noexcept-swap.html>`_
+for more information.

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 2b5f8e8291e0a..919d5362f45f1 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -329,7 +329,9 @@ Clang-Tidy Checks
    `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-destructor <performance/noexcept-destructor.html>`_, "Yes"
    `performance-noexcept-move-constructor <performance/noexcept-move-constructor.html>`_, "Yes"
+   `performance-noexcept-swap <performance/noexcept-swap.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"
@@ -481,6 +483,9 @@ Clang-Tidy Checks
    `cppcoreguidelines-c-copy-assignment-signature <cppcoreguidelines/c-copy-assignment-signature.html>`_, `misc-unconventional-assign-operator <misc/unconventional-assign-operator.html>`_,
    `cppcoreguidelines-explicit-virtual-functions <cppcoreguidelines/explicit-virtual-functions.html>`_, `modernize-use-override <modernize/use-override.html>`_, "Yes"
    `cppcoreguidelines-macro-to-enum <cppcoreguidelines/macro-to-enum.html>`_, `modernize-macro-to-enum <modernize/macro-to-enum.html>`_, "Yes"
+   `cppcoreguidelines-noexcept-destructor <cppcoreguidelines/noexcept-destructor.html>`_, `performance-noexcept-destructor <performance/noexcept-destructor.html>`_, "Yes"
+   `cppcoreguidelines-noexcept-move-operations <cppcoreguidelines/noexcept-move-operations.html>`_, `performance-noexcept-move-constructor <performance/noexcept-move-constructor.html>`_, "Yes"
+   `cppcoreguidelines-noexcept-swap <cppcoreguidelines/noexcept-swap.html>`_, `performance-noexcept-swap <performance/noexcept-swap.html>`_, "Yes"
    `cppcoreguidelines-non-private-member-variables-in-classes <cppcoreguidelines/non-private-member-variables-in-classes.html>`_, `misc-non-private-member-variables-in-classes <misc/non-private-member-variables-in-classes.html>`_,
    `cppcoreguidelines-use-default-member-init <cppcoreguidelines/use-default-member-init.html>`_, `modernize-use-default-member-init <modernize/use-default-member-init.html>`_,
    `fuchsia-header-anon-namespaces <fuchsia/header-anon-namespaces.html>`_, `google-build-namespaces <google/build-namespaces.html>`_,

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-destructor.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-destructor.rst
new file mode 100644
index 0000000000000..88f55fab619af
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-destructor.rst
@@ -0,0 +1,12 @@
+.. title:: clang-tidy - performance-noexcept-destructor
+
+performance-noexcept-destructor
+===============================
+
+The check flags user-defined destructors marked with ``noexcept(expr)``
+where ``expr`` evaluates to ``false`` (but is not a ``false`` literal itself).
+
+When a destructor is marked as ``noexcept``, it assures the compiler that
+no exceptions will be thrown during the destruction of an object, which
+allows the compiler to perform certain optimizations such as omitting
+exception handling code.

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-swap.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-swap.rst
new file mode 100644
index 0000000000000..fa4007618ba0f
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/performance/noexcept-swap.rst
@@ -0,0 +1,13 @@
+.. title:: clang-tidy - performance-noexcept-swap
+
+performance-noexcept-swap
+=========================
+
+The check flags user-defined swap functions not marked with ``noexcept`` or
+marked with ``noexcept(expr)`` where ``expr`` evaluates to ``false``
+(but is not a ``false`` literal itself).
+
+When a swap function is marked as ``noexcept``, it assures the compiler that
+no exceptions will be thrown during the swapping of two objects, which allows
+the compiler to perform certain optimizations such as omitting exception
+handling code.

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-destructor.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-destructor.cpp
new file mode 100644
index 0000000000000..8df45b89afab8
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-destructor.cpp
@@ -0,0 +1,306 @@
+// RUN: %check_clang_tidy %s performance-noexcept-destructor %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);
+};
+
+struct B {
+  static constexpr bool kFalse = false;
+  ~B() noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-destructor]
+};
+
+struct D {
+  static constexpr bool kFalse = false;
+  ~D() noexcept(kFalse) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-destructor]
+};
+
+template <typename>
+struct E {
+  static constexpr bool kFalse = false;
+  ~E() noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false'
+};
+
+template <typename>
+struct F {
+  static constexpr bool kFalse = false;
+  ~F() noexcept(kFalse) = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-destructor]
+};
+
+struct G {
+  ~G() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructors should be marked noexcept [performance-noexcept-destructor]
+  // CHECK-FIXES: ~G() noexcept  = default;
+
+  ThrowOnAnything field;
+};
+
+void throwing_function() noexcept(false) {}
+
+struct H {
+  ~H() noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-destructor]
+};
+
+template <typename>
+struct I {
+  ~I() noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-destructor]
+};
+
+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]]:17: warning: noexcept specifier on the destructor evaluates to 'false' [performance-noexcept-destructor]
+};
+
+struct K : public ThrowOnAnything {
+  ~K() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructors should be marked noexcept [performance-noexcept-destructor]
+  // CHECK-FIXES: ~K() noexcept  = default;
+};
+
+struct InheritFromThrowOnAnything : public ThrowOnAnything
+{};
+
+struct L {
+  ~L() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructors should be marked noexcept [performance-noexcept-destructor]
+  // CHECK-FIXES: ~L() noexcept  = default;
+
+  InheritFromThrowOnAnything IFF;
+};
+
+struct M : public InheritFromThrowOnAnything {
+  ~M() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructors should be marked noexcept [performance-noexcept-destructor]
+  // CHECK-FIXES: ~M() noexcept  = default;
+};
+
+struct N : public IntWrapper, ThrowOnAnything {
+  ~N() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructors should be marked noexcept [performance-noexcept-destructor]
+  // CHECK-FIXES: ~N() noexcept  = default;
+};
+
+struct O : virtual IntWrapper, ThrowOnAnything {
+  ~O() = default;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: destructors should be marked noexcept [performance-noexcept-destructor]
+  // CHECK-FIXES: ~O() noexcept  = default;
+};
+
+class OK {};
+
+struct OK1 {
+  ~OK1() noexcept;
+};
+
+struct OK2 {
+  static constexpr bool kTrue = true;
+
+  ~OK2() noexcept(true) {}
+};
+
+struct OK4 {
+  ~OK4() noexcept(false) {}
+};
+
+struct OK3 {
+  ~OK3() = default;
+};
+
+struct OK5 {
+  ~OK5() noexcept(true) = default;
+};
+
+struct OK6 {
+  ~OK6() = default;
+};
+
+template <typename>
+struct OK7 {
+  ~OK7() = default;
+};
+
+template <typename>
+struct OK8 {
+  ~OK8() noexcept = default;
+};
+
+template <typename>
+struct OK9 {
+  ~OK9() noexcept(true) = default;
+};
+
+template <typename>
+struct OK10 {
+  ~OK10() noexcept(false) = default;
+};
+
+template <typename>
+struct OK11 {
+  ~OK11() = delete;
+};
+
+void noexcept_function() noexcept {}
+
+struct OK12 {
+  ~OK12() noexcept(noexcept(noexcept_function()));
+};
+
+struct OK13 {
+  ~OK13() noexcept(noexcept(noexcept_function())) = default;
+};
+
+template <typename>
+struct OK14 {
+  ~OK14() noexcept(noexcept(TemplatedType<int>::f()));
+};
+
+struct OK15 {
+  ~OK15() = default;
+
+  int member;
+};
+
+template <typename>
+struct OK16 {
+  ~OK16() = default;
+
+  int member;
+};
+
+struct OK17 {
+  ~OK17() = default;
+
+  OK empty_field;
+};
+
+template <typename>
+struct OK18 {
+  ~OK18() = default;
+
+  OK empty_field;
+};
+
+struct OK19 : public OK {
+  ~OK19() = default;
+};
+
+struct OK20 : virtual OK {
+  ~OK20() = default;
+};
+
+template <typename T>
+struct OK21 : public T {
+  ~OK21() = default;
+};
+
+template <typename T>
+struct OK22 : virtual T {
+  ~OK22() = default;
+};
+
+template <typename T>
+struct OK23 {
+  ~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;
+};
+
+struct OK25 : virtual Empty, OK1 {
+  ~OK25() = default;
+};
+
+struct OK26 : public Empty, IntWrapper {
+  ~OK26() = default;
+};
+
+template <typename T>
+struct OK27 : public T {
+  ~OK27() = default;
+};
+
+template <typename T>
+struct OK28 : virtual T {
+  ~OK28() = default;
+};
+
+template <typename T>
+struct OK29 {
+  ~OK29() = default;
+
+  T member;
+};
+
+struct OK30 {
+  ~OK30() noexcept(TrueT<OK30>::value) = default;
+};
+
+template <typename>
+struct OK31 {
+  ~OK31() noexcept(TrueT<int>::value) = default;
+};
+
+struct OK32 {
+  ~OK32();
+};
+
+template <typename>
+struct OK33 {
+  ~OK33();
+};
+
+struct OK34 {
+  ~OK34() {}
+};
+
+template <typename>
+struct OK35 {
+  ~OK35() {}
+};

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
index 1ccdd0a2a0aae..60596c2876c0a 100644
--- 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
@@ -17,50 +17,50 @@ struct TrueT {
   static constexpr bool value = true;
 };
 
-struct ThrowingMoveConstructor
-{
-  ThrowingMoveConstructor() = default;
-  ThrowingMoveConstructor(ThrowingMoveConstructor&&) noexcept(false) {
-  }
-  ThrowingMoveConstructor& operator=(ThrowingMoveConstructor &&) noexcept(false) {
-    return *this;
-  }
+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
-{
+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
-{
+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'
+  // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
 };
 
 template <typename>
-struct E
-{
+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]
@@ -69,22 +69,23 @@ struct E
 };
 
 template <typename>
-struct F
-{
+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'
+  // 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;
 
-  ThrowingMoveConstructor field;
+  ThrowOnAnything field;
 };
 
 void throwing_function() noexcept(false) {}
@@ -93,7 +94,7 @@ 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'
+  // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
 };
 
 template <typename>
@@ -101,10 +102,10 @@ 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'
+  // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
 };
 
-template <typename TemplateType> struct TemplatedType {
+template <typename T> struct TemplatedType {
   static void f() {}
 };
 
@@ -119,44 +120,54 @@ struct J {
   // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: noexcept specifier on the move assignment operator evaluates to 'false' [performance-noexcept-move-constructor]
 };
 
-struct K : public ThrowingMoveConstructor {
+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 InheritFromThrowingMoveConstrcutor : public ThrowingMoveConstructor
+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;
 
-  InheritFromThrowingMoveConstrcutor IFF;
+  InheritFromThrowOnAnything IFF;
 };
 
-struct M : public InheritFromThrowingMoveConstrcutor {
+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, ThrowingMoveConstructor {
+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, ThrowingMoveConstructor {
+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 {};
@@ -166,9 +177,7 @@ void f() {
   a = OK();
 }
 
-class OK1 {
-public:
-  OK1();
+struct OK1 {
   OK1(const OK1 &);
   OK1(OK1 &&) noexcept;
   OK1 &operator=(OK1 &&) noexcept;
@@ -183,14 +192,14 @@ struct OK2 {
   OK2 &operator=(OK2 &&) noexcept(kTrue) { return *this; }
 };
 
-struct OK3 {
-  OK3(OK3 &&) noexcept(false) {}
-  OK3 &operator=(OK3 &&) = delete;
+struct OK4 {
+  OK4(OK4 &&) noexcept(false) {}
+  OK4 &operator=(OK4 &&) = delete;
 };
 
-struct OK4 {
-  OK4(OK4 &&) noexcept = default;
-  OK4 &operator=(OK4 &&) noexcept = default;
+struct OK3 {
+  OK3(OK3 &&) noexcept = default;
+  OK3 &operator=(OK3 &&) noexcept = default;
 };
 
 struct OK5 {
@@ -245,7 +254,8 @@ struct OK13 {
   OK13 &operator=(OK13 &&) noexcept(noexcept(noexcept_function)) = default;
 };
 
-template <typename> struct OK14 {
+template <typename>
+struct OK14 {
   OK14(OK14 &&) noexcept(noexcept(TemplatedType<int>::f()));
   OK14 &operator=(OK14 &&) noexcept(noexcept(TemplatedType<int>::f()));
 };
@@ -265,45 +275,40 @@ struct OK16 {
   int member;
 };
 
-struct OK17
-{
+struct OK17 {
   OK17(OK17 &&) = default;
   OK17 &operator=(OK17 &&) = default;
+
   OK empty_field;
 };
 
 template <typename>
-struct OK18
-{
+struct OK18 {
   OK18(OK18 &&) = default;
   OK18 &operator=(OK18 &&) = default;
 
   OK empty_field;
 };
 
-struct OK19 : public OK
-{
+struct OK19 : public OK {
   OK19(OK19 &&) = default;
   OK19 &operator=(OK19 &&) = default;
 };
 
-struct OK20 : virtual OK
-{
+struct OK20 : virtual OK {
   OK20(OK20 &&) = default;
   OK20 &operator=(OK20 &&) = default;
 };
 
 template <typename T>
-struct OK21 : public T
-{
+struct OK21 : public T {
   OK21() = default;
   OK21(OK21 &&) = default;
   OK21 &operator=(OK21 &&) = default;
 };
 
 template <typename T>
-struct OK22 : virtual T
-{
+struct OK22 : virtual T {
   OK22() = default;
   OK22(OK22 &&) = default;
   OK22 &operator=(OK22 &&) = default;
@@ -311,7 +316,7 @@ struct OK22 : virtual T
 
 template <typename T>
 struct OK23 {
-  OK23()= default;
+  OK23() = default;
   OK23(OK23 &&) = default;
   OK23 &operator=(OK23 &&) = default;
 
@@ -345,15 +350,13 @@ struct OK26 : public Empty, IntWrapper {
 };
 
 template <typename T>
-struct OK27 : public T
-{
+struct OK27 : public T {
   OK27(OK27 &&) = default;
   OK27 &operator=(OK27 &&) = default;
 };
 
 template <typename T>
-struct OK28 : virtual T
-{
+struct OK28 : virtual T {
   OK28(OK28 &&) = default;
   OK28 &operator=(OK28 &&) = default;
 };

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp
new file mode 100644
index 0000000000000..11c65906e8968
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance/noexcept-swap.cpp
@@ -0,0 +1,203 @@
+// RUN: %check_clang_tidy %s performance-noexcept-swap %t -- -- -fexceptions
+
+void throwing_function() noexcept(false);
+void noexcept_function() noexcept;
+
+template <typename>
+struct TemplateNoexceptWithInt {
+  static void f() {}
+};
+
+template <>
+struct TemplateNoexceptWithInt<int> {
+  static void f() noexcept {}
+};
+
+class A {
+  void swap(A &);
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: swap functions should be marked noexcept [performance-noexcept-swap]
+  // CHECK-FIXES: void swap(A &) noexcept ;
+};
+
+void swap(A &, A &);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap functions should be marked noexcept [performance-noexcept-swap]
+// CHECK-FIXES: void swap(A &, A &) noexcept ;
+
+struct B {
+  static constexpr bool kFalse = false;
+  void swap(B &) noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+};
+
+void swap(B &, B &) noexcept(B::kFalse);
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+
+template <typename>
+struct C {
+  void swap(C&);
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: swap functions should be marked noexcept [performance-noexcept-swap]
+  // CHECK-FIXES: void swap(C&) noexcept ;
+};
+
+template <typename T>
+void swap(C<T>&, C<T>&);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap functions should be marked noexcept [performance-noexcept-swap]
+// CHECK-FIXES: void swap(C<T>&, C<T>&) noexcept ;
+void swap(C<int>&, C<int>&);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap functions should be marked noexcept [performance-noexcept-swap]
+// CHECK-FIXES: void swap(C<int>&, C<int>&) noexcept ;
+
+template <typename>
+struct D {
+  static constexpr bool kFalse = false;
+  void swap(D &) noexcept(kFalse);
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+};
+
+template <typename T>
+void swap(D<T> &, D<T> &) noexcept(D<T>::kFalse);
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+void swap(D<int> &, D<int> &) noexcept(D<int>::kFalse);
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+
+struct E {
+  void swap(E &) noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+};
+
+void swap(E &, E &) noexcept(noexcept(throwing_function()));
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+
+template <typename>
+struct F {
+  void swap(F &) noexcept(noexcept(throwing_function()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+};
+
+template <typename T>
+void swap(F<T> &, F<T> &) noexcept(noexcept(throwing_function()));
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+void swap(F<int> &, F<int> &) noexcept(noexcept(throwing_function()));
+// CHECK-MESSAGES: :[[@LINE-1]]:40: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+
+struct G {
+  void swap(G &) noexcept(noexcept(TemplateNoexceptWithInt<double>::f()));
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+};
+
+void swap(G &, G &) noexcept(noexcept(TemplateNoexceptWithInt<double>::f()));
+// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: noexcept specifier on swap function evaluates to 'false' [performance-noexcept-swap]
+
+class OK {};
+
+struct OK1 {
+  void swap(OK1 &) noexcept;
+};
+
+void swap(OK1 &, OK1 &) noexcept;
+
+struct OK2 {
+  static constexpr bool kTrue = true;
+  void swap(OK2 &) noexcept(kTrue) {}
+};
+
+void swap(OK2 &, OK2 &) noexcept(OK2::kTrue);
+
+struct OK3 {
+    void swap(OK3 &) = delete;
+};
+
+void swap(OK3 &, OK3 &) = delete;
+
+struct OK4 {
+  void swap(OK4 &) noexcept(false);
+};
+
+void swap(OK4 &, OK4 &) noexcept(false);
+
+struct OK5 {
+  void swap(OK5 &) noexcept(true);
+};
+
+void swap(OK5 &, OK5 &)noexcept(true);
+
+struct OK12 {
+  void swap(OK12 &) noexcept(noexcept(noexcept_function()));
+};
+
+void swap(OK12 &, OK12 &) noexcept(noexcept(noexcept_function()));
+
+struct OK13 {
+  void swap(OK13 &) noexcept(noexcept(TemplateNoexceptWithInt<int>::f()));
+};
+
+void swap(OK13 &, OK13 &) noexcept(noexcept(TemplateNoexceptWithInt<int>::f()));
+
+template <typename>
+class OK14 {};
+
+template <typename>
+struct OK15 {
+  void swap(OK15 &) noexcept;
+};
+
+template <typename T>
+void swap(OK15<T> &, OK15<T> &) noexcept;
+void swap(OK15<int> &, OK15<int> &) noexcept;
+
+template <typename>
+struct OK16 {
+  static constexpr bool kTrue = true;
+  void swap(OK16 &) noexcept(kTrue);
+};
+
+// FIXME: This gives a warning, but it should be OK.
+//template <typename T>
+//void swap(OK16<T> &, OK16<T> &) noexcept(OK16<T>::kTrue);
+template <typename T>
+void swap(OK16<int> &, OK16<int> &) noexcept(OK16<int>::kTrue);
+
+template <typename>
+struct OK17 {
+    void swap(OK17 &) = delete;
+};
+
+template <typename T>
+void swap(OK17<T> &, OK17<T> &) = delete;
+void swap(OK17<int> &, OK17<int> &) = delete;
+
+template <typename>
+struct OK18 {
+  void swap(OK18 &) noexcept(false);
+};
+
+template <typename T>
+void swap(OK18<T> &, OK18<T> &) noexcept(false);
+void swap(OK18<int> &, OK18<int> &) noexcept(false);
+
+template <typename>
+struct OK19 {
+  void swap(OK19 &) noexcept(true);
+};
+
+template <typename T>
+void swap(OK19<T> &, OK19<T> &)noexcept(true);
+void swap(OK19<int> &, OK19<int> &)noexcept(true);
+
+template <typename>
+struct OK20 {
+  void swap(OK20 &) noexcept(noexcept(noexcept_function()));
+};
+
+template <typename T>
+void swap(OK20<T> &, OK20<T> &) noexcept(noexcept(noexcept_function()));
+void swap(OK20<int> &, OK20<int> &) noexcept(noexcept(noexcept_function()));
+
+template <typename>
+struct OK21 {
+  void swap(OK21 &) noexcept(noexcept(TemplateNoexceptWithInt<int>::f()));
+};
+
+template <typename T>
+void swap(OK21<T> &, OK21<T> &) noexcept(noexcept(TemplateNoexceptWithInt<int>::f()));
+void swap(OK21<int> &, OK21<int> &) noexcept(noexcept(TemplateNoexceptWithInt<int>::f()));


        


More information about the cfe-commits mailing list