https://github.com/chfast updated 
https://github.com/llvm/llvm-project/pull/190945

From dc3b3933ca81f6f185097deebb5eaccc70ba04cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pawe=C5=82=20Bylica?= <[email protected]>
Date: Wed, 8 Apr 2026 10:57:03 +0200
Subject: [PATCH] [Clang] Allow musttail in noexcept functions when callee is
 nounwind

noexcept functions push an EHTerminateScope onto the cleanup stack.
The musttail codegen did not know how to skip this scope, causing
a "cannot compile this tail call skipping over cleanups yet" error
even when both caller and callee are noexcept.

Skip the EHTerminateScope when the callee is nounwind (noexcept).
The callee's own noexcept handler prevents any exception from
propagating, so the caller's terminate handler is unnecessary.

When the callee is not noexcept, emit a specific diagnostic:
"'musttail' in a noexcept function requires a noexcept callee".

Fixes #53087.
---
 .../clang/Basic/DiagnosticCommonKinds.td      |  2 ++
 clang/lib/CodeGen/CGCall.cpp                  | 12 +++++++
 .../CodeGenCXX/musttail-noexcept-error.cpp    |  9 +++++
 clang/test/CodeGenCXX/musttail-noexcept.cpp   | 34 +++++++++++++++++++
 4 files changed, 57 insertions(+)
 create mode 100644 clang/test/CodeGenCXX/musttail-noexcept-error.cpp
 create mode 100644 clang/test/CodeGenCXX/musttail-noexcept.cpp

diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td 
b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index cb267e3ee05c1..40ef9684f991c 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -385,6 +385,8 @@ def err_mips_impossible_musttail: Error<
   >;
 def err_aix_musttail_unsupported: Error<
   "'musttail' attribute is not supported on AIX">;
+def err_musttail_noexcept_mismatch: Error<
+  "'musttail' in a noexcept function requires a noexcept callee">;
 
 // Source manager
 def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal;
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 7d5dc53091c2b..fce9f4b12352e 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -6224,6 +6224,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo 
&CallInfo,
   if (IsMustTail) {
     for (auto it = EHStack.find(CurrentCleanupScopeDepth); it != EHStack.end();
          ++it) {
+      // A noexcept caller pushes an EHTerminateScope to call std::terminate()
+      // if an exception escapes. A musttail call replaces the caller's frame,
+      // removing this handler. This is safe if the callee is also nounwind:
+      // the callee's own noexcept handler prevents any exception from reaching
+      // where the caller's handler would have been.
+      if (isa<EHTerminateScope>(&*it)) {
+        if (CI->doesNotThrow())
+          continue;
+        CGM.getDiags().Report(MustTailCall->getBeginLoc(),
+                              diag::err_musttail_noexcept_mismatch);
+        break;
+      }
       EHCleanupScope *Cleanup = dyn_cast<EHCleanupScope>(&*it);
       // Fake uses can be safely emitted immediately prior to the tail call, so
       // we choose to emit them just before the call here.
diff --git a/clang/test/CodeGenCXX/musttail-noexcept-error.cpp 
b/clang/test/CodeGenCXX/musttail-noexcept-error.cpp
new file mode 100644
index 0000000000000..796bc908bd954
--- /dev/null
+++ b/clang/test/CodeGenCXX/musttail-noexcept-error.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm %s -triple 
x86_64-unknown-linux-gnu -o /dev/null -verify
+
+// Negative: musttail to a non-noexcept callee from a noexcept function.
+
+int ThrowingFunc(int);
+
+int TestThrowingCallee(int x) noexcept {
+  [[clang::musttail]] return ThrowingFunc(x); // expected-error {{'musttail' 
in a noexcept function requires a noexcept callee}}
+}
diff --git a/clang/test/CodeGenCXX/musttail-noexcept.cpp 
b/clang/test/CodeGenCXX/musttail-noexcept.cpp
new file mode 100644
index 0000000000000..2e60ac6889a24
--- /dev/null
+++ b/clang/test/CodeGenCXX/musttail-noexcept.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm %s -triple 
x86_64-unknown-linux-gnu -o - | FileCheck %s
+
+// musttail in noexcept functions should work when the callee is also noexcept.
+
+int NoexceptCallee(int) noexcept;
+int ThrowingFunc(int);
+
+// CHECK-LABEL: define {{.*}} @_Z12TestNoexcepti(
+// CHECK: musttail call {{.*}} @_Z14NoexceptCalleei(
+// CHECK-NEXT: ret i32
+int TestNoexcept(int x) noexcept {
+  [[clang::musttail]] return NoexceptCallee(x);
+}
+
+// Noexcept caller with regular call to non-noexcept, then musttail to 
noexcept.
+// CHECK-LABEL: define {{.*}} @_Z21TestMixedCallNoexcepti(
+// CHECK: invoke {{.*}} @_Z12ThrowingFunci(
+// CHECK-NEXT: to label %{{.*}} unwind label %terminate.lpad
+// CHECK: musttail call {{.*}} @_Z14NoexceptCalleei(
+// CHECK-NEXT: ret i32
+// CHECK: terminate.lpad:
+// CHECK: call void @__clang_call_terminate(
+int TestMixedCallNoexcept(int x) noexcept {
+  int y = ThrowingFunc(x);
+  [[clang::musttail]] return NoexceptCallee(y);
+}
+
+// Noexcept caller musttails to itself (recursive).
+// CHECK-LABEL: define {{.*}} @_Z13TestRecursivei(
+// CHECK: musttail call {{.*}} @_Z13TestRecursivei(
+// CHECK-NEXT: ret i32
+int TestRecursive(int x) noexcept {
+  [[clang::musttail]] return TestRecursive(x);
+}

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

Reply via email to