提交 d371ebe1 编写于 作者: L lcnr

only compute `codegen_fn_attrs` where needed

上级 66ff6c32
......@@ -1007,7 +1007,9 @@ fn encode_def_ids(&mut self) {
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));
}
......
......@@ -95,7 +95,9 @@ pub struct CodegenFnAttrFlags: u32 {
}
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,
......
......@@ -246,7 +246,8 @@ pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
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,
......
......@@ -139,6 +139,42 @@ pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
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> {
match res {
Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => {
......
......@@ -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<Symbol>,
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<LocalD
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 =
if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
let mut visitor = UnsafetyVisitor {
......
......@@ -375,7 +375,12 @@ fn check_target_features(&mut self, func_did: DefId) {
}
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)) {
......
......@@ -104,6 +104,9 @@ fn check_attributes(
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 @@ fn check_attributes(
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 @@ fn check_repr(
}
}
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 @@ fn check_rustc_allow_const_fn_unstable(
}
}
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,
......
......@@ -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);
// #[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;
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;
}
}
tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
......
......@@ -208,7 +208,11 @@ fn propagate_node(&mut self, node: &Node<'tcx>, search_item: LocalDefId) {
} 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 @@ fn push_to_worklist_if_has_custom_linkage(&mut self, def_id: LocalDefId) {
// 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);
}
}
}
}
......
......@@ -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 };
......
......@@ -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<Symbol> {
fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
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)
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册