[clang-tools-extra] 0b7f01a - [clang-tidy] Add frames for bugprone-exception-escape options (#187971)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Apr 5 07:07:25 PDT 2026
Author: Zeyi Xu
Date: 2026-04-05T22:07:20+08:00
New Revision: 0b7f01ad515d83f1f3144a44a1b0145187eff484
URL: https://github.com/llvm/llvm-project/commit/0b7f01ad515d83f1f3144a44a1b0145187eff484
DIFF: https://github.com/llvm/llvm-project/commit/0b7f01ad515d83f1f3144a44a1b0145187eff484.diff
LOG: [clang-tidy] Add frames for bugprone-exception-escape options (#187971)
This patch adds frames emitting for
`bugprone-exception-escape.TreatFunctionsWithoutSpecificationAsThrowing`.
As of AI Usage: Gemini 3 is used for pre-commit reviewing.
Closes https://github.com/llvm/llvm-project/issues/184781
Added:
Modified:
clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-treat-functions-without-specification-as-throwing.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
index e4facdad2c7aa..7d23e2d2b5630 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
@@ -155,11 +155,19 @@ void ExceptionEscapeCheck::check(const MatchFinder::MatchResult &Result) {
return;
const utils::ExceptionAnalyzer::CallStack &Stack = ThrowInfo.Stack;
- diag(ThrowInfo.Loc,
- "frame #0: unhandled exception of type %0 may be thrown in function %1 "
- "here",
- DiagnosticIDs::Note)
- << QualType(ThrowType, 0U) << Stack.back().first;
+ if (ThrowType) {
+ diag(ThrowInfo.Loc,
+ "frame #0: unhandled exception of type %0 may be thrown in function "
+ "%1 here",
+ DiagnosticIDs::Note)
+ << QualType(ThrowType, 0U) << Stack.back().first;
+ } else {
+ diag(ThrowInfo.Loc,
+ "frame #0: an exception of unknown type may be thrown in function %0 "
+ "here",
+ DiagnosticIDs::Note)
+ << Stack.back().first;
+ }
size_t FrameNo = 1;
for (auto CurrIt = ++Stack.rbegin(), PrevIt = Stack.rbegin();
diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
index 2a54de88dc4d6..9165be3c850d7 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -12,7 +12,6 @@ namespace clang::tidy::utils {
void ExceptionAnalyzer::ExceptionInfo::registerException(
const Type *ExceptionType, const ThrowInfo &ThrowInfo) {
- assert(ExceptionType != nullptr && "Only valid types are accepted");
Behaviour = State::Throwing;
ThrownExceptions.insert({ExceptionType, ThrowInfo});
}
@@ -432,6 +431,8 @@ ExceptionAnalyzer::ExceptionInfo::filterIgnoredExceptions(
// Therefore this slightly hacky implementation is required.
for (const auto &ThrownException : ThrownExceptions) {
const Type *T = ThrownException.getFirst();
+ if (!T)
+ continue;
if (const auto *TD = T->getAsTagDecl()) {
if (TD->getDeclName().isIdentifier()) {
if ((IgnoreBadAlloc &&
@@ -484,13 +485,14 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
}
}
- CallStack.erase(Func);
// Optionally treat unannotated functions as potentially throwing if they
// are not explicitly non-throwing and no throw was discovered.
if (AssumeUnannotatedFunctionsAsThrowing &&
Result.getBehaviour() == State::NotThrowing && canThrow(Func)) {
- Result.registerUnknownException();
+ Result.registerException(nullptr, {Func->getLocation(), CallStack});
}
+
+ CallStack.erase(Func);
return Result;
}
@@ -507,8 +509,11 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
}
if (AssumeMissingDefinitionsFunctionsAsThrowing &&
- Result.getBehaviour() == State::Unknown)
- Result.registerUnknownException();
+ Result.getBehaviour() == State::Unknown) {
+ CallStack.insert({Func, CallLoc});
+ Result.registerException(nullptr, {Func->getLocation(), CallStack});
+ CallStack.erase(Func);
+ }
return Result;
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-treat-functions-without-specification-as-throwing.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-treat-functions-without-specification-as-throwing.cpp
index 6e9aa03323ec7..6f955fa5a012a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-treat-functions-without-specification-as-throwing.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-treat-functions-without-specification-as-throwing.cpp
@@ -15,6 +15,8 @@ void unannotated_no_throw_body() {}
void calls_unannotated() noexcept {
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'calls_unannotated' which should not throw exceptions
+ // CHECK-MESSAGES-ALL: :[[@LINE-4]]:6: note: frame #0: an exception of unknown type may be thrown in function 'unannotated_no_throw_body' here
+ // CHECK-MESSAGES-ALL: :[[@LINE+3]]:3: note: frame #1: function 'calls_unannotated' calls function 'unannotated_no_throw_body' here
// CHECK-MESSAGES-UNDEFINED-NOT: warning:
// CHECK-MESSAGES-NONE-NOT: warning:
unannotated_no_throw_body();
@@ -24,7 +26,11 @@ void extern_declared();
void calls_unknown() noexcept {
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'calls_unknown' which should not throw exceptions
- // CHECK-MESSAGES-UNDEFINED: :[[@LINE-2]]:6: warning: an exception may be thrown in function 'calls_unknown' which should not throw exceptions
+ // CHECK-MESSAGES-ALL: :[[@LINE-4]]:6: note: frame #0: an exception of unknown type may be thrown in function 'extern_declared' here
+ // CHECK-MESSAGES-ALL: :[[@LINE+5]]:3: note: frame #1: function 'calls_unknown' calls function 'extern_declared' here
+ // CHECK-MESSAGES-UNDEFINED: :[[@LINE-4]]:6: warning: an exception may be thrown in function 'calls_unknown' which should not throw exceptions
+ // CHECK-MESSAGES-UNDEFINED: :[[@LINE-7]]:6: note: frame #0: an exception of unknown type may be thrown in function 'extern_declared' here
+ // CHECK-MESSAGES-UNDEFINED: :[[@LINE+2]]:3: note: frame #1: function 'calls_unknown' calls function 'extern_declared' here
// CHECK-MESSAGES-NONE-NOT: warning:
extern_declared();
}
@@ -54,6 +60,30 @@ void call() noexcept {
nothrow_nobody();
}
+struct Member {
+ Member() noexcept {}
+ Member(const Member &) noexcept {}
+ Member &operator=(const Member &) noexcept { return *this; }
+ ~Member() noexcept {}
+};
+
+struct S {
+ // CHECK-MESSAGES-ALL: :[[@LINE-1]]:8: warning: an exception may be thrown in function 'S' which should not throw exceptions
+ // CHECK-MESSAGES-ALL: :[[@LINE-2]]:8: note: frame #0: an exception of unknown type may be thrown in function 'S' here
+ // CHECK-MESSAGES-ALL: :[[@LINE-3]]:8: warning: an exception may be thrown in function 'operator=' which should not throw exceptions
+ // CHECK-MESSAGES-ALL: :[[@LINE-4]]:8: note: frame #0: an exception of unknown type may be thrown in function 'operator=' here
+ // CHECK-MESSAGES-ALL: :[[@LINE-5]]:8: warning: an exception may be thrown in function '~S' which should not throw exceptions
+ // CHECK-MESSAGES-ALL: :[[@LINE-6]]:8: note: frame #0: an exception of unknown type may be thrown in function '~S' here
+ // CHECK-MESSAGES-UNDEFINED: :[[@LINE-7]]:8: warning: an exception may be thrown in function 'S' which should not throw exceptions
+ // CHECK-MESSAGES-UNDEFINED: :[[@LINE-8]]:8: note: frame #0: an exception of unknown type may be thrown in function 'S' here
+ // CHECK-MESSAGES-UNDEFINED: :[[@LINE-9]]:8: warning: an exception may be thrown in function 'operator=' which should not throw exceptions
+ // CHECK-MESSAGES-UNDEFINED: :[[@LINE-10]]:8: note: frame #0: an exception of unknown type may be thrown in function 'operator=' here
+ // CHECK-MESSAGES-UNDEFINED: :[[@LINE-11]]:8: warning: an exception may be thrown in function '~S' which should not throw exceptions
+ // CHECK-MESSAGES-UNDEFINED: :[[@LINE-12]]:8: note: frame #0: an exception of unknown type may be thrown in function '~S' here
+ // FIXME: clearly non-throwing functions should not be marked as throwing
+ Member m;
+};
+
void explicit_throw() { throw 1; }
void calls_explicit_throw() noexcept {
// CHECK-MESSAGES-ALL: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'calls_explicit_throw' which should not throw exceptions
More information about the cfe-commits
mailing list