1
Fork 0

Auto merge of #97012 - oli-obk:🦀_intrinsics, r=davidtwco

Add a query for checking whether a function is an intrinsic.

work towards #93145

This will reduce churn when we add more ways to declare intrinsics

r? `@scottmcm`
This commit is contained in:
bors 2022-05-17 09:39:26 +00:00
commit 735efc0c70
17 changed files with 52 additions and 45 deletions

View file

@ -4,7 +4,6 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{DefIdTree, TyCtxt}; use rustc_middle::ty::{DefIdTree, TyCtxt};
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_target::spec::abi::Abi;
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> { pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
@ -34,10 +33,7 @@ fn impl_constness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Constness {
hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => { hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) => {
// Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
// foreign items cannot be evaluated at compile-time. // foreign items cannot be evaluated at compile-time.
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let is_const = if tcx.is_intrinsic(def_id) {
let is_const = if let Abi::RustIntrinsic | Abi::PlatformIntrinsic =
tcx.hir().get_foreign_abi(hir_id)
{
tcx.lookup_const_stability(def_id).is_some() tcx.lookup_const_stability(def_id).is_some()
} else { } else {
false false

View file

@ -312,8 +312,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}; };
match instance.def { match instance.def {
ty::InstanceDef::Intrinsic(..) => { ty::InstanceDef::Intrinsic(def_id) => {
assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic); assert!(self.tcx.is_intrinsic(def_id));
// caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic. // caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic.
M::call_intrinsic(self, instance, args, ret, unwind) M::call_intrinsic(self, instance, args, ret, unwind)
} }

View file

@ -702,8 +702,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
use rustc_target::spec::abi::Abi::RustIntrinsic;
self.super_terminator(terminator, location); self.super_terminator(terminator, location);
match &terminator.kind { match &terminator.kind {
@ -885,7 +883,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
return; return;
} }
let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic; let is_intrinsic = tcx.is_intrinsic(callee);
if !tcx.is_const_fn_raw(callee) { if !tcx.is_const_fn_raw(callee) {
if tcx.trait_of_item(callee).is_some() { if tcx.trait_of_item(callee).is_some() {

View file

@ -1252,7 +1252,6 @@ declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]);
impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
use rustc_target::spec::abi::Abi::RustIntrinsic;
if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) = if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) =
get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
{ {
@ -1287,8 +1286,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
} }
fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool { fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool {
cx.tcx.fn_sig(def_id).abi() == RustIntrinsic cx.tcx.is_intrinsic(def_id) && cx.tcx.item_name(def_id) == sym::transmute
&& cx.tcx.item_name(def_id) == sym::transmute
} }
} }
} }

View file

@ -1752,6 +1752,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
fn get_may_have_doc_links(self, index: DefIndex) -> bool { fn get_may_have_doc_links(self, index: DefIndex) -> bool {
self.root.tables.may_have_doc_links.get(self, index).is_some() self.root.tables.may_have_doc_links.get(self, index).is_some()
} }
fn get_is_intrinsic(self, index: DefIndex) -> bool {
self.root.tables.is_intrinsic.get(self, index).is_some()
}
} }
impl CrateMetadata { impl CrateMetadata {

View file

@ -224,6 +224,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
tcx.arena.alloc_slice(&result) tcx.arena.alloc_slice(&result)
} }
defined_lib_features => { cdata.get_lib_features(tcx) } defined_lib_features => { cdata.get_lib_features(tcx) }
is_intrinsic => { cdata.get_is_intrinsic(def_id.index) }
defined_lang_items => { cdata.get_lang_items(tcx) } defined_lang_items => { cdata.get_lang_items(tcx) }
diagnostic_items => { cdata.get_diagnostic_items() } diagnostic_items => { cdata.get_diagnostic_items() }
missing_lang_items => { cdata.get_missing_lang_items(tcx) } missing_lang_items => { cdata.get_missing_lang_items(tcx) }

View file

@ -1318,6 +1318,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} }
if impl_item.kind == ty::AssocKind::Fn { if impl_item.kind == ty::AssocKind::Fn {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
if tcx.is_intrinsic(def_id) {
self.tables.is_intrinsic.set(def_id.index, ());
}
} }
} }
@ -1562,6 +1565,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
} }
if let hir::ItemKind::Fn(..) = item.kind { if let hir::ItemKind::Fn(..) = item.kind {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
if tcx.is_intrinsic(def_id) {
self.tables.is_intrinsic.set(def_id.index, ());
}
} }
if let hir::ItemKind::Impl { .. } = item.kind { if let hir::ItemKind::Impl { .. } = item.kind {
if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) { if let Some(trait_ref) = self.tcx.impl_trait_ref(def_id) {
@ -1958,6 +1964,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
self.encode_item_type(def_id); self.encode_item_type(def_id);
if let hir::ForeignItemKind::Fn(..) = nitem.kind { if let hir::ForeignItemKind::Fn(..) = nitem.kind {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
if tcx.is_intrinsic(def_id) {
self.tables.is_intrinsic.set(def_id.index, ());
}
} }
} }
} }

View file

@ -340,6 +340,7 @@ define_tables! {
impl_parent: Table<DefIndex, RawDefId>, impl_parent: Table<DefIndex, RawDefId>,
impl_polarity: Table<DefIndex, ty::ImplPolarity>, impl_polarity: Table<DefIndex, ty::ImplPolarity>,
impl_constness: Table<DefIndex, hir::Constness>, impl_constness: Table<DefIndex, hir::Constness>,
is_intrinsic: Table<DefIndex, ()>,
impl_defaultness: Table<DefIndex, hir::Defaultness>, impl_defaultness: Table<DefIndex, hir::Defaultness>,
// FIXME(eddyb) perhaps compute this on the fly if cheap enough? // FIXME(eddyb) perhaps compute this on the fly if cheap enough?
coerce_unsized_info: Table<DefIndex, Lazy!(ty::adjustment::CoerceUnsizedInfo)>, coerce_unsized_info: Table<DefIndex, Lazy!(ty::adjustment::CoerceUnsizedInfo)>,

View file

@ -1601,6 +1601,11 @@ rustc_queries! {
desc { "calculating the lib features defined in a crate" } desc { "calculating the lib features defined in a crate" }
separate_provide_extern separate_provide_extern
} }
/// Whether the function is an intrinsic
query is_intrinsic(def_id: DefId) -> bool {
desc { |tcx| "is_intrinsic({})", tcx.def_path_str(def_id) }
separate_provide_extern
}
/// Returns the lang items defined in another crate by loading it from metadata. /// Returns the lang items defined in another crate by loading it from metadata.
query get_lang_items(_: ()) -> LanguageItems { query get_lang_items(_: ()) -> LanguageItems {
storage(ArenaCacheSelector<'tcx>) storage(ArenaCacheSelector<'tcx>)

View file

@ -21,6 +21,7 @@ use rustc_hir::def_id::DefId;
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_span::{sym, DUMMY_SP}; use rustc_span::{sym, DUMMY_SP};
use rustc_target::abi::{Integer, Size, TargetDataLayout}; use rustc_target::abi::{Integer, Size, TargetDataLayout};
use rustc_target::spec::abi::Abi;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{fmt, iter}; use std::{fmt, iter};
@ -1195,6 +1196,12 @@ pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
.any(|items| items.iter().any(|item| item.has_name(sym::hidden))) .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
} }
pub fn provide(providers: &mut ty::query::Providers) { /// Determines whether an item is an intrinsic by Abi.
*providers = ty::query::Providers { normalize_opaque_types, is_doc_hidden, ..*providers } pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
matches!(tcx.fn_sig(def_id).abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
}
pub fn provide(providers: &mut ty::query::Providers) {
*providers =
ty::query::Providers { normalize_opaque_types, is_doc_hidden, is_intrinsic, ..*providers }
} }

View file

@ -1,6 +1,5 @@
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
use rustc_target::spec::abi::Abi;
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_middle::mir::MirPass; use rustc_middle::mir::MirPass;
@ -193,9 +192,8 @@ impl PeekCall {
&terminator.kind &terminator.kind
{ {
if let ty::FnDef(def_id, substs) = *func.literal.ty().kind() { if let ty::FnDef(def_id, substs) = *func.literal.ty().kind() {
let sig = tcx.fn_sig(def_id);
let name = tcx.item_name(def_id); let name = tcx.item_name(def_id);
if sig.abi() != Abi::RustIntrinsic || name != sym::rustc_peek { if !tcx.is_intrinsic(def_id) || name != sym::rustc_peek {
return None; return None;
} }

View file

@ -418,8 +418,7 @@ impl<'tcx> Inliner<'tcx> {
} }
} }
// Don't give intrinsics the extra penalty for calls // Don't give intrinsics the extra penalty for calls
let f = tcx.fn_sig(def_id); if tcx.is_intrinsic(def_id) {
if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
cost += INSTR_COST; cost += INSTR_COST;
} else { } else {
cost += CALL_PENALTY; cost += CALL_PENALTY;

View file

@ -6,7 +6,6 @@ use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::symbol::{sym, Symbol}; use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span; use rustc_span::Span;
use rustc_target::spec::abi::Abi;
pub struct LowerIntrinsics; pub struct LowerIntrinsics;
@ -139,8 +138,7 @@ fn resolve_rust_intrinsic<'tcx>(
func_ty: Ty<'tcx>, func_ty: Ty<'tcx>,
) -> Option<(Symbol, SubstsRef<'tcx>)> { ) -> Option<(Symbol, SubstsRef<'tcx>)> {
if let ty::FnDef(def_id, substs) = *func_ty.kind() { if let ty::FnDef(def_id, substs) = *func_ty.kind() {
let fn_sig = func_ty.fn_sig(tcx); if tcx.is_intrinsic(def_id) {
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() {
return Some((tcx.item_name(def_id), substs)); return Some((tcx.item_name(def_id), substs));
} }
} }

View file

@ -14,7 +14,6 @@ use rustc_session::lint;
use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_span::{sym, Span, Symbol, DUMMY_SP};
use rustc_target::abi::{Pointer, VariantIdx}; use rustc_target::abi::{Pointer, VariantIdx};
use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType}; use rustc_target::asm::{InlineAsmRegOrRegClass, InlineAsmType};
use rustc_target::spec::abi::Abi::RustIntrinsic;
fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { fn check_mod_intrinsics(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx }); tcx.hir().deep_visit_item_likes_in_module(module_def_id, &mut ItemVisitor { tcx });
@ -63,8 +62,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
impl<'tcx> ExprVisitor<'tcx> { impl<'tcx> ExprVisitor<'tcx> {
fn def_id_is_transmute(&self, def_id: DefId) -> bool { fn def_id_is_transmute(&self, def_id: DefId) -> bool {
self.tcx.fn_sig(def_id).abi() == RustIntrinsic self.tcx.is_intrinsic(def_id) && self.tcx.item_name(def_id) == sym::transmute
&& self.tcx.item_name(def_id) == sym::transmute
} }
fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) { fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {

View file

@ -5,7 +5,6 @@ use rustc_middle::traits::CodegenObligationError;
use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_middle::ty::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::{sym, DUMMY_SP}; use rustc_span::{sym, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits; use rustc_trait_selection::traits;
use traits::{translate_substs, Reveal}; use traits::{translate_substs, Reveal};
@ -155,12 +154,7 @@ fn inner_resolve_instance<'tcx>(
let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty); let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
let def = match *item_type.kind() { let def = match *item_type.kind() {
ty::FnDef(..) ty::FnDef(def_id, ..) if tcx.is_intrinsic(def_id) => {
if {
let f = item_type.fn_sig(tcx);
f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic
} =>
{
debug!(" => intrinsic"); debug!(" => intrinsic");
ty::InstanceDef::Intrinsic(def.did) ty::InstanceDef::Intrinsic(def.did)
} }

View file

@ -775,17 +775,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
match b.kind() { match b.kind() {
ty::FnPtr(b_sig) => { ty::FnPtr(b_sig) => {
let a_sig = a.fn_sig(self.tcx); let a_sig = a.fn_sig(self.tcx);
// Intrinsics are not coercible to function pointers if let ty::FnDef(def_id, _) = *a.kind() {
if a_sig.abi() == Abi::RustIntrinsic || a_sig.abi() == Abi::PlatformIntrinsic { // Intrinsics are not coercible to function pointers
return Err(TypeError::IntrinsicCast); if self.tcx.is_intrinsic(def_id) {
} return Err(TypeError::IntrinsicCast);
}
// Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396). // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
if let ty::FnDef(def_id, _) = *a.kind()
&& b_sig.unsafety() == hir::Unsafety::Normal if b_sig.unsafety() == hir::Unsafety::Normal
&& !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
{ {
return Err(TypeError::TargetFeatureCast(def_id)); return Err(TypeError::TargetFeatureCast(def_id));
}
} }
let InferOk { value: a_sig, obligations: o1 } = let InferOk { value: a_sig, obligations: o1 } =

View file

@ -14,7 +14,6 @@ use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
use rustc_semver::RustcVersion; use rustc_semver::RustcVersion;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::Span; use rustc_span::Span;
use rustc_target::spec::abi::Abi::RustIntrinsic;
use std::borrow::Cow; use std::borrow::Cow;
type McfResult = Result<(), (Span, Cow<'static, str>)>; type McfResult = Result<(), (Span, Cow<'static, str>)>;
@ -323,7 +322,7 @@ fn check_terminator<'a, 'tcx>(
// within const fns. `transmute` is allowed in all other const contexts. // 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 // 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. // transmutes in const fn before we add more hacks to this.
if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic && tcx.item_name(fn_def_id) == sym::transmute { if tcx.is_intrinsic(fn_def_id) && tcx.item_name(fn_def_id) == sym::transmute {
return Err(( return Err((
span, span,
"can only call `transmute` from const items, not `const fn`".into(), "can only call `transmute` from const items, not `const fn`".into(),