[clang-tools-extra] [clang-tidy] Add fine-graded configuration for 'bugprone-exception-escape' (PR #164081)
Baranov Victor via cfe-commits
cfe-commits at lists.llvm.org
Sat Oct 18 07:40:36 PDT 2025
https://github.com/vbvictor updated https://github.com/llvm/llvm-project/pull/164081
>From fb25544a0a090272018fb97e41fee902d23cd0ef Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Sat, 18 Oct 2025 15:52:12 +0300
Subject: [PATCH 1/2] [clang-tidy] Add fine-graded configuration for
'bugprone-exception-escape'
---
.../bugprone/ExceptionEscapeCheck.cpp | 39 +++++++++++----
.../bugprone/ExceptionEscapeCheck.h | 7 +++
clang-tools-extra/docs/ReleaseNotes.rst | 4 +-
.../checks/bugprone/exception-escape.rst | 25 ++++++++++
.../bugprone/exception-escape-options.cpp | 49 +++++++++++++++++++
5 files changed, 113 insertions(+), 11 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-options.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
index 837a86ff8655e..b07aad09ed2af 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
@@ -36,13 +36,22 @@ ExceptionEscapeCheck::ExceptionEscapeCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context), RawFunctionsThatShouldNotThrow(Options.get(
"FunctionsThatShouldNotThrow", "")),
- RawIgnoredExceptions(Options.get("IgnoredExceptions", "")) {
+ RawIgnoredExceptions(Options.get("IgnoredExceptions", "")),
+ RawCheckedSwapFunctions(
+ Options.get("CheckedSwapFunctions", "swap,iter_swap,iter_move")),
+ CheckDestructors(Options.get("CheckDestructors", true)),
+ CheckMoveMemberFunctions(Options.get("CheckMoveMemberFunctions", true)),
+ CheckMain(Options.get("CheckMain", true)),
+ CheckNothrowFunctions(Options.get("CheckNothrowFunctions", true)) {
llvm::SmallVector<StringRef, 8> FunctionsThatShouldNotThrowVec,
- IgnoredExceptionsVec;
+ IgnoredExceptionsVec, CheckedSwapFunctionsVec;
RawFunctionsThatShouldNotThrow.split(FunctionsThatShouldNotThrowVec, ",", -1,
false);
FunctionsThatShouldNotThrow.insert_range(FunctionsThatShouldNotThrowVec);
+ RawCheckedSwapFunctions.split(CheckedSwapFunctionsVec, ",", -1, false);
+ CheckedSwapFunctions.insert_range(CheckedSwapFunctionsVec);
+
llvm::StringSet<> IgnoredExceptions;
RawIgnoredExceptions.split(IgnoredExceptionsVec, ",", -1, false);
IgnoredExceptions.insert_range(IgnoredExceptionsVec);
@@ -54,20 +63,30 @@ void ExceptionEscapeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "FunctionsThatShouldNotThrow",
RawFunctionsThatShouldNotThrow);
Options.store(Opts, "IgnoredExceptions", RawIgnoredExceptions);
+ Options.store(Opts, "CheckedSwapFunctions", RawCheckedSwapFunctions);
+ Options.store(Opts, "CheckDestructors", CheckDestructors);
+ Options.store(Opts, "CheckMoveMemberFunctions", CheckMoveMemberFunctions);
+ Options.store(Opts, "CheckMain", CheckMain);
+ Options.store(Opts, "CheckNothrowFunctions", CheckNothrowFunctions);
}
void ExceptionEscapeCheck::registerMatchers(MatchFinder *Finder) {
+ ast_matchers::internal::Matcher<FunctionDecl> Nothing = unless(anything());
Finder->addMatcher(
functionDecl(
isDefinition(),
- anyOf(isNoThrow(),
- allOf(anyOf(cxxDestructorDecl(),
- cxxConstructorDecl(isMoveConstructor()),
- cxxMethodDecl(isMoveAssignmentOperator()), isMain(),
- allOf(hasAnyName("swap", "iter_swap", "iter_move"),
- hasAtLeastOneParameter())),
- unless(isExplicitThrow())),
- isEnabled(FunctionsThatShouldNotThrow)))
+ anyOf(
+ CheckNothrowFunctions ? isNoThrow() : Nothing,
+ allOf(anyOf(CheckDestructors ? cxxDestructorDecl() : Nothing,
+ CheckMoveMemberFunctions
+ ? anyOf(cxxConstructorDecl(isMoveConstructor()),
+ cxxMethodDecl(isMoveAssignmentOperator()))
+ : Nothing,
+ CheckMain ? isMain() : Nothing,
+ allOf(isEnabled(CheckedSwapFunctions),
+ hasAtLeastOneParameter())),
+ unless(isExplicitThrow())),
+ isEnabled(FunctionsThatShouldNotThrow)))
.bind("thrower"),
this);
}
diff --git a/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.h b/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.h
index bd1e7bae57f5d..db5e71901962e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.h
@@ -35,8 +35,15 @@ class ExceptionEscapeCheck : public ClangTidyCheck {
private:
StringRef RawFunctionsThatShouldNotThrow;
StringRef RawIgnoredExceptions;
+ StringRef RawCheckedSwapFunctions;
+
+ const bool CheckDestructors;
+ const bool CheckMoveMemberFunctions;
+ const bool CheckMain;
+ const bool CheckNothrowFunctions;
llvm::StringSet<> FunctionsThatShouldNotThrow;
+ llvm::StringSet<> CheckedSwapFunctions;
utils::ExceptionAnalyzer Tracer;
};
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a94dd9737468c..c5247074244d2 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -260,7 +260,9 @@ Changes in existing checks
- Improved :doc:`bugprone-exception-escape
<clang-tidy/checks/bugprone/exception-escape>` check's handling of lambdas:
exceptions from captures are now diagnosed, exceptions in the bodies of
- lambdas that aren't actually invoked are not.
+ lambdas that aren't actually invoked are not. Added fine-grained configuration
+ via options `CheckDestructors`, `CheckMoveMemberFunctions`, `CheckMain`,
+ `CheckedSwapFunctions`, and `CheckNothrowFunctions`.
- Improved :doc:`bugprone-infinite-loop
<clang-tidy/checks/bugprone/infinite-loop>` check by adding detection for
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/exception-escape.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/exception-escape.rst
index 182fade7f47a0..07abbedd109b0 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/exception-escape.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/exception-escape.rst
@@ -35,6 +35,31 @@ WARNING! This check may be expensive on large source files.
Options
-------
+.. option:: CheckDestructors
+
+ When `true`, destructors are analyzed to not throw exceptions.
+ Default value is `true`.
+
+.. option:: CheckMoveMemberFunctions
+
+ When `true`, move constructors and move assignment operators are analyzed
+ to not throw exceptions. Default value is `true`.
+
+.. option:: CheckMain
+
+ When `true`, ``main()`` function is analyzed to not throw exceptions.
+ Default value is `true`.
+
+.. option:: CheckNothrowFunctions
+
+ When `true`, functions marked with ``noexcept`` or ``throw()`` exception
+ specifications are analyzed to not throw exceptions. Default value is `true`.
+
+.. option:: CheckedSwapFunctions
+
+ Comma separated list of swap function names which should not throw exceptions.
+ Default value is `swap,iter_swap,iter_move`.
+
.. option:: FunctionsThatShouldNotThrow
Comma separated list containing function names which should not throw. An
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-options.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-options.cpp
new file mode 100644
index 0000000000000..b448770561dbb
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-options.cpp
@@ -0,0 +1,49 @@
+// RUN: %check_clang_tidy -std=c++11-or-later %s bugprone-exception-escape %t -- \
+// RUN: -config="{CheckOptions: { \
+// RUN: bugprone-exception-escape.CheckDestructors: false, \
+// RUN: bugprone-exception-escape.CheckMoveMemberFunctions: false, \
+// RUN: bugprone-exception-escape.CheckMain: false, \
+// RUN: bugprone-exception-escape.CheckedSwapFunctions: '', \
+// RUN: bugprone-exception-escape.CheckNothrowFunctions: false \
+// RUN: }}" \
+// RUN: -- -fexceptions
+
+// CHECK-MESSAGES-NOT: warning:
+
+struct destructor {
+ ~destructor() {
+ throw 1;
+ }
+};
+
+struct move {
+ move(const move&) { throw 42; }
+ move(move&&) { throw 42; }
+ move& operator=(const move&) { throw 42; }
+ move& operator=(move&&) { throw 42; }
+};
+
+void swap(int&, int&) {
+ throw 1;
+}
+
+void iter_swap(int&, int&) {
+ throw 1;
+}
+
+void iter_move(int&) {
+ throw 1;
+}
+
+void nothrow_func() throw() {
+ throw 1;
+}
+
+void noexcept_func() noexcept {
+ throw 1;
+}
+
+int main() {
+ throw 1;
+ return 0;
+}
>From 1ee861b1f4b6c19748d8ec1bb14421ba1be2f715 Mon Sep 17 00:00:00 2001
From: Baranov Victor <bar.victor.2002 at gmail.com>
Date: Sat, 18 Oct 2025 17:40:29 +0300
Subject: [PATCH 2/2] Update
clang-tools-extra/docs/clang-tidy/checks/bugprone/exception-escape.rst
Co-authored-by: EugeneZelenko <eugene.zelenko at gmail.com>
---
.../docs/clang-tidy/checks/bugprone/exception-escape.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/exception-escape.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/exception-escape.rst
index 07abbedd109b0..2e0b37f7e2e8b 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/exception-escape.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/exception-escape.rst
@@ -57,7 +57,7 @@ Options
.. option:: CheckedSwapFunctions
- Comma separated list of swap function names which should not throw exceptions.
+ Comma-separated list of swap function names which should not throw exceptions.
Default value is `swap,iter_swap,iter_move`.
.. option:: FunctionsThatShouldNotThrow
More information about the cfe-commits
mailing list