Handle calls to upstream monomorphizations in compiler_builtins
This commit is contained in:
parent
1ca424ca43
commit
5f4f2526b8
@ -3673,6 +3673,7 @@ dependencies = [
|
||||
"rustc_macros",
|
||||
"rustc_metadata",
|
||||
"rustc_middle",
|
||||
"rustc_monomorphize",
|
||||
"rustc_query_system",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
|
@ -8,8 +8,11 @@
|
||||
|
||||
use cranelift_codegen::ir::SigRef;
|
||||
use cranelift_module::ModuleError;
|
||||
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::ty::layout::FnAbiOf;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_target::abi::call::{Conv, FnAbi};
|
||||
@ -372,6 +375,17 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
||||
ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, fn_args)
|
||||
.polymorphize(fx.tcx);
|
||||
|
||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
||||
if target.is_some() {
|
||||
let caller = with_no_trimmed_paths!(fx.tcx.def_path_str(fx.instance.def_id()));
|
||||
let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id));
|
||||
fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
|
||||
} else {
|
||||
fx.bcx.ins().trap(TrapCode::User(0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if fx.tcx.symbol_name(instance).name.starts_with("llvm.") {
|
||||
crate::intrinsics::codegen_llvm_intrinsic_call(
|
||||
fx,
|
||||
|
@ -8,6 +8,7 @@
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::layout::FnAbiOf;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
|
||||
|
||||
use crate::constant::ConstantCx;
|
||||
use crate::debuginfo::FunctionDebugContext;
|
||||
@ -999,6 +1000,12 @@ fn codegen_panic_inner<'tcx>(
|
||||
let def_id = fx.tcx.require_lang_item(lang_item, span);
|
||||
|
||||
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
|
||||
|
||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
|
||||
fx.bcx.ins().trap(TrapCode::User(0));
|
||||
return;
|
||||
}
|
||||
|
||||
let symbol_name = fx.tcx.symbol_name(instance).name;
|
||||
|
||||
fx.lib_call(
|
||||
|
@ -21,6 +21,7 @@
|
||||
extern crate rustc_incremental;
|
||||
extern crate rustc_index;
|
||||
extern crate rustc_metadata;
|
||||
extern crate rustc_monomorphize;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
extern crate rustc_target;
|
||||
|
@ -25,6 +25,7 @@ rustc_index = { path = "../rustc_index" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_metadata = { path = "../rustc_metadata" }
|
||||
rustc_middle = { path = "../rustc_middle" }
|
||||
rustc_monomorphize = { path = "../rustc_monomorphize" }
|
||||
rustc_query_system = { path = "../rustc_query_system" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
|
@ -16,6 +16,9 @@ codegen_ssa_cgu_not_recorded =
|
||||
|
||||
codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
|
||||
|
||||
codegen_ssa_compiler_builtins_cannot_call =
|
||||
`compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from `{$caller}` to `{$callee}`
|
||||
|
||||
codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
|
||||
|
||||
codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
|
||||
use rustc_span::Span;
|
||||
|
||||
@ -120,11 +121,11 @@ pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &Bx,
|
||||
span: Option<Span>,
|
||||
li: LangItem,
|
||||
) -> (Bx::FnAbiOfResult, Bx::Value) {
|
||||
) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) {
|
||||
let tcx = bx.tcx();
|
||||
let def_id = tcx.require_lang_item(li, span);
|
||||
let instance = ty::Instance::mono(tcx, def_id);
|
||||
(bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance))
|
||||
(bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance)
|
||||
}
|
||||
|
||||
// To avoid UB from LLVM, these two functions mask RHS with an
|
||||
|
@ -1030,3 +1030,10 @@ pub struct FailedToGetLayout<'tcx> {
|
||||
pub struct ErrorCreatingRemarkDir {
|
||||
pub error: std::io::Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_compiler_builtins_cannot_call)]
|
||||
pub struct CompilerBuiltinsCannotCall {
|
||||
pub caller: String,
|
||||
pub callee: String,
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
use crate::base;
|
||||
use crate::common::{self, IntPredicate};
|
||||
use crate::errors::CompilerBuiltinsCannotCall;
|
||||
use crate::meth;
|
||||
use crate::traits::*;
|
||||
use crate::MemFlags;
|
||||
@ -16,6 +17,7 @@
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
|
||||
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
|
||||
use rustc_middle::ty::{self, Instance, Ty};
|
||||
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
|
||||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::{source_map::Spanned, sym, Span};
|
||||
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
|
||||
@ -157,8 +159,28 @@ fn do_call<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
|
||||
mut unwind: mir::UnwindAction,
|
||||
copied_constant_arguments: &[PlaceRef<'tcx, <Bx as BackendTypes>::Value>],
|
||||
instance: Option<Instance<'tcx>>,
|
||||
mergeable_succ: bool,
|
||||
) -> MergingSucc {
|
||||
let tcx = bx.tcx();
|
||||
if let Some(instance) = instance {
|
||||
if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) {
|
||||
if destination.is_some() {
|
||||
let caller = with_no_trimmed_paths!(tcx.def_path_str(fx.instance.def_id()));
|
||||
let callee = with_no_trimmed_paths!(tcx.def_path_str(instance.def_id()));
|
||||
tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
|
||||
} else {
|
||||
info!(
|
||||
"compiler_builtins call to diverging function {:?} replaced with abort",
|
||||
instance.def_id()
|
||||
);
|
||||
bx.abort();
|
||||
bx.unreachable();
|
||||
return MergingSucc::False;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a cleanup block and the function we're calling can unwind, then
|
||||
// do an invoke, otherwise do a call.
|
||||
let fn_ty = bx.fn_decl_backend_type(fn_abi);
|
||||
@ -480,6 +502,7 @@ fn codegen_drop_terminator(
|
||||
let ty = location.ty(self.mir, bx.tcx()).ty;
|
||||
let ty = self.monomorphize(ty);
|
||||
let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty);
|
||||
let instance = drop_fn.clone();
|
||||
|
||||
if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
|
||||
// we don't actually need to drop anything.
|
||||
@ -582,6 +605,7 @@ fn codegen_drop_terminator(
|
||||
Some((ReturnDest::Nothing, target)),
|
||||
unwind,
|
||||
&[],
|
||||
Some(instance),
|
||||
mergeable_succ,
|
||||
)
|
||||
}
|
||||
@ -658,10 +682,11 @@ fn codegen_assert_terminator(
|
||||
}
|
||||
};
|
||||
|
||||
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item);
|
||||
let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), lang_item);
|
||||
|
||||
// Codegen the actual panic invoke/call.
|
||||
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], false);
|
||||
let merging_succ =
|
||||
helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], Some(instance), false);
|
||||
assert_eq!(merging_succ, MergingSucc::False);
|
||||
MergingSucc::False
|
||||
}
|
||||
@ -677,7 +702,7 @@ fn codegen_terminate_terminator(
|
||||
self.set_debug_loc(bx, terminator.source_info);
|
||||
|
||||
// Obtain the panic entry point.
|
||||
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), reason.lang_item());
|
||||
let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), reason.lang_item());
|
||||
|
||||
// Codegen the actual panic invoke/call.
|
||||
let merging_succ = helper.do_call(
|
||||
@ -689,6 +714,7 @@ fn codegen_terminate_terminator(
|
||||
None,
|
||||
mir::UnwindAction::Unreachable,
|
||||
&[],
|
||||
Some(instance),
|
||||
false,
|
||||
);
|
||||
assert_eq!(merging_succ, MergingSucc::False);
|
||||
@ -738,7 +764,7 @@ fn codegen_panic_intrinsic(
|
||||
let msg = bx.const_str(&msg_str);
|
||||
|
||||
// Obtain the panic entry point.
|
||||
let (fn_abi, llfn) =
|
||||
let (fn_abi, llfn, instance) =
|
||||
common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind);
|
||||
|
||||
// Codegen the actual panic invoke/call.
|
||||
@ -751,6 +777,7 @@ fn codegen_panic_intrinsic(
|
||||
target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
|
||||
unwind,
|
||||
&[],
|
||||
Some(instance),
|
||||
mergeable_succ,
|
||||
)
|
||||
} else {
|
||||
@ -798,6 +825,7 @@ fn codegen_call_terminator(
|
||||
ty::FnPtr(_) => (None, Some(callee.immediate())),
|
||||
_ => bug!("{} is not callable", callee.layout.ty),
|
||||
};
|
||||
|
||||
let def = instance.map(|i| i.def);
|
||||
|
||||
if let Some(ty::InstanceDef::DropGlue(_, None)) = def {
|
||||
@ -1106,6 +1134,7 @@ fn codegen_call_terminator(
|
||||
destination,
|
||||
unwind,
|
||||
&copied_constant_arguments,
|
||||
instance,
|
||||
mergeable_succ,
|
||||
)
|
||||
}
|
||||
@ -1664,7 +1693,7 @@ fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock {
|
||||
|
||||
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
|
||||
|
||||
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, reason.lang_item());
|
||||
let (fn_abi, fn_ptr, _instance) = common::build_langcall(&bx, None, reason.lang_item());
|
||||
let fn_ty = bx.fn_decl_backend_type(fn_abi);
|
||||
|
||||
let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref());
|
||||
|
@ -62,7 +62,8 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
let msg = bx.const_str(&msg_str);
|
||||
|
||||
// Obtain the panic entry point.
|
||||
let (fn_abi, llfn) = common::build_langcall(bx, None, LangItem::PanicNounwind);
|
||||
let (fn_abi, llfn, _instance) =
|
||||
common::build_langcall(bx, None, LangItem::PanicNounwind);
|
||||
|
||||
// Generate the call.
|
||||
// Cannot use `do_call` since we don't have a MIR terminator so we can't create a `TerminationCodegenHelper`.
|
||||
|
@ -1020,7 +1020,7 @@ fn visit_instance_use<'tcx>(
|
||||
|
||||
/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
|
||||
/// can just link to the upstream crate and therefore don't need a mono item.
|
||||
fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
|
||||
pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
|
||||
let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else {
|
||||
return true;
|
||||
};
|
||||
|
@ -11,7 +11,10 @@
|
||||
use rustc_middle::query::{Providers, TyCtxtAt};
|
||||
use rustc_middle::traits;
|
||||
use rustc_middle::ty::adjustment::CustomCoerceUnsized;
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::def_id::LOCAL_CRATE;
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
|
||||
mod collector;
|
||||
@ -20,6 +23,8 @@
|
||||
mod polymorphize;
|
||||
mod util;
|
||||
|
||||
use collector::should_codegen_locally;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
||||
fn custom_coerce_unsize_info<'tcx>(
|
||||
@ -45,6 +50,22 @@ fn custom_coerce_unsize_info<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether a call from the current crate to the [`Instance`] would produce a call
|
||||
/// from `compiler_builtins` to a symbol the linker must resolve.
|
||||
///
|
||||
/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some
|
||||
/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
|
||||
/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
|
||||
/// unlinkable calls.
|
||||
pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
) -> bool {
|
||||
!instance.def_id().is_local()
|
||||
&& tcx.is_compiler_builtins(LOCAL_CRATE)
|
||||
&& !should_codegen_locally(tcx, &instance)
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
partitioning::provide(providers);
|
||||
polymorphize::provide(providers);
|
||||
|
Loading…
Reference in New Issue
Block a user