Skip to content
Merged
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2026-09-08"
channel = "nightly-2026-09-14"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
32 changes: 25 additions & 7 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::{
BackendTypes, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods,
LayoutTypeCodegenMethods, OverflowOp, StaticBuilderMethods,
LayoutTypeCodegenMethods, OverflowOp, ReturnSlot, StaticBuilderMethods,
};
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug;
Expand All @@ -34,6 +34,7 @@ use rustc_target::callconv::FnAbi;
use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi};

use crate::abi::FnAbiGccExt;
use crate::builder;
use crate::common::{SignType, TypeReflection, type_is_pointer};
use crate::context::CodegenCx;
#[cfg(feature = "master")]
Expand Down Expand Up @@ -347,24 +348,36 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {

/// Shared implementation of `call` and `tail_call`. For tail call it is important that this
/// returns a bare call, and not the result assigned to a local, or the result of `add_eval`.
#[allow(clippy::too_many_arguments)]
fn build_call(
&mut self,
typ: Type<'gcc>,
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
func: RValue<'gcc>,
return_slot: ReturnSlot<<builder::Builder<'a, 'gcc, 'tcx> as BackendTypes>::Value>,
args: &[RValue<'gcc>],
funclet: Option<&Funclet>,
must_tail: bool,
) -> RValue<'gcc> {
// FIXME: change this in the `rustc_codegen_gcc` repo after the sync, to use the `libgccjit` indirect return suppport.
let args = match return_slot {
ReturnSlot::Direct => Cow::Borrowed(args),
ReturnSlot::Indirect(sret_ptr) => {
let mut args = args.to_vec();
// Prepend the indirect return pointer
args.insert(0, sret_ptr);
Cow::Owned(args)
}
};
// FIXME(antoyo): remove when having a proper API.
let gcc_func = unsafe { std::mem::transmute::<RValue<'gcc>, Function<'gcc>>(func) };
let call = if self.functions.borrow().values().any(|value| *value == gcc_func) {
// FIXME(antoyo): remove when the API supports a different type for functions.
let func: Function<'gcc> = self.cx.rvalue_as_function(func);
self.function_call(func, args, funclet, must_tail)
self.function_call(func, &args, funclet, must_tail)
} else {
// If it's a not function that was defined, it's a function pointer.
self.function_ptr_call(typ, fn_abi, func, args, funclet, must_tail)
self.function_ptr_call(typ, fn_abi, func, &args, funclet, must_tail)
};
if let Some(_fn_abi) = fn_abi {
// FIXME(bjorn3): Apply function attributes
Expand Down Expand Up @@ -680,6 +693,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
fn_attrs: Option<&CodegenFnAttrs>,
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
func: RValue<'gcc>,
return_slot: ReturnSlot<RValue<'gcc>>,
args: &[RValue<'gcc>],
then: Block<'gcc>,
catch: Block<'gcc>,
Expand All @@ -692,7 +706,8 @@ 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?
// FIXME(antoyo): use funclet here?
let call = self.call(typ, fn_attrs, fn_abi, func, return_slot, args, None, instance);
self.block = current_block;

let return_value = self.new_temp(current_func, self.location, call.get_type());
Expand Down Expand Up @@ -728,13 +743,14 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
fn_attrs: Option<&CodegenFnAttrs>,
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
func: RValue<'gcc>,
return_slot: ReturnSlot<RValue<'gcc>>,
args: &[RValue<'gcc>],
then: Block<'gcc>,
catch: Block<'gcc>,
_funclet: Option<&Funclet>,
instance: Option<Instance<'tcx>>,
) -> RValue<'gcc> {
let call_site = self.call(typ, fn_attrs, fn_abi, func, args, None, instance);
let call_site = self.call(typ, fn_attrs, fn_abi, func, return_slot, 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 {
Expand Down Expand Up @@ -1855,11 +1871,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
_fn_attrs: Option<&CodegenFnAttrs>,
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
func: RValue<'gcc>,
return_slot: ReturnSlot<RValue<'gcc>>,
args: &[RValue<'gcc>],
funclet: Option<&Funclet>,
_instance: Option<Instance<'tcx>>,
) -> RValue<'gcc> {
self.build_call(typ, fn_abi, func, args, funclet, false)
self.build_call(typ, fn_abi, func, return_slot, args, funclet, false)
}

fn tail_call(
Expand All @@ -1868,12 +1885,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
_fn_attrs: Option<&CodegenFnAttrs>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
llfn: Self::Value,
return_slot: ReturnSlot<Self::Value>,
args: &[Self::Value],
funclet: Option<&Self::Funclet>,
_instance: Option<Instance<'tcx>>,
) {
// `emit_call` returns a bare call for here, it has not been assigned or passed to add_eval.
let call = self.build_call(llty, Some(fn_abi), llfn, args, funclet, true);
let call = self.build_call(llty, Some(fn_abi), llfn, return_slot, args, funclet, true);
call.set_require_tail_call(true);

let return_type = self.current_func().get_return_type();
Expand Down
23 changes: 3 additions & 20 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,15 @@ use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_middle::mir::interpret::Allocation;
use rustc_middle::mono::CodegenUnit;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasTyCtxt, HasTypingEnv, LayoutError,
LayoutOfHelpers,
LayoutOfHelpers, codegen_handle_fn_abi_err,
};
use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt};
#[cfg(feature = "master")]
use rustc_session::config::DebugInfo;
use rustc_session::{PointerAuthSchema, Session};
use rustc_span::{DUMMY_SP, Span, Symbol, respan};
use rustc_span::{DUMMY_SP, Span, Symbol};
use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, TlsModel, X86Abi};

#[cfg(feature = "master")]
Expand Down Expand Up @@ -610,23 +609,7 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
span: Span,
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
if let FnAbiError::Layout(LayoutError::SizeOverflow(_) | LayoutError::InvalidSimd { .. }) =
err
{
self.tcx.dcx().emit_fatal(respan(span, err))
} else {
match fn_abi_request {
FnAbiRequest::OfFnPtr { sig, extra_args } => {
span_bug!(span, "`fn_abi_of_fn_ptr({sig}, {extra_args:?})` failed: {err:?}");
}
FnAbiRequest::OfInstance { instance, extra_args } => {
span_bug!(
span,
"`fn_abi_of_instance({instance}, {extra_args:?})` failed: {err:?}"
);
}
}
}
codegen_handle_fn_abi_err(self.tcx, err, span, fn_abi_request).raise_fatal()
}
}

Expand Down
33 changes: 27 additions & 6 deletions src/intrinsic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
use rustc_codegen_ssa::traits::MiscCodegenMethods;
use rustc_codegen_ssa::traits::{
ArgAbiBuilderMethods, BaseTypeCodegenMethods, BuilderMethods, ConstCodegenMethods,
IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods,
IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods, ReturnSlot,
};
use rustc_codegen_ssa::{MemFlags, RetagInfo};
use rustc_data_structures::fx::FxHashSet;
Expand Down Expand Up @@ -653,7 +653,8 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
}

// FIXME directly use the llvm intrinsic adjustment functions here
let llret = self.call(fn_ty, None, None, fn_ptr, &call_args, None, None);
let llret =
self.call(fn_ty, None, None, fn_ptr, ReturnSlot::Direct, &call_args, None, None);
if is_cleanup {
self.apply_attrs_to_cleanup_callsite(llret);
}
Expand Down Expand Up @@ -1365,7 +1366,7 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(
let param_type = bx.u8_type.make_pointer();
let fn_type =
bx.context.new_function_pointer_type(None, bx.type_void(), &[param_type], false);
bx.call(fn_type, None, None, try_func, &[data], None, None);
bx.call(fn_type, None, None, try_func, ReturnSlot::Direct, &[data], None, None);
// Return 0 unconditionally from the intrinsic call;
// we can never unwind.
OperandValue::Immediate(bx.const_bool(false)).store(bx, dest);
Expand Down Expand Up @@ -1438,21 +1439,41 @@ fn codegen_gnu_try<'gcc, 'tcx>(
let zero = bx.cx.context.new_rvalue_zero(bx.int_type);
let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]);
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
bx.call(catch_ty, None, None, catch_func, &[data, ptr], None, None);
bx.call(catch_ty, None, None, catch_func, ReturnSlot::Direct, &[data, ptr], None, None);
bx.ret(bx.const_bool(true));

// NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not
// generate a try/catch.
// FIXME(antoyo): add a check in the libgccjit API to prevent this.
bx.switch_to_block(current_block);
bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None);
bx.invoke(
try_func_ty,
None,
None,
try_func,
ReturnSlot::Direct,
&[data],
then,
catch,
None,
None,
);
});

let func = unsafe { std::mem::transmute::<Function<'gcc>, RValue<'gcc>>(func) };

// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None, None);
let ret = bx.call(
llty,
None,
None,
func,
ReturnSlot::Direct,
&[try_func, data, catch_func],
None,
None,
);
OperandValue::Immediate(ret).store(bx, dest);
}

Expand Down
Loading