Skip to content

Commit 2eeff46

Browse files
committed
Auto merge of rust-lang#120675 - oli-obk:intrinsics3.0, r=pnkfelix
Add a scheme for moving away from `extern "rust-intrinsic"` entirely All `rust-intrinsic`s can become free functions now, either with a fallback body, or with a dummy body and an attribute, requiring backends to actually implement the intrinsic. This PR demonstrates the dummy-body scheme with the `vtable_size` intrinsic. cc rust-lang#63585 follow-up to rust-lang#120500 MCP at rust-lang/compiler-team#720
2 parents 50e77f1 + c04f0ca commit 2eeff46

File tree

31 files changed

+207
-51
lines changed

31 files changed

+207
-51
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1667,7 +1667,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16671667
// (Eventually this should use const-generics, but those are not up for the task yet:
16681668
// https://github.com/rust-lang/rust/issues/85229.)
16691669
if let Some(name @ (sym::simd_shuffle | sym::simd_insert | sym::simd_extract)) =
1670-
self.tcx().intrinsic(def_id)
1670+
self.tcx().intrinsic(def_id).map(|i| i.name)
16711671
{
16721672
let idx = match name {
16731673
sym::simd_shuffle => 2,

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -1255,7 +1255,17 @@ fn codegen_regular_intrinsic_call<'tcx>(
12551255

12561256
// Unimplemented intrinsics must have a fallback body. The fallback body is obtained
12571257
// by converting the `InstanceDef::Intrinsic` to an `InstanceDef::Item`.
1258-
_ => return Err(Instance::new(instance.def_id(), instance.args)),
1258+
_ => {
1259+
let intrinsic = fx.tcx.intrinsic(instance.def_id()).unwrap();
1260+
if intrinsic.must_be_overridden {
1261+
span_bug!(
1262+
source_info.span,
1263+
"intrinsic {} must be overridden by codegen_cranelift, but isn't",
1264+
intrinsic.name,
1265+
);
1266+
}
1267+
return Err(Instance::new(instance.def_id(), instance.args));
1268+
}
12591269
}
12601270

12611271
let ret_block = fx.get_block(destination.unwrap());

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+4
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
8181
return library.kind.is_statically_included().then_some(def_id);
8282
}
8383

84+
if tcx.intrinsic(def_id).is_some_and(|i| i.must_be_overridden) {
85+
return None;
86+
}
87+
8488
// Only consider nodes that actually have exported symbols.
8589
match tcx.def_kind(def_id) {
8690
DefKind::Fn | DefKind::Static(_) => {}

compiler/rustc_codegen_ssa/src/mir/block.rs

+42-17
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ use crate::MemFlags;
1212
use rustc_ast as ast;
1313
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
1414
use rustc_hir::lang_items::LangItem;
15-
use rustc_middle::mir::{self, AssertKind, SwitchTargets, UnwindTerminateReason};
15+
use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTerminateReason};
1616
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
1717
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
1818
use rustc_middle::ty::{self, Instance, Ty};
1919
use rustc_session::config::OptLevel;
20-
use rustc_span::{source_map::Spanned, sym, Span, Symbol};
20+
use rustc_span::{source_map::Spanned, sym, Span};
2121
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
2222
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
2323
use rustc_target::spec::abi::Abi;
@@ -680,7 +680,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
680680
&mut self,
681681
helper: &TerminatorCodegenHelper<'tcx>,
682682
bx: &mut Bx,
683-
intrinsic: Option<Symbol>,
683+
intrinsic: Option<ty::IntrinsicDef>,
684684
instance: Option<Instance<'tcx>>,
685685
source_info: mir::SourceInfo,
686686
target: Option<mir::BasicBlock>,
@@ -690,7 +690,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
690690
// Emit a panic or a no-op for `assert_*` intrinsics.
691691
// These are intrinsics that compile to panics so that we can get a message
692692
// which mentions the offending type, even from a const context.
693-
let panic_intrinsic = intrinsic.and_then(|s| ValidityRequirement::from_intrinsic(s));
693+
let panic_intrinsic = intrinsic.and_then(|i| ValidityRequirement::from_intrinsic(i.name));
694694
if let Some(requirement) = panic_intrinsic {
695695
let ty = instance.unwrap().args.type_at(0);
696696

@@ -826,14 +826,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
826826
// The arguments we'll be passing. Plus one to account for outptr, if used.
827827
let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
828828

829-
if intrinsic == Some(sym::caller_location) {
829+
if matches!(intrinsic, Some(ty::IntrinsicDef { name: sym::caller_location, .. })) {
830830
return if let Some(target) = target {
831831
let location =
832832
self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info });
833833

834834
let mut llargs = Vec::with_capacity(arg_count);
835-
let ret_dest =
836-
self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, true, true);
835+
let ret_dest = self.make_return_dest(
836+
bx,
837+
destination,
838+
&fn_abi.ret,
839+
&mut llargs,
840+
intrinsic,
841+
Some(target),
842+
);
837843
assert_eq!(llargs, []);
838844
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
839845
location.val.store(bx, tmp);
@@ -846,16 +852,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
846852
}
847853

848854
let instance = match intrinsic {
849-
None | Some(sym::drop_in_place) => instance,
855+
None | Some(ty::IntrinsicDef { name: sym::drop_in_place, .. }) => instance,
850856
Some(intrinsic) => {
851857
let mut llargs = Vec::with_capacity(1);
852858
let ret_dest = self.make_return_dest(
853859
bx,
854860
destination,
855861
&fn_abi.ret,
856862
&mut llargs,
857-
true,
858-
target.is_some(),
863+
Some(intrinsic),
864+
target,
859865
);
860866
let dest = match ret_dest {
861867
_ if fn_abi.ret.is_indirect() => llargs[0],
@@ -873,7 +879,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
873879
// The indices passed to simd_shuffle in the
874880
// third argument must be constant. This is
875881
// checked by the type-checker.
876-
if i == 2 && intrinsic == sym::simd_shuffle {
882+
if i == 2 && intrinsic.name == sym::simd_shuffle {
877883
if let mir::Operand::Constant(constant) = &arg.node {
878884
let (llval, ty) = self.simd_shuffle_indices(bx, constant);
879885
return OperandRef {
@@ -903,14 +909,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
903909
MergingSucc::False
904910
};
905911
}
906-
Err(instance) => Some(instance),
912+
Err(instance) => {
913+
if intrinsic.must_be_overridden {
914+
span_bug!(
915+
span,
916+
"intrinsic {} must be overridden by codegen backend, but isn't",
917+
intrinsic.name,
918+
);
919+
}
920+
Some(instance)
921+
}
907922
}
908923
}
909924
};
910925

911926
let mut llargs = Vec::with_capacity(arg_count);
912927
let destination = target.as_ref().map(|&target| {
913-
(self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, false, true), target)
928+
(
929+
self.make_return_dest(
930+
bx,
931+
destination,
932+
&fn_abi.ret,
933+
&mut llargs,
934+
None,
935+
Some(target),
936+
),
937+
target,
938+
)
914939
});
915940

916941
// Split the rust-call tupled arguments off.
@@ -1643,10 +1668,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
16431668
dest: mir::Place<'tcx>,
16441669
fn_ret: &ArgAbi<'tcx, Ty<'tcx>>,
16451670
llargs: &mut Vec<Bx::Value>,
1646-
is_intrinsic: bool,
1647-
has_target: bool,
1671+
intrinsic: Option<ty::IntrinsicDef>,
1672+
target: Option<BasicBlock>,
16481673
) -> ReturnDest<'tcx, Bx::Value> {
1649-
if !has_target {
1674+
if target.is_none() {
16501675
return ReturnDest::Nothing;
16511676
}
16521677
// If the return is ignored, we can just return a do-nothing `ReturnDest`.
@@ -1667,7 +1692,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
16671692
tmp.storage_live(bx);
16681693
llargs.push(tmp.llval);
16691694
ReturnDest::IndirectOperand(tmp, index)
1670-
} else if is_intrinsic {
1695+
} else if intrinsic.is_some() {
16711696
// Currently, intrinsics always need a location to store
16721697
// the result, so we create a temporary `alloca` for the
16731698
// result.

compiler/rustc_feature/src/builtin_attrs.rs

+4
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
867867
rustc_no_mir_inline, Normal, template!(Word), WarnFollowing,
868868
"#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
869869
),
870+
rustc_attr!(
871+
rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing,
872+
"the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies",
873+
),
870874

871875
// ==========================================================================
872876
// Internal attributes, Testing:

compiler/rustc_hir_analysis/src/check/check.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -527,12 +527,12 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
527527
check_enum(tcx, def_id);
528528
}
529529
DefKind::Fn => {
530-
if let Some(name) = tcx.intrinsic(def_id) {
530+
if let Some(i) = tcx.intrinsic(def_id) {
531531
intrinsic::check_intrinsic_type(
532532
tcx,
533533
def_id,
534534
tcx.def_ident_span(def_id).unwrap(),
535-
name,
535+
i.name,
536536
Abi::Rust,
537537
)
538538
}

compiler/rustc_hir_typeck/src/callee.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
545545

546546
if let Some(def_id) = def_id
547547
&& self.tcx.def_kind(def_id) == hir::def::DefKind::Fn
548-
&& matches!(self.tcx.intrinsic(def_id), Some(sym::const_eval_select))
548+
&& self.tcx.is_intrinsic(def_id, sym::const_eval_select)
549549
{
550550
let fn_sig = self.resolve_vars_if_possible(fn_sig);
551551
for idx in 0..=1 {

compiler/rustc_lint/src/builtin.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1231,7 +1231,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
12311231
}
12321232

12331233
fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
1234-
matches!(cx.tcx.intrinsic(def_id), Some(sym::transmute))
1234+
cx.tcx.is_intrinsic(def_id, sym::transmute)
12351235
}
12361236
}
12371237
}

compiler/rustc_metadata/src/rmeta/decoder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1749,7 +1749,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
17491749
self.root.tables.attr_flags.get(self, index)
17501750
}
17511751

1752-
fn get_intrinsic(self, index: DefIndex) -> Option<Symbol> {
1752+
fn get_intrinsic(self, index: DefIndex) -> Option<ty::IntrinsicDef> {
17531753
self.root.tables.intrinsic.get(self, index).map(|d| d.decode(self))
17541754
}
17551755

compiler/rustc_metadata/src/rmeta/encoder.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1053,11 +1053,14 @@ fn should_encode_mir(
10531053
// Full-fledged functions + closures
10541054
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
10551055
let generics = tcx.generics_of(def_id);
1056-
let opt = tcx.sess.opts.unstable_opts.always_encode_mir
1056+
let mut opt = tcx.sess.opts.unstable_opts.always_encode_mir
10571057
|| (tcx.sess.opts.output_types.should_codegen()
10581058
&& reachable_set.contains(&def_id)
10591059
&& (generics.requires_monomorphization(tcx)
10601060
|| tcx.cross_crate_inlinable(def_id)));
1061+
if let Some(intrinsic) = tcx.intrinsic(def_id) {
1062+
opt &= !intrinsic.must_be_overridden;
1063+
}
10611064
// The function has a `const` modifier or is in a `#[const_trait]`.
10621065
let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
10631066
|| tcx.is_const_default_method(def_id.to_def_id());
@@ -1409,9 +1412,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
14091412
if let DefKind::Fn | DefKind::AssocFn = def_kind {
14101413
self.tables.asyncness.set_some(def_id.index, tcx.asyncness(def_id));
14111414
record_array!(self.tables.fn_arg_names[def_id] <- tcx.fn_arg_names(def_id));
1412-
if let Some(name) = tcx.intrinsic(def_id) {
1413-
record!(self.tables.intrinsic[def_id] <- name);
1414-
}
1415+
}
1416+
if let Some(name) = tcx.intrinsic(def_id) {
1417+
record!(self.tables.intrinsic[def_id] <- name);
14151418
}
14161419
if let DefKind::TyParam = def_kind {
14171420
let default = self.tcx.object_lifetime_default(def_id);

compiler/rustc_metadata/src/rmeta/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ macro_rules! define_tables {
375375

376376
define_tables! {
377377
- defaulted:
378-
intrinsic: Table<DefIndex, Option<LazyValue<Symbol>>>,
378+
intrinsic: Table<DefIndex, Option<LazyValue<ty::IntrinsicDef>>>,
379379
is_macro_rules: Table<DefIndex, bool>,
380380
is_type_alias_impl_trait: Table<DefIndex, bool>,
381381
type_alias_is_lazy: Table<DefIndex, bool>,

compiler/rustc_middle/src/query/erase.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ trivial! {
241241
Option<rustc_target::abi::FieldIdx>,
242242
Option<rustc_target::spec::PanicStrategy>,
243243
Option<usize>,
244-
Option<rustc_span::Symbol>,
244+
Option<rustc_middle::ty::IntrinsicDef>,
245245
Result<(), rustc_errors::ErrorGuaranteed>,
246246
Result<(), rustc_middle::traits::query::NoSolution>,
247247
Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>,

compiler/rustc_middle/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1760,7 +1760,7 @@ rustc_queries! {
17601760
separate_provide_extern
17611761
}
17621762
/// Whether the function is an intrinsic
1763-
query intrinsic(def_id: DefId) -> Option<Symbol> {
1763+
query intrinsic(def_id: DefId) -> Option<rustc_middle::ty::IntrinsicDef> {
17641764
desc { |tcx| "fetch intrinsic name if `{}` is an intrinsic", tcx.def_path_str(def_id) }
17651765
separate_provide_extern
17661766
}
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use rustc_span::{def_id::DefId, Symbol};
2+
3+
use super::TyCtxt;
4+
5+
#[derive(Copy, Clone, Debug, Decodable, Encodable, HashStable)]
6+
pub struct IntrinsicDef {
7+
pub name: Symbol,
8+
/// Whether the intrinsic has no meaningful body and all backends need to shim all calls to it.
9+
pub must_be_overridden: bool,
10+
}
11+
12+
impl TyCtxt<'_> {
13+
pub fn is_intrinsic(self, def_id: DefId, name: Symbol) -> bool {
14+
let Some(i) = self.intrinsic(def_id) else { return false };
15+
i.name == name
16+
}
17+
}

compiler/rustc_middle/src/ty/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub use adt::*;
3030
pub use assoc::*;
3131
pub use generic_args::*;
3232
pub use generics::*;
33+
pub use intrinsic::IntrinsicDef;
3334
use rustc_ast as ast;
3435
use rustc_ast::node_id::NodeMap;
3536
pub use rustc_ast_ir::{Movability, Mutability};
@@ -149,6 +150,7 @@ mod generic_args;
149150
mod generics;
150151
mod impls_ty;
151152
mod instance;
153+
mod intrinsic;
152154
mod list;
153155
mod opaque_types;
154156
mod parameterized;

compiler/rustc_middle/src/ty/parameterized.rs

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ trivially_parameterized_over_tcx! {
7575
ty::Visibility<DefIndex>,
7676
ty::adjustment::CoerceUnsizedInfo,
7777
ty::fast_reject::SimplifiedType,
78+
ty::IntrinsicDef,
7879
rustc_ast::Attribute,
7980
rustc_ast::DelimArgs,
8081
rustc_ast::expand::StrippedCfgItem<rustc_hir::def_id::DefIndex>,

compiler/rustc_middle/src/ty/util.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
1919
use rustc_index::bit_set::GrowableBitSet;
2020
use rustc_macros::HashStable;
2121
use rustc_session::Limit;
22-
use rustc_span::{sym, Symbol};
22+
use rustc_span::sym;
2323
use rustc_target::abi::{Integer, IntegerType, Primitive, Size};
2424
use rustc_target::spec::abi::Abi;
2525
use smallvec::SmallVec;
@@ -1641,12 +1641,19 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
16411641
.any(|items| items.iter().any(|item| item.has_name(sym::notable_trait)))
16421642
}
16431643

1644-
/// Determines whether an item is an intrinsic by Abi. or by whether it has a `rustc_intrinsic` attribute
1645-
pub fn intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Symbol> {
1644+
/// Determines whether an item is an intrinsic (which may be via Abi or via the `rustc_intrinsic` attribute)
1645+
pub fn intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef> {
1646+
match tcx.def_kind(def_id) {
1647+
DefKind::Fn | DefKind::AssocFn => {}
1648+
_ => return None,
1649+
}
16461650
if matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic)
16471651
|| tcx.has_attr(def_id, sym::rustc_intrinsic)
16481652
{
1649-
Some(tcx.item_name(def_id.into()))
1653+
Some(ty::IntrinsicDef {
1654+
name: tcx.item_name(def_id.into()),
1655+
must_be_overridden: tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden),
1656+
})
16501657
} else {
16511658
None
16521659
}

compiler/rustc_mir_dataflow/src/rustc_peek.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ impl PeekCall {
202202
&terminator.kind
203203
{
204204
if let ty::FnDef(def_id, fn_args) = *func.const_.ty().kind() {
205-
if tcx.intrinsic(def_id)? != sym::rustc_peek {
205+
if tcx.intrinsic(def_id)?.name != sym::rustc_peek {
206206
return None;
207207
}
208208

compiler/rustc_mir_transform/src/cross_crate_inline.rs

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
2323
return false;
2424
}
2525

26+
if tcx.intrinsic(def_id).is_some_and(|i| i.must_be_overridden) {
27+
return false;
28+
}
29+
2630
// This just reproduces the logic from Instance::requires_inline.
2731
match tcx.def_kind(def_id) {
2832
DefKind::Ctor(..) | DefKind::Closure => return true,

compiler/rustc_mir_transform/src/instsimplify.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -323,8 +323,8 @@ fn resolve_rust_intrinsic<'tcx>(
323323
func_ty: Ty<'tcx>,
324324
) -> Option<(Symbol, GenericArgsRef<'tcx>)> {
325325
if let ty::FnDef(def_id, args) = *func_ty.kind() {
326-
let name = tcx.intrinsic(def_id)?;
327-
return Some((name, args));
326+
let intrinsic = tcx.intrinsic(def_id)?;
327+
return Some((intrinsic.name, args));
328328
}
329329
None
330330
}

0 commit comments

Comments
 (0)