From 1a8c5be17f954dd8ec097d2f87c96c77b5f99455 Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Fri, 10 Apr 2026 09:11:56 +0800 Subject: [PATCH 1/8] Fix transmuted function pointer calls Cast function pointers to the ABI expected at the call site before emitting indirect calls so transmuted ZST arguments don't trip libgccjit's arity checks. Add a compile-only regression test for the ignored-argument case. --- src/builder.rs | 14 ++++++-------- tests/compile/fn_ptr_transmute_ignored_arg.rs | 11 +++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 tests/compile/fn_ptr_transmute_ignored_arg.rs diff --git a/src/builder.rs b/src/builder.rs index 6add7f05c2a..64b462667a0 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -354,14 +354,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { args: &[RValue<'gcc>], _funclet: Option<&Funclet>, ) -> RValue<'gcc> { - let gcc_func = match func_ptr.get_type().dyncast_function_ptr_type() { - Some(func) => func, - None => { - // NOTE: due to opaque pointers now being used, we need to cast here. - let new_func_type = typ.dyncast_function_ptr_type().expect("function ptr"); - func_ptr = self.context.new_cast(self.location, func_ptr, typ); - new_func_type - } + let gcc_func = if func_ptr.get_type() != typ { + let new_func_type = typ.dyncast_function_ptr_type().expect("function ptr"); + func_ptr = self.context.new_cast(self.location, func_ptr, typ); + new_func_type + } else { + func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr") }; let func_name = format!("{:?}", func_ptr); let previous_arg_count = args.len(); diff --git a/tests/compile/fn_ptr_transmute_ignored_arg.rs b/tests/compile/fn_ptr_transmute_ignored_arg.rs new file mode 100644 index 00000000000..5b69f02ef25 --- /dev/null +++ b/tests/compile/fn_ptr_transmute_ignored_arg.rs @@ -0,0 +1,11 @@ +// Compiler: + +extern "C" fn third(_a: usize, b: usize, c: usize) { + let throw_away_f: fn((), usize, usize) = + unsafe { std::mem::transmute(third as extern "C" fn(_, _, _)) }; + throw_away_f((), b, c) +} + +fn main() { + third(1, 2, 3); +} From ed85398ad210aec54d642e256bde7fe50f39591f Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Fri, 10 Apr 2026 09:29:52 +0800 Subject: [PATCH 2/8] Use crate_type = lib --- tests/compile/fn_ptr_transmute_ignored_arg.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/compile/fn_ptr_transmute_ignored_arg.rs b/tests/compile/fn_ptr_transmute_ignored_arg.rs index 5b69f02ef25..30f176abb7f 100644 --- a/tests/compile/fn_ptr_transmute_ignored_arg.rs +++ b/tests/compile/fn_ptr_transmute_ignored_arg.rs @@ -1,11 +1,11 @@ // Compiler: +// Regression test for + +#![crate_type = "lib"] + extern "C" fn third(_a: usize, b: usize, c: usize) { let throw_away_f: fn((), usize, usize) = unsafe { std::mem::transmute(third as extern "C" fn(_, _, _)) }; - throw_away_f((), b, c) -} - -fn main() { - third(1, 2, 3); + throw_away_f((), 2, 3) } From d252dd6473fb6f82424472bd41e74e89eda3efc9 Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Fri, 10 Apr 2026 09:52:26 +0800 Subject: [PATCH 3/8] Refactor --- src/builder.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 64b462667a0..8af9ee33c66 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -354,13 +354,16 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { args: &[RValue<'gcc>], _funclet: Option<&Funclet>, ) -> RValue<'gcc> { - let gcc_func = if func_ptr.get_type() != typ { - let new_func_type = typ.dyncast_function_ptr_type().expect("function ptr"); - func_ptr = self.context.new_cast(self.location, func_ptr, typ); - new_func_type - } else { - func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr") + let func_ptr_type = { + let func_ptr_type = func_ptr.get_type(); + if func_ptr_type != typ { + func_ptr = self.context.new_cast(self.location, func_ptr, typ); + typ + } else { + func_ptr_type + } }; + let gcc_func = func_ptr_type.dyncast_function_ptr_type().expect("function ptr"); let func_name = format!("{:?}", func_ptr); let previous_arg_count = args.len(); let orig_args = args; From e41c82ac0cc4798d452f1334a673f1071d713a29 Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Fri, 10 Apr 2026 10:14:51 +0800 Subject: [PATCH 4/8] Fix on-stack handling for indirect calls --- src/builder.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 8af9ee33c66..9b7a8d6504e 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -32,6 +32,7 @@ use rustc_span::def_id::DefId; use rustc_target::callconv::FnAbi; use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi}; +use crate::abi::FnAbiGccExt; use crate::common::{SignType, TypeReflection, type_is_pointer}; use crate::context::CodegenCx; use crate::errors; @@ -212,6 +213,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>], + on_stack_param_indices: &FxHashSet, ) -> Cow<'b, [RValue<'gcc>]> { let mut all_args_match = true; let mut param_types = vec![]; @@ -224,11 +226,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { param_types.push(param); } - let mut on_stack_param_indices = FxHashSet::default(); - if let Some(indices) = self.on_stack_params.borrow().get(&gcc_func) { - on_stack_param_indices.clone_from(indices); - } - if all_args_match { return Cow::Borrowed(args); } @@ -350,6 +347,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fn function_ptr_call( &mut self, typ: Type<'gcc>, + fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, mut func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>, @@ -364,6 +362,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } }; let gcc_func = func_ptr_type.dyncast_function_ptr_type().expect("function ptr"); + let on_stack_param_indices = if let Some(fn_abi) = fn_abi { + fn_abi.gcc_type(self.cx).on_stack_param_indices + } else { + self.on_stack_params.borrow().get(&gcc_func).cloned().unwrap_or_default() + }; let func_name = format!("{:?}", func_ptr); let previous_arg_count = args.len(); let orig_args = args; @@ -372,7 +375,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { llvm::adjust_intrinsic_arguments(self, gcc_func, args.into(), &func_name) }; let args_adjusted = args.len() != previous_arg_count; - let args = self.check_ptr_call("call", func_ptr, &args); + let args = self.check_ptr_call("call", func_ptr, &args, &on_stack_param_indices); // gccjit requires to use the result of functions, even when it's not used. // That's why we assign the result to a local or call add_eval(). @@ -1777,7 +1780,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.function_call(func, args, funclet) } else { // If it's a not function that was defined, it's a function pointer. - self.function_ptr_call(typ, func, args, funclet) + self.function_ptr_call(typ, fn_abi, func, args, funclet) }; if let Some(_fn_abi) = fn_abi { // FIXME(bjorn3): Apply function attributes From c8634656fe12f1a1dada0b095364349b1fa6c1a1 Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Fri, 10 Apr 2026 15:12:13 +0800 Subject: [PATCH 5/8] Add `#[unsafe(no_mangle)]` --- tests/compile/fn_ptr_transmute_ignored_arg.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compile/fn_ptr_transmute_ignored_arg.rs b/tests/compile/fn_ptr_transmute_ignored_arg.rs index 30f176abb7f..a4947da248e 100644 --- a/tests/compile/fn_ptr_transmute_ignored_arg.rs +++ b/tests/compile/fn_ptr_transmute_ignored_arg.rs @@ -4,6 +4,7 @@ #![crate_type = "lib"] +#[unsafe(no_mangle)] extern "C" fn third(_a: usize, b: usize, c: usize) { let throw_away_f: fn((), usize, usize) = unsafe { std::mem::transmute(third as extern "C" fn(_, _, _)) }; From 6824c31b3d1dae4112e1530df7106c692fcc7547 Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Fri, 17 Apr 2026 16:30:30 +0800 Subject: [PATCH 6/8] Use FnAbi for indirect call ABI --- src/abi.rs | 11 ++--------- src/builder.rs | 12 +++++------- src/context.rs | 7 +------ 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/abi.rs b/src/abi.rs index 4d1274a63d1..d923e1e4863 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -222,15 +222,8 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { // FIXME(antoyo): Should we do something with `FnAbiGcc::fn_attributes`? - let FnAbiGcc { return_type, arguments_type, is_c_variadic, on_stack_param_indices, .. } = - self.gcc_type(cx); - let pointer_type = - cx.context.new_function_pointer_type(None, return_type, &arguments_type, is_c_variadic); - cx.on_stack_params.borrow_mut().insert( - pointer_type.dyncast_function_ptr_type().expect("function ptr type"), - on_stack_param_indices, - ); - pointer_type + let FnAbiGcc { return_type, arguments_type, is_c_variadic, .. } = self.gcc_type(cx); + cx.context.new_function_pointer_type(None, return_type, &arguments_type, is_c_variadic) } #[cfg(feature = "master")] diff --git a/src/builder.rs b/src/builder.rs index 9b7a8d6504e..91fdc520cb3 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -362,11 +362,9 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } }; let gcc_func = func_ptr_type.dyncast_function_ptr_type().expect("function ptr"); - let on_stack_param_indices = if let Some(fn_abi) = fn_abi { - fn_abi.gcc_type(self.cx).on_stack_param_indices - } else { - self.on_stack_params.borrow().get(&gcc_func).cloned().unwrap_or_default() - }; + let on_stack_param_indices = fn_abi + .map(|fn_abi| fn_abi.gcc_type(self.cx).on_stack_param_indices) + .unwrap_or_default(); let func_name = format!("{:?}", func_ptr); let previous_arg_count = args.len(); let orig_args = args; @@ -614,7 +612,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let current_block = self.block; self.block = try_block; - let call = self.call(typ, fn_attrs, None, func, args, None, instance); // FIXME(antoyo): use funclet here? + let call = self.call(typ, fn_attrs, _fn_abi, func, args, None, instance); // FIXME(antoyo): use funclet here? self.block = current_block; let return_value = @@ -648,7 +646,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _funclet: Option<&Funclet>, instance: Option>, ) -> RValue<'gcc> { - let call_site = self.call(typ, fn_attrs, None, func, args, None, instance); + let call_site = self.call(typ, fn_attrs, fn_abi, func, args, None, instance); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); self.llbb().end_with_conditional(self.location, condition, then, catch); if let Some(_fn_abi) = fn_abi { diff --git a/src/context.rs b/src/context.rs index c34c615306a..6a3d25bfbd8 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,9 +1,7 @@ use std::cell::{Cell, RefCell}; use std::collections::HashMap; -use gccjit::{ - Block, CType, Context, Function, FunctionPtrType, FunctionType, LValue, Location, RValue, Type, -}; +use gccjit::{Block, CType, Context, Function, FunctionType, LValue, Location, RValue, Type}; use rustc_abi::{Align, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::errors as ssa_errors; @@ -100,8 +98,6 @@ pub struct CodegenCx<'gcc, 'tcx> { RefCell, Option>), RValue<'gcc>>>, // FIXME(antoyo): improve the SSA API to not require those. - /// Mapping from function pointer type to indexes of on stack parameters. - pub on_stack_params: RefCell, FxHashSet>>, /// Mapping from function to indexes of on stack parameters. pub on_stack_function_params: RefCell, FxHashSet>>, @@ -289,7 +285,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { instances: Default::default(), function_instances: Default::default(), intrinsic_instances: Default::default(), - on_stack_params: Default::default(), on_stack_function_params: Default::default(), vtables: Default::default(), const_globals: Default::default(), From 9eac862de4dc4e56199fa3f2731326a56d8d99e1 Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Fri, 17 Apr 2026 16:55:49 +0800 Subject: [PATCH 7/8] Unmark dylib-dep.rs as failing --- tests/failing-ui-tests.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/failing-ui-tests.txt b/tests/failing-ui-tests.txt index 5739b2cbd5d..b22ddde153f 100644 --- a/tests/failing-ui-tests.txt +++ b/tests/failing-ui-tests.txt @@ -47,7 +47,6 @@ tests/ui/sanitizer/cfi/virtual-auto.rs tests/ui/sanitizer/cfi/sized-associated-ty.rs tests/ui/sanitizer/cfi/can-reveal-opaques.rs tests/ui/sanitizer/kcfi-mangling.rs -tests/ui/backtrace/dylib-dep.rs tests/ui/delegation/fn-header.rs tests/ui/consts/const-eval/parse_ints.rs tests/ui/simd/intrinsic/generic-as.rs From 308452042def5d5d997ddb81da65a3fcbaeebf04 Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Fri, 17 Apr 2026 17:09:08 +0800 Subject: [PATCH 8/8] Rename invoke fn_abi param --- src/builder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/builder.rs b/src/builder.rs index 91fdc520cb3..7baca6e77ac 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -600,7 +600,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { &mut self, typ: Type<'gcc>, fn_attrs: Option<&CodegenFnAttrs>, - _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, + fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, @@ -612,7 +612,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let current_block = self.block; self.block = try_block; - let call = self.call(typ, fn_attrs, _fn_abi, func, args, None, instance); // FIXME(antoyo): use funclet here? + let call = self.call(typ, fn_attrs, fn_abi, func, args, None, instance); // FIXME(antoyo): use funclet here? self.block = current_block; let return_value =