Author: Victor Chernyakin
Date: 2025-11-08T02:23:32-08:00
New Revision: 577b5194bf7a0decfec1b88c5afe96426c2b45fe

URL: 
https://github.com/llvm/llvm-project/commit/577b5194bf7a0decfec1b88c5afe96426c2b45fe
DIFF: 
https://github.com/llvm/llvm-project/commit/577b5194bf7a0decfec1b88c5afe96426c2b45fe.diff

LOG: [clang-tidy] Fix `bugprone-exception-escape` not diagnosing throws in 
argument lists (#165955)

Fixes #165766.

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
    clang-tools-extra/docs/ReleaseNotes.rst
    clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp 
b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
index 5fd1b731707e7..8ead26407ee5d 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -562,17 +562,6 @@ ExceptionAnalyzer::throwsException(const Stmt *St,
       }
     }
     Results.merge(Uncaught);
-  } else if (const auto *Call = dyn_cast<CallExpr>(St)) {
-    if (const FunctionDecl *Func = Call->getDirectCallee()) {
-      const ExceptionInfo Excs =
-          throwsException(Func, Caught, CallStack, Call->getBeginLoc());
-      Results.merge(Excs);
-    }
-  } else if (const auto *Construct = dyn_cast<CXXConstructExpr>(St)) {
-    const ExceptionInfo Excs =
-        throwsException(Construct->getConstructor(), Caught, CallStack,
-                        Construct->getBeginLoc());
-    Results.merge(Excs);
   } else if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(St)) {
     const ExceptionInfo Excs =
         throwsException(DefaultInit->getExpr(), Caught, CallStack);
@@ -602,10 +591,25 @@ ExceptionAnalyzer::throwsException(const Stmt *St,
       Results.merge(Excs);
     }
   } else {
+    // Check whether any of this node's subexpressions throws.
     for (const Stmt *Child : St->children()) {
       const ExceptionInfo Excs = throwsException(Child, Caught, CallStack);
       Results.merge(Excs);
     }
+
+    // If this node is a call to a function or constructor, also check
+    // whether the call itself throws.
+    if (const auto *Call = dyn_cast<CallExpr>(St)) {
+      if (const FunctionDecl *Func = Call->getDirectCallee()) {
+        ExceptionInfo Excs =
+            throwsException(Func, Caught, CallStack, Call->getBeginLoc());
+        Results.merge(Excs);
+      }
+    } else if (const auto *Construct = dyn_cast<CXXConstructExpr>(St)) {
+      ExceptionInfo Excs = throwsException(Construct->getConstructor(), Caught,
+                                           CallStack, 
Construct->getBeginLoc());
+      Results.merge(Excs);
+    }
   }
   return Results;
 }

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 92a2d33d8fa16..666865cfb2fcd 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -300,7 +300,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. Additionally, fixed an issue
+  where the check wouldn't diagnose throws in arguments to functions or
+  constructors.
 
 - Improved :doc:`bugprone-infinite-loop
   <clang-tidy/checks/bugprone/infinite-loop>` check by adding detection for

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 a52bbe2246d1e..140c93f5c2536 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
@@ -948,7 +948,7 @@ const auto throw_in_noexcept_lambda = [] () noexcept { 
throw 42; };
 // CHECK-MESSAGES: :[[@LINE-1]]:39: warning: an exception may be thrown in 
function 'operator()' which should not throw exceptions
 // CHECK-MESSAGES: :[[@LINE-2]]:56: note: frame #0: unhandled exception of 
type 'int' may be thrown in function 'operator()' here
 
-void thrower() {
+int thrower() {
   throw 42;
 }
 
@@ -956,3 +956,54 @@ const auto indirect_throw_in_noexcept_lambda = [] () 
noexcept { thrower(); };
 // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: an exception may be thrown in 
function 'operator()' which should not throw exceptions
 // CHECK-MESSAGES: :[[@LINE-5]]:3: note: frame #0: unhandled exception of type 
'int' may be thrown in function 'thrower' here
 // CHECK-MESSAGES: :[[@LINE-3]]:65: note: frame #1: function 'operator()' 
calls function 'thrower' here
+
+int f(int);
+void throw_in_function_arg() noexcept {
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in 
function 'throw_in_function_arg' which should not throw exceptions
+  f(false ? 0 : throw 1);
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:17: note: frame #0: unhandled exception of 
type 'int' may be thrown in function 'throw_in_function_arg' here
+
+int g(int, int, int);
+void throw_in_last_function_arg() noexcept {
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in 
function 'throw_in_last_function_arg' which should not throw exceptions
+  g(42, 67, false ? 0 : throw 1);
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:25: note: frame #0: unhandled exception of 
type 'int' may be thrown in function 'throw_in_last_function_arg' here
+
+void indirect_throw_in_function_arg() noexcept {
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in 
function 'indirect_throw_in_function_arg' which should not throw exceptions
+  f(thrower());
+}
+// CHECK-MESSAGES: :[[@LINE-26]]:3: note: frame #0: unhandled exception of 
type 'int' may be thrown in function 'thrower' here
+// CHECK-MESSAGES: :[[@LINE-3]]:5: note: frame #1: function 
'indirect_throw_in_function_arg' calls function 'thrower' here
+
+void indirect_throw_from_lambda_in_function_arg() noexcept {
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in 
function 'indirect_throw_from_lambda_in_function_arg' which should not throw 
exceptions
+  f([] { throw 1; return 0; }());
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:10: note: frame #0: unhandled exception of 
type 'int' may be thrown in function 'operator()' here
+// CHECK-MESSAGES: :[[@LINE-3]]:30: note: frame #1: function 
'indirect_throw_from_lambda_in_function_arg' calls function 'operator()' here
+
+struct S {
+  S(int) noexcept {}
+};
+
+void throw_in_constructor_arg() noexcept {
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in 
function 'throw_in_constructor_arg' which should not throw exceptions
+  S s(false ? 0 : throw 1);
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:19: note: frame #0: unhandled exception of 
type 'int' may be thrown in function 'throw_in_constructor_arg' here
+
+void indirect_throw_in_constructor_arg() noexcept {
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in 
function 'indirect_throw_in_constructor_arg' which should not throw exceptions
+  S s = thrower();
+}
+// CHECK-MESSAGES: :[[@LINE-50]]:3: note: frame #0: unhandled exception of 
type 'int' may be thrown in function 'thrower' here
+// CHECK-MESSAGES: :[[@LINE-3]]:9: note: frame #1: function 
'indirect_throw_in_constructor_arg' calls function 'thrower' here
+
+void weird_throw_in_call_subexpression() noexcept {
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in 
function 'weird_throw_in_call_subexpression' which should not throw exceptions
+  (false ? []{} : throw 1)();
+}
+// CHECK-MESSAGES: :[[@LINE-2]]:19: note: frame #0: unhandled exception of 
type 'int' may be thrown in function 'weird_throw_in_call_subexpression' here


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to