Skip to content

Commit 5f4f252

Browse files
committed
Handle calls to upstream monomorphizations in compiler_builtins
1 parent 1ca424c commit 5f4f252

File tree

12 files changed

+95
-9
lines changed

12 files changed

+95
-9
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3673,6 +3673,7 @@ dependencies = [
36733673
"rustc_macros",
36743674
"rustc_metadata",
36753675
"rustc_middle",
3676+
"rustc_monomorphize",
36763677
"rustc_query_system",
36773678
"rustc_serialize",
36783679
"rustc_session",

compiler/rustc_codegen_cranelift/src/abi/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ use std::borrow::Cow;
88

99
use cranelift_codegen::ir::SigRef;
1010
use cranelift_module::ModuleError;
11+
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
1112
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1213
use rustc_middle::ty::layout::FnAbiOf;
14+
use rustc_middle::ty::print::with_no_trimmed_paths;
15+
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
1316
use rustc_session::Session;
1417
use rustc_span::source_map::Spanned;
1518
use rustc_target::abi::call::{Conv, FnAbi};
@@ -372,6 +375,17 @@ pub(crate) fn codegen_terminator_call<'tcx>(
372375
ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, fn_args)
373376
.polymorphize(fx.tcx);
374377

378+
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
379+
if target.is_some() {
380+
let caller = with_no_trimmed_paths!(fx.tcx.def_path_str(fx.instance.def_id()));
381+
let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id));
382+
fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
383+
} else {
384+
fx.bcx.ins().trap(TrapCode::User(0));
385+
return;
386+
}
387+
}
388+
375389
if fx.tcx.symbol_name(instance).name.starts_with("llvm.") {
376390
crate::intrinsics::codegen_llvm_intrinsic_call(
377391
fx,

compiler/rustc_codegen_cranelift/src/base.rs

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_index::IndexVec;
88
use rustc_middle::ty::adjustment::PointerCoercion;
99
use rustc_middle::ty::layout::FnAbiOf;
1010
use rustc_middle::ty::print::with_no_trimmed_paths;
11+
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
1112

1213
use crate::constant::ConstantCx;
1314
use crate::debuginfo::FunctionDebugContext;
@@ -999,6 +1000,12 @@ fn codegen_panic_inner<'tcx>(
9991000
let def_id = fx.tcx.require_lang_item(lang_item, span);
10001001

10011002
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
1003+
1004+
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
1005+
fx.bcx.ins().trap(TrapCode::User(0));
1006+
return;
1007+
}
1008+
10021009
let symbol_name = fx.tcx.symbol_name(instance).name;
10031010

10041011
fx.lib_call(

compiler/rustc_codegen_cranelift/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extern crate rustc_hir;
2121
extern crate rustc_incremental;
2222
extern crate rustc_index;
2323
extern crate rustc_metadata;
24+
extern crate rustc_monomorphize;
2425
extern crate rustc_session;
2526
extern crate rustc_span;
2627
extern crate rustc_target;

compiler/rustc_codegen_ssa/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ rustc_index = { path = "../rustc_index" }
2525
rustc_macros = { path = "../rustc_macros" }
2626
rustc_metadata = { path = "../rustc_metadata" }
2727
rustc_middle = { path = "../rustc_middle" }
28+
rustc_monomorphize = { path = "../rustc_monomorphize" }
2829
rustc_query_system = { path = "../rustc_query_system" }
2930
rustc_serialize = { path = "../rustc_serialize" }
3031
rustc_session = { path = "../rustc_session" }

compiler/rustc_codegen_ssa/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ codegen_ssa_cgu_not_recorded =
1616
1717
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.
1818
19+
codegen_ssa_compiler_builtins_cannot_call =
20+
`compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from `{$caller}` to `{$callee}`
21+
1922
codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
2023
2124
codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}

compiler/rustc_codegen_ssa/src/common.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use rustc_hir::LangItem;
44
use rustc_middle::mir;
5+
use rustc_middle::ty::Instance;
56
use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
67
use rustc_span::Span;
78

@@ -120,11 +121,11 @@ pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
120121
bx: &Bx,
121122
span: Option<Span>,
122123
li: LangItem,
123-
) -> (Bx::FnAbiOfResult, Bx::Value) {
124+
) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) {
124125
let tcx = bx.tcx();
125126
let def_id = tcx.require_lang_item(li, span);
126127
let instance = ty::Instance::mono(tcx, def_id);
127-
(bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance))
128+
(bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance)
128129
}
129130

130131
// To avoid UB from LLVM, these two functions mask RHS with an

compiler/rustc_codegen_ssa/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1030,3 +1030,10 @@ pub struct FailedToGetLayout<'tcx> {
10301030
pub struct ErrorCreatingRemarkDir {
10311031
pub error: std::io::Error,
10321032
}
1033+
1034+
#[derive(Diagnostic)]
1035+
#[diag(codegen_ssa_compiler_builtins_cannot_call)]
1036+
pub struct CompilerBuiltinsCannotCall {
1037+
pub caller: String,
1038+
pub callee: String,
1039+
}

compiler/rustc_codegen_ssa/src/mir/block.rs

+34-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::{CachedLlbb, FunctionCx, LocalRef};
55

66
use crate::base;
77
use crate::common::{self, IntPredicate};
8+
use crate::errors::CompilerBuiltinsCannotCall;
89
use crate::meth;
910
use crate::traits::*;
1011
use crate::MemFlags;
@@ -16,6 +17,7 @@ use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTermi
1617
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
1718
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
1819
use rustc_middle::ty::{self, Instance, Ty};
20+
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
1921
use rustc_session::config::OptLevel;
2022
use rustc_span::{source_map::Spanned, sym, Span};
2123
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
@@ -157,8 +159,28 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
157159
destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
158160
mut unwind: mir::UnwindAction,
159161
copied_constant_arguments: &[PlaceRef<'tcx, <Bx as BackendTypes>::Value>],
162+
instance: Option<Instance<'tcx>>,
160163
mergeable_succ: bool,
161164
) -> MergingSucc {
165+
let tcx = bx.tcx();
166+
if let Some(instance) = instance {
167+
if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) {
168+
if destination.is_some() {
169+
let caller = with_no_trimmed_paths!(tcx.def_path_str(fx.instance.def_id()));
170+
let callee = with_no_trimmed_paths!(tcx.def_path_str(instance.def_id()));
171+
tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
172+
} else {
173+
info!(
174+
"compiler_builtins call to diverging function {:?} replaced with abort",
175+
instance.def_id()
176+
);
177+
bx.abort();
178+
bx.unreachable();
179+
return MergingSucc::False;
180+
}
181+
}
182+
}
183+
162184
// If there is a cleanup block and the function we're calling can unwind, then
163185
// do an invoke, otherwise do a call.
164186
let fn_ty = bx.fn_decl_backend_type(fn_abi);
@@ -480,6 +502,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
480502
let ty = location.ty(self.mir, bx.tcx()).ty;
481503
let ty = self.monomorphize(ty);
482504
let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty);
505+
let instance = drop_fn.clone();
483506

484507
if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
485508
// we don't actually need to drop anything.
@@ -582,6 +605,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
582605
Some((ReturnDest::Nothing, target)),
583606
unwind,
584607
&[],
608+
Some(instance),
585609
mergeable_succ,
586610
)
587611
}
@@ -658,10 +682,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
658682
}
659683
};
660684

661-
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item);
685+
let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), lang_item);
662686

663687
// Codegen the actual panic invoke/call.
664-
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], false);
688+
let merging_succ =
689+
helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], Some(instance), false);
665690
assert_eq!(merging_succ, MergingSucc::False);
666691
MergingSucc::False
667692
}
@@ -677,7 +702,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
677702
self.set_debug_loc(bx, terminator.source_info);
678703

679704
// Obtain the panic entry point.
680-
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), reason.lang_item());
705+
let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), reason.lang_item());
681706

682707
// Codegen the actual panic invoke/call.
683708
let merging_succ = helper.do_call(
@@ -689,6 +714,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
689714
None,
690715
mir::UnwindAction::Unreachable,
691716
&[],
717+
Some(instance),
692718
false,
693719
);
694720
assert_eq!(merging_succ, MergingSucc::False);
@@ -738,7 +764,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
738764
let msg = bx.const_str(&msg_str);
739765

740766
// Obtain the panic entry point.
741-
let (fn_abi, llfn) =
767+
let (fn_abi, llfn, instance) =
742768
common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind);
743769

744770
// Codegen the actual panic invoke/call.
@@ -751,6 +777,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
751777
target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
752778
unwind,
753779
&[],
780+
Some(instance),
754781
mergeable_succ,
755782
)
756783
} else {
@@ -798,6 +825,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
798825
ty::FnPtr(_) => (None, Some(callee.immediate())),
799826
_ => bug!("{} is not callable", callee.layout.ty),
800827
};
828+
801829
let def = instance.map(|i| i.def);
802830

803831
if let Some(ty::InstanceDef::DropGlue(_, None)) = def {
@@ -1106,6 +1134,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11061134
destination,
11071135
unwind,
11081136
&copied_constant_arguments,
1137+
instance,
11091138
mergeable_succ,
11101139
)
11111140
}
@@ -1664,7 +1693,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
16641693

16651694
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
16661695

1667-
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, reason.lang_item());
1696+
let (fn_abi, fn_ptr, _instance) = common::build_langcall(&bx, None, reason.lang_item());
16681697
let fn_ty = bx.fn_decl_backend_type(fn_abi);
16691698

16701699
let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref());

compiler/rustc_codegen_ssa/src/size_of_val.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
6262
let msg = bx.const_str(&msg_str);
6363

6464
// Obtain the panic entry point.
65-
let (fn_abi, llfn) = common::build_langcall(bx, None, LangItem::PanicNounwind);
65+
let (fn_abi, llfn, _instance) =
66+
common::build_langcall(bx, None, LangItem::PanicNounwind);
6667

6768
// Generate the call.
6869
// Cannot use `do_call` since we don't have a MIR terminator so we can't create a `TerminationCodegenHelper`.

compiler/rustc_monomorphize/src/collector.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1020,7 +1020,7 @@ fn visit_instance_use<'tcx>(
10201020

10211021
/// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
10221022
/// can just link to the upstream crate and therefore don't need a mono item.
1023-
fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
1023+
pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
10241024
let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else {
10251025
return true;
10261026
};

compiler/rustc_monomorphize/src/lib.rs

+21
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ use rustc_hir::lang_items::LangItem;
1111
use rustc_middle::query::{Providers, TyCtxtAt};
1212
use rustc_middle::traits;
1313
use rustc_middle::ty::adjustment::CustomCoerceUnsized;
14+
use rustc_middle::ty::Instance;
15+
use rustc_middle::ty::TyCtxt;
1416
use rustc_middle::ty::{self, Ty};
17+
use rustc_span::def_id::LOCAL_CRATE;
1518
use rustc_span::ErrorGuaranteed;
1619

1720
mod collector;
@@ -20,6 +23,8 @@ mod partitioning;
2023
mod polymorphize;
2124
mod util;
2225

26+
use collector::should_codegen_locally;
27+
2328
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
2429

2530
fn custom_coerce_unsize_info<'tcx>(
@@ -45,6 +50,22 @@ fn custom_coerce_unsize_info<'tcx>(
4550
}
4651
}
4752

53+
/// Returns whether a call from the current crate to the [`Instance`] would produce a call
54+
/// from `compiler_builtins` to a symbol the linker must resolve.
55+
///
56+
/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some
57+
/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
58+
/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
59+
/// unlinkable calls.
60+
pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
61+
tcx: TyCtxt<'tcx>,
62+
instance: Instance<'tcx>,
63+
) -> bool {
64+
!instance.def_id().is_local()
65+
&& tcx.is_compiler_builtins(LOCAL_CRATE)
66+
&& !should_codegen_locally(tcx, &instance)
67+
}
68+
4869
pub fn provide(providers: &mut Providers) {
4970
partitioning::provide(providers);
5071
polymorphize::provide(providers);

0 commit comments

Comments
 (0)