Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 29 additions & 10 deletions clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Comment on lines +52 to +53
Copy link
Contributor Author

@vbvictor vbvictor Oct 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not ideal, we better use hasAnyName with ArrayRef<StringRef> but for now I keep uniform with existing style.

Will refactor later.


llvm::StringSet<> IgnoredExceptions;
RawIgnoredExceptions.split(IgnoredExceptionsVec, ",", -1, false);
IgnoredExceptions.insert_range(IgnoredExceptionsVec);
Expand All @@ -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);
}
Expand Down
7 changes: 7 additions & 0 deletions clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
4 changes: 3 additions & 1 deletion clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}