From d371ebe117419b9815bd8743f981d8fa67a876d8 Mon Sep 17 00:00:00 2001 From: lcnr Date: Wed, 4 May 2022 11:18:37 +0200 Subject: [PATCH] only compute `codegen_fn_attrs` where needed --- compiler/rustc_metadata/src/rmeta/encoder.rs | 4 +- .../src/middle/codegen_fn_attrs.rs | 4 +- compiler/rustc_middle/src/ty/instance.rs | 3 +- compiler/rustc_middle/src/ty/util.rs | 36 +++++++++++++++++ .../rustc_mir_build/src/check_unsafety.rs | 8 +++- .../rustc_mir_transform/src/check_unsafety.rs | 7 +++- compiler/rustc_passes/src/check_attr.rs | 25 +++++++++++- compiler/rustc_passes/src/dead.rs | 18 +++++---- compiler/rustc_passes/src/reachable.rs | 28 +++++++------ compiler/rustc_symbol_mangling/src/lib.rs | 39 ++++++++++++------- compiler/rustc_typeck/src/collect.rs | 31 ++++++++++----- 11 files changed, 153 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 72c38d41d5b..433ef978b64 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1007,7 +1007,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.def_span[def_id] <- tcx.def_span(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.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) { record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id)); } diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 54eb2dc9e28..321fcd43797 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -95,7 +95,9 @@ bitflags! { } impl CodegenFnAttrs { - pub fn new() -> CodegenFnAttrs { + pub const EMPTY: &'static Self = &Self::new(); + + pub const fn new() -> CodegenFnAttrs { CodegenFnAttrs { flags: CodegenFnAttrFlags::empty(), inline: InlineAttr::None, diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 03d3a4a8c5f..f0710ef42de 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -246,7 +246,8 @@ impl<'tcx> InstanceDef<'tcx> { match *self { InstanceDef::Item(ty::WithOptConstParam { did: 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, _ => false, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 1c8af13ce9c..646d4c9f8f5 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -139,6 +139,42 @@ impl<'tcx> TyCtxt<'tcx> { 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 { match res { Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => { diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index a841cce23de..b90eecefc0c 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -27,7 +27,7 @@ struct UnsafetyVisitor<'a, 'tcx> { body_unsafety: BodyUnsafety, /// The `#[target_feature]` attributes of the body. Used for checking /// calls to functions with `#[target_feature]` (RFC 2396). - body_target_features: &'tcx Vec, + body_target_features: &'tcx [Symbol], /// When inside the LHS of an assignment to a field, this is the type /// of the LHS and the span of the assignment expression. assignment_info: Option<(Ty<'tcx>, Span)>, @@ -661,7 +661,11 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam UnsafetyChecker<'_, 'tcx> { } 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`? if !callee_features.iter().all(|feature| self_features.contains(feature)) { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index b297012f19f..72cbdbcf8cf 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -104,6 +104,9 @@ impl CheckAttrVisitor<'_> { sym::rustc_allow_const_fn_unstable => { 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::rustc_legacy_const_generics => { self.check_rustc_legacy_const_generics(&attr, span, target, item) @@ -193,6 +196,7 @@ impl CheckAttrVisitor<'_> { return; } + // FIXME(@lcnr): this doesn't belong here. 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)); } @@ -1659,7 +1663,7 @@ impl CheckAttrVisitor<'_> { } } 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( &self.tcx.sess.parse_sess, 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. fn check_default_method_body_is_const( &self, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 991d0d45546..f0451352b45 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -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 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 - // forcefully, e.g., for placing it in a specific section. - if cg_attrs.contains_extern_indicator() - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) - || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) - { - return true; + // #[used], #[no_mangle], #[export_name], etc also keeps the item alive + // forcefully, e.g., for placing it in a specific section. + if cg_attrs.contains_extern_indicator() + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) + || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) + { + return true; + } } tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index b603352a9be..e9f4bfee3de 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -208,7 +208,11 @@ impl<'tcx> ReachableContext<'tcx> { } else { 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 std_internal = 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 // matter where it is in the crate, along with "special std symbols" // which are currently akin to allocator symbols. - let codegen_attrs = self.tcx.codegen_fn_attrs(def_id); - if codegen_attrs.contains_extern_indicator() - || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) - // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by - // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their - // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs. - || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) - || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) - { - self.worklist.push(def_id); + if self.tcx.has_codegen_attrs(self.tcx.def_kind(def_id)) { + let codegen_attrs = self.tcx.codegen_fn_attrs(def_id); + if codegen_attrs.contains_extern_indicator() + || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) + // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by + // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their + // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs. + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED) + || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) + { + self.worklist.push(def_id); + } } } } diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 0ff0267d0ce..2936b6775d1 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -96,8 +96,10 @@ #[macro_use] extern crate rustc_middle; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; 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::ty::query::Providers; 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. - 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 // few exceptions to this rule though: @@ -213,20 +219,25 @@ fn compute_symbol_name<'tcx>( 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 + // 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 + // codegen units) then this symbol may become an exported (but hidden + // visibility) symbol. This means that multiple crates may do the same + // 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 - // 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 - // codegen units) then this symbol may become an exported (but hidden - // visibility) symbol. This means that multiple crates may do the same - // and we want to be sure to avoid any symbol conflicts here. - 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 = if avoid_cross_crate_conflicts { Some(compute_instantiating_crate()) } else { None }; diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index bf62a8e84d7..7be5d7b8e97 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -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 { + 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 attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did)); 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 /// inline assembly. -fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, id: DefId) -> &'tcx FxHashSet { +fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet { let mut target_features = tcx.sess.target_features.clone(); - let attrs = tcx.codegen_fn_attrs(id); - target_features.extend(&attrs.target_features); - match attrs.instruction_set { - None => {} - Some(InstructionSetAttr::ArmA32) => { - target_features.remove(&sym::thumb_mode); - } - Some(InstructionSetAttr::ArmT32) => { - target_features.insert(sym::thumb_mode); + if tcx.has_codegen_attrs(tcx.def_kind(did)) { + let attrs = tcx.codegen_fn_attrs(did); + target_features.extend(&attrs.target_features); + match attrs.instruction_set { + None => {} + Some(InstructionSetAttr::ArmA32) => { + target_features.remove(&sym::thumb_mode); + } + Some(InstructionSetAttr::ArmT32) => { + target_features.insert(sym::thumb_mode); + } } } + tcx.arena.alloc(target_features) }