Author: Zeyi Xu
Date: 2026-04-11T12:39:24+08:00
New Revision: f6167ec430d9323652e8914602085ae1d4ee780c

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

LOG: [clang-tidy] Fix FP in bugprone-exception-escape with unevaluated 
exception specs (#190593)

Functions whose exception spec has not yet been evaluated have no body
in the AST. Because the compiler does not generate call sites for these
functions before evaluating their spec, they cannot propagate
exceptions.

Closes https://github.com/llvm/llvm-project/issues/188730

Added: 
    

Modified: 
    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/utils/ExceptionAnalyzer.cpp 
b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
index 9165be3c850d7..8f0d6b1360cd5 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -330,6 +330,12 @@ static bool canThrow(const FunctionDecl *Func) {
   if (!FunProto)
     return true;
 
+  // Clang evaluates unresolved exception specs before generating any call to
+  // the function, so these functions cannot appear at a call site and cannot
+  // throw.
+  if (isUnresolvedExceptionSpec(FunProto->getExceptionSpecType()))
+    return false;
+
   switch (FunProto->canThrow()) {
   case CT_Cannot:
     return false;
@@ -499,6 +505,9 @@ ExceptionAnalyzer::ExceptionInfo 
ExceptionAnalyzer::throwsException(
   auto Result = ExceptionInfo::createUnknown();
 
   if (const auto *FPT = Func->getType()->getAs<FunctionProtoType>()) {
+    if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
+      return ExceptionInfo::createNonThrowing();
+
     for (const QualType &Ex : FPT->exceptions()) {
       CallStack.insert({Func, CallLoc});
       Result.registerException(

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 6f955fa5a012a..9ff54acff6729 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
@@ -68,22 +68,18 @@ struct Member {
 };
 
 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;
 };
 
+template <typename T>
+struct TmplNoexcept {
+  void method() noexcept(noexcept(T())) {}
+};
+
+void instantiate_tmpl_noexcept() {
+  TmplNoexcept<int> t;
+}
+
 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


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

Reply via email to