[clang-tools-extra] [clang-tidy] Improve `bugprone-exception-escape`: add stacktrace of escaped exception (PR #134375)
Baranov Victor via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 4 05:47:22 PDT 2025
https://github.com/vbvictor created https://github.com/llvm/llvm-project/pull/134375
This PR add stacktrace of escaped exception to `bugprone-exception-escape` check.
Changes:
1. Modified `ExceptionAnalyzer` and `ExceptionInfo` classes to hold stacktrace of escaped exception in `llvm::SetVector`. `SetVector` is needed to hold relative positions of functions in stack as well as have fast lookup.
2. Added new diagnostics based of `misc-no-recursion` check.
Example of new diagnostics:
> warning: an exception may be thrown in function 'calls_non_and_throwing' which should not throw exceptions [bugprone-exception-escape]
note: example of unhandled exception throw stack, starting from function 'calls_non_and_throwing'
note: frame #0: function 'calls_non_and_throwing'
note: frame #1: function 'test_basic_throw' throws unhandled exception here
More example can be found it tests.
>From b0d131a38e73f97d533d46ed9b10c8dcbeda0672 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Fri, 4 Apr 2025 15:28:45 +0300
Subject: [PATCH 1/2] [clang-tidy] add stacktrase to exception-escape
---
.../bugprone/ExceptionEscapeCheck.cpp | 47 ++++++-
.../clang-tidy/utils/ExceptionAnalyzer.cpp | 76 ++++++-----
.../clang-tidy/utils/ExceptionAnalyzer.h | 42 ++++--
.../bugprone/exception-escape-coro.cpp | 124 ++++++++++++++++++
.../bugprone/exception-escape-rethrow.cpp | 4 +
.../bugprone/exception-escape-throw.cpp | 9 ++
.../checkers/bugprone/exception-escape.cpp | 107 +++++++++++++++
7 files changed, 357 insertions(+), 52 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
index 7e9551532b72f..0113da6ec1ac1 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp
@@ -80,13 +80,46 @@ void ExceptionEscapeCheck::check(const MatchFinder::MatchResult &Result) {
if (!MatchedDecl)
return;
- if (Tracer.analyze(MatchedDecl).getBehaviour() ==
- utils::ExceptionAnalyzer::State::Throwing)
- // FIXME: We should provide more information about the exact location where
- // the exception is thrown, maybe the full path the exception escapes
- diag(MatchedDecl->getLocation(), "an exception may be thrown in function "
- "%0 which should not throw exceptions")
- << MatchedDecl;
+ const utils::ExceptionAnalyzer::ExceptionInfo Info =
+ Tracer.analyze(MatchedDecl);
+
+ if (Info.getBehaviour() != utils::ExceptionAnalyzer::State::Throwing) {
+ return;
+ }
+
+ diag(MatchedDecl->getLocation(), "an exception may be thrown in function "
+ "%0 which should not throw exceptions")
+ << MatchedDecl;
+
+ const utils::ExceptionAnalyzer::ExceptionInfo::ThrowInfo ThrowInfo =
+ Info.getExceptions().begin()->getSecond();
+
+ if (ThrowInfo.Loc.isInvalid()) {
+ return;
+ }
+
+ // FIXME: We should provide exact position of functions calls, not only call
+ // stack of thrown exception.
+ const utils::ExceptionAnalyzer::CallStack &Stack = ThrowInfo.Stack;
+ diag(Stack.front()->getLocation(),
+ "example of unhandled exception throw stack, starting from function %0",
+ DiagnosticIDs::Note)
+ << Stack.front();
+
+ size_t FrameNo = 0;
+ for (const FunctionDecl *CallNode : Stack) {
+ if (FrameNo != Stack.size() - 1) {
+ diag(CallNode->getLocation(), "frame #%0: function %1",
+ DiagnosticIDs::Note)
+ << FrameNo << CallNode;
+ } else {
+ diag(ThrowInfo.Loc,
+ "frame #%0: function %1 throws unhandled exception here",
+ DiagnosticIDs::Note)
+ << FrameNo << CallNode;
+ }
+ ++FrameNo;
+ }
}
} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
index e28ee7d9c70f7..42f04b07d88f8 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -11,10 +11,10 @@
namespace clang::tidy::utils {
void ExceptionAnalyzer::ExceptionInfo::registerException(
- const Type *ExceptionType) {
+ const Type *ExceptionType, const ThrowInfo &ThrowInfo) {
assert(ExceptionType != nullptr && "Only valid types are accepted");
Behaviour = State::Throwing;
- ThrownExceptions.insert(ExceptionType);
+ ThrownExceptions.insert({ExceptionType, ThrowInfo});
}
void ExceptionAnalyzer::ExceptionInfo::registerExceptions(
@@ -354,10 +354,12 @@ static bool canThrow(const FunctionDecl *Func) {
};
}
-bool ExceptionAnalyzer::ExceptionInfo::filterByCatch(
- const Type *HandlerTy, const ASTContext &Context) {
+ExceptionAnalyzer::ExceptionInfo::Throwables
+ExceptionAnalyzer::ExceptionInfo::filterByCatch(const Type *HandlerTy,
+ const ASTContext &Context) {
llvm::SmallVector<const Type *, 8> TypesToDelete;
- for (const Type *ExceptionTy : ThrownExceptions) {
+ for (const auto &ThrownException : ThrownExceptions) {
+ const Type *ExceptionTy = ThrownException.getFirst();
CanQualType ExceptionCanTy = ExceptionTy->getCanonicalTypeUnqualified();
CanQualType HandlerCanTy = HandlerTy->getCanonicalTypeUnqualified();
@@ -407,11 +409,18 @@ bool ExceptionAnalyzer::ExceptionInfo::filterByCatch(
}
}
- for (const Type *T : TypesToDelete)
- ThrownExceptions.erase(T);
+ Throwables DeletedExceptions;
+
+ for (const Type *TypeToDelete : TypesToDelete) {
+ const auto DeleteIt = ThrownExceptions.find(TypeToDelete);
+ if (DeleteIt != ThrownExceptions.end()) {
+ DeletedExceptions.insert(*DeleteIt);
+ ThrownExceptions.erase(DeleteIt);
+ }
+ }
reevaluateBehaviour();
- return !TypesToDelete.empty();
+ return DeletedExceptions;
}
ExceptionAnalyzer::ExceptionInfo &
@@ -420,7 +429,8 @@ ExceptionAnalyzer::ExceptionInfo::filterIgnoredExceptions(
llvm::SmallVector<const Type *, 8> TypesToDelete;
// Note: Using a 'SmallSet' with 'llvm::remove_if()' is not possible.
// Therefore this slightly hacky implementation is required.
- for (const Type *T : ThrownExceptions) {
+ for (const auto &ThrownException : ThrownExceptions) {
+ const Type *T = ThrownException.getFirst();
if (const auto *TD = T->getAsTagDecl()) {
if (TD->getDeclName().isIdentifier()) {
if ((IgnoreBadAlloc &&
@@ -452,10 +462,10 @@ void ExceptionAnalyzer::ExceptionInfo::reevaluateBehaviour() {
else
Behaviour = State::Throwing;
}
-
-ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
- const FunctionDecl *Func, const ExceptionInfo::Throwables &Caught,
- llvm::SmallSet<const FunctionDecl *, 32> &CallStack) {
+ExceptionAnalyzer::ExceptionInfo
+ExceptionAnalyzer::throwsException(const FunctionDecl *Func,
+ const ExceptionInfo::Throwables &Caught,
+ CallStack &CallStack) {
if (!Func || CallStack.contains(Func) ||
(!CallStack.empty() && !canThrow(Func)))
return ExceptionInfo::createNonThrowing();
@@ -473,23 +483,25 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
}
}
- CallStack.erase(Func);
+ CallStack.remove(Func);
return Result;
}
auto Result = ExceptionInfo::createUnknown();
if (const auto *FPT = Func->getType()->getAs<FunctionProtoType>()) {
for (const QualType &Ex : FPT->exceptions())
- Result.registerException(Ex.getTypePtr());
+ // FIXME add something to ThrowInfo
+ Result.registerException(Ex.getTypePtr(), {});
}
return Result;
}
/// Analyzes a single statement on it's throwing behaviour. This is in principle
/// possible except some 'Unknown' functions are called.
-ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
- const Stmt *St, const ExceptionInfo::Throwables &Caught,
- llvm::SmallSet<const FunctionDecl *, 32> &CallStack) {
+ExceptionAnalyzer::ExceptionInfo
+ExceptionAnalyzer::throwsException(const Stmt *St,
+ const ExceptionInfo::Throwables &Caught,
+ CallStack &CallStack) {
auto Results = ExceptionInfo::createNonThrowing();
if (!St)
return Results;
@@ -503,7 +515,8 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
->getPointeeType()
->getUnqualifiedDesugaredType();
Results.registerException(
- ThrownExpr->getType()->getUnqualifiedDesugaredType());
+ ThrownExpr->getType()->getUnqualifiedDesugaredType(),
+ {Throw->getBeginLoc(), CallStack});
} else
// A rethrow of a caught exception happens which makes it possible
// to throw all exception that are caught in the 'catch' clause of
@@ -518,7 +531,7 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
// Everything is caught through 'catch(...)'.
if (!Catch->getExceptionDecl()) {
ExceptionInfo Rethrown = throwsException(
- Catch->getHandlerBlock(), Uncaught.getExceptionTypes(), CallStack);
+ Catch->getHandlerBlock(), Uncaught.getExceptions(), CallStack);
Results.merge(Rethrown);
Uncaught.clear();
} else {
@@ -534,12 +547,12 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
// thrown types (because it's sensitive to inheritance) the throwing
// situation changes. First of all filter the exception types and
// analyze if the baseclass-exception is rethrown.
- if (Uncaught.filterByCatch(
- CaughtType, Catch->getExceptionDecl()->getASTContext())) {
- ExceptionInfo::Throwables CaughtExceptions;
- CaughtExceptions.insert(CaughtType);
- ExceptionInfo Rethrown = throwsException(Catch->getHandlerBlock(),
- CaughtExceptions, CallStack);
+ const ExceptionInfo::Throwables FilteredExceptions =
+ Uncaught.filterByCatch(CaughtType,
+ Catch->getExceptionDecl()->getASTContext());
+ if (!FilteredExceptions.empty()) {
+ ExceptionInfo Rethrown = throwsException(
+ Catch->getHandlerBlock(), FilteredExceptions, CallStack);
Results.merge(Rethrown);
}
}
@@ -567,9 +580,10 @@ ExceptionAnalyzer::ExceptionInfo ExceptionAnalyzer::throwsException(
}
ExceptionInfo Excs = throwsException(Coro->getBody(), Caught, CallStack);
Results.merge(throwsException(Coro->getExceptionHandler(),
- Excs.getExceptionTypes(), CallStack));
- for (const Type *Throwable : Excs.getExceptionTypes()) {
- if (const auto ThrowableRec = Throwable->getAsCXXRecordDecl()) {
+ Excs.getExceptions(), CallStack));
+ for (const auto &Exception : Excs.getExceptions()) {
+ const Type *ExcType = Exception.getFirst();
+ if (const CXXRecordDecl *ThrowableRec = ExcType->getAsCXXRecordDecl()) {
ExceptionInfo DestructorExcs =
throwsException(ThrowableRec->getDestructor(), Caught, CallStack);
Results.merge(DestructorExcs);
@@ -591,7 +605,7 @@ ExceptionAnalyzer::analyzeImpl(const FunctionDecl *Func) {
// Check if the function has already been analyzed and reuse that result.
const auto CacheEntry = FunctionCache.find(Func);
if (CacheEntry == FunctionCache.end()) {
- llvm::SmallSet<const FunctionDecl *, 32> CallStack;
+ CallStack CallStack;
ExceptionList =
throwsException(Func, ExceptionInfo::Throwables(), CallStack);
@@ -608,7 +622,7 @@ ExceptionAnalyzer::analyzeImpl(const FunctionDecl *Func) {
ExceptionAnalyzer::ExceptionInfo
ExceptionAnalyzer::analyzeImpl(const Stmt *Stmt) {
- llvm::SmallSet<const FunctionDecl *, 32> CallStack;
+ CallStack CallStack;
return throwsException(Stmt, ExceptionInfo::Throwables(), CallStack);
}
diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.h b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.h
index 6c2d693d64b50..0fea44fc8a622 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.h
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.h
@@ -12,6 +12,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSet.h"
namespace clang::tidy::utils {
@@ -28,6 +29,12 @@ class ExceptionAnalyzer {
///< definition.
};
+ /// We use a SetVector to preserve the order of the functions in the call
+ /// stack as well as have fast lookup.
+ using CallStack = llvm::SetVector<const FunctionDecl *,
+ llvm::SmallVector<const FunctionDecl *, 32>,
+ llvm::DenseSet<const FunctionDecl *>, 32>;
+
/// Bundle the gathered information about an entity like a function regarding
/// it's exception behaviour. The 'NonThrowing'-state can be considered as the
/// neutral element in terms of information propagation.
@@ -37,7 +44,15 @@ class ExceptionAnalyzer {
/// exception at runtime.
class ExceptionInfo {
public:
- using Throwables = llvm::SmallSet<const Type *, 2>;
+ /// Holds information about where an exception is thrown.
+ /// First element in the call stack is analyzed function.
+ struct ThrowInfo {
+ SourceLocation Loc;
+ CallStack Stack;
+ };
+
+ using Throwables = llvm::SmallDenseMap<const Type *, ThrowInfo, 2>;
+
static ExceptionInfo createUnknown() { return {State::Unknown}; }
static ExceptionInfo createNonThrowing() { return {State::Throwing}; }
@@ -56,7 +71,8 @@ class ExceptionAnalyzer {
/// Register a single exception type as recognized potential exception to be
/// thrown.
- void registerException(const Type *ExceptionType);
+ void registerException(const Type *ExceptionType,
+ const ThrowInfo &ThrowInfo);
/// Registers a `SmallVector` of exception types as recognized potential
/// exceptions to be thrown.
@@ -73,8 +89,8 @@ class ExceptionAnalyzer {
/// This method is useful in case 'catch' clauses are analyzed as it is
/// possible to catch multiple exception types by one 'catch' if they
/// are a subclass of the 'catch'ed exception type.
- /// Returns 'true' if some exceptions were filtered, otherwise 'false'.
- bool filterByCatch(const Type *HandlerTy, const ASTContext &Context);
+ /// Returns filtered exceptions.
+ Throwables filterByCatch(const Type *HandlerTy, const ASTContext &Context);
/// Filter the set of thrown exception type against a set of ignored
/// types that shall not be considered in the exception analysis.
@@ -87,9 +103,9 @@ class ExceptionAnalyzer {
/// neutral.
void clear();
- /// References the set of known exception types that can escape from the
+ /// References the set of known exceptions that can escape from the
/// corresponding entity.
- const Throwables &getExceptionTypes() const { return ThrownExceptions; }
+ const Throwables &getExceptions() const { return ThrownExceptions; }
/// Signal if the there is any 'Unknown' element within the scope of
/// the related entity. This might be relevant if the entity is 'Throwing'
@@ -126,14 +142,12 @@ class ExceptionAnalyzer {
ExceptionInfo analyze(const Stmt *Stmt);
private:
- ExceptionInfo
- throwsException(const FunctionDecl *Func,
- const ExceptionInfo::Throwables &Caught,
- llvm::SmallSet<const FunctionDecl *, 32> &CallStack);
- ExceptionInfo
- throwsException(const Stmt *St, const ExceptionInfo::Throwables &Caught,
- llvm::SmallSet<const FunctionDecl *, 32> &CallStack);
-
+ ExceptionInfo throwsException(const FunctionDecl *Func,
+ const ExceptionInfo::Throwables &Caught,
+ CallStack &CallStack);
+ ExceptionInfo throwsException(const Stmt *St,
+ const ExceptionInfo::Throwables &Caught,
+ CallStack &CallStack);
ExceptionInfo analyzeImpl(const FunctionDecl *Func);
ExceptionInfo analyzeImpl(const Stmt *Stmt);
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-coro.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-coro.cpp
index aff13d19fd209..829ec30353b94 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-coro.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-coro.cpp
@@ -221,6 +221,9 @@ Task<int> c_ShouldDiag(const int a, const int b) noexcept {
co_return a / b;
}
+// CHECK-MESSAGES: :[[@LINE-7]]:11: note: example of unhandled exception throw stack, starting from function 'c_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-8]]:11: note: frame #0: function 'c_ShouldDiag'
+// CHECK-MESSAGES: :186:5: note: frame #1: function '~Evil' throws unhandled exception here
Task<int, true> d_ShouldNotDiag(const int a, const int b) {
co_return a / b;
@@ -230,6 +233,10 @@ Task<int, true> d_ShouldDiag(const int a, const int b) noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: an exception may be thrown in function 'd_ShouldDiag' which should not throw exceptions
co_return a / b;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:17: note: example of unhandled exception throw stack, starting from function 'd_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:17: note: frame #0: function 'd_ShouldDiag'
+// CHECK-MESSAGES: :104:8: note: frame #1: function 'get_return_object'
+// CHECK-MESSAGES: :54:7: note: frame #2: function 'Task' throws unhandled exception here
Task<int, false, true> e_ShouldNotDiag(const int a, const int b) {
co_return a / b;
@@ -239,6 +246,9 @@ Task<int, false, true> e_ShouldDiag(const int a, const int b) noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: an exception may be thrown in function 'e_ShouldDiag' which should not throw exceptions
co_return a / b;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:24: note: example of unhandled exception throw stack, starting from function 'e_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:24: note: frame #0: function 'e_ShouldDiag'
+// CHECK-MESSAGES: :100:7: note: frame #1: function 'Promise' throws unhandled exception here
Task<int, false, false, true> f_ShouldNotDiag(const int a, const int b) {
co_return a / b;
@@ -248,6 +258,9 @@ Task<int, false, false, true> f_ShouldDiag(const int a, const int b) noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: an exception may be thrown in function 'f_ShouldDiag' which should not throw exceptions
co_return a / b;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:31: note: example of unhandled exception throw stack, starting from function 'f_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:31: note: frame #0: function 'f_ShouldDiag'
+// CHECK-MESSAGES: :114:7: note: frame #1: function 'initial_suspend' throws unhandled exception here
Task<int, false, false, false, true> g_ShouldNotDiag(const int a, const int b) {
co_return a / b;
@@ -258,6 +271,9 @@ Task<int, false, false, false, true> g_ShouldDiag(const int a,
// CHECK-MESSAGES: :[[@LINE-2]]:38: warning: an exception may be thrown in function 'g_ShouldDiag' which should not throw exceptions
co_return a / b;
}
+// CHECK-MESSAGES: :[[@LINE-5]]:38: note: example of unhandled exception throw stack, starting from function 'g_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-6]]:38: note: frame #0: function 'g_ShouldDiag'
+// CHECK-MESSAGES: :106:7: note: frame #1: function 'get_return_object' throws unhandled exception here
Task<int, false, false, false, false, true> h_ShouldNotDiag(const int a,
const int b) {
@@ -269,6 +285,9 @@ Task<int, false, false, false, false, true> h_ShouldDiag(const int a,
// CHECK-MESSAGES: :[[@LINE-2]]:45: warning: an exception may be thrown in function 'h_ShouldDiag' which should not throw exceptions
co_return a / b;
}
+// CHECK-MESSAGES: :[[@LINE-5]]:45: note: example of unhandled exception throw stack, starting from function 'h_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-6]]:45: note: frame #0: function 'h_ShouldDiag'
+// CHECK-MESSAGES: :133:7: note: frame #1: function 'unhandled_exception' throws unhandled exception here
Task<int, false, false, false, false, false, true>
i_ShouldNotDiag(const int a, const int b) {
@@ -296,6 +315,8 @@ j_ShouldDiag(const int a, const int b) noexcept {
co_return a / b;
}
+// CHECK-MESSAGES: :[[@LINE-7]]:1: note: example of unhandled exception throw stack, starting from function 'j_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'j_ShouldDiag' throws unhandled exception here
} // namespace coreturn
@@ -329,6 +350,9 @@ Task<int> c_ShouldDiag(const int a, const int b) noexcept {
co_yield a / b;
}
+// CHECK-MESSAGES: :[[@LINE-7]]:11: note: example of unhandled exception throw stack, starting from function 'c_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-8]]:11: note: frame #0: function 'c_ShouldDiag'
+// CHECK-MESSAGES: :186:5: note: frame #1: function '~Evil' throws unhandled exception here
Task<int, true> d_ShouldNotDiag(const int a, const int b) {
co_yield a / b;
@@ -338,6 +362,10 @@ Task<int, true> d_ShouldDiag(const int a, const int b) noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: an exception may be thrown in function 'd_ShouldDiag' which should not throw exceptions
co_yield a / b;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:17: note: example of unhandled exception throw stack, starting from function 'd_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:17: note: frame #0: function 'd_ShouldDiag'
+// CHECK-MESSAGES: :104:8: note: frame #1: function 'get_return_object'
+// CHECK-MESSAGES: :54:7: note: frame #2: function 'Task' throws unhandled exception here
Task<int, false, true> e_ShouldNotDiag(const int a, const int b) {
co_yield a / b;
@@ -347,6 +375,9 @@ Task<int, false, true> e_ShouldDiag(const int a, const int b) noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: an exception may be thrown in function 'e_ShouldDiag' which should not throw exceptions
co_yield a / b;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:24: note: example of unhandled exception throw stack, starting from function 'e_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:24: note: frame #0: function 'e_ShouldDiag'
+// CHECK-MESSAGES: :100:7: note: frame #1: function 'Promise' throws unhandled exception here
Task<int, false, false, true> f_ShouldNotDiag(const int a, const int b) {
co_yield a / b;
@@ -356,6 +387,9 @@ Task<int, false, false, true> f_ShouldDiag(const int a, const int b) noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: an exception may be thrown in function 'f_ShouldDiag' which should not throw exceptions
co_yield a / b;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:31: note: example of unhandled exception throw stack, starting from function 'f_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:31: note: frame #0: function 'f_ShouldDiag'
+// CHECK-MESSAGES: :114:7: note: frame #1: function 'initial_suspend' throws unhandled exception here
Task<int, false, false, false, true> g_ShouldNotDiag(const int a, const int b) {
co_yield a / b;
@@ -366,6 +400,9 @@ Task<int, false, false, false, true> g_ShouldDiag(const int a,
// CHECK-MESSAGES: :[[@LINE-2]]:38: warning: an exception may be thrown in function 'g_ShouldDiag' which should not throw exceptions
co_yield a / b;
}
+// CHECK-MESSAGES: :[[@LINE-5]]:38: note: example of unhandled exception throw stack, starting from function 'g_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-6]]:38: note: frame #0: function 'g_ShouldDiag'
+// CHECK-MESSAGES: :106:7: note: frame #1: function 'get_return_object' throws unhandled exception here
Task<int, false, false, false, false, true> h_ShouldNotDiag(const int a,
const int b) {
@@ -377,6 +414,9 @@ Task<int, false, false, false, false, true> h_ShouldDiag(const int a,
// CHECK-MESSAGES: :[[@LINE-2]]:45: warning: an exception may be thrown in function 'h_ShouldDiag' which should not throw exceptions
co_yield a / b;
}
+// CHECK-MESSAGES: :[[@LINE-5]]:45: note: example of unhandled exception throw stack, starting from function 'h_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-6]]:45: note: frame #0: function 'h_ShouldDiag'
+// CHECK-MESSAGES: :133:7: note: frame #1: function 'unhandled_exception' throws unhandled exception here
Task<int, false, false, false, false, false, true>
i_ShouldNotDiag(const int a, const int b) {
@@ -404,6 +444,8 @@ j_ShouldDiag(const int a, const int b) noexcept {
co_yield a / b;
}
+// CHECK-MESSAGES: :[[@LINE-7]]:1: note: example of unhandled exception throw stack, starting from function 'j_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'j_ShouldDiag' throws unhandled exception here
} // namespace coyield
@@ -437,6 +479,9 @@ Task<void> c_ShouldDiag(const int a, const int b) noexcept {
co_await returnOne();
}
+// CHECK-MESSAGES: :[[@LINE-7]]:12: note: example of unhandled exception throw stack, starting from function 'c_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-8]]:12: note: frame #0: function 'c_ShouldDiag'
+// CHECK-MESSAGES: :186:5: note: frame #1: function '~Evil' throws unhandled exception here
Task<void, true> d_ShouldNotDiag(const int a, const int b) {
co_await returnOne();
@@ -446,6 +491,10 @@ Task<void, true> d_ShouldDiag(const int a, const int b) noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: an exception may be thrown in function 'd_ShouldDiag' which should not throw exceptions
co_await returnOne();
}
+// CHECK-MESSAGES: :[[@LINE-4]]:18: note: example of unhandled exception throw stack, starting from function 'd_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:18: note: frame #0: function 'd_ShouldDiag'
+// CHECK-MESSAGES: :153:8: note: frame #1: function 'get_return_object'
+// CHECK-MESSAGES: :81:7: note: frame #2: function 'Task' throws unhandled exception here
Task<void, false, true> e_ShouldNotDiag(const int a, const int b) {
co_await returnOne();
@@ -455,6 +504,9 @@ Task<void, false, true> e_ShouldDiag(const int a, const int b) noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:25: warning: an exception may be thrown in function 'e_ShouldDiag' which should not throw exceptions
co_await returnOne();
}
+// CHECK-MESSAGES: :[[@LINE-4]]:25: note: example of unhandled exception throw stack, starting from function 'e_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:25: note: frame #0: function 'e_ShouldDiag'
+// CHECK-MESSAGES: :149:7: note: frame #1: function 'Promise' throws unhandled exception here
Task<void, false, false, true> f_ShouldNotDiag(const int a, const int b) {
co_await returnOne();
@@ -464,6 +516,9 @@ Task<void, false, false, true> f_ShouldDiag(const int a, const int b) noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: an exception may be thrown in function 'f_ShouldDiag' which should not throw exceptions
co_await returnOne();
}
+// CHECK-MESSAGES: :[[@LINE-4]]:32: note: example of unhandled exception throw stack, starting from function 'f_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:32: note: frame #0: function 'f_ShouldDiag'
+// CHECK-MESSAGES: :163:7: note: frame #1: function 'initial_suspend' throws unhandled exception here
Task<void, false, false, false, true> g_ShouldNotDiag(const int a,
const int b) {
@@ -475,6 +530,9 @@ Task<void, false, false, false, true> g_ShouldDiag(const int a,
// CHECK-MESSAGES: :[[@LINE-2]]:39: warning: an exception may be thrown in function 'g_ShouldDiag' which should not throw exceptions
co_await returnOne();
}
+// CHECK-MESSAGES: :[[@LINE-5]]:39: note: example of unhandled exception throw stack, starting from function 'g_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-6]]:39: note: frame #0: function 'g_ShouldDiag'
+// CHECK-MESSAGES: :155:7: note: frame #1: function 'get_return_object' throws unhandled exception here
Task<void, false, false, false, false, true> h_ShouldNotDiag(const int a,
const int b) {
@@ -486,6 +544,9 @@ h_ShouldDiag(const int a, const int b) noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: an exception may be thrown in function 'h_ShouldDiag' which should not throw exceptions
co_await returnOne();
}
+// CHECK-MESSAGES: :[[@LINE-4]]:1: note: example of unhandled exception throw stack, starting from function 'h_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-5]]:1: note: frame #0: function 'h_ShouldDiag'
+// CHECK-MESSAGES: :175:7: note: frame #1: function 'unhandled_exception' throws unhandled exception here
Task<int, false, false, false, false, false, true>
i_ShouldNotDiag(const int a, const int b) {
@@ -511,6 +572,8 @@ j_ShouldDiag(const int a, const int b) noexcept {
if (b == 0)
throw b;
}
+// CHECK-MESSAGES: :[[@LINE-6]]:1: note: example of unhandled exception throw stack, starting from function 'j_ShouldDiag'
+// CHECK-MESSAGES: :[[@LINE-3]]:5: note: frame #0: function 'j_ShouldDiag' throws unhandled exception here
} // namespace coawait
@@ -549,6 +612,9 @@ const auto c_ShouldDiag = [](const int a, const int b) noexcept -> Task<int> {
co_return a / b;
};
+// CHECK-MESSAGES: :[[@LINE-7]]:27: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-8]]:27: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :186:5: note: frame #1: function '~Evil' throws unhandled exception here
const auto d_ShouldNotDiag = [](const int a, const int b) -> Task<int, true> {
co_return a / b;
@@ -559,6 +625,10 @@ const auto d_ShouldDiag = [](const int a,
// CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_return a / b;
};
+// CHECK-MESSAGES: :[[@LINE-5]]:27: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:27: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :104:8: note: frame #1: function 'get_return_object'
+// CHECK-MESSAGES: :54:7: note: frame #2: function 'Task' throws unhandled exception here
const auto e_ShouldNotDiag = [](const int a,
const int b) -> Task<int, false, true> {
@@ -570,6 +640,9 @@ const auto e_ShouldDiag = [](const int a,
// CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_return a / b;
};
+// CHECK-MESSAGES: :[[@LINE-5]]:27: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:27: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :100:7: note: frame #1: function 'Promise' throws unhandled exception here
const auto f_ShouldNotDiag = [](const int a,
const int b) -> Task<int, false, false, true> {
@@ -581,6 +654,9 @@ const auto f_ShouldDiag =
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_return a / b;
};
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :114:7: note: frame #1: function 'initial_suspend' throws unhandled exception here
const auto g_ShouldNotDiag =
[](const int a, const int b) -> Task<int, false, false, false, true> {
@@ -593,6 +669,9 @@ const auto g_ShouldDiag =
// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_return a / b;
};
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:5: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :106:7: note: frame #1: function 'get_return_object' throws unhandled exception here
const auto h_ShouldNotDiag =
[](const int a,
@@ -606,6 +685,9 @@ const auto h_ShouldDiag =
// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_return a / b;
};
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:5: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :133:7: note: frame #1: function 'unhandled_exception' throws unhandled exception here
const auto i_ShouldNotDiag =
[](const int a,
@@ -637,6 +719,8 @@ const auto j_ShouldDiag =
co_return a / b;
};
+// CHECK-MESSAGES: :[[@LINE-8]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'operator()' throws unhandled exception here
} // namespace coreturn
@@ -671,6 +755,9 @@ const auto c_ShouldDiag = [](const int a, const int b) noexcept -> Task<int> {
co_yield a / b;
};
+// CHECK-MESSAGES: :[[@LINE-7]]:27: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-8]]:27: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :186:5: note: frame #1: function '~Evil' throws unhandled exception here
const auto d_ShouldNotDiag = [](const int a, const int b) -> Task<int, true> {
co_yield a / b;
@@ -681,6 +768,9 @@ const auto d_ShouldDiag = [](const int a,
// CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_yield a / b;
};
+// CHECK-MESSAGES: :[[@LINE-5]]:27: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:27: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :104:8: note: frame #1: function 'get_return_object'
const auto e_ShouldNotDiag = [](const int a,
const int b) -> Task<int, false, true> {
@@ -692,6 +782,9 @@ const auto e_ShouldDiag = [](const int a,
// CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_yield a / b;
};
+// CHECK-MESSAGES: :[[@LINE-5]]:27: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:27: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :100:7: note: frame #1: function 'Promise' throws unhandled exception here
const auto f_ShouldNotDiag = [](const int a,
const int b) -> Task<int, false, false, true> {
@@ -703,6 +796,9 @@ const auto f_ShouldDiag =
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_yield a / b;
};
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :114:7: note: frame #1: function 'initial_suspend' throws unhandled exception here
const auto g_ShouldNotDiag =
[](const int a, const int b) -> Task<int, false, false, false, true> {
@@ -715,6 +811,9 @@ const auto g_ShouldDiag =
// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_yield a / b;
};
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:5: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :106:7: note: frame #1: function 'get_return_object' throws unhandled exception here
const auto h_ShouldNotDiag =
[](const int a,
@@ -728,6 +827,9 @@ const auto h_ShouldDiag =
// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_yield a / b;
};
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:5: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :133:7: note: frame #1: function 'unhandled_exception' throws unhandled exception here
const auto i_ShouldNotDiag =
[](const int a,
@@ -759,6 +861,8 @@ const auto j_ShouldDiag =
co_yield a / b;
};
+// CHECK-MESSAGES: :[[@LINE-8]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'operator()' throws unhandled exception here
} // namespace coyield
@@ -793,6 +897,9 @@ const auto c_ShouldDiag = [](const int a, const int b) noexcept -> Task<void> {
co_await returnOne();
};
+// CHECK-MESSAGES: :[[@LINE-7]]:27: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-8]]:27: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :186:5: note: frame #1: function '~Evil' throws unhandled exception here
const auto d_ShouldNotDiag = [](const int a, const int b) -> Task<void, true> {
co_await returnOne();
@@ -803,6 +910,9 @@ const auto d_ShouldDiag = [](const int a,
// CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_await returnOne();
};
+// CHECK-MESSAGES: :[[@LINE-5]]:27: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:27: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :153:8: note: frame #1: function 'get_return_object'
const auto e_ShouldNotDiag = [](const int a,
const int b) -> Task<void, false, true> {
@@ -814,6 +924,9 @@ const auto e_ShouldDiag = [](const int a,
// CHECK-MESSAGES: :[[@LINE-2]]:27: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_await returnOne();
};
+// CHECK-MESSAGES: :[[@LINE-5]]:27: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:27: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :149:7: note: frame #1: function 'Promise' throws unhandled exception here
const auto f_ShouldNotDiag = [](const int a,
const int b) -> Task<void, false, false, true> {
@@ -825,6 +938,9 @@ const auto f_ShouldDiag =
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_await returnOne();
};
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :163:7: note: frame #1: function 'initial_suspend' throws unhandled exception here
const auto g_ShouldNotDiag =
[](const int a, const int b) -> Task<void, false, false, false, true> {
@@ -837,6 +953,9 @@ const auto g_ShouldDiag =
// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_await returnOne();
};
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:5: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :155:7: note: frame #1: function 'get_return_object' throws unhandled exception here
const auto h_ShouldNotDiag =
[](const int a,
@@ -850,6 +969,9 @@ const auto h_ShouldDiag =
// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: an exception may be thrown in function 'operator()' which should not throw exceptions
co_await returnOne();
};
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-6]]:5: note: frame #0: function 'operator()'
+// CHECK-MESSAGES: :175:7: note: frame #1: function 'unhandled_exception' throws unhandled exception here
const auto i_ShouldNotDiag =
[](const int a,
@@ -879,6 +1001,8 @@ const auto j_ShouldDiag =
if (b == 0)
throw b;
};
+// CHECK-MESSAGES: :[[@LINE-7]]:5: note: example of unhandled exception throw stack, starting from function 'operator()'
+// CHECK-MESSAGES: :[[@LINE-3]]:5: note: frame #0: function 'operator()' throws unhandled exception here
} // namespace coawait
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-rethrow.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-rethrow.cpp
index 6f961a247b9d2..a58717fc7104b 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-rethrow.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-rethrow.cpp
@@ -22,6 +22,8 @@ int throwsAndCallsRethrower() noexcept {
}
return 1;
}
+// CHECK-MESSAGES: :[[@LINE-9]]:5: note: example of unhandled exception throw stack, starting from function 'throwsAndCallsRethrower'
+// CHECK-MESSAGES: :[[@LINE-7]]:9: note: frame #0: function 'throwsAndCallsRethrower' throws unhandled exception here
int throwsAndCallsCallsRethrower() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'throwsAndCallsCallsRethrower' which should not throw exceptions
@@ -32,6 +34,8 @@ int throwsAndCallsCallsRethrower() noexcept {
}
return 1;
}
+// CHECK-MESSAGES: :[[@LINE-9]]:5: note: example of unhandled exception throw stack, starting from function 'throwsAndCallsCallsRethrower'
+// CHECK-MESSAGES: :[[@LINE-7]]:9: note: frame #0: function 'throwsAndCallsCallsRethrower' throws unhandled exception here
void rethrowerNoexcept() noexcept {
throw;
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-throw.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-throw.cpp
index 4a0113b8be3b3..1dd569de94af2 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-throw.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape-throw.cpp
@@ -4,6 +4,8 @@ void throwing_throw_nothing() throw() {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throwing_throw_nothing' which should not throw exceptions
throw 1;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: example of unhandled exception throw stack, starting from function 'throwing_throw_nothing'
+// CHECK-MESSAGES: :[[@LINE-3]]:3: note: frame #0: function 'throwing_throw_nothing' throws unhandled exception here
void explicit_int_thrower() throw(int);
@@ -15,11 +17,15 @@ void indirect_implicit() throw() {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'indirect_implicit' which should not throw exceptions
implicit_int_thrower();
}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: example of unhandled exception throw stack, starting from function 'indirect_implicit'
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: frame #0: function 'indirect_implicit'
+// CHECK-MESSAGES: :[[@LINE-9]]:3: note: frame #1: function 'implicit_int_thrower' throws unhandled exception here
void indirect_explicit() throw() {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'indirect_explicit' which should not throw exceptions
explicit_int_thrower();
}
+// FIXME: no diagnostics because 'explicit_int_thrower' has no explicit 'throw' expression
struct super_throws {
super_throws() throw(int) { throw 42; }
@@ -29,3 +35,6 @@ struct sub_throws : super_throws {
sub_throws() throw() : super_throws() {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'sub_throws' which should not throw exceptions
};
+// CHECK-MESSAGES: :[[@LINE-3]]:3: note: example of unhandled exception throw stack, starting from function 'sub_throws'
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: frame #0: function 'sub_throws'
+// CHECK-MESSAGES: :[[@LINE-9]]:31: note: frame #1: function 'super_throws' throws unhandled exception here
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
index aae957dd7e090..8f9178eb64852 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
@@ -12,6 +12,8 @@ struct throwing_destructor {
throw 1;
}
};
+// CHECK-MESSAGES: :[[@LINE-5]]:3: note: example of unhandled exception throw stack, starting from function '~throwing_destructor'
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: frame #0: function '~throwing_destructor' throws unhandled exception here
struct throwing_move_constructor {
throwing_move_constructor(throwing_move_constructor&&) {
@@ -19,6 +21,8 @@ struct throwing_move_constructor {
throw 1;
}
};
+// CHECK-MESSAGES: :[[@LINE-5]]:3: note: example of unhandled exception throw stack, starting from function 'throwing_move_constructor'
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: frame #0: function 'throwing_move_constructor' throws unhandled exception here
struct throwing_move_assignment {
throwing_move_assignment& operator=(throwing_move_assignment&&) {
@@ -26,11 +30,15 @@ struct throwing_move_assignment {
throw 1;
}
};
+// CHECK-MESSAGES: :[[@LINE-5]]:29: note: example of unhandled exception throw stack, starting from function 'operator='
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: frame #0: function 'operator=' throws unhandled exception here
void throwing_noexcept() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throwing_noexcept' which should not throw exceptions
throw 1;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: example of unhandled exception throw stack, starting from function 'throwing_noexcept'
+// CHECK-MESSAGES: :[[@LINE-3]]:3: note: frame #0: function 'throwing_noexcept' throws unhandled exception here
void throw_and_catch() noexcept {
// CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_and_catch' which should not throw exceptions
@@ -48,6 +56,8 @@ void throw_and_catch_some(int n) noexcept {
} catch(int &) {
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_and_catch_some'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_and_catch_some' throws unhandled exception here
void throw_and_catch_each(int n) noexcept {
// CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_and_catch_each' which should not throw exceptions
@@ -76,6 +86,8 @@ void throw_and_rethrow() noexcept {
throw;
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_and_rethrow'
+// CHECK-MESSAGES: :[[@LINE-6]]:5: note: frame #0: function 'throw_and_rethrow' throws unhandled exception here
void throw_catch_throw() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_catch_throw' which should not throw exceptions
@@ -85,6 +97,8 @@ void throw_catch_throw() noexcept {
throw 2;
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_catch_throw'
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: frame #0: function 'throw_catch_throw' throws unhandled exception here
void throw_catch_rethrow_the_rest(int n) noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_catch_rethrow_the_rest' which should not throw exceptions
@@ -96,6 +110,8 @@ void throw_catch_rethrow_the_rest(int n) noexcept {
throw;
}
}
+// CHECK-MESSAGES: :[[@LINE-10]]:6: note: example of unhandled exception throw stack, starting from function 'throw_catch_rethrow_the_rest'
+// CHECK-MESSAGES: :[[@LINE-7]]:5: note: frame #0: function 'throw_catch_rethrow_the_rest' throws unhandled exception here
void throw_catch_pointer_c() noexcept {
try {
@@ -126,6 +142,8 @@ void throw_catch_multi_ptr_1() noexcept {
} catch (const char **) {
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_catch_multi_ptr_1'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_catch_multi_ptr_1' throws unhandled exception here
void throw_catch_multi_ptr_2() noexcept {
try {
@@ -171,6 +189,8 @@ void throw_c_catch_pointer() noexcept {
throw p;
} catch(int *) {}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_c_catch_pointer'
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: frame #0: function 'throw_c_catch_pointer' throws unhandled exception here
void throw_c_catch_pointer_v() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_c_catch_pointer_v' which should not throw exceptions
@@ -180,6 +200,8 @@ void throw_c_catch_pointer_v() noexcept {
throw p;
} catch(volatile int *) {}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_c_catch_pointer_v'
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: frame #0: function 'throw_c_catch_pointer_v' throws unhandled exception here
void throw_v_catch_pointer() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_v_catch_pointer' which should not throw exceptions
@@ -189,6 +211,8 @@ void throw_v_catch_pointer() noexcept {
throw p;
} catch(int *) {}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_v_catch_pointer'
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: frame #0: function 'throw_v_catch_pointer' throws unhandled exception here
void throw_v_catch_pointer_c() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_v_catch_pointer_c' which should not throw exceptions
@@ -198,6 +222,8 @@ void throw_v_catch_pointer_c() noexcept {
throw p;
} catch(const int *) {}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_v_catch_pointer_c'
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: frame #0: function 'throw_v_catch_pointer_c' throws unhandled exception here
void throw_cv_catch_pointer_c() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_cv_catch_pointer_c' which should not throw exceptions
@@ -207,6 +233,8 @@ void throw_cv_catch_pointer_c() noexcept {
throw p;
} catch(const int *) {}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_cv_catch_pointer_c'
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: frame #0: function 'throw_cv_catch_pointer_c' throws unhandled exception here
void throw_cv_catch_pointer_v() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_cv_catch_pointer_v' which should not throw exceptions
@@ -216,6 +244,8 @@ void throw_cv_catch_pointer_v() noexcept {
throw p;
} catch(volatile int *) {}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_cv_catch_pointer_v'
+// CHECK-MESSAGES: :[[@LINE-4]]:5: note: frame #0: function 'throw_cv_catch_pointer_v' throws unhandled exception here
class base {};
class derived: public base {};
@@ -263,6 +293,8 @@ void throw_derived_catch_base_ptr() noexcept {
} catch(base *) {
}
}
+// CHECK-MESSAGES: :[[@LINE-9]]:6: note: example of unhandled exception throw stack, starting from function 'throw_derived_catch_base_ptr'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_derived_catch_base_ptr' throws unhandled exception here
class A {};
class B : A {};
@@ -286,6 +318,8 @@ void throw_derived_catch_base_private() noexcept {
} catch(A) {
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_derived_catch_base_private'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_derived_catch_base_private' throws unhandled exception here
void throw_derived_catch_base_private_ptr() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base_private_ptr' which should not throw exceptions
@@ -295,6 +329,8 @@ void throw_derived_catch_base_private_ptr() noexcept {
} catch(A *) {
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_derived_catch_base_private_ptr'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_derived_catch_base_private_ptr' throws unhandled exception here
void throw_derived_catch_base_protected() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base_protected' which should not throw exceptions
@@ -304,6 +340,8 @@ void throw_derived_catch_base_protected() noexcept {
} catch(A) {
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_derived_catch_base_protected'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_derived_catch_base_protected' throws unhandled exception here
void throw_derived_catch_base_protected_ptr() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base_protected_ptr' which should not throw exceptions
@@ -313,6 +351,8 @@ void throw_derived_catch_base_protected_ptr() noexcept {
} catch(A *) {
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_derived_catch_base_protected_ptr'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_derived_catch_base_protected_ptr' throws unhandled exception here
void throw_derived_catch_base_ambiguous() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base_ambiguous' which should not throw exceptions
@@ -322,6 +362,8 @@ void throw_derived_catch_base_ambiguous() noexcept {
} catch(A) {
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_derived_catch_base_ambiguous'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_derived_catch_base_ambiguous' throws unhandled exception here
void throw_derived_catch_base_ambiguous_ptr() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derived_catch_base_ambiguous_ptr' which should not throw exceptions
@@ -331,6 +373,8 @@ void throw_derived_catch_base_ambiguous_ptr() noexcept {
} catch(A) {
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_derived_catch_base_ambiguous_ptr'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_derived_catch_base_ambiguous_ptr' throws unhandled exception here
void throw_alias_catch_original() noexcept {
using alias = int;
@@ -352,6 +396,8 @@ void throw_alias_catch_original_warn() noexcept {
} catch (int) {
}
}
+// CHECK-MESSAGES: :[[@LINE-10]]:6: note: example of unhandled exception throw stack, starting from function 'throw_alias_catch_original_warn'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_alias_catch_original_warn' throws unhandled exception here
void throw_original_catch_alias() noexcept {
using alias = char;
@@ -373,6 +419,8 @@ void throw_original_catch_alias_warn() noexcept {
} catch (volatile const alias *const *) {
}
}
+// CHECK-MESSAGES: :[[@LINE-10]]:6: note: example of unhandled exception throw stack, starting from function 'throw_original_catch_alias_warn'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_original_catch_alias_warn' throws unhandled exception here
void throw_original_catch_alias_2() noexcept {
using alias = const char *const;
@@ -433,6 +481,8 @@ void throw_basefn_catch_derivedfn() noexcept {
} catch(void(derivedMember::*)()) {
}
}
+// CHECK-MESSAGES: :[[@LINE-7]]:6: note: example of unhandled exception throw stack, starting from function 'throw_basefn_catch_derivedfn'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_basefn_catch_derivedfn' throws unhandled exception here
void throw_basefn_catch_basefn() noexcept {
try {
@@ -449,6 +499,8 @@ void throw_basem_catch_basem_throw() noexcept {
} catch(const int* baseMember::* const *) {
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_basem_catch_basem_throw'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_basem_catch_basem_throw' throws unhandled exception here
void throw_basem_catch_basem() noexcept {
try {
@@ -466,6 +518,8 @@ void throw_basem_catch_derivedm() noexcept {
} catch(const int* const derivedMember::* const *) {
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_basem_catch_derivedm'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_basem_catch_derivedm' throws unhandled exception here
void throw_derivedm_catch_basem() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_derivedm_catch_basem' which should not throw exceptions
@@ -475,6 +529,8 @@ void throw_derivedm_catch_basem() noexcept {
} catch(const int* const baseMember::* const *) {
}
}
+// CHECK-MESSAGES: :[[@LINE-8]]:6: note: example of unhandled exception throw stack, starting from function 'throw_derivedm_catch_basem'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_derivedm_catch_basem' throws unhandled exception here
void throw_original_catch_alias_2_warn() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_original_catch_alias_2_warn' which should not throw exceptions
@@ -486,6 +542,8 @@ void throw_original_catch_alias_2_warn() noexcept {
} catch (volatile alias *) {
}
}
+// CHECK-MESSAGES: :[[@LINE-10]]:6: note: example of unhandled exception throw stack, starting from function 'throw_original_catch_alias_2_warn'
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: frame #0: function 'throw_original_catch_alias_2_warn' throws unhandled exception here
void try_nested_try(int n) noexcept {
// CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'try_nested_try' which should not throw exceptions
@@ -510,6 +568,8 @@ void bad_try_nested_try(int n) noexcept {
} catch(double &) {
}
}
+// CHECK-MESSAGES: :[[@LINE-11]]:6: note: example of unhandled exception throw stack, starting from function 'bad_try_nested_try'
+// CHECK-MESSAGES: :[[@LINE-9]]:12: note: frame #0: function 'bad_try_nested_try' throws unhandled exception here
void try_nested_catch() noexcept {
// CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'try_nested_catch' which should not throw exceptions
@@ -547,6 +607,8 @@ void bad_catch_nested_try() noexcept {
} catch(double &) {
}
}
+// CHECK-MESSAGES: :[[@LINE-12]]:6: note: example of unhandled exception throw stack, starting from function 'bad_catch_nested_try'
+// CHECK-MESSAGES: :[[@LINE-7]]:7: note: frame #0: function 'bad_catch_nested_try' throws unhandled exception here
void implicit_int_thrower() {
throw 1;
@@ -560,11 +622,17 @@ void indirect_implicit() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'indirect_implicit' which should not throw exceptions
implicit_int_thrower();
}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: example of unhandled exception throw stack, starting from function 'indirect_implicit'
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: frame #0: function 'indirect_implicit'
+// CHECK-MESSAGES: :[[@LINE-13]]:3: note: frame #1: function 'implicit_int_thrower' throws unhandled exception here
void indirect_explicit() noexcept {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'indirect_explicit' which should not throw exceptions
explicit_int_thrower();
}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: example of unhandled exception throw stack, starting from function 'indirect_explicit'
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: frame #0: function 'indirect_explicit'
+// CHECK-MESSAGES: :[[@LINE-17]]:3: note: frame #1: function 'explicit_int_thrower' throws unhandled exception here
void indirect_catch() noexcept {
// CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'indirect_catch' which should not throw exceptions
@@ -585,16 +653,22 @@ void swap(int&, int&) {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'swap' which should not throw exceptions
throw 1;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: example of unhandled exception throw stack, starting from function 'swap'
+// CHECK-MESSAGES: :[[@LINE-3]]:3: note: frame #0: function 'swap' throws unhandled exception here
void iter_swap(int&, int&) {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'iter_swap' which should not throw exceptions
throw 1;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: example of unhandled exception throw stack, starting from function 'iter_swap'
+// CHECK-MESSAGES: :[[@LINE-3]]:3: note: frame #0: function 'iter_swap' throws unhandled exception here
void iter_move(int&) {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'iter_move' which should not throw exceptions
throw 1;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: example of unhandled exception throw stack, starting from function 'iter_move'
+// CHECK-MESSAGES: :[[@LINE-3]]:3: note: frame #0: function 'iter_move' throws unhandled exception here
namespace std {
class bad_alloc {};
@@ -613,11 +687,16 @@ void enabled1() {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'enabled1' which should not throw exceptions
throw 1;
}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: example of unhandled exception throw stack, starting from function 'enabled1'
+// CHECK-MESSAGES: :[[@LINE-3]]:3: note: frame #0: function 'enabled1' throws unhandled exception here
void enabled2() {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'enabled2' which should not throw exceptions
enabled1();
}
+// CHECK-MESSAGES: :[[@LINE-4]]:6: note: example of unhandled exception throw stack, starting from function 'enabled2'
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: frame #0: function 'enabled2'
+// CHECK-MESSAGES: :[[@LINE-11]]:3: note: frame #1: function 'enabled1' throws unhandled exception here
void enabled3() {
// CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'enabled3' which should not throw exceptions
@@ -649,6 +728,8 @@ void this_counts(int n) noexcept {
if (n) throw 1;
throw ignored1();
}
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: example of unhandled exception throw stack, starting from function 'this_counts'
+// CHECK-MESSAGES: :[[@LINE-4]]:10: note: frame #0: function 'this_counts' throws unhandled exception here
void thrower(int n) {
throw n;
@@ -660,6 +741,9 @@ int directly_recursive(int n) noexcept {
thrower(n);
return directly_recursive(n);
}
+// CHECK-MESSAGES: :[[@LINE-6]]:5: note: example of unhandled exception throw stack, starting from function 'directly_recursive'
+// CHECK-MESSAGES: :[[@LINE-7]]:5: note: frame #0: function 'directly_recursive'
+// CHECK-MESSAGES: :[[@LINE-11]]:3: note: frame #1: function 'thrower' throws unhandled exception here
int indirectly_recursive(int n) noexcept;
@@ -683,6 +767,9 @@ struct sub_throws : super_throws {
sub_throws() noexcept : super_throws() {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'sub_throws' which should not throw exceptions
};
+// CHECK-MESSAGES: :[[@LINE-3]]:3: note: example of unhandled exception throw stack, starting from function 'sub_throws'
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: frame #0: function 'sub_throws'
+// CHECK-MESSAGES: :[[@LINE-9]]:36: note: frame #1: function 'super_throws' throws unhandled exception here
struct init_member_throws {
super_throws s;
@@ -690,6 +777,8 @@ struct init_member_throws {
init_member_throws() noexcept : s() {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'init_member_throws' which should not throw exceptions
};
+// CHECK-MESSAGES: :[[@LINE-3]]:3: note: example of unhandled exception throw stack, starting from function 'init_member_throws'
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: frame #0: function 'init_member_throws'
struct implicit_init_member_throws {
super_throws s;
@@ -697,6 +786,8 @@ struct implicit_init_member_throws {
implicit_init_member_throws() noexcept {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'implicit_init_member_throws' which should not throw exceptions
};
+// CHECK-MESSAGES: :[[@LINE-3]]:3: note: example of unhandled exception throw stack, starting from function 'implicit_init_member_throws'
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: frame #0: function 'implicit_init_member_throws'
struct init {
explicit init(int, int) noexcept(false) { throw 42; }
@@ -708,18 +799,25 @@ struct in_class_init_throws {
in_class_init_throws() noexcept {}
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: an exception may be thrown in function 'in_class_init_throws' which should not throw exceptions
};
+// CHECK-MESSAGES: :[[@LINE-3]]:3: note: example of unhandled exception throw stack, starting from function 'in_class_init_throws'
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: frame #0: function 'in_class_init_throws'
+// CHECK-MESSAGES: :[[@LINE-11]]:45: note: frame #1: function 'init' throws unhandled exception here
int main() {
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'main' which should not throw exceptions
throw 1;
return 0;
}
+// CHECK-MESSAGES: :[[@LINE-5]]:5: note: example of unhandled exception throw stack, starting from function 'main'
+// CHECK-MESSAGES: :[[@LINE-4]]:3: note: frame #0: function 'main' throws unhandled exception here
// The following function all incorrectly throw exceptions, *but* calling them
// should not yield a warning because they are marked as noexcept.
void test_basic_no_throw() noexcept { throw 42; }
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'test_basic_no_throw' which should not throw exceptions
+// CHECK-MESSAGES: :[[@LINE-2]]:6: note: example of unhandled exception throw stack, starting from function 'test_basic_no_throw'
+// CHECK-MESSAGES: :[[@LINE-3]]:39: note: frame #0: function 'test_basic_no_throw' throws unhandled exception here
void test_basic_throw() noexcept(false) { throw 42; }
@@ -732,6 +830,9 @@ void calls_non_and_throwing() noexcept {
test_basic_no_throw();
test_basic_throw();
}
+// CHECK-MESSAGES: :[[@LINE-5]]:6: note: example of unhandled exception throw stack, starting from function 'calls_non_and_throwing'
+// CHECK-MESSAGES: :[[@LINE-6]]:6: note: frame #0: function 'calls_non_and_throwing'
+// CHECK-MESSAGES: :[[@LINE-13]]:43: note: frame #1: function 'test_basic_throw' throws unhandled exception here
namespace PR55143 { namespace PR40583 {
@@ -749,11 +850,17 @@ struct test_implicit_throw {
test_implicit_throw(const test_implicit_throw&) { throw 42; }
test_implicit_throw(test_implicit_throw&&) { throw 42; }
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function 'test_implicit_throw' which should not throw exceptions
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: note: example of unhandled exception throw stack, starting from function 'test_implicit_throw'
+ // CHECK-MESSAGES: :[[@LINE-3]]:50: note: frame #0: function 'test_implicit_throw'
test_implicit_throw& operator=(const test_implicit_throw&) { throw 42; }
test_implicit_throw& operator=(test_implicit_throw&&) { throw 42; }
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: an exception may be thrown in function 'operator=' which should not throw exceptions
+ // CHECK-MESSAGES: :[[@LINE-2]]:26: note: example of unhandled exception throw stack, starting from function 'operator='
+ // CHECK-MESSAGES: :[[@LINE-3]]:61: note: frame #0: function 'operator='
~test_implicit_throw() { throw 42; }
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: an exception may be thrown in function '~test_implicit_throw' which should not throw exceptions
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: note: example of unhandled exception throw stack, starting from function '~test_implicit_throw'
+ // CHECK-MESSAGES: :[[@LINE-3]]:30: note: frame #0: function '~test_implicit_throw'
};
}}
>From 63c7ec8051a10ece69ad6bef777b76f7a3222ff9 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Fri, 4 Apr 2025 15:39:20 +0300
Subject: [PATCH 2/2] [clang-tidy] add ReleaseNotes
---
clang-tools-extra/docs/ReleaseNotes.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 6cb8d572d3a78..36d06fce7232e 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -121,6 +121,10 @@ New check aliases
Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^
+- Improved :doc:`bugprone-exception-escape
+ <clang-tidy/checks/bugprone/exception-escape>` check to print stack trace
+ of a potentially escaped exception.
+
- Improved :doc:`bugprone-optional-value-conversion
<clang-tidy/checks/bugprone/optional-value-conversion>` check to detect
conversion in argument of ``std::make_optional``.
More information about the cfe-commits
mailing list