only compute codegen_fn_attrs where needed

This commit is contained in:
lcnr 2022-05-04 11:18:37 +02:00
parent 66ff6c32e5
commit d371ebe117
11 changed files with 153 additions and 50 deletions

View File

@ -1007,7 +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));
record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id)); if tcx.has_codegen_attrs(def_kind) {
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

@ -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

@ -246,7 +246,8 @@ 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.has_codegen_attrs(tcx.def_kind(def_id))
&& tcx.codegen_fn_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

@ -139,6 +139,42 @@ impl<'tcx> TyCtxt<'tcx> {
hasher.finish() hasher.finish()
} }
pub fn has_codegen_attrs(self, def_kind: DefKind) -> bool {
match def_kind {
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,
}
}
pub fn res_generics_def_id(self, res: Res) -> Option<DefId> { pub fn res_generics_def_id(self, res: Res) -> Option<DefId> {
match res { match res {
Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => { Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => {

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)>,
@ -661,7 +661,11 @@ 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: &[_] = if tcx.has_codegen_attrs(tcx.def_kind(def.did)) {
&tcx.codegen_fn_attrs(def.did).target_features
} else {
&[]
};
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

@ -375,7 +375,12 @@ 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; // Constants don't have codegen attributes, so the body might not have codegen attributes.
let self_features: &[_] = if self.tcx.has_codegen_attrs(self.tcx.def_kind(self.body_did)) {
&self.tcx.codegen_fn_attrs(self.body_did).target_features
} else {
&[]
};
// 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

@ -104,6 +104,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)
@ -193,6 +196,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));
} }
@ -1659,7 +1663,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,
@ -1980,6 +1984,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,15 +452,17 @@ 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);
let cg_attrs = tcx.codegen_fn_attrs(def_id); if tcx.has_codegen_attrs(tcx.def_kind(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
// forcefully, e.g., for placing it in a specific section. // forcefully, e.g., for placing it in a specific section.
if cg_attrs.contains_extern_indicator() if cg_attrs.contains_extern_indicator()
|| cg_attrs.flags.contains(CodegenFnAttrFlags::USED) || cg_attrs.flags.contains(CodegenFnAttrFlags::USED)
|| cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
{ {
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.has_codegen_attrs(self.tcx.def_kind(search_item)) {
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,16 +333,18 @@ 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.
let codegen_attrs = self.tcx.codegen_fn_attrs(def_id); if self.tcx.has_codegen_attrs(self.tcx.def_kind(def_id)) {
if codegen_attrs.contains_extern_indicator() let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) if codegen_attrs.contains_extern_indicator()
// FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
// `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
// `SymbolExportLevel::Rust` export level but may end up being exported in dylibs. // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED)
{ || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
self.worklist.push(def_id); {
self.worklist.push(def_id);
}
} }
} }
} }

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.has_codegen_attrs(tcx.def_kind(def_id)) {
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 we're dealing with an instance of a function that's inlined from
// If this is an instance of a generic function, we also hash in // another crate but we're marking it as globally shared to our
// the ID of the instantiating crate. This avoids symbol conflicts // compilation (aka we're not making an internal copy in each of our
// in case the same instances is emitted in two crates of the same // codegen units) then this symbol may become an exported (but hidden
// project. // visibility) symbol. This means that multiple crates may do the same
is_generic(substs) || // and we want to be sure to avoid any symbol conflicts here.
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 we're dealing with an instance of a function that's inlined from // If this is an instance of a generic function, we also hash in
// another crate but we're marking it as globally shared to our // the ID of the instantiating crate. This avoids symbol conflicts
// compilation (aka we're not making an internal copy in each of our // in case the same instances is emitted in two crates of the same
// codegen units) then this symbol may become an exported (but hidden // project.
// visibility) symbol. This means that multiple crates may do the same let avoid_cross_crate_conflicts = is_generic(substs) || is_globally_shared_function;
// 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 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

@ -2720,6 +2720,14 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
} }
fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
if cfg!(debug_assertions) {
let def_kind = tcx.def_kind(did);
assert!(
tcx.has_codegen_attrs(def_kind),
"unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
);
}
let did = did.expect_local(); let did = did.expect_local();
let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did)); 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();
@ -3223,19 +3231,22 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: 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.has_codegen_attrs(tcx.def_kind(did)) {
target_features.extend(&attrs.target_features); let attrs = tcx.codegen_fn_attrs(did);
match attrs.instruction_set { target_features.extend(&attrs.target_features);
None => {} match attrs.instruction_set {
Some(InstructionSetAttr::ArmA32) => { None => {}
target_features.remove(&sym::thumb_mode); Some(InstructionSetAttr::ArmA32) => {
} target_features.remove(&sym::thumb_mode);
Some(InstructionSetAttr::ArmT32) => { }
target_features.insert(sym::thumb_mode); Some(InstructionSetAttr::ArmT32) => {
target_features.insert(sym::thumb_mode);
}
} }
} }
tcx.arena.alloc(target_features) tcx.arena.alloc(target_features)
} }