diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 2bb0ce68b17..5675a5d9812 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -928,8 +928,12 @@ fn landing_pad( pers_fn: &'ll Value, num_clauses: usize, ) -> &'ll Value { + // Use LLVMSetPersonalityFn to set the personality. It supports arbitrary Consts while, + // LLVMBuildLandingPad requires the argument to be a Function (as of LLVM 12). The + // personality lives on the parent function anyway. + self.set_personality_fn(pers_fn); unsafe { - llvm::LLVMBuildLandingPad(self.llbuilder, ty, pers_fn, num_clauses as c_uint, UNNAMED) + llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED) } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index d6a60956555..59259857b4b 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -386,11 +386,16 @@ fn eh_personality(&self) -> &'ll Value { } else { "rust_eh_personality" }; - let fty = self.type_variadic_func(&[], self.type_i32()); - self.declare_cfn(name, llvm::UnnamedAddr::Global, fty) + if let Some(llfn) = self.get_declared_value(name) { + llfn + } else { + let fty = self.type_variadic_func(&[], self.type_i32()); + let llfn = self.declare_cfn(name, llvm::UnnamedAddr::Global, fty); + attributes::apply_target_cpu_attr(self, llfn); + llfn + } } }; - attributes::apply_target_cpu_attr(self, llfn); self.eh_personality.set(Some(llfn)); llfn } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 2ade66ac41e..68d566cca09 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1165,7 +1165,7 @@ pub fn LLVMRustBuildInvoke( pub fn LLVMBuildLandingPad( B: &Builder<'a>, Ty: &'a Type, - PersFn: &'a Value, + PersFn: Option<&'a Value>, NumClauses: c_uint, Name: *const c_char, ) -> &'a Value; diff --git a/src/test/ui/panic-runtime/incompatible-type.rs b/src/test/ui/panic-runtime/incompatible-type.rs new file mode 100644 index 00000000000..026364a2058 --- /dev/null +++ b/src/test/ui/panic-runtime/incompatible-type.rs @@ -0,0 +1,24 @@ +// Check that rust_eh_personality can have a different type signature than the +// one hardcoded in the compiler. Regression test for #70117. Used to fail with: +// +// Assertion `isa(Val) && "cast() argument of incompatible type!"' failed. +// +// build-pass +// compile-flags: --crate-type=lib -Ccodegen-units=1 +#![no_std] +#![panic_runtime] +#![feature(panic_runtime)] +#![feature(rustc_attrs)] + +pub struct DropMe; + +impl Drop for DropMe { + fn drop(&mut self) {} +} + +pub fn test(_: DropMe) { + unreachable!(); +} + +#[rustc_std_internal_symbol] +pub unsafe extern "C" fn rust_eh_personality() {}