1
Fork 0

Auto merge of #96473 - lcnr:querify-codegen-fn-attrs, r=cjgillot

store `codegen_fn_attrs` in crate metadata

extracted from #95562 because the change isn't trivial.
This commit is contained in:
bors 2022-05-09 19:52:59 +00:00
commit 88860d5474
17 changed files with 229 additions and 122 deletions

View file

@ -229,6 +229,43 @@ impl DefKind {
_ => false, _ => false,
} }
} }
/// Whether `query get_codegen_attrs` should be used with this definition.
pub fn has_codegen_attrs(self) -> bool {
match self {
DefKind::Fn
| DefKind::AssocFn
| DefKind::Ctor(..)
| DefKind::Closure
| DefKind::Generator
| DefKind::Static(_) => true,
DefKind::Mod
| DefKind::Struct
| DefKind::Union
| DefKind::Enum
| DefKind::Variant
| DefKind::Trait
| DefKind::TyAlias
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
| DefKind::Const
| DefKind::AssocConst
| DefKind::Macro(..)
| DefKind::Use
| DefKind::ForeignMod
| DefKind::OpaqueTy
| DefKind::Impl
| DefKind::Field
| DefKind::TyParam
| DefKind::ConstParam
| DefKind::LifetimeParam
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::ExternCrate => false,
}
}
} }
/// The resolution of a path or export. /// The resolution of a path or export.

View file

@ -129,6 +129,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
type_of => { table } type_of => { table }
variances_of => { table } variances_of => { table }
fn_sig => { table } fn_sig => { table }
codegen_fn_attrs => { table }
impl_trait_ref => { table } impl_trait_ref => { table }
const_param_default => { table } const_param_default => { table }
thir_abstract_const => { table } thir_abstract_const => { table }

View file

@ -1007,6 +1007,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
record!(self.tables.def_span[def_id] <- tcx.def_span(def_id)); record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
self.encode_attrs(def_id); self.encode_attrs(def_id);
record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id)); record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
if def_kind.has_codegen_attrs() {
record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
}
if should_encode_visibility(def_kind) { if should_encode_visibility(def_kind) {
record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
} }

View file

@ -14,6 +14,7 @@ use rustc_hir::definitions::DefKey;
use rustc_hir::lang_items; use rustc_hir::lang_items;
use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
use rustc_middle::metadata::ModChild; use rustc_middle::metadata::ModChild;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::thir; use rustc_middle::thir;
@ -329,6 +330,7 @@ define_tables! {
type_of: Table<DefIndex, Lazy!(Ty<'tcx>)>, type_of: Table<DefIndex, Lazy!(Ty<'tcx>)>,
variances_of: Table<DefIndex, Lazy<[ty::Variance]>>, variances_of: Table<DefIndex, Lazy<[ty::Variance]>>,
fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>, fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
codegen_fn_attrs: Table<DefIndex, Lazy!(CodegenFnAttrs)>,
impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>, impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,
const_param_default: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>, const_param_default: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>,
optimized_mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>, optimized_mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,

View file

@ -95,7 +95,9 @@ bitflags! {
} }
impl CodegenFnAttrs { impl CodegenFnAttrs {
pub fn new() -> CodegenFnAttrs { pub const EMPTY: &'static Self = &Self::new();
pub const fn new() -> CodegenFnAttrs {
CodegenFnAttrs { CodegenFnAttrs {
flags: CodegenFnAttrFlags::empty(), flags: CodegenFnAttrFlags::empty(),
inline: InlineAttr::None, inline: InlineAttr::None,

View file

@ -1080,7 +1080,8 @@ rustc_queries! {
query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs { query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) } desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) }
storage(ArenaCacheSelector<'tcx>) storage(ArenaCacheSelector<'tcx>)
cache_on_disk_if { true } cache_on_disk_if { def_id.is_local() }
separate_provide_extern
} }
query asm_target_features(def_id: DefId) -> &'tcx FxHashSet<Symbol> { query asm_target_features(def_id: DefId) -> &'tcx FxHashSet<Symbol> {

View file

@ -5,6 +5,7 @@ use crate::dep_graph::{DepGraph, DepKind, DepKindStruct};
use crate::hir::place::Place as HirPlace; use crate::hir::place::Place as HirPlace;
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos}; use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource}; use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath}; use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
use crate::middle::stability; use crate::middle::stability;
use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar}; use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
@ -1066,6 +1067,28 @@ pub struct GlobalCtxt<'tcx> {
} }
impl<'tcx> TyCtxt<'tcx> { impl<'tcx> TyCtxt<'tcx> {
/// Expects a body and returns its codegen attributes.
///
/// Unlike `codegen_fn_attrs`, this returns `CodegenFnAttrs::EMPTY` for
/// constants.
pub fn body_codegen_attrs(self, def_id: DefId) -> &'tcx CodegenFnAttrs {
let def_kind = self.def_kind(def_id);
if def_kind.has_codegen_attrs() {
self.codegen_fn_attrs(def_id)
} else if matches!(
def_kind,
DefKind::AnonConst | DefKind::AssocConst | DefKind::Const | DefKind::InlineConst
) {
CodegenFnAttrs::EMPTY
} else {
bug!(
"body_codegen_fn_attrs called on unexpected definition: {:?} {:?}",
def_id,
def_kind
)
}
}
pub fn typeck_opt_const_arg( pub fn typeck_opt_const_arg(
self, self,
def: ty::WithOptConstParam<LocalDefId>, def: ty::WithOptConstParam<LocalDefId>,

View file

@ -246,7 +246,7 @@ impl<'tcx> InstanceDef<'tcx> {
match *self { match *self {
InstanceDef::Item(ty::WithOptConstParam { did: def_id, .. }) InstanceDef::Item(ty::WithOptConstParam { did: def_id, .. })
| InstanceDef::Virtual(def_id, _) => { | InstanceDef::Virtual(def_id, _) => {
tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) tcx.body_codegen_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
} }
InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller, InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller,
_ => false, _ => false,

View file

@ -6,6 +6,7 @@ use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
use rustc_ast as ast; use rustc_ast as ast;
use rustc_attr as attr; use rustc_attr as attr;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec}; use rustc_index::vec::{Idx, IndexVec};
@ -2762,16 +2763,24 @@ impl<'tcx> ty::Instance<'tcx> {
/// with `-Cpanic=abort` will look like they can't unwind when in fact they /// with `-Cpanic=abort` will look like they can't unwind when in fact they
/// might (from a foreign exception or similar). /// might (from a foreign exception or similar).
#[inline] #[inline]
pub fn fn_can_unwind<'tcx>( pub fn fn_can_unwind<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: Option<DefId>, abi: SpecAbi) -> bool {
tcx: TyCtxt<'tcx>, if let Some(did) = fn_def_id {
codegen_fn_attr_flags: CodegenFnAttrFlags,
abi: SpecAbi,
) -> bool {
// Special attribute for functions which can't unwind. // Special attribute for functions which can't unwind.
if codegen_fn_attr_flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) { if tcx.codegen_fn_attrs(did).flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
return false; return false;
} }
// With -Z panic-in-drop=abort, drop_in_place never unwinds.
//
// This is not part of `codegen_fn_attrs` as it can differ between crates
// and therefore cannot be computed in core.
if tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Abort {
if Some(did) == tcx.lang_items().drop_in_place_fn() {
return false;
}
}
}
// Otherwise if this isn't special then unwinding is generally determined by // Otherwise if this isn't special then unwinding is generally determined by
// the ABI of the itself. ABIs like `C` have variants which also // the ABI of the itself. ABIs like `C` have variants which also
// specifically allow unwinding (`C-unwind`), but not all platform-specific // specifically allow unwinding (`C-unwind`), but not all platform-specific
@ -2991,13 +3000,7 @@ fn fn_abi_of_fn_ptr<'tcx>(
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
let (param_env, (sig, extra_args)) = query.into_parts(); let (param_env, (sig, extra_args)) = query.into_parts();
LayoutCx { tcx, param_env }.fn_abi_new_uncached( LayoutCx { tcx, param_env }.fn_abi_new_uncached(sig, extra_args, None, None, false)
sig,
extra_args,
None,
CodegenFnAttrFlags::empty(),
false,
)
} }
fn fn_abi_of_instance<'tcx>( fn fn_abi_of_instance<'tcx>(
@ -3014,13 +3017,11 @@ fn fn_abi_of_instance<'tcx>(
None None
}; };
let attrs = tcx.codegen_fn_attrs(instance.def_id()).flags;
LayoutCx { tcx, param_env }.fn_abi_new_uncached( LayoutCx { tcx, param_env }.fn_abi_new_uncached(
sig, sig,
extra_args, extra_args,
caller_location, caller_location,
attrs, Some(instance.def_id()),
matches!(instance.def, ty::InstanceDef::Virtual(..)), matches!(instance.def, ty::InstanceDef::Virtual(..)),
) )
} }
@ -3033,7 +3034,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
sig: ty::PolyFnSig<'tcx>, sig: ty::PolyFnSig<'tcx>,
extra_args: &[Ty<'tcx>], extra_args: &[Ty<'tcx>],
caller_location: Option<Ty<'tcx>>, caller_location: Option<Ty<'tcx>>,
codegen_fn_attr_flags: CodegenFnAttrFlags, fn_def_id: Option<DefId>,
// FIXME(eddyb) replace this with something typed, like an `enum`. // FIXME(eddyb) replace this with something typed, like an `enum`.
force_thin_self_ptr: bool, force_thin_self_ptr: bool,
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
@ -3205,7 +3206,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
c_variadic: sig.c_variadic, c_variadic: sig.c_variadic,
fixed_count: inputs.len(), fixed_count: inputs.len(),
conv, conv,
can_unwind: fn_can_unwind(self.tcx(), codegen_fn_attr_flags, sig.abi), can_unwind: fn_can_unwind(self.tcx(), fn_def_id, sig.abi),
}; };
self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?; self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?;
debug!("fn_abi_new_uncached = {:?}", fn_abi); debug!("fn_abi_new_uncached = {:?}", fn_abi);

View file

@ -27,7 +27,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
body_unsafety: BodyUnsafety, body_unsafety: BodyUnsafety,
/// The `#[target_feature]` attributes of the body. Used for checking /// The `#[target_feature]` attributes of the body. Used for checking
/// calls to functions with `#[target_feature]` (RFC 2396). /// calls to functions with `#[target_feature]` (RFC 2396).
body_target_features: &'tcx Vec<Symbol>, body_target_features: &'tcx [Symbol],
/// When inside the LHS of an assignment to a field, this is the type /// When inside the LHS of an assignment to a field, this is the type
/// of the LHS and the span of the assignment expression. /// of the LHS and the span of the assignment expression.
assignment_info: Option<(Ty<'tcx>, Span)>, assignment_info: Option<(Ty<'tcx>, Span)>,
@ -643,9 +643,8 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
return; return;
} }
let (thir, expr) = match tcx.thir_body(def) { let Ok((thir, expr)) = tcx.thir_body(def) else {
Ok(body) => body, return
Err(_) => return,
}; };
let thir = &thir.borrow(); let thir = &thir.borrow();
// If `thir` is empty, a type error occurred, skip this body. // If `thir` is empty, a type error occurred, skip this body.
@ -661,7 +660,7 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
BodyUnsafety::Safe BodyUnsafety::Safe
} }
}); });
let body_target_features = &tcx.codegen_fn_attrs(def.did).target_features; let body_target_features = &tcx.body_codegen_attrs(def.did.to_def_id()).target_features;
let safety_context = let safety_context =
if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe }; if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
let mut visitor = UnsafetyVisitor { let mut visitor = UnsafetyVisitor {

View file

@ -1,6 +1,5 @@
use crate::MirPass; use crate::MirPass;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty::layout; use rustc_middle::ty::layout;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
@ -46,7 +45,6 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
// //
// Here we test for this function itself whether its ABI allows // Here we test for this function itself whether its ABI allows
// unwinding or not. // unwinding or not.
let body_flags = tcx.codegen_fn_attrs(def_id).flags;
let body_ty = tcx.type_of(def_id); let body_ty = tcx.type_of(def_id);
let body_abi = match body_ty.kind() { let body_abi = match body_ty.kind() {
ty::FnDef(..) => body_ty.fn_sig(tcx).abi(), ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
@ -54,7 +52,7 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
ty::Generator(..) => Abi::Rust, ty::Generator(..) => Abi::Rust,
_ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty), _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
}; };
let body_can_unwind = layout::fn_can_unwind(tcx, body_flags, body_abi); let body_can_unwind = layout::fn_can_unwind(tcx, Some(def_id), body_abi);
// Look in this function body for any basic blocks which are terminated // Look in this function body for any basic blocks which are terminated
// with a function call, and whose function we're calling may unwind. // with a function call, and whose function we're calling may unwind.
@ -73,19 +71,19 @@ impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
TerminatorKind::Call { func, .. } => { TerminatorKind::Call { func, .. } => {
let ty = func.ty(body, tcx); let ty = func.ty(body, tcx);
let sig = ty.fn_sig(tcx); let sig = ty.fn_sig(tcx);
let flags = match ty.kind() { let fn_def_id = match ty.kind() {
ty::FnPtr(_) => CodegenFnAttrFlags::empty(), ty::FnPtr(_) => None,
ty::FnDef(def_id, _) => tcx.codegen_fn_attrs(*def_id).flags, &ty::FnDef(def_id, _) => Some(def_id),
_ => span_bug!(span, "invalid callee of type {:?}", ty), _ => span_bug!(span, "invalid callee of type {:?}", ty),
}; };
layout::fn_can_unwind(tcx, flags, sig.abi()) layout::fn_can_unwind(tcx, fn_def_id, sig.abi())
} }
TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => { TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => {
tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Unwind tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Unwind
&& layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust) && layout::fn_can_unwind(tcx, None, Abi::Rust)
} }
TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } => { TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } => {
layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust) layout::fn_can_unwind(tcx, None, Abi::Rust)
} }
_ => continue, _ => continue,
}; };

View file

@ -375,7 +375,8 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
} }
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features; let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features; // The body might be a constant, so it doesn't have codegen attributes.
let self_features = &self.tcx.body_codegen_attrs(self.body_did.to_def_id()).target_features;
// Is `callee_features` a subset of `calling_features`? // Is `callee_features` a subset of `calling_features`?
if !callee_features.iter().all(|feature| self_features.contains(feature)) { if !callee_features.iter().all(|feature| self_features.contains(feature)) {

View file

@ -105,6 +105,9 @@ impl CheckAttrVisitor<'_> {
sym::rustc_allow_const_fn_unstable => { sym::rustc_allow_const_fn_unstable => {
self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target) self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
} }
sym::rustc_std_internal_symbol => {
self.check_rustc_std_internal_symbol(&attr, span, target)
}
sym::naked => self.check_naked(hir_id, attr, span, target), sym::naked => self.check_naked(hir_id, attr, span, target),
sym::rustc_legacy_const_generics => { sym::rustc_legacy_const_generics => {
self.check_rustc_legacy_const_generics(&attr, span, target, item) self.check_rustc_legacy_const_generics(&attr, span, target, item)
@ -194,6 +197,7 @@ impl CheckAttrVisitor<'_> {
return; return;
} }
// FIXME(@lcnr): this doesn't belong here.
if matches!(target, Target::Closure | Target::Fn | Target::Method(_) | Target::ForeignFn) { if matches!(target, Target::Closure | Target::Fn | Target::Method(_) | Target::ForeignFn) {
self.tcx.ensure().codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id)); self.tcx.ensure().codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id));
} }
@ -1731,7 +1735,7 @@ impl CheckAttrVisitor<'_> {
} }
} }
sym::align => { sym::align => {
if let (Target::Fn, true) = (target, !self.tcx.features().fn_align) { if let (Target::Fn, false) = (target, self.tcx.features().fn_align) {
feature_err( feature_err(
&self.tcx.sess.parse_sess, &self.tcx.sess.parse_sess,
sym::fn_align, sym::fn_align,
@ -2052,6 +2056,25 @@ impl CheckAttrVisitor<'_> {
} }
} }
fn check_rustc_std_internal_symbol(
&self,
attr: &Attribute,
span: Span,
target: Target,
) -> bool {
match target {
Target::Fn | Target::Static => true,
_ => {
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied functions or statics")
.span_label(span, "not a function or static")
.emit();
false
}
}
}
/// default_method_body_is_const should only be applied to trait methods with default bodies. /// default_method_body_is_const should only be applied to trait methods with default bodies.
fn check_default_method_body_is_const( fn check_default_method_body_is_const(
&self, &self,

View file

@ -452,6 +452,7 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
} }
let def_id = tcx.hir().local_def_id(id); let def_id = tcx.hir().local_def_id(id);
if tcx.def_kind(def_id).has_codegen_attrs() {
let cg_attrs = tcx.codegen_fn_attrs(def_id); let cg_attrs = tcx.codegen_fn_attrs(def_id);
// #[used], #[no_mangle], #[export_name], etc also keeps the item alive // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
@ -462,6 +463,7 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
{ {
return true; return true;
} }
}
tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
} }

View file

@ -208,7 +208,11 @@ impl<'tcx> ReachableContext<'tcx> {
} else { } else {
false false
}; };
let codegen_attrs = self.tcx.codegen_fn_attrs(search_item); let codegen_attrs = if self.tcx.def_kind(search_item).has_codegen_attrs() {
self.tcx.codegen_fn_attrs(search_item)
} else {
CodegenFnAttrs::EMPTY
};
let is_extern = codegen_attrs.contains_extern_indicator(); let is_extern = codegen_attrs.contains_extern_indicator();
let std_internal = let std_internal =
codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
@ -329,6 +333,7 @@ impl CollectPrivateImplItemsVisitor<'_, '_> {
// Anything which has custom linkage gets thrown on the worklist no // Anything which has custom linkage gets thrown on the worklist no
// matter where it is in the crate, along with "special std symbols" // matter where it is in the crate, along with "special std symbols"
// which are currently akin to allocator symbols. // which are currently akin to allocator symbols.
if self.tcx.def_kind(def_id).has_codegen_attrs() {
let codegen_attrs = self.tcx.codegen_fn_attrs(def_id); let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
if codegen_attrs.contains_extern_indicator() if codegen_attrs.contains_extern_indicator()
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
@ -341,6 +346,7 @@ impl CollectPrivateImplItemsVisitor<'_, '_> {
self.worklist.push(def_id); self.worklist.push(def_id);
} }
} }
}
} }
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> { impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {

View file

@ -96,8 +96,10 @@
#[macro_use] #[macro_use]
extern crate rustc_middle; extern crate rustc_middle;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::subst::SubstsRef;
@ -175,7 +177,11 @@ fn compute_symbol_name<'tcx>(
} }
// FIXME(eddyb) Precompute a custom symbol name based on attributes. // FIXME(eddyb) Precompute a custom symbol name based on attributes.
let attrs = tcx.codegen_fn_attrs(def_id); let attrs = if tcx.def_kind(def_id).has_codegen_attrs() {
tcx.codegen_fn_attrs(def_id)
} else {
CodegenFnAttrs::EMPTY
};
// Foreign items by default use no mangling for their symbol name. There's a // Foreign items by default use no mangling for their symbol name. There's a
// few exceptions to this rule though: // few exceptions to this rule though:
@ -213,20 +219,25 @@ fn compute_symbol_name<'tcx>(
return tcx.item_name(def_id).to_string(); return tcx.item_name(def_id).to_string();
} }
let avoid_cross_crate_conflicts =
// If this is an instance of a generic function, we also hash in
// the ID of the instantiating crate. This avoids symbol conflicts
// in case the same instances is emitted in two crates of the same
// project.
is_generic(substs) ||
// If we're dealing with an instance of a function that's inlined from // If we're dealing with an instance of a function that's inlined from
// another crate but we're marking it as globally shared to our // another crate but we're marking it as globally shared to our
// compilation (aka we're not making an internal copy in each of our // compilation (aka we're not making an internal copy in each of our
// codegen units) then this symbol may become an exported (but hidden // codegen units) then this symbol may become an exported (but hidden
// visibility) symbol. This means that multiple crates may do the same // visibility) symbol. This means that multiple crates may do the same
// and we want to be sure to avoid any symbol conflicts here. // and we want to be sure to avoid any symbol conflicts here.
matches!(MonoItem::Fn(instance).instantiation_mode(tcx), InstantiationMode::GloballyShared { may_conflict: true }); let is_globally_shared_function = matches!(
tcx.def_kind(instance.def_id()),
DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator | DefKind::Ctor(..)
) && matches!(
MonoItem::Fn(instance).instantiation_mode(tcx),
InstantiationMode::GloballyShared { may_conflict: true }
);
// If this is an instance of a generic function, we also hash in
// the ID of the instantiating crate. This avoids symbol conflicts
// in case the same instances is emitted in two crates of the same
// project.
let avoid_cross_crate_conflicts = is_generic(substs) || is_globally_shared_function;
let instantiating_crate = let instantiating_crate =
if avoid_cross_crate_conflicts { Some(compute_instantiating_crate()) } else { None }; if avoid_cross_crate_conflicts { Some(compute_instantiating_crate()) } else { None };

View file

@ -45,7 +45,7 @@ use rustc_session::lint;
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::{abi, PanicStrategy, SanitizerSet}; use rustc_target::spec::{abi, SanitizerSet};
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use std::iter; use std::iter;
@ -2610,7 +2610,6 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: DefId) -> Option<hir::GeneratorKind>
fn from_target_feature( fn from_target_feature(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
id: DefId,
attr: &ast::Attribute, attr: &ast::Attribute,
supported_target_features: &FxHashMap<String, Option<Symbol>>, supported_target_features: &FxHashMap<String, Option<Symbol>>,
target_features: &mut Vec<Symbol>, target_features: &mut Vec<Symbol>,
@ -2679,7 +2678,7 @@ fn from_target_feature(
Some(name) => bug!("unknown target feature gate {}", name), Some(name) => bug!("unknown target feature gate {}", name),
None => true, None => true,
}; };
if !allowed && id.is_local() { if !allowed {
feature_err( feature_err(
&tcx.sess.parse_sess, &tcx.sess.parse_sess,
feature_gate.unwrap(), feature_gate.unwrap(),
@ -2693,7 +2692,7 @@ fn from_target_feature(
} }
} }
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Linkage { fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
use rustc_middle::mir::mono::Linkage::*; use rustc_middle::mir::mono::Linkage::*;
// Use the names from src/llvm/docs/LangRef.rst here. Most types are only // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
@ -2716,36 +2715,30 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Linkage {
"private" => Private, "private" => Private,
"weak" => WeakAny, "weak" => WeakAny,
"weak_odr" => WeakODR, "weak_odr" => WeakODR,
_ => { _ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
let span = tcx.hir().span_if_local(def_id);
if let Some(span) = span {
tcx.sess.span_fatal(span, "invalid linkage specified")
} else {
tcx.sess.fatal(&format!("invalid linkage specified: {}", name))
}
}
} }
} }
fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
let attrs = tcx.get_attrs(id); if cfg!(debug_assertions) {
let def_kind = tcx.def_kind(did);
assert!(
def_kind.has_codegen_attrs(),
"unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
);
}
let did = did.expect_local();
let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did));
let mut codegen_fn_attrs = CodegenFnAttrs::new(); let mut codegen_fn_attrs = CodegenFnAttrs::new();
if tcx.should_inherit_track_caller(id) { if tcx.should_inherit_track_caller(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
} }
// With -Z panic-in-drop=abort, drop_in_place never unwinds.
if tcx.sess.opts.debugging_opts.panic_in_drop == PanicStrategy::Abort {
if Some(id) == tcx.lang_items().drop_in_place_fn() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
}
}
// The panic_no_unwind function called by TerminatorKind::Abort will never // The panic_no_unwind function called by TerminatorKind::Abort will never
// unwind. If the panic handler that it invokes unwind then it will simply // unwind. If the panic handler that it invokes unwind then it will simply
// call the panic handler again. // call the panic handler again.
if Some(id) == tcx.lang_items().panic_no_unwind() { if Some(did.to_def_id()) == tcx.lang_items().panic_no_unwind() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
} }
@ -2760,7 +2753,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
} else if attr.has_name(sym::rustc_allocator) { } else if attr.has_name(sym::rustc_allocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR; codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
} else if attr.has_name(sym::ffi_returns_twice) { } else if attr.has_name(sym::ffi_returns_twice) {
if tcx.is_foreign_item(id) { if tcx.is_foreign_item(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE; codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
} else { } else {
// `#[ffi_returns_twice]` is only allowed `extern fn`s. // `#[ffi_returns_twice]` is only allowed `extern fn`s.
@ -2773,7 +2766,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
.emit(); .emit();
} }
} else if attr.has_name(sym::ffi_pure) { } else if attr.has_name(sym::ffi_pure) {
if tcx.is_foreign_item(id) { if tcx.is_foreign_item(did) {
if attrs.iter().any(|a| a.has_name(sym::ffi_const)) { if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
// `#[ffi_const]` functions cannot be `#[ffi_pure]` // `#[ffi_const]` functions cannot be `#[ffi_pure]`
struct_span_err!( struct_span_err!(
@ -2797,7 +2790,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
.emit(); .emit();
} }
} else if attr.has_name(sym::ffi_const) { } else if attr.has_name(sym::ffi_const) {
if tcx.is_foreign_item(id) { if tcx.is_foreign_item(did) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST; codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
} else { } else {
// `#[ffi_const]` is only allowed on foreign functions // `#[ffi_const]` is only allowed on foreign functions
@ -2857,7 +2850,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
None => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED, None => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED,
} }
} else if attr.has_name(sym::cmse_nonsecure_entry) { } else if attr.has_name(sym::cmse_nonsecure_entry) {
if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) { if !matches!(tcx.fn_sig(did).abi(), abi::Abi::C { .. }) {
struct_span_err!( struct_span_err!(
tcx.sess, tcx.sess,
attr.span, attr.span,
@ -2874,11 +2867,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
} else if attr.has_name(sym::thread_local) { } else if attr.has_name(sym::thread_local) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
} else if attr.has_name(sym::track_caller) { } else if attr.has_name(sym::track_caller) {
if !tcx.is_closure(id) && tcx.fn_sig(id).abi() != abi::Abi::Rust { if !tcx.is_closure(did.to_def_id()) && tcx.fn_sig(did).abi() != abi::Abi::Rust {
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
.emit(); .emit();
} }
if tcx.is_closure(id) && !tcx.features().closure_track_caller { if tcx.is_closure(did.to_def_id()) && !tcx.features().closure_track_caller {
feature_err( feature_err(
&tcx.sess.parse_sess, &tcx.sess.parse_sess,
sym::closure_track_caller, sym::closure_track_caller,
@ -2904,7 +2897,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
codegen_fn_attrs.export_name = Some(s); codegen_fn_attrs.export_name = Some(s);
} }
} else if attr.has_name(sym::target_feature) { } else if attr.has_name(sym::target_feature) {
if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { if !tcx.is_closure(did.to_def_id())
&& tcx.fn_sig(did).unsafety() == hir::Unsafety::Normal
{
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
// The `#[target_feature]` attribute is allowed on // The `#[target_feature]` attribute is allowed on
// WebAssembly targets on all functions, including safe // WebAssembly targets on all functions, including safe
@ -2930,22 +2925,21 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
attr.span, attr.span,
"`#[target_feature(..)]` can only be applied to `unsafe` functions", "`#[target_feature(..)]` can only be applied to `unsafe` functions",
); );
err.span_label(tcx.def_span(id), "not an `unsafe` function"); err.span_label(tcx.def_span(did), "not an `unsafe` function");
err.emit(); err.emit();
} else if let Some(local_id) = id.as_local() { } else {
check_target_feature_trait_unsafe(tcx, local_id, attr.span); check_target_feature_trait_unsafe(tcx, did, attr.span);
} }
} }
from_target_feature( from_target_feature(
tcx, tcx,
id,
attr, attr,
supported_target_features, supported_target_features,
&mut codegen_fn_attrs.target_features, &mut codegen_fn_attrs.target_features,
); );
} else if attr.has_name(sym::linkage) { } else if attr.has_name(sym::linkage) {
if let Some(val) = attr.value_str() { if let Some(val) = attr.value_str() {
codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, val.as_str())); codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, did, val.as_str()));
} }
} else if attr.has_name(sym::link_section) { } else if attr.has_name(sym::link_section) {
if let Some(val) = attr.value_str() { if let Some(val) = attr.value_str() {
@ -3161,8 +3155,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
}); });
// #73631: closures inherit `#[target_feature]` annotations // #73631: closures inherit `#[target_feature]` annotations
if tcx.features().target_feature_11 && tcx.is_closure(id) { if tcx.features().target_feature_11 && tcx.is_closure(did.to_def_id()) {
let owner_id = tcx.parent(id); let owner_id = tcx.parent(did.to_def_id());
codegen_fn_attrs codegen_fn_attrs
.target_features .target_features
.extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied()) .extend(tcx.codegen_fn_attrs(owner_id).target_features.iter().copied())
@ -3187,7 +3181,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
if !codegen_fn_attrs.no_sanitize.is_empty() { if !codegen_fn_attrs.no_sanitize.is_empty() {
if codegen_fn_attrs.inline == InlineAttr::Always { if codegen_fn_attrs.inline == InlineAttr::Always {
if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) { if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
let hir_id = tcx.hir().local_def_id_to_hir_id(id.expect_local()); let hir_id = tcx.hir().local_def_id_to_hir_id(did);
tcx.struct_span_lint_hir( tcx.struct_span_lint_hir(
lint::builtin::INLINE_NO_SANITIZE, lint::builtin::INLINE_NO_SANITIZE,
hir_id, hir_id,
@ -3207,7 +3201,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
// strippable by the linker. // strippable by the linker.
// //
// Additionally weak lang items have predetermined symbol names. // Additionally weak lang items have predetermined symbol names.
if tcx.is_weak_lang_item(id) { if tcx.is_weak_lang_item(did.to_def_id()) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
} }
if let Some(name) = weak_lang_items::link_name(attrs) { if let Some(name) = weak_lang_items::link_name(attrs) {
@ -3237,9 +3231,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
/// Computes the set of target features used in a function for the purposes of /// Computes the set of target features used in a function for the purposes of
/// inline assembly. /// inline assembly.
fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, id: DefId) -> &'tcx FxHashSet<Symbol> { fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
let mut target_features = tcx.sess.target_features.clone(); let mut target_features = tcx.sess.target_features.clone();
let attrs = tcx.codegen_fn_attrs(id); if tcx.def_kind(did).has_codegen_attrs() {
let attrs = tcx.codegen_fn_attrs(did);
target_features.extend(&attrs.target_features); target_features.extend(&attrs.target_features);
match attrs.instruction_set { match attrs.instruction_set {
None => {} None => {}
@ -3250,6 +3245,8 @@ fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, id: DefId) -> &'tcx FxHashSet<Sy
target_features.insert(sym::thumb_mode); target_features.insert(sym::thumb_mode);
} }
} }
}
tcx.arena.alloc(target_features) tcx.arena.alloc(target_features)
} }