Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 1abd851

Browse files
committed
Auto merge of rust-lang#120675 - oli-obk:intrinsics3.0, r=<try>
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 026b3b8 + af49444 commit 1abd851

File tree

30 files changed

+204
-46
lines changed

30 files changed

+204
-46
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1664,7 +1664,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16641664

16651665
let func_ty = func.ty(body, self.infcx.tcx);
16661666
if let ty::FnDef(def_id, _) = *func_ty.kind() {
1667-
if let Some(sym::simd_shuffle) = self.tcx().intrinsic(def_id) {
1667+
if self.tcx().is_intrinsic(def_id, sym::simd_shuffle) {
16681668
if !matches!(args[2], Spanned { node: Operand::Constant(_), .. }) {
16691669
self.tcx().dcx().emit_err(SimdShuffleLastConst { span: term.source_info.span });
16701670
}

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

Lines changed: 11 additions & 1 deletion
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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use rustc_middle::ty::{self, SymbolName, TyCtxt};
1616
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
1717
use rustc_middle::util::Providers;
1818
use rustc_session::config::{CrateType, OomStrategy};
19+
use rustc_span::sym;
1920
use rustc_target::spec::{SanitizerSet, TlsModel};
2021

2122
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
@@ -81,6 +82,10 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
8182
return library.kind.is_statically_included().then_some(def_id);
8283
}
8384

85+
if tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden) {
86+
return None;
87+
}
88+
8489
// Only consider nodes that actually have exported symbols.
8590
match tcx.def_kind(def_id) {
8691
DefKind::Fn | DefKind::Static(_) => {}

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 42 additions & 17 deletions
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;
@@ -672,7 +672,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
672672
&mut self,
673673
helper: &TerminatorCodegenHelper<'tcx>,
674674
bx: &mut Bx,
675-
intrinsic: Option<Symbol>,
675+
intrinsic: Option<ty::IntrinsicDef>,
676676
instance: Option<Instance<'tcx>>,
677677
source_info: mir::SourceInfo,
678678
target: Option<mir::BasicBlock>,
@@ -682,7 +682,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
682682
// Emit a panic or a no-op for `assert_*` intrinsics.
683683
// These are intrinsics that compile to panics so that we can get a message
684684
// which mentions the offending type, even from a const context.
685-
let panic_intrinsic = intrinsic.and_then(|s| ValidityRequirement::from_intrinsic(s));
685+
let panic_intrinsic = intrinsic.and_then(|i| ValidityRequirement::from_intrinsic(i.name));
686686
if let Some(requirement) = panic_intrinsic {
687687
let ty = instance.unwrap().args.type_at(0);
688688

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

821-
if intrinsic == Some(sym::caller_location) {
821+
if matches!(intrinsic, Some(ty::IntrinsicDef { name: sym::caller_location, .. })) {
822822
return if let Some(target) = target {
823823
let location =
824824
self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info });
825825

826826
let mut llargs = Vec::with_capacity(arg_count);
827-
let ret_dest =
828-
self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, true, true);
827+
let ret_dest = self.make_return_dest(
828+
bx,
829+
destination,
830+
&fn_abi.ret,
831+
&mut llargs,
832+
intrinsic,
833+
Some(target),
834+
);
829835
assert_eq!(llargs, []);
830836
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
831837
location.val.store(bx, tmp);
@@ -838,16 +844,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
838844
}
839845

840846
let instance = match intrinsic {
841-
None | Some(sym::drop_in_place) => instance,
847+
None | Some(ty::IntrinsicDef { name: sym::drop_in_place, .. }) => instance,
842848
Some(intrinsic) => {
843849
let mut llargs = Vec::with_capacity(1);
844850
let ret_dest = self.make_return_dest(
845851
bx,
846852
destination,
847853
&fn_abi.ret,
848854
&mut llargs,
849-
true,
850-
target.is_some(),
855+
Some(intrinsic),
856+
target,
851857
);
852858
let dest = match ret_dest {
853859
_ if fn_abi.ret.is_indirect() => llargs[0],
@@ -866,7 +872,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
866872
// third argument must be constant. This is
867873
// checked by const-qualification, which also
868874
// promotes any complex rvalues to constants.
869-
if i == 2 && intrinsic == sym::simd_shuffle {
875+
if i == 2 && intrinsic.name == sym::simd_shuffle {
870876
if let mir::Operand::Constant(constant) = &arg.node {
871877
let (llval, ty) = self.simd_shuffle_indices(bx, constant);
872878
return OperandRef {
@@ -896,14 +902,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
896902
MergingSucc::False
897903
};
898904
}
899-
Err(instance) => Some(instance),
905+
Err(instance) => {
906+
if intrinsic.must_be_overridden {
907+
span_bug!(
908+
span,
909+
"intrinsic {} must be overridden by codegen backend, but isn't",
910+
intrinsic.name,
911+
);
912+
}
913+
Some(instance)
914+
}
900915
}
901916
}
902917
};
903918

904919
let mut llargs = Vec::with_capacity(arg_count);
905920
let destination = target.as_ref().map(|&target| {
906-
(self.make_return_dest(bx, destination, &fn_abi.ret, &mut llargs, false, true), target)
921+
(
922+
self.make_return_dest(
923+
bx,
924+
destination,
925+
&fn_abi.ret,
926+
&mut llargs,
927+
None,
928+
Some(target),
929+
),
930+
target,
931+
)
907932
});
908933

909934
// Split the rust-call tupled arguments off.
@@ -1636,10 +1661,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
16361661
dest: mir::Place<'tcx>,
16371662
fn_ret: &ArgAbi<'tcx, Ty<'tcx>>,
16381663
llargs: &mut Vec<Bx::Value>,
1639-
is_intrinsic: bool,
1640-
has_target: bool,
1664+
intrinsic: Option<ty::IntrinsicDef>,
1665+
target: Option<BasicBlock>,
16411666
) -> ReturnDest<'tcx, Bx::Value> {
1642-
if !has_target {
1667+
if target.is_none() {
16431668
return ReturnDest::Nothing;
16441669
}
16451670
// If the return is ignored, we can just return a do-nothing `ReturnDest`.
@@ -1660,7 +1685,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
16601685
tmp.storage_live(bx);
16611686
llargs.push(tmp.llval);
16621687
ReturnDest::IndirectOperand(tmp, index)
1663-
} else if is_intrinsic {
1688+
} else if intrinsic.is_some() {
16641689
// Currently, intrinsics always need a location to store
16651690
// the result, so we create a temporary `alloca` for the
16661691
// result.

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
792792
rustc_intrinsic, Normal, template!(Word), ErrorFollowing,
793793
"the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies",
794794
),
795+
rustc_attr!(
796+
rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing,
797+
"the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies",
798+
),
795799

796800
// ==========================================================================
797801
// Internal attributes, Testing:

compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 2 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
540540

541541
if let Some(def_id) = def_id
542542
&& self.tcx.def_kind(def_id) == hir::def::DefKind::Fn
543-
&& matches!(self.tcx.intrinsic(def_id), Some(sym::const_eval_select))
543+
&& self.tcx.is_intrinsic(def_id, sym::const_eval_select)
544544
{
545545
let fn_sig = self.resolve_vars_if_possible(fn_sig);
546546
for idx in 0..=1 {

compiler/rustc_lint/src/builtin.rs

Lines changed: 1 addition & 1 deletion
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,13 +1051,18 @@ fn should_encode_mir(
10511051
// Coroutines require optimized MIR to compute layout.
10521052
DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => (false, true),
10531053
// Full-fledged functions + closures
1054-
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
1054+
def_kind @ (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 matches!(def_kind, DefKind::AssocFn | DefKind::Fn) {
1062+
if let Some(intrinsic) = tcx.intrinsic(def_id) {
1063+
opt &= !intrinsic.must_be_overridden;
1064+
}
1065+
}
10611066
// The function has a `const` modifier or is in a `#[const_trait]`.
10621067
let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
10631068
|| tcx.is_const_default_method(def_id.to_def_id());

0 commit comments

Comments
 (0)