From 95d7abf48627b25a91f24f861459f1e912988ee7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 5 Feb 2024 11:52:55 +0000 Subject: [PATCH] Add a scheme for moving away from `extern "rust-intrinsic"` entirely --- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- .../rustc_codegen_cranelift/src/abi/mod.rs | 12 +++++++++- .../src/back/symbol_export.rs | 5 ++++ compiler/rustc_codegen_ssa/src/mir/block.rs | 23 +++++++++++++------ compiler/rustc_feature/src/builtin_attrs.rs | 4 ++++ .../rustc_hir_analysis/src/check/check.rs | 4 ++-- compiler/rustc_hir_typeck/src/callee.rs | 2 +- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/query/erase.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/intrinsic.rs | 17 ++++++++++++++ compiler/rustc_middle/src/ty/mod.rs | 2 ++ compiler/rustc_middle/src/ty/parameterized.rs | 1 + compiler/rustc_middle/src/ty/util.rs | 9 +++++--- compiler/rustc_mir_dataflow/src/rustc_peek.rs | 2 +- .../src/cross_crate_inline.rs | 5 ++++ .../rustc_mir_transform/src/instsimplify.rs | 4 ++-- compiler/rustc_mir_transform/src/lib.rs | 8 ++++++- .../src/lower_intrinsics.rs | 10 ++++---- compiler/rustc_monomorphize/src/collector.rs | 5 ++++ compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics.rs | 15 ++++++++---- .../clippy_utils/src/qualify_min_const_fn.rs | 2 +- tests/ui/intrinsics/always-gets-overridden.rs | 20 ++++++++++++++++ tests/ui/intrinsics/not-overridden.rs | 18 +++++++++++++++ tests/ui/intrinsics/not-overridden.stderr | 10 ++++++++ 28 files changed, 156 insertions(+), 35 deletions(-) create mode 100644 compiler/rustc_middle/src/ty/intrinsic.rs create mode 100644 tests/ui/intrinsics/always-gets-overridden.rs create mode 100644 tests/ui/intrinsics/not-overridden.rs create mode 100644 tests/ui/intrinsics/not-overridden.stderr diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 5b943ab8ae975..131427ae4acc4 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1648,7 +1648,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let func_ty = func.ty(body, self.infcx.tcx); if let ty::FnDef(def_id, _) = *func_ty.kind() { - if let Some(sym::simd_shuffle) = self.tcx().intrinsic(def_id) { + if self.tcx().is_intrinsic(def_id, sym::simd_shuffle) { if !matches!(args[2], Spanned { node: Operand::Constant(_), .. }) { self.tcx().dcx().emit_err(SimdShuffleLastConst { span: term.source_info.span }); } diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index fd1f081a0a8e7..2bca20b2d0391 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -398,7 +398,17 @@ pub(crate) fn codegen_terminator_call<'tcx>( Ok(()) => return, // Unimplemented intrinsics must have a fallback body. The fallback body is obtained // by converting the `InstanceDef::Intrinsic` to an `InstanceDef::Item`. - Err(()) => Some(Instance::new(instance.def_id(), instance.args)), + Err(()) => { + let intrinsic = fx.tcx.intrinsic(instance.def_id()).unwrap(); + if intrinsic.must_be_overridden { + span_bug!( + source_info.span, + "intrinsic {} must be overridden by codegen_cranelift, but isn't", + intrinsic.name, + ); + } + Some(Instance::new(instance.def_id(), instance.args)) + } } } InstanceDef::DropGlue(_, None) => { diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 2dba04e0bb71b..347a968a303ba 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -16,6 +16,7 @@ use rustc_middle::ty::{self, SymbolName, TyCtxt}; use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; use rustc_middle::util::Providers; use rustc_session::config::{CrateType, OomStrategy}; +use rustc_span::sym; use rustc_target::spec::{SanitizerSet, TlsModel}; pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { @@ -81,6 +82,10 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap {} diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 765c86548c42c..f09889cb24ae6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -17,7 +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_session::config::OptLevel; -use rustc_span::{source_map::Spanned, sym, Span, Symbol}; +use rustc_span::{source_map::Spanned, sym, Span}; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg}; use rustc_target::abi::{self, HasDataLayout, WrappingRange}; use rustc_target::spec::abi::Abi; @@ -672,7 +672,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, helper: &TerminatorCodegenHelper<'tcx>, bx: &mut Bx, - intrinsic: Option, + intrinsic: Option, instance: Option>, source_info: mir::SourceInfo, target: Option, @@ -682,7 +682,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Emit a panic or a no-op for `assert_*` intrinsics. // These are intrinsics that compile to panics so that we can get a message // which mentions the offending type, even from a const context. - let panic_intrinsic = intrinsic.and_then(|s| ValidityRequirement::from_intrinsic(s)); + let panic_intrinsic = intrinsic.and_then(|i| ValidityRequirement::from_intrinsic(i.name)); if let Some(requirement) = panic_intrinsic { let ty = instance.unwrap().args.type_at(0); @@ -818,7 +818,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // The arguments we'll be passing. Plus one to account for outptr, if used. let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize; - if intrinsic == Some(sym::caller_location) { + if matches!(intrinsic, Some(ty::IntrinsicDef { name: sym::caller_location, .. })) { return if let Some(target) = target { let location = self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); @@ -838,7 +838,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let instance = match intrinsic { - None | Some(sym::drop_in_place) => instance, + None | Some(ty::IntrinsicDef { name: sym::drop_in_place, .. }) => instance, Some(intrinsic) => { let mut llargs = Vec::with_capacity(1); let ret_dest = self.make_return_dest( @@ -866,7 +866,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // third argument must be constant. This is // checked by const-qualification, which also // promotes any complex rvalues to constants. - if i == 2 && intrinsic == sym::simd_shuffle { + if i == 2 && intrinsic.name == sym::simd_shuffle { if let mir::Operand::Constant(constant) = &arg.node { let (llval, ty) = self.simd_shuffle_indices(bx, constant); return OperandRef { @@ -897,7 +897,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; } // Call the fallback body instead of generating the intrinsic code - Err(()) => Some(Instance::new(instance.def_id(), instance.args)), + Err(()) => { + if intrinsic.must_be_overridden { + span_bug!( + span, + "intrinsic {} must be overridden by codegen backend, but isn't", + intrinsic.name, + ); + } + Some(Instance::new(instance.def_id(), instance.args)) + } } } }; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 7484309a780aa..5234d9d2af1bb 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -795,6 +795,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_intrinsic, Normal, template!(Word), ErrorFollowing, "the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies", ), + rustc_attr!( + rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, + "the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies", + ), // ========================================================================== // Internal attributes, Testing: diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 31e796dd6331d..4bdb185144fa8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -473,12 +473,12 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_enum(tcx, def_id); } DefKind::Fn => { - if let Some(name) = tcx.intrinsic(def_id) { + if let Some(i) = tcx.intrinsic(def_id) { intrinsic::check_intrinsic_type( tcx, def_id, tcx.def_ident_span(def_id).unwrap(), - name, + i.name, Abi::Rust, ) } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index c49d965683648..86118cfc88a54 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -480,7 +480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(def_id) = def_id && self.tcx.def_kind(def_id) == hir::def::DefKind::Fn - && matches!(self.tcx.intrinsic(def_id), Some(sym::const_eval_select)) + && self.tcx.is_intrinsic(def_id, sym::const_eval_select) { let fn_sig = self.resolve_vars_if_possible(fn_sig); for idx in 0..=1 { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 8c234f85425f3..e9b12865d2a0f 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1227,7 +1227,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { } fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool { - matches!(cx.tcx.intrinsic(def_id), Some(sym::transmute)) + cx.tcx.is_intrinsic(def_id, sym::transmute) } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 3ac284034882e..7076a7c83a7d3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1744,7 +1744,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.root.tables.attr_flags.get(self, index) } - fn get_intrinsic(self, index: DefIndex) -> Option { + fn get_intrinsic(self, index: DefIndex) -> Option { self.root.tables.intrinsic.get(self, index).map(|d| d.decode(self)) } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 0814308755fa8..4660a2c97fa8e 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -375,7 +375,7 @@ macro_rules! define_tables { define_tables! { - defaulted: - intrinsic: Table>>, + intrinsic: Table>>, is_macro_rules: Table, is_type_alias_impl_trait: Table, type_alias_is_lazy: Table, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 92ce3854b92a8..f2862b9d5295c 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -240,7 +240,7 @@ trivial! { Option, Option, Option, - Option, + Option, Result<(), rustc_errors::ErrorGuaranteed>, Result<(), rustc_middle::traits::query::NoSolution>, Result, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 1df62518621e5..522b26b79dfc7 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1748,7 +1748,7 @@ rustc_queries! { separate_provide_extern } /// Whether the function is an intrinsic - query intrinsic(def_id: DefId) -> Option { + query intrinsic(def_id: DefId) -> Option { desc { |tcx| "fetch intrinsic name if `{}` is an intrinsic", tcx.def_path_str(def_id) } separate_provide_extern } diff --git a/compiler/rustc_middle/src/ty/intrinsic.rs b/compiler/rustc_middle/src/ty/intrinsic.rs new file mode 100644 index 0000000000000..18d08ed23a5e5 --- /dev/null +++ b/compiler/rustc_middle/src/ty/intrinsic.rs @@ -0,0 +1,17 @@ +use rustc_span::{def_id::DefId, Symbol}; + +use super::TyCtxt; + +#[derive(Copy, Clone, Debug, Decodable, Encodable, HashStable)] +pub struct IntrinsicDef { + pub name: Symbol, + /// Whether the intrinsic has no meaningful body and all backends need to shim all calls to it. + pub must_be_overridden: bool, +} + +impl TyCtxt<'_> { + pub fn is_intrinsic(self, def_id: DefId, name: Symbol) -> bool { + let Some(i) = self.intrinsic(def_id) else { return false }; + i.name == name + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 8e51db82f95ae..232d22ff11833 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -30,6 +30,7 @@ pub use adt::*; pub use assoc::*; pub use generic_args::*; pub use generics::*; +pub use intrinsic::IntrinsicDef; use rustc_ast as ast; use rustc_ast::node_id::NodeMap; use rustc_attr as attr; @@ -147,6 +148,7 @@ mod generic_args; mod generics; mod impls_ty; mod instance; +mod intrinsic; mod list; mod opaque_types; mod parameterized; diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 47f9d9e61ad96..6e9bb101191d2 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -75,6 +75,7 @@ trivially_parameterized_over_tcx! { ty::Visibility, ty::adjustment::CoerceUnsizedInfo, ty::fast_reject::SimplifiedType, + ty::IntrinsicDef, rustc_ast::Attribute, rustc_ast::DelimArgs, rustc_ast::expand::StrippedCfgItem, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 56db543d24207..1e40e9f19c12e 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -18,7 +18,7 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_index::bit_set::GrowableBitSet; use rustc_macros::HashStable; use rustc_session::Limit; -use rustc_span::{sym, Symbol}; +use rustc_span::sym; use rustc_target::abi::{Integer, IntegerType, Primitive, Size}; use rustc_target::spec::abi::Abi; use smallvec::SmallVec; @@ -1539,11 +1539,14 @@ pub fn is_doc_notable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } /// Determines whether an item is an intrinsic by Abi. or by whether it has a `rustc_intrinsic` attribute -pub fn intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { +pub fn intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { if matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) || tcx.has_attr(def_id, sym::rustc_intrinsic) { - Some(tcx.item_name(def_id.into())) + Some(ty::IntrinsicDef { + name: tcx.item_name(def_id.into()), + must_be_overridden: tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden), + }) } else { None } diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 1575f31e75e0e..d7e3c91b875f8 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -202,7 +202,7 @@ impl PeekCall { &terminator.kind { if let ty::FnDef(def_id, fn_args) = *func.const_.ty().kind() { - if tcx.intrinsic(def_id)? != sym::rustc_peek { + if tcx.intrinsic(def_id)?.name != sym::rustc_peek { return None; } diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 5f01b841867ea..2f0ab05de26ab 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -9,6 +9,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::InliningThreshold; use rustc_session::config::OptLevel; +use rustc_span::sym; pub fn provide(providers: &mut Providers) { providers.cross_crate_inlinable = cross_crate_inlinable; @@ -22,6 +23,10 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return false; } + if tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden) { + return false; + } + // This just reproduces the logic from Instance::requires_inline. match tcx.def_kind(def_id) { DefKind::Ctor(..) | DefKind::Closure => return true, diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 6800b227e4346..5d645d78cc346 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -305,8 +305,8 @@ fn resolve_rust_intrinsic<'tcx>( func_ty: Ty<'tcx>, ) -> Option<(Symbol, GenericArgsRef<'tcx>)> { if let ty::FnDef(def_id, args) = *func_ty.kind() { - let name = tcx.intrinsic(def_id)?; - return Some((name, args)); + let intrinsic = tcx.intrinsic(def_id)?; + return Some((intrinsic.name, args)); } None } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index af7010772632c..07f0f1717a69b 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -165,7 +165,7 @@ fn remap_mir_for_const_eval_select<'tcx>( fn_span, .. } if let ty::FnDef(def_id, _) = *const_.ty().kind() - && matches!(tcx.intrinsic(def_id), Some(sym::const_eval_select)) => + && tcx.is_intrinsic(def_id, sym::const_eval_select) => { let [tupled_args, called_in_const, called_at_rt]: [_; 3] = std::mem::take(args).try_into().unwrap(); @@ -637,6 +637,12 @@ fn optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &Body<'_> { } fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { + if let Some(attr) = tcx.get_attr(did, sym::rustc_intrinsic_must_be_overridden) { + span_bug!( + attr.span, + "this intrinsic must be overridden by the codegen backend, it has no meaningful body", + ) + } if tcx.is_constructor(did.to_def_id()) { // There's no reason to run all of the MIR passes on constructors when // we can just output the MIR we want directly. This also saves const diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 1c7ea094327c7..37e23dc4a9819 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -14,9 +14,9 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { if let TerminatorKind::Call { func, args, destination, target, .. } = &mut terminator.kind && let ty::FnDef(def_id, generic_args) = *func.ty(local_decls, tcx).kind() - && let Some(intrinsic_name) = tcx.intrinsic(def_id) + && let Some(intrinsic) = tcx.intrinsic(def_id) { - match intrinsic_name { + match intrinsic.name { sym::unreachable => { terminator.kind = TerminatorKind::Unreachable; } @@ -94,7 +94,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { lhs = args.next().unwrap(); rhs = args.next().unwrap(); } - let bin_op = match intrinsic_name { + let bin_op = match intrinsic.name { sym::wrapping_add => BinOp::Add, sym::wrapping_sub => BinOp::Sub, sym::wrapping_mul => BinOp::Mul, @@ -125,7 +125,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { lhs = args.next().unwrap(); rhs = args.next().unwrap(); } - let bin_op = match intrinsic_name { + let bin_op = match intrinsic.name { sym::add_with_overflow => BinOp::Add, sym::sub_with_overflow => BinOp::Sub, sym::mul_with_overflow => BinOp::Mul, @@ -144,7 +144,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { sym::size_of | sym::min_align_of => { if let Some(target) = *target { let tp_ty = generic_args.type_at(0); - let null_op = match intrinsic_name { + let null_op = match intrinsic.name { sym::size_of => NullOp::SizeOf, sym::min_align_of => NullOp::AlignOf, _ => bug!("unexpected intrinsic"), diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 2e9e9a2a8c254..24dc167508c5d 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1009,6 +1009,11 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> return false; } + if tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden) { + // These are implemented by backends directly and have no meaningful body. + return false; + } + if def_id.is_local() { // Local items cannot be referred to locally without monomorphizing them locally. return true; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2529c7f1256ad..2030f495f1002 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1412,6 +1412,7 @@ symbols! { rustc_inherit_overflow_checks, rustc_insignificant_dtor, rustc_intrinsic, + rustc_intrinsic_must_be_overridden, rustc_layout, rustc_layout_scalar_valid_range_end, rustc_layout_scalar_valid_range_start, diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 5f6b43f0f5d91..8b6553a38c8e8 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2419,11 +2419,6 @@ extern "rust-intrinsic" { #[rustc_nounwind] pub fn black_box(dummy: T) -> T; - /// `ptr` must point to a vtable. - /// The intrinsic will return the size stored in that vtable. - #[rustc_nounwind] - pub fn vtable_size(ptr: *const ()) -> usize; - /// `ptr` must point to a vtable. /// The intrinsic will return the alignment stored in that vtable. #[rustc_nounwind] @@ -2576,6 +2571,16 @@ pub const unsafe fn const_allocate(_size: usize, _align: usize) -> *mut u8 { #[cfg_attr(not(bootstrap), rustc_intrinsic)] pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} +/// `ptr` must point to a vtable. +/// The intrinsic will return the size stored in that vtable. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[cfg_attr(not(bootstrap), rustc_intrinsic_must_be_overridden)] +pub unsafe fn vtable_size(_ptr: *const ()) -> usize { + loop {} +} + // Some functions are defined here because they accidentally got made // available in this module on stable. See . // (`transmute` also falls into this category, but it cannot be wrapped due to the diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index c44edc21005ea..8432cbfcd3cbd 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -335,7 +335,7 @@ fn check_terminator<'tcx>( // within const fns. `transmute` is allowed in all other const contexts. // This won't really scale to more intrinsics or functions. Let's allow const // transmutes in const fn before we add more hacks to this. - if matches!(tcx.intrinsic(fn_def_id), Some(sym::transmute)) { + if tcx.is_intrinsic(fn_def_id, sym::transmute) { return Err(( span, "can only call `transmute` from const items, not `const fn`".into(), diff --git a/tests/ui/intrinsics/always-gets-overridden.rs b/tests/ui/intrinsics/always-gets-overridden.rs new file mode 100644 index 0000000000000..3f5dce9ee8a14 --- /dev/null +++ b/tests/ui/intrinsics/always-gets-overridden.rs @@ -0,0 +1,20 @@ +//! Check that `vtable_size` gets overridden by llvm backend even if there is no +//! `rustc_intrinsic_must_be_overridden` attribute on this usage. +#![feature(rustc_attrs)] +// run-pass + +#[rustc_intrinsic] +pub unsafe fn vtable_size(_ptr: *const ()) -> usize { + panic!(); +} + +trait Trait {} +impl Trait for () {} + +fn main() { + let x: &dyn Trait = &(); + unsafe { + let (_data, vtable): (*const (), *const ()) = core::mem::transmute(x); + assert_eq!(vtable_size(vtable), 0); + } +} diff --git a/tests/ui/intrinsics/not-overridden.rs b/tests/ui/intrinsics/not-overridden.rs new file mode 100644 index 0000000000000..04bb7bf13513a --- /dev/null +++ b/tests/ui/intrinsics/not-overridden.rs @@ -0,0 +1,18 @@ +//! Check that intrinsics that do not get overridden, but are marked as such, +//! cause an error instead of silently invoking the body. +#![feature(rustc_attrs, effects)] +// build-fail +// failure-status:101 +// normalize-stderr-test ".*note: .*\n\n" -> "" +// normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> "" +// normalize-stderr-test "internal compiler error:.*: intrinsic const_deallocate " -> "" +// rustc-env:RUST_BACKTRACE=0 + +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {} + +fn main() { + unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) } + //~^ ERROR: must be overridden +} diff --git a/tests/ui/intrinsics/not-overridden.stderr b/tests/ui/intrinsics/not-overridden.stderr new file mode 100644 index 0000000000000..9b8849cea1ced --- /dev/null +++ b/tests/ui/intrinsics/not-overridden.stderr @@ -0,0 +1,10 @@ +error: must be overridden by codegen backend, but isn't + --> $DIR/not-overridden.rs:16:14 + | +LL | unsafe { const_deallocate(std::ptr::null_mut(), 0, 0) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +query stack during panic: +end of query stack +error: aborting due to 1 previous error +