[clang] [Clang][CodeGen] Inherit calling convention from runtime function declarations (PR #222200)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 8 17:04:43 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: AZero13 (AZero13)
<details>
<summary>Changes</summary>
On 32-bit x86 targets using the Microsoft C++ ABI, `_CxxThrowException` requires the `__stdcall` (`x86_stdcallcc`) calling convention. While `MicrosoftCXXABI::getThrowFn()` correctly set this calling convention on the function declaration, the generated LLVM IR `call` instructions were incorrectly emitted using the default `__cdecl` calling convention. This mismatch corrupted the stack (since `stdcall` requires the callee to clean up arguments, but `cdecl` expects the caller to do it), leading to crashes when throwing exceptions.
Fixes #<!-- -->158302
---
Full diff: https://github.com/llvm/llvm-project/pull/222200.diff
2 Files Affected:
- (modified) clang/lib/CodeGen/CGCall.cpp (+15-3)
- (added) clang/test/CodeGenCXX/microsoft-abi-throw-stdcall.cpp (+13)
``````````diff
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 1221829871b9f..50e6403846259 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -5487,15 +5487,22 @@ void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(
SmallVector<llvm::OperandBundleDef, 1> BundleList =
getBundlesForFunclet(callee.getCallee());
+ llvm::CallingConv::ID CC;
+ // Get the calling convention from the callee if it's a function.
+ if (auto *Fn = dyn_cast<llvm::Function>(callee.getCallee()))
+ CC = Fn->getCallingConv();
+ else
+ CC = getRuntimeCC();
+
if (getInvokeDest()) {
llvm::InvokeInst *invoke = Builder.CreateInvoke(
callee, getUnreachableBlock(), getInvokeDest(), args, BundleList);
invoke->setDoesNotReturn();
- invoke->setCallingConv(getRuntimeCC());
+ invoke->setCallingConv(CC);
} else {
llvm::CallInst *call = Builder.CreateCall(callee, args, BundleList);
call->setDoesNotReturn();
- call->setCallingConv(getRuntimeCC());
+ call->setCallingConv(CC);
Builder.CreateUnreachable();
}
}
@@ -5513,7 +5520,12 @@ CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::FunctionCallee callee,
ArrayRef<llvm::Value *> args,
const Twine &name) {
llvm::CallBase *call = EmitCallOrInvoke(callee, args, name);
- call->setCallingConv(getRuntimeCC());
+ llvm::CallingConv::ID CC;
+ if (auto *Fn = dyn_cast<llvm::Function>(callee.getCallee()))
+ CC = Fn->getCallingConv();
+ else
+ CC = getRuntimeCC();
+ call->setCallingConv(CC);
return call;
}
diff --git a/clang/test/CodeGenCXX/microsoft-abi-throw-stdcall.cpp b/clang/test/CodeGenCXX/microsoft-abi-throw-stdcall.cpp
new file mode 100644
index 0000000000000..fa4e33b5a018d
--- /dev/null
+++ b/clang/test/CodeGenCXX/microsoft-abi-throw-stdcall.cpp
@@ -0,0 +1,13 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-windows-msvc19.0.0 -fcxx-exceptions -fms-extensions -fexceptions | FileCheck %s
+
+struct MyException {};
+// CHECK-LABEL: @f(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_MYEXCEPTION:%.*]], align 1
+// CHECK-NEXT: call x86_stdcallcc void @_CxxThrowException(ptr [[TMP]], ptr @"_TI1?AUMyException@@") #[[ATTR1:[0-9]+]]
+// CHECK-NEXT: unreachable
+//
+extern "C" void f() {
+ throw MyException();
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/222200
More information about the cfe-commits
mailing list