Auto merge of #95562 - lcnr:attr-no-encode, r=davidtwco

don't encode only locally used attrs

Part of https://github.com/rust-lang/compiler-team/issues/505.

We now filter builtin attributes before encoding them in the crate metadata in case they should only be used in the local crate. To prevent accidental misuse `get_attrs` now requires the caller to state which attribute they are interested in. For places where that isn't trivially possible, I've added a method `fn get_attrs_unchecked` which I intend to remove in a followup PR.

After this pull request landed, we can then slowly move all attributes to only be used in the local crate while being certain that we don't accidentally try to access them from extern crates.

cc https://github.com/rust-lang/rust/pull/94963#issuecomment-1082924289
This commit is contained in:
bors 2022-05-12 12:48:30 +00:00
commit 481db40311
55 changed files with 455 additions and 467 deletions

View file

@ -868,11 +868,15 @@ impl IntType {
/// structure layout, `packed` to remove padding, and `transparent` to delegate representation /// structure layout, `packed` to remove padding, and `transparent` to delegate representation
/// concerns to the only non-ZST field. /// concerns to the only non-ZST field.
pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> { pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
use ReprAttr::*; if attr.has_name(sym::repr) { parse_repr_attr(sess, attr) } else { Vec::new() }
}
pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {:?}", attr);
use ReprAttr::*;
let mut acc = Vec::new(); let mut acc = Vec::new();
let diagnostic = &sess.parse_sess.span_diagnostic; let diagnostic = &sess.parse_sess.span_diagnostic;
if attr.has_name(sym::repr) {
if let Some(items) = attr.meta_item_list() { if let Some(items) = attr.meta_item_list() {
for item in items { for item in items {
let mut recognised = false; let mut recognised = false;
@ -1042,7 +1046,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
} }
} }
} }
}
acc acc
} }

View file

@ -6,6 +6,7 @@ use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::OptLevel; use rustc_session::config::OptLevel;
use rustc_span::symbol::sym;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector}; use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -329,9 +330,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
) { ) {
let span = cx let span = cx
.tcx .tcx
.get_attrs(instance.def_id()) .get_attr(instance.def_id(), sym::target_feature)
.iter()
.find(|a| a.has_name(rustc_span::sym::target_feature))
.map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
let msg = format!( let msg = format!(
"the target features {} must all be either enabled or disabled together", "the target features {} must all be either enabled or disabled together",

View file

@ -312,11 +312,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
Status::Unstable(gate) if self.tcx.features().enabled(gate) => { Status::Unstable(gate) if self.tcx.features().enabled(gate) => {
let unstable_in_stable = self.ccx.is_const_stable_const_fn() let unstable_in_stable = self.ccx.is_const_stable_const_fn()
&& !super::rustc_allow_const_fn_unstable( && !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate);
self.tcx,
self.def_id().to_def_id(),
gate,
);
if unstable_in_stable { if unstable_in_stable {
emit_unstable_in_stable_error(self.ccx, span, gate); emit_unstable_in_stable_error(self.ccx, span, gate);
} }
@ -713,7 +709,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
match &terminator.kind { match &terminator.kind {
TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => { TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => {
let ConstCx { tcx, body, param_env, .. } = *self.ccx; let ConstCx { tcx, body, param_env, .. } = *self.ccx;
let caller = self.def_id().to_def_id(); let caller = self.def_id();
let fn_ty = func.ty(body, tcx); let fn_ty = func.ty(body, tcx);
@ -797,7 +793,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// trait. // trait.
let callee_trait = tcx.trait_of_item(callee); let callee_trait = tcx.trait_of_item(callee);
if callee_trait.is_some() if callee_trait.is_some()
&& tcx.has_attr(caller, sym::default_method_body_is_const) && tcx.has_attr(caller.to_def_id(), sym::default_method_body_is_const)
&& callee_trait == tcx.trait_of_item(caller) && callee_trait == tcx.trait_of_item(caller)
// Can only call methods when it's `<Self as TheTrait>::f`. // Can only call methods when it's `<Self as TheTrait>::f`.
&& tcx.types.self_param == substs.type_at(0) && tcx.types.self_param == substs.type_at(0)

View file

@ -66,8 +66,12 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
} }
} }
pub fn rustc_allow_const_fn_unstable(tcx: TyCtxt<'_>, def_id: DefId, feature_gate: Symbol) -> bool { pub fn rustc_allow_const_fn_unstable(
let attrs = tcx.get_attrs(def_id); tcx: TyCtxt<'_>,
def_id: LocalDefId,
feature_gate: Symbol,
) -> bool {
let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id));
attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate) attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate)
} }

View file

@ -1,5 +1,6 @@
//! Concrete error types for all operations which may be invalid in a certain const context. //! Concrete error types for all operations which may be invalid in a certain const context.
use hir::def_id::LocalDefId;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
@ -95,7 +96,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
/// A function call where the callee is not marked as `const`. /// A function call where the callee is not marked as `const`.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct FnCallNonConst<'tcx> { pub struct FnCallNonConst<'tcx> {
pub caller: DefId, pub caller: LocalDefId,
pub callee: DefId, pub callee: DefId,
pub substs: SubstsRef<'tcx>, pub substs: SubstsRef<'tcx>,
pub span: Span, pub span: Span,
@ -117,13 +118,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
match self_ty.kind() { match self_ty.kind() {
Param(param_ty) => { Param(param_ty) => {
debug!(?param_ty); debug!(?param_ty);
if let Some(generics) = caller let caller_hir_id = tcx.hir().local_def_id_to_hir_id(caller);
.as_local() if let Some(generics) = tcx.hir().get(caller_hir_id).generics() {
.map(|id| tcx.hir().local_def_id_to_hir_id(id))
.map(|id| tcx.hir().get(id))
.as_ref()
.and_then(|node| node.generics())
{
let constraint = with_no_trimmed_paths!(format!( let constraint = with_no_trimmed_paths!(format!(
"~const {}", "~const {}",
trait_ref.print_only_trait_path() trait_ref.print_only_trait_path()

View file

@ -147,6 +147,16 @@ pub enum AttributeDuplicates {
FutureWarnPreceding, FutureWarnPreceding,
} }
/// A conveniece macro to deal with `$($expr)?`.
macro_rules! or_default {
($default:expr,) => {
$default
};
($default:expr, $next:expr) => {
$next
};
}
/// A convenience macro for constructing attribute templates. /// A convenience macro for constructing attribute templates.
/// E.g., `template!(Word, List: "description")` means that the attribute /// E.g., `template!(Word, List: "description")` means that the attribute
/// supports forms `#[attr]` and `#[attr(description)]`. /// supports forms `#[attr]` and `#[attr(description)]`.
@ -168,9 +178,10 @@ macro_rules! template {
} }
macro_rules! ungated { macro_rules! ungated {
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(,)?) => { ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)? $(,)?) => {
BuiltinAttribute { BuiltinAttribute {
name: sym::$attr, name: sym::$attr,
only_local: or_default!(false, $($only_local)?),
type_: $typ, type_: $typ,
template: $tpl, template: $tpl,
gate: Ungated, gate: Ungated,
@ -180,18 +191,20 @@ macro_rules! ungated {
} }
macro_rules! gated { macro_rules! gated {
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $gate:ident, $msg:expr $(,)?) => { ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $gate:ident, $msg:expr $(,)?) => {
BuiltinAttribute { BuiltinAttribute {
name: sym::$attr, name: sym::$attr,
only_local: or_default!(false, $($only_local)?),
type_: $typ, type_: $typ,
template: $tpl, template: $tpl,
duplicates: $duplicates, duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
} }
}; };
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $msg:expr $(,)?) => { ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $msg:expr $(,)?) => {
BuiltinAttribute { BuiltinAttribute {
name: sym::$attr, name: sym::$attr,
only_local: or_default!(false, $($only_local)?),
type_: $typ, type_: $typ,
template: $tpl, template: $tpl,
duplicates: $duplicates, duplicates: $duplicates,
@ -201,12 +214,13 @@ macro_rules! gated {
} }
macro_rules! rustc_attr { macro_rules! rustc_attr {
(TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr $(,)?) => { (TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr $(, @only_local: $only_local:expr)? $(,)?) => {
rustc_attr!( rustc_attr!(
$attr, $attr,
$typ, $typ,
$tpl, $tpl,
$duplicate, $duplicate,
$(@only_local: $only_local,)?
concat!( concat!(
"the `#[", "the `#[",
stringify!($attr), stringify!($attr),
@ -215,9 +229,10 @@ macro_rules! rustc_attr {
), ),
) )
}; };
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $msg:expr $(,)?) => { ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr $(, @only_local: $only_local:expr)?, $msg:expr $(,)?) => {
BuiltinAttribute { BuiltinAttribute {
name: sym::$attr, name: sym::$attr,
only_local: or_default!(false, $($only_local)?),
type_: $typ, type_: $typ,
template: $tpl, template: $tpl,
duplicates: $duplicates, duplicates: $duplicates,
@ -237,6 +252,10 @@ const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never b
pub struct BuiltinAttribute { pub struct BuiltinAttribute {
pub name: Symbol, pub name: Symbol,
/// Whether this attribute is only used in the local crate.
///
/// If so, it is not encoded in the crate metadata.
pub only_local: bool,
pub type_: AttributeType, pub type_: AttributeType,
pub template: AttributeTemplate, pub template: AttributeTemplate,
pub duplicates: AttributeDuplicates, pub duplicates: AttributeDuplicates,
@ -295,7 +314,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing), ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing),
gated!( gated!(
must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing,
must_not_suspend, experimental!(must_not_suspend) experimental!(must_not_suspend)
), ),
ungated!( ungated!(
deprecated, Normal, deprecated, Normal,
@ -324,8 +343,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk), ungated!(repr, Normal, template!(List: "C"), DuplicatesOk),
ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding), ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(no_mangle, Normal, template!(Word), WarnFollowing), ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing), ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, @only_local: true),
// Limits: // Limits:
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing), ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
@ -358,8 +377,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(panic_handler, Normal, template!(Word), WarnFollowing), // RFC 2070 ungated!(panic_handler, Normal, template!(Word), WarnFollowing), // RFC 2070
// Code generation: // Code generation:
ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing), ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true),
ungated!(cold, Normal, template!(Word), WarnFollowing), ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true),
ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing), ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing),
ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk), ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk),
ungated!(track_caller, Normal, template!(Word), WarnFollowing), ungated!(track_caller, Normal, template!(Word), WarnFollowing),
@ -385,7 +404,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
// Linking: // Linking:
gated!(naked, Normal, template!(Word), WarnFollowing, naked_functions, experimental!(naked)), gated!(naked, Normal, template!(Word), WarnFollowing, @only_local: true, naked_functions, experimental!(naked)),
gated!( gated!(
link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, raw_dylib, link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, raw_dylib,
experimental!(link_ordinal) experimental!(link_ordinal)
@ -394,6 +413,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Plugins: // Plugins:
BuiltinAttribute { BuiltinAttribute {
name: sym::plugin, name: sym::plugin,
only_local: false,
type_: CrateLevel, type_: CrateLevel,
template: template!(List: "name"), template: template!(List: "name"),
duplicates: DuplicatesOk, duplicates: DuplicatesOk,
@ -475,7 +495,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
// DuplicatesOk since it has its own validation // DuplicatesOk since it has its own validation
ungated!( ungated!(
stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk,
), ),
ungated!( ungated!(
unstable, Normal, unstable, Normal,
@ -546,11 +566,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// ========================================================================== // ==========================================================================
gated!( gated!(
linkage, Normal, template!(NameValueStr: "external|internal|..."), ErrorPreceding, linkage, Normal, template!(NameValueStr: "external|internal|..."), ErrorPreceding, @only_local: true,
"the `linkage` attribute is experimental and not portable across platforms", "the `linkage` attribute is experimental and not portable across platforms",
), ),
rustc_attr!( rustc_attr!(
rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, @only_local: true, INTERNAL_UNSTABLE
), ),
// ========================================================================== // ==========================================================================
@ -633,7 +653,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Internal attributes, Misc: // Internal attributes, Misc:
// ========================================================================== // ==========================================================================
gated!( gated!(
lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, lang_items, lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, @only_local: true, lang_items,
"language items are subject to change", "language items are subject to change",
), ),
rustc_attr!( rustc_attr!(
@ -642,11 +662,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
), ),
rustc_attr!( rustc_attr!(
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, @only_local: true,
"#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`." "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
), ),
rustc_attr!( rustc_attr!(
rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true,
"#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
), ),
rustc_attr!( rustc_attr!(
@ -656,6 +676,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
BuiltinAttribute { BuiltinAttribute {
name: sym::rustc_diagnostic_item, name: sym::rustc_diagnostic_item,
// FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
only_local: false,
type_: Normal, type_: Normal,
template: template!(NameValueStr: "name"), template: template!(NameValueStr: "name"),
duplicates: ErrorFollowing, duplicates: ErrorFollowing,
@ -676,7 +698,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"unboxed_closures are still evolving", "unboxed_closures are still evolving",
), ),
rustc_attr!( rustc_attr!(
rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, @only_local: true,
"the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
overflow checking behavior of several libcore functions that are inlined \ overflow checking behavior of several libcore functions that are inlined \
across crates and will never be stable", across crates and will never be stable",
@ -778,6 +800,10 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool {
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
} }
pub fn is_builtin_only_local(name: Symbol) -> bool {
BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local)
}
pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &BuiltinAttribute>> = pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &BuiltinAttribute>> =
SyncLazy::new(|| { SyncLazy::new(|| {
let mut map = FxHashMap::default(); let mut map = FxHashMap::default();

View file

@ -149,7 +149,8 @@ pub use accepted::ACCEPTED_FEATURES;
pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES}; pub use active::{Features, ACTIVE_FEATURES, INCOMPATIBLE_FEATURES};
pub use builtin_attrs::AttributeDuplicates; pub use builtin_attrs::AttributeDuplicates;
pub use builtin_attrs::{ pub use builtin_attrs::{
deprecated_attributes, find_gated_cfg, is_builtin_attr_name, AttributeGate, AttributeTemplate, deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local,
AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg,
BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
}; };
pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};

View file

@ -183,10 +183,7 @@ pub struct DirtyCleanVisitor<'tcx> {
impl<'tcx> DirtyCleanVisitor<'tcx> { impl<'tcx> DirtyCleanVisitor<'tcx> {
/// Possibly "deserialize" the attribute into a clean/dirty assertion /// Possibly "deserialize" the attribute into a clean/dirty assertion
fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> { fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> {
if !attr.has_name(sym::rustc_clean) { assert!(attr.has_name(sym::rustc_clean));
// skip: not rustc_clean/dirty
return None;
}
if !check_config(self.tcx, attr) { if !check_config(self.tcx, attr) {
// skip: not the correct `cfg=` // skip: not the correct `cfg=`
return None; return None;
@ -384,7 +381,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
fn check_item(&mut self, item_id: LocalDefId) { fn check_item(&mut self, item_id: LocalDefId) {
let item_span = self.tcx.def_span(item_id.to_def_id()); let item_span = self.tcx.def_span(item_id.to_def_id());
let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id()); let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id());
for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() { for attr in self.tcx.get_attrs(item_id.to_def_id(), sym::rustc_clean) {
let Some(assertion) = self.assertion_maybe(item_id, attr) else { let Some(assertion) = self.assertion_maybe(item_id, attr) else {
continue; continue;
}; };

View file

@ -258,10 +258,7 @@ impl<'tcx> Queries<'tcx> {
/// an error. /// an error.
fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) { fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
let Some((def_id, _)) = tcx.entry_fn(()) else { return }; let Some((def_id, _)) = tcx.entry_fn(()) else { return };
for attr in tcx.get_attrs(def_id, sym::rustc_error) {
let attrs = &*tcx.get_attrs(def_id);
let attrs = attrs.iter().filter(|attr| attr.has_name(sym::rustc_error));
for attr in attrs {
match attr.meta_item_list() { match attr.meta_item_list() {
// Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`. // Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`.
Some(list) Some(list)

View file

@ -551,7 +551,7 @@ impl MissingDoc {
} }
} }
let attrs = cx.tcx.get_attrs(def_id.to_def_id()); let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
let has_doc = attrs.iter().any(has_doc); let has_doc = attrs.iter().any(has_doc);
if !has_doc { if !has_doc {
cx.struct_span_lint( cx.struct_span_lint(
@ -2738,11 +2738,7 @@ impl ClashingExternDeclarations {
// bottleneck, this does just fine. // bottleneck, this does just fine.
( (
overridden_link_name, overridden_link_name,
tcx.get_attrs(fi.def_id.to_def_id()) tcx.get_attr(fi.def_id.to_def_id(), sym::link_name).unwrap().span,
.iter()
.find(|at| at.has_name(sym::link_name))
.unwrap()
.span,
) )
}) })
{ {

View file

@ -668,7 +668,7 @@ enum FfiResult<'tcx> {
} }
crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: ty::AdtDef<'tcx>) -> bool { crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
tcx.get_attrs(def.did()).iter().any(|a| a.has_name(sym::rustc_nonnull_optimization_guaranteed)) tcx.has_attr(def.did(), sym::rustc_nonnull_optimization_guaranteed)
} }
/// `repr(transparent)` structs can have a single non-ZST field, this function returns that /// `repr(transparent)` structs can have a single non-ZST field, this function returns that

View file

@ -303,8 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_pre_path: &str, descr_pre_path: &str,
descr_post_path: &str, descr_post_path: &str,
) -> bool { ) -> bool {
for attr in cx.tcx.get_attrs(def_id).iter() { if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
if attr.has_name(sym::must_use) {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let msg = format!( let msg = format!(
"unused {}`{}`{} that must be used", "unused {}`{}`{} that must be used",
@ -319,12 +318,12 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
} }
err.emit(); err.emit();
}); });
return true; true
} } else {
}
false false
} }
} }
}
} }
declare_lint! { declare_lint! {

View file

@ -985,11 +985,17 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
} }
impl<'a, 'tcx> EncodeContext<'a, 'tcx> { impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_attrs(&mut self, def_id: DefId) { fn encode_attrs(&mut self, def_id: LocalDefId) {
let attrs = self.tcx.get_attrs(def_id); let mut attrs = self
record!(self.tables.attributes[def_id] <- attrs); .tcx
if attrs.iter().any(|attr| attr.may_have_doc_links()) { .hir()
self.tables.may_have_doc_links.set(def_id.index, ()); .attrs(self.tcx.hir().local_def_id_to_hir_id(def_id))
.iter()
.filter(|attr| !rustc_feature::is_builtin_only_local(attr.name_or_empty()));
record!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone());
if attrs.any(|attr| attr.may_have_doc_links()) {
self.tables.may_have_doc_links.set(def_id.local_def_index, ());
} }
} }
@ -1005,7 +1011,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let Some(def_kind) = def_kind else { continue }; let Some(def_kind) = def_kind else { continue };
self.tables.opt_def_kind.set(def_id.index, def_kind); self.tables.opt_def_kind.set(def_id.index, def_kind);
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(local_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() { if def_kind.has_codegen_attrs() {
record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id)); record!(self.tables.codegen_fn_attrs[def_id] <- self.tcx.codegen_fn_attrs(def_id));
@ -1670,7 +1676,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod); self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id())); record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
self.encode_attrs(LOCAL_CRATE.as_def_id()); self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local());
record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id())); record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
if let Some(stability) = stability { if let Some(stability) = stability {
record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability); record!(self.tables.lookup_stability[LOCAL_CRATE.as_def_id()] <- stability);
@ -1711,7 +1717,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
let def_id = id.to_def_id(); let def_id = id.to_def_id();
self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind)); self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind)); record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
self.encode_attrs(def_id); self.encode_attrs(id);
record!(self.tables.def_keys[def_id] <- def_key); record!(self.tables.def_keys[def_id] <- def_key);
record!(self.tables.def_ident_span[def_id] <- span); record!(self.tables.def_ident_span[def_id] <- span);
record!(self.tables.def_span[def_id] <- span); record!(self.tables.def_span[def_id] <- span);

View file

@ -1072,6 +1072,9 @@ rustc_queries! {
desc { |tcx| "checking whether `{}` is `doc(hidden)`", tcx.def_path_str(def_id) } desc { |tcx| "checking whether `{}` is `doc(hidden)`", tcx.def_path_str(def_id) }
} }
/// Returns the attributes on the item at `def_id`.
///
/// Do not use this directly, use `tcx.get_attrs` instead.
query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] { query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] {
desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) } desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) }
separate_provide_extern separate_provide_extern

View file

@ -230,8 +230,7 @@ impl AdtDefData {
flags |= AdtFlags::HAS_CTOR; flags |= AdtFlags::HAS_CTOR;
} }
let attrs = tcx.get_attrs(did); if tcx.has_attr(did, sym::fundamental) {
if tcx.sess.contains_name(&attrs, sym::fundamental) {
flags |= AdtFlags::IS_FUNDAMENTAL; flags |= AdtFlags::IS_FUNDAMENTAL;
} }
if Some(did) == tcx.lang_items().phantom_data() { if Some(did) == tcx.lang_items().phantom_data() {

View file

@ -1148,9 +1148,8 @@ impl<'tcx> TyCtxt<'tcx> {
/// `rustc_layout_scalar_valid_range` attribute. /// `rustc_layout_scalar_valid_range` attribute.
// FIXME(eddyb) this is an awkward spot for this method, maybe move it? // FIXME(eddyb) this is an awkward spot for this method, maybe move it?
pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) { pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
let attrs = self.get_attrs(def_id);
let get = |name| { let get = |name| {
let Some(attr) = attrs.iter().find(|a| a.has_name(name)) else { let Some(attr) = self.get_attr(def_id, name) else {
return Bound::Unbounded; return Bound::Unbounded;
}; };
debug!("layout_scalar_valid_range: attr={:?}", attr); debug!("layout_scalar_valid_range: attr={:?}", attr);

View file

@ -568,11 +568,8 @@ impl<T> Trait<T> for X {
} }
} }
TargetFeatureCast(def_id) => { TargetFeatureCast(def_id) => {
let attrs = self.get_attrs(*def_id); let target_spans =
let target_spans = attrs self.get_attrs(*def_id, sym::target_feature).map(|attr| attr.span);
.iter()
.filter(|attr| attr.has_name(sym::target_feature))
.map(|attr| attr.span);
diag.note( diag.note(
"functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
); );

View file

@ -8,6 +8,7 @@ use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_middle::ty::normalize_erasing_regions::NormalizationError; use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
use rustc_span::Symbol;
use std::fmt; use std::fmt;
@ -185,8 +186,8 @@ impl<'tcx> InstanceDef<'tcx> {
} }
#[inline] #[inline]
pub fn attrs(&self, tcx: TyCtxt<'tcx>) -> ty::Attributes<'tcx> { pub fn get_attrs(&self, tcx: TyCtxt<'tcx>, attr: Symbol) -> ty::Attributes<'tcx> {
tcx.get_attrs(self.def_id()) tcx.get_attrs(self.def_id(), attr)
} }
/// Returns `true` if the LLVM version of this instance is unconditionally /// Returns `true` if the LLVM version of this instance is unconditionally

View file

@ -14,12 +14,6 @@ pub use self::AssocItemContainer::*;
pub use self::BorrowKind::*; pub use self::BorrowKind::*;
pub use self::IntVarValue::*; pub use self::IntVarValue::*;
pub use self::Variance::*; pub use self::Variance::*;
pub use adt::*;
pub use assoc::*;
pub use generics::*;
use rustc_data_structures::fingerprint::Fingerprint;
pub use vtable::*;
use crate::metadata::ModChild; use crate::metadata::ModChild;
use crate::middle::privacy::AccessLevels; use crate::middle::privacy::AccessLevels;
use crate::mir::{Body, GeneratorLayout}; use crate::mir::{Body, GeneratorLayout};
@ -28,8 +22,12 @@ use crate::ty;
use crate::ty::fast_reject::SimplifiedType; use crate::ty::fast_reject::SimplifiedType;
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
use crate::ty::util::Discr; use crate::ty::util::Discr;
pub use adt::*;
pub use assoc::*;
pub use generics::*;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_attr as attr; use rustc_attr as attr;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_data_structures::intern::{Interned, WithStableHash};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@ -44,6 +42,7 @@ use rustc_session::cstore::CrateStoreDyn;
use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span; use rustc_span::Span;
use rustc_target::abi::Align; use rustc_target::abi::Align;
pub use vtable::*;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
@ -1818,8 +1817,8 @@ impl ReprOptions {
field_shuffle_seed ^= user_seed; field_shuffle_seed ^= user_seed;
} }
for attr in tcx.get_attrs(did).iter() { for attr in tcx.get_attrs(did, sym::repr) {
for r in attr::find_repr_attrs(&tcx.sess, attr) { for r in attr::parse_repr_attr(&tcx.sess, attr) {
flags.insert(match r { flags.insert(match r {
attr::ReprC => ReprFlags::IS_C, attr::ReprC => ReprFlags::IS_C,
attr::ReprPacked(pack) => { attr::ReprPacked(pack) => {
@ -1941,8 +1940,7 @@ impl<'tcx> FieldDef {
} }
} }
pub type Attributes<'tcx> = &'tcx [ast::Attribute]; pub type Attributes<'tcx> = impl Iterator<Item = &'tcx ast::Attribute>;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum ImplOverlapKind { pub enum ImplOverlapKind {
/// These impls are always allowed to overlap. /// These impls are always allowed to overlap.
@ -2186,8 +2184,8 @@ impl<'tcx> TyCtxt<'tcx> {
} }
} }
/// Gets the attributes of a definition. // FIXME(@lcnr): Remove this function.
pub fn get_attrs(self, did: DefId) -> Attributes<'tcx> { pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [ast::Attribute] {
if let Some(did) = did.as_local() { if let Some(did) = did.as_local() {
self.hir().attrs(self.hir().local_def_id_to_hir_id(did)) self.hir().attrs(self.hir().local_def_id_to_hir_id(did))
} else { } else {
@ -2195,9 +2193,29 @@ impl<'tcx> TyCtxt<'tcx> {
} }
} }
/// Gets all attributes with the given name.
pub fn get_attrs(self, did: DefId, attr: Symbol) -> ty::Attributes<'tcx> {
let filter_fn = move |a: &&ast::Attribute| a.has_name(attr);
if let Some(did) = did.as_local() {
self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn)
} else if cfg!(debug_assertions) && rustc_feature::is_builtin_only_local(attr) {
bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr);
} else {
self.item_attrs(did).iter().filter(filter_fn)
}
}
pub fn get_attr(self, did: DefId, attr: Symbol) -> Option<&'tcx ast::Attribute> {
self.get_attrs(did, attr).next()
}
/// Determines whether an item is annotated with an attribute. /// Determines whether an item is annotated with an attribute.
pub fn has_attr(self, did: DefId, attr: Symbol) -> bool { pub fn has_attr(self, did: DefId, attr: Symbol) -> bool {
self.sess.contains_name(&self.get_attrs(did), attr) if cfg!(debug_assertions) && !did.is_local() && rustc_feature::is_builtin_only_local(attr) {
bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr);
} else {
self.get_attrs(did, attr).next().is_some()
}
} }
/// Returns `true` if this is an `auto trait`. /// Returns `true` if this is an `auto trait`.

View file

@ -1163,9 +1163,8 @@ pub fn normalize_opaque_types<'tcx>(
/// Determines whether an item is annotated with `doc(hidden)`. /// Determines whether an item is annotated with `doc(hidden)`.
pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool { pub fn is_doc_hidden(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
tcx.get_attrs(def_id) tcx.get_attrs(def_id, sym::doc)
.iter() .filter_map(|attr| attr.meta_item_list())
.filter_map(|attr| if attr.has_name(sym::doc) { attr.meta_item_list() } else { None })
.any(|items| items.iter().any(|item| item.has_name(sym::hidden))) .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
} }

View file

@ -679,7 +679,6 @@ where
} else { } else {
None None
}; };
debug!("fn_id {:?} has attrs {:?}", fn_def, tcx.get_attrs(fn_def.did.to_def_id()));
let mut body = builder.finish(); let mut body = builder.finish();
body.spread_arg = spread_arg; body.spread_arg = spread_arg;

View file

@ -333,14 +333,11 @@ struct RustcMirAttrs {
impl RustcMirAttrs { impl RustcMirAttrs {
fn parse(tcx: TyCtxt<'_>, def_id: DefId) -> Result<Self, ()> { fn parse(tcx: TyCtxt<'_>, def_id: DefId) -> Result<Self, ()> {
let attrs = tcx.get_attrs(def_id);
let mut result = Ok(()); let mut result = Ok(());
let mut ret = RustcMirAttrs::default(); let mut ret = RustcMirAttrs::default();
let rustc_mir_attrs = attrs let rustc_mir_attrs = tcx
.iter() .get_attrs(def_id, sym::rustc_mir)
.filter(|attr| attr.has_name(sym::rustc_mir))
.flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter())); .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
for attr in rustc_mir_attrs { for attr in rustc_mir_attrs {

View file

@ -14,9 +14,9 @@ extern crate tracing;
#[macro_use] #[macro_use]
extern crate rustc_middle; extern crate rustc_middle;
use rustc_ast::{self as ast, MetaItem}; use rustc_ast::MetaItem;
use rustc_middle::ty; use rustc_hir::def_id::DefId;
use rustc_session::Session; use rustc_middle::ty::{self, TyCtxt};
use rustc_span::symbol::{sym, Symbol}; use rustc_span::symbol::{sym, Symbol};
pub use self::drop_flag_effects::{ pub use self::drop_flag_effects::{
@ -49,13 +49,8 @@ pub struct MoveDataParamEnv<'tcx> {
pub param_env: ty::ParamEnv<'tcx>, pub param_env: ty::ParamEnv<'tcx>,
} }
pub fn has_rustc_mir_with( pub fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option<MetaItem> {
_sess: &Session, for attr in tcx.get_attrs(def_id, sym::rustc_mir) {
attrs: &[ast::Attribute],
name: Symbol,
) -> Option<MetaItem> {
for attr in attrs {
if attr.has_name(sym::rustc_mir) {
let items = attr.meta_item_list(); let items = attr.meta_item_list();
for item in items.iter().flat_map(|l| l.iter()) { for item in items.iter().flat_map(|l| l.iter()) {
match item.meta_item() { match item.meta_item() {
@ -64,6 +59,5 @@ pub fn has_rustc_mir_with(
} }
} }
} }
}
None None
} }

View file

@ -1,4 +1,3 @@
use rustc_ast::ast;
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_target::spec::abi::Abi;
@ -31,43 +30,41 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
} }
let attributes = tcx.get_attrs(def_id);
let param_env = tcx.param_env(def_id); let param_env = tcx.param_env(def_id);
let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap(); let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
let mdpe = MoveDataParamEnv { move_data, param_env }; let mdpe = MoveDataParamEnv { move_data, param_env };
let sess = &tcx.sess;
if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_init).is_some() { if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe) let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
.into_engine(tcx, body) .into_engine(tcx, body)
.iterate_to_fixpoint(); .iterate_to_fixpoint();
sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_inits); sanity_check_via_rustc_peek(tcx, body, &flow_inits);
} }
if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_uninit).is_some() { if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe) let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
.into_engine(tcx, body) .into_engine(tcx, body)
.iterate_to_fixpoint(); .iterate_to_fixpoint();
sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_uninits); sanity_check_via_rustc_peek(tcx, body, &flow_uninits);
} }
if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_definite_init).is_some() { if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe) let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe)
.into_engine(tcx, body) .into_engine(tcx, body)
.iterate_to_fixpoint(); .iterate_to_fixpoint();
sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits); sanity_check_via_rustc_peek(tcx, body, &flow_def_inits);
} }
if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() { if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint(); let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_liveness); sanity_check_via_rustc_peek(tcx, body, &flow_liveness);
} }
if has_rustc_mir_with(sess, &attributes, sym::stop_after_dataflow).is_some() { if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
tcx.sess.fatal("stop_after_dataflow ended compilation"); tcx.sess.fatal("stop_after_dataflow ended compilation");
} }
} }
@ -92,7 +89,6 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
pub fn sanity_check_via_rustc_peek<'tcx, A>( pub fn sanity_check_via_rustc_peek<'tcx, A>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
body: &Body<'tcx>, body: &Body<'tcx>,
_attributes: &[ast::Attribute],
results: &Results<'tcx, A>, results: &Results<'tcx, A>,
) where ) where
A: RustcPeekAt<'tcx>, A: RustcPeekAt<'tcx>,

View file

@ -197,7 +197,7 @@ fn emit_unused_generic_params_error<'tcx>(
unused_parameters: &FiniteBitSet<u32>, unused_parameters: &FiniteBitSet<u32>,
) { ) {
let base_def_id = tcx.typeck_root_def_id(def_id); let base_def_id = tcx.typeck_root_def_id(def_id);
if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) { if !tcx.has_attr(base_def_id, sym::rustc_polymorphize_error) {
return; return;
} }

View file

@ -170,7 +170,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
// If `def_id` is `None`, we don't need to consider stability attributes. // If `def_id` is `None`, we don't need to consider stability attributes.
let def_id = match def_id { let def_id = match def_id {
Some(x) => x.to_def_id(), Some(x) => x,
None => return true, None => return true,
}; };
@ -182,14 +182,16 @@ impl<'tcx> CheckConstVisitor<'tcx> {
// If this crate is not using stability attributes, or this function is not claiming to be a // If this crate is not using stability attributes, or this function is not claiming to be a
// stable `const fn`, that is all that is required. // stable `const fn`, that is all that is required.
if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { if !tcx.features().staged_api
|| tcx.has_attr(def_id.to_def_id(), sym::rustc_const_unstable)
{
return true; return true;
} }
// However, we cannot allow stable `const fn`s to use unstable features without an explicit // However, we cannot allow stable `const fn`s to use unstable features without an explicit
// opt-in via `rustc_allow_const_fn_unstable`. // opt-in via `rustc_allow_const_fn_unstable`.
attr::rustc_allow_const_fn_unstable(&tcx.sess, &tcx.get_attrs(def_id)) let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id));
.any(|name| name == feature_gate) attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate)
}; };
match required_gates { match required_gates {

View file

@ -83,7 +83,7 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item
} }
} }
/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.p /// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.
fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> { fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
attrs.iter().find_map(|attr| { attrs.iter().find_map(|attr| {
if attr.has_name(sym::rustc_diagnostic_item) { attr.value_str() } else { None } if attr.has_name(sym::rustc_diagnostic_item) { attr.value_str() } else { None }

View file

@ -27,12 +27,10 @@ impl<'tcx> ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
| ItemKind::Enum(..) | ItemKind::Enum(..)
| ItemKind::Struct(..) | ItemKind::Struct(..)
| ItemKind::Union(..) => { | ItemKind::Union(..) => {
for attr in self.tcx.get_attrs(item.def_id.to_def_id()).iter() { for attr in self.tcx.get_attrs(item.def_id.to_def_id(), sym::rustc_layout) {
if attr.has_name(sym::rustc_layout) {
self.dump_layout_of(item.def_id, item, attr); self.dump_layout_of(item.def_id, item, attr);
} }
} }
}
_ => {} _ => {}
} }
} }

View file

@ -110,7 +110,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
) where ) where
F: FnOnce(&mut Self), F: FnOnce(&mut Self),
{ {
let attrs = self.tcx.get_attrs(def_id.to_def_id()); let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id));
debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
let depr = attr::find_deprecation(&self.tcx.sess, attrs); let depr = attr::find_deprecation(&self.tcx.sess, attrs);

View file

@ -2002,12 +2002,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
let parent_def_id = self.tcx.parent(def_id); let parent_def_id = self.tcx.parent(def_id);
if let Some(def_id) = parent_def_id.as_local() { if let Some(def_id) = parent_def_id.as_local() {
// lifetimes in `derive` expansions don't count (Issue #53738) // lifetimes in `derive` expansions don't count (Issue #53738)
if self if self.tcx.has_attr(def_id.to_def_id(), sym::automatically_derived) {
.tcx
.get_attrs(def_id.to_def_id())
.iter()
.any(|attr| attr.has_name(sym::automatically_derived))
{
continue; continue;
} }

View file

@ -49,8 +49,10 @@ struct SymbolNamesTest<'tcx> {
impl SymbolNamesTest<'_> { impl SymbolNamesTest<'_> {
fn process_attrs(&mut self, def_id: LocalDefId) { fn process_attrs(&mut self, def_id: LocalDefId) {
let tcx = self.tcx; let tcx = self.tcx;
for attr in tcx.get_attrs(def_id.to_def_id()).iter() { // The formatting of `tag({})` is chosen so that tests can elect
if attr.has_name(SYMBOL_NAME) { // to test the entirety of the string, if they choose, or else just
// some subset.
for attr in tcx.get_attrs(def_id.to_def_id(), SYMBOL_NAME) {
let def_id = def_id.to_def_id(); let def_id = def_id.to_def_id();
let instance = Instance::new( let instance = Instance::new(
def_id, def_id,
@ -62,14 +64,11 @@ impl SymbolNamesTest<'_> {
tcx.sess.span_err(attr.span, &format!("demangling({})", demangling)); tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling)); tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
} }
} else if attr.has_name(DEF_PATH) { }
for attr in tcx.get_attrs(def_id.to_def_id(), DEF_PATH) {
let path = with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id())); let path = with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id()));
tcx.sess.span_err(attr.span, &format!("def-path({})", path)); tcx.sess.span_err(attr.span, &format!("def-path({})", path));
} }
// (*) The formatting of `tag({})` is chosen so that tests can elect
// to test the entirety of the string, if they choose, or else just
// some subset.
}
} }
} }

View file

@ -175,9 +175,7 @@ impl<'tcx> OnUnimplementedDirective {
} }
pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> { pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
let attrs = tcx.get_attrs(item_def_id); let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else {
let Some(attr) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else {
return Ok(None); return Ok(None);
}; };

View file

@ -1156,9 +1156,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let ImplCandidate(def_id) = candidate { if let ImplCandidate(def_id) = candidate {
if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) { if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes { if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
let attrs = tcx.get_attrs(def_id); let value = tcx
let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl); .get_attr(def_id, sym::rustc_reservation_impl)
let value = attr.and_then(|a| a.value_str()); .and_then(|a| a.value_str());
if let Some(value) = value { if let Some(value) = value {
debug!( debug!(
"filter_reservation_impls: \ "filter_reservation_impls: \

View file

@ -1056,9 +1056,7 @@ fn check_impl_items_against_trait<'tcx>(
if let Some(missing_items) = must_implement_one_of { if let Some(missing_items) = must_implement_one_of {
let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
let attr_span = tcx let attr_span = tcx
.get_attrs(impl_trait_ref.def_id) .get_attr(impl_trait_ref.def_id, sym::rustc_must_implement_one_of)
.iter()
.find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
.map(|attr| attr.span); .map(|attr| attr.span);
missing_items_must_implement_one_of_err(tcx, impl_span, missing_items, attr_span); missing_items_must_implement_one_of_err(tcx, impl_span, missing_items, attr_span);
@ -1158,8 +1156,8 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
let repr = def.repr(); let repr = def.repr();
if repr.packed() { if repr.packed() {
for attr in tcx.get_attrs(def.did()).iter() { for attr in tcx.get_attrs(def.did(), sym::repr) {
for r in attr::find_repr_attrs(&tcx.sess, attr) { for r in attr::parse_repr_attr(&tcx.sess, attr) {
if let attr::ReprPacked(pack) = r if let attr::ReprPacked(pack) = r
&& let Some(repr_pack) = repr.pack && let Some(repr_pack) = repr.pack
&& pack as u64 != repr_pack.bytes() && pack as u64 != repr_pack.bytes()
@ -1321,8 +1319,7 @@ fn check_enum<'tcx>(
def.destructor(tcx); // force the destructor to be evaluated def.destructor(tcx); // force the destructor to be evaluated
if vs.is_empty() { if vs.is_empty() {
let attributes = tcx.get_attrs(def_id.to_def_id()); if let Some(attr) = tcx.get_attr(def_id.to_def_id(), sym::repr) {
if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) {
struct_span_err!( struct_span_err!(
tcx.sess, tcx.sess,
attr.span, attr.span,

View file

@ -407,8 +407,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.has_only_self_parameter(m) self.has_only_self_parameter(m)
&& self && self
.tcx .tcx
.get_attrs(m.def_id)
.iter()
// This special internal attribute is used to permit // This special internal attribute is used to permit
// "identity-like" conversion methods to be suggested here. // "identity-like" conversion methods to be suggested here.
// //
@ -419,7 +417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// //
// FIXME? Other potential candidate methods: `as_ref` and // FIXME? Other potential candidate methods: `as_ref` and
// `as_mut`? // `as_mut`?
.any(|a| a.has_name(sym::rustc_conversion_suggestion)) .has_attr(m.def_id, sym::rustc_conversion_suggestion)
}); });
methods methods

View file

@ -609,8 +609,7 @@ fn check_must_not_suspend_def(
hir_id: HirId, hir_id: HirId,
data: SuspendCheckData<'_, '_>, data: SuspendCheckData<'_, '_>,
) -> bool { ) -> bool {
for attr in tcx.get_attrs(def_id).iter() { if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
if attr.has_name(sym::must_not_suspend) {
tcx.struct_span_lint_hir( tcx.struct_span_lint_hir(
rustc_session::lint::builtin::MUST_NOT_SUSPEND, rustc_session::lint::builtin::MUST_NOT_SUSPEND,
hir_id, hir_id,
@ -645,8 +644,8 @@ fn check_must_not_suspend_def(
}, },
); );
return true; true
} } else {
}
false false
}
} }

View file

@ -128,7 +128,8 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
tcx.struct_span_lint_hir(lint, id, span, |lint| { tcx.struct_span_lint_hir(lint, id, span, |lint| {
// Removal suggestion span needs to include attributes (Issue #54400) // Removal suggestion span needs to include attributes (Issue #54400)
let span_with_attrs = tcx let span_with_attrs = tcx
.get_attrs(extern_crate.def_id) .hir()
.attrs(id)
.iter() .iter()
.map(|attr| attr.span) .map(|attr| attr.span)
.fold(span, |acc, attr_span| acc.to(attr_span)); .fold(span, |acc, attr_span| acc.to(attr_span));
@ -166,13 +167,13 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
continue; continue;
} }
let id = tcx.hir().local_def_id_to_hir_id(def_id);
// If the extern crate has any attributes, they may have funky // If the extern crate has any attributes, they may have funky
// semantics we can't faithfully represent using `use` (most // semantics we can't faithfully represent using `use` (most
// notably `#[macro_use]`). Ignore it. // notably `#[macro_use]`). Ignore it.
if !tcx.get_attrs(extern_crate.def_id).is_empty() { if !tcx.hir().attrs(id).is_empty() {
continue; continue;
} }
let id = tcx.hir().local_def_id_to_hir_id(def_id);
tcx.struct_span_lint_hir(lint, id, extern_crate.span, |lint| { tcx.struct_span_lint_hir(lint, id, extern_crate.span, |lint| {
// Otherwise, we can convert it into a `use` of some kind. // Otherwise, we can convert it into a `use` of some kind.
let base_replacement = match extern_crate.orig_name { let base_replacement = match extern_crate.orig_name {

View file

@ -1200,9 +1200,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
ty::trait_def::TraitSpecializationKind::None ty::trait_def::TraitSpecializationKind::None
}; };
let must_implement_one_of = tcx let must_implement_one_of = tcx
.get_attrs(def_id) .get_attr(def_id, sym::rustc_must_implement_one_of)
.iter()
.find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
// Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]` // Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]`
// and that they are all identifiers // and that they are all identifiers
.and_then(|attr| match attr.meta_item_list() { .and_then(|attr| match attr.meta_item_list() {

View file

@ -298,18 +298,13 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
error = true; error = true;
} }
for attr in tcx.get_attrs(main_def_id) { for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
if attr.has_name(sym::track_caller) {
tcx.sess tcx.sess
.struct_span_err( .struct_span_err(attr.span, "`main` function is not allowed to be `#[track_caller]`")
attr.span,
"`main` function is not allowed to be `#[track_caller]`",
)
.span_label(main_span, "`main` function is not allowed to be `#[track_caller]`") .span_label(main_span, "`main` function is not allowed to be `#[track_caller]`")
.emit(); .emit();
error = true; error = true;
} }
}
if error { if error {
return; return;

View file

@ -22,7 +22,7 @@ use crate::clean::{
use crate::core::DocContext; use crate::core::DocContext;
use crate::formats::item_type::ItemType; use crate::formats::item_type::ItemType;
type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>; type Attrs<'hir> = &'hir [ast::Attribute];
/// Attempt to inline a definition into this AST. /// Attempt to inline a definition into this AST.
/// ///
@ -155,7 +155,7 @@ crate fn try_inline_glob(
} }
crate fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> { crate fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> {
cx.tcx.get_attrs(did) cx.tcx.get_attrs_unchecked(did)
} }
/// Record an external fully qualified name in the external_paths cache. /// Record an external fully qualified name in the external_paths cache.
@ -691,7 +691,7 @@ crate fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
let trait_ = clean::TraitWithExtraInfo { let trait_ = clean::TraitWithExtraInfo {
trait_, trait_,
is_notable: clean::utils::has_doc_flag(cx.tcx.get_attrs(did), sym::notable_trait), is_notable: clean::utils::has_doc_flag(cx.tcx, did, sym::notable_trait),
}; };
cx.external_traits.borrow_mut().insert(did, trait_); cx.external_traits.borrow_mut().insert(did, trait_);
cx.active_extern_traits.remove(&did); cx.active_extern_traits.remove(&did);

View file

@ -211,8 +211,8 @@ impl ExternalCrate {
// Failing that, see if there's an attribute specifying where to find this // Failing that, see if there's an attribute specifying where to find this
// external crate // external crate
let did = self.crate_num.as_def_id(); let did = self.crate_num.as_def_id();
tcx.get_attrs(did) tcx.get_attrs(did, sym::doc)
.lists(sym::doc) .flat_map(|attr| attr.meta_item_list().unwrap_or_default())
.filter(|a| a.has_name(sym::html_root_url)) .filter(|a| a.has_name(sym::html_root_url))
.filter_map(|a| a.value_str()) .filter_map(|a| a.value_str())
.map(to_remote) .map(to_remote)
@ -226,11 +226,13 @@ impl ExternalCrate {
let as_keyword = |res: Res<!>| { let as_keyword = |res: Res<!>| {
if let Res::Def(DefKind::Mod, def_id) = res { if let Res::Def(DefKind::Mod, def_id) = res {
let attrs = tcx.get_attrs(def_id);
let mut keyword = None; let mut keyword = None;
for attr in attrs.lists(sym::doc) { let meta_items = tcx
if attr.has_name(sym::keyword) { .get_attrs(def_id, sym::doc)
if let Some(v) = attr.value_str() { .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
for meta in meta_items {
if meta.has_name(sym::keyword) {
if let Some(v) = meta.value_str() {
keyword = Some(v); keyword = Some(v);
break; break;
} }
@ -288,11 +290,13 @@ impl ExternalCrate {
// rendering by delegating everything to a hash map. // rendering by delegating everything to a hash map.
let as_primitive = |res: Res<!>| { let as_primitive = |res: Res<!>| {
if let Res::Def(DefKind::Mod, def_id) = res { if let Res::Def(DefKind::Mod, def_id) = res {
let attrs = tcx.get_attrs(def_id);
let mut prim = None; let mut prim = None;
for attr in attrs.lists(sym::doc) { let meta_items = tcx
if let Some(v) = attr.value_str() { .get_attrs(def_id, sym::doc)
if attr.has_name(sym::primitive) { .flat_map(|attr| attr.meta_item_list().unwrap_or_default());
for meta in meta_items {
if let Some(v) = meta.value_str() {
if meta.has_name(sym::primitive) {
prim = PrimitiveType::from_symbol(v); prim = PrimitiveType::from_symbol(v);
if prim.is_some() { if prim.is_some() {
break; break;
@ -413,7 +417,10 @@ impl Item {
} }
crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool { crate fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
self.item_id.as_def_id().map(|did| tcx.get_attrs(did).inner_docs()).unwrap_or(false) self.item_id
.as_def_id()
.map(|did| tcx.get_attrs_unchecked(did).inner_docs())
.unwrap_or(false)
} }
crate fn span(&self, tcx: TyCtxt<'_>) -> Span { crate fn span(&self, tcx: TyCtxt<'_>) -> Span {
@ -464,7 +471,7 @@ impl Item {
kind: ItemKind, kind: ItemKind,
cx: &mut DocContext<'_>, cx: &mut DocContext<'_>,
) -> Item { ) -> Item {
let ast_attrs = cx.tcx.get_attrs(def_id); let ast_attrs = cx.tcx.get_attrs_unchecked(def_id);
Self::from_def_id_and_attrs_and_parts( Self::from_def_id_and_attrs_and_parts(
def_id, def_id,

View file

@ -474,10 +474,9 @@ crate fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Option<De
/// ///
/// This function exists because it runs on `hir::Attributes` whereas the other is a /// This function exists because it runs on `hir::Attributes` whereas the other is a
/// `clean::Attributes` method. /// `clean::Attributes` method.
crate fn has_doc_flag(attrs: ty::Attributes<'_>, flag: Symbol) -> bool { crate fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool {
attrs.iter().any(|attr| { tcx.get_attrs(did, sym::doc).any(|attr| {
attr.has_name(sym::doc) attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
&& attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
}) })
} }

View file

@ -323,7 +323,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
clean::ImportItem(ref import) => { clean::ImportItem(ref import) => {
let (stab, stab_tags) = if let Some(import_def_id) = import.source.did { let (stab, stab_tags) = if let Some(import_def_id) = import.source.did {
let ast_attrs = cx.tcx().get_attrs(import_def_id); let ast_attrs = cx.tcx().get_attrs_unchecked(import_def_id);
let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs, None)); let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs, None));
// Just need an item with the correct def_id and attrs // Just need an item with the correct def_id and attrs

View file

@ -53,9 +53,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
while let Some(did) = parent { while let Some(did) = parent {
attr_buf.extend( attr_buf.extend(
cx.tcx cx.tcx
.get_attrs(did) .get_attrs(did, sym::doc)
.iter()
.filter(|attr| attr.has_name(sym::doc))
.filter(|attr| { .filter(|attr| {
if let Some([attr]) = attr.meta_item_list().as_deref() { if let Some([attr]) = attr.meta_item_list().as_deref() {
attr.has_name(sym::cfg) attr.has_name(sym::cfg)

View file

@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::{is_automatically_derived, is_default_equivalent, peel_blocks}; use clippy_utils::{is_default_equivalent, peel_blocks};
use rustc_hir::{ use rustc_hir::{
def::{DefKind, Res}, def::{DefKind, Res},
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind, Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
@ -71,8 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
self_ty, self_ty,
.. ..
}) = item.kind; }) = item.kind;
if let attrs = cx.tcx.hir().attrs(item.hir_id()); if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
if !is_automatically_derived(attrs);
if !item.span.from_expansion(); if !item.span.from_expansion();
if let Some(def_id) = trait_ref.trait_def_id(); if let Some(def_id) = trait_ref.trait_def_id();
if cx.tcx.is_diagnostic_item(sym::Default, def_id); if cx.tcx.is_diagnostic_item(sym::Default, def_id);
@ -81,6 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
if let ImplItemKind::Fn(_, b) = &impl_item.kind; if let ImplItemKind::Fn(_, b) = &impl_item.kind;
if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b); if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
if let Some(adt_def) = cx.tcx.type_of(item.def_id).ty_adt_def(); if let Some(adt_def) = cx.tcx.type_of(item.def_id).ty_adt_def();
if let attrs = cx.tcx.hir().attrs(item.hir_id());
if !attrs.iter().any(|attr| attr.doc_str().is_some()); if !attrs.iter().any(|attr| attr.doc_str().is_some());
if let child_attrs = cx.tcx.hir().attrs(impl_item_hir); if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
if !child_attrs.iter().any(|attr| attr.doc_str().is_some()); if !child_attrs.iter().any(|attr| attr.doc_str().is_some());

View file

@ -1,7 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note, span_lint_and_then};
use clippy_utils::paths; use clippy_utils::paths;
use clippy_utils::ty::{implements_trait, is_copy}; use clippy_utils::ty::{implements_trait, is_copy};
use clippy_utils::{is_automatically_derived, is_lint_allowed, match_def_path}; use clippy_utils::{is_lint_allowed, match_def_path};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor}; use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
use rustc_hir::{ use rustc_hir::{
@ -171,8 +171,8 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
}) = item.kind }) = item.kind
{ {
let ty = cx.tcx.type_of(item.def_id); let ty = cx.tcx.type_of(item.def_id);
let attrs = cx.tcx.hir().attrs(item.hir_id()); let is_automatically_derived =
let is_automatically_derived = is_automatically_derived(attrs); cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived); check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived); check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
@ -201,7 +201,7 @@ fn check_hash_peq<'tcx>(
then { then {
// Look for the PartialEq implementations for `ty` // Look for the PartialEq implementations for `ty`
cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| { cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
let peq_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id)); let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
if peq_is_automatically_derived == hash_is_automatically_derived { if peq_is_automatically_derived == hash_is_automatically_derived {
return; return;
@ -255,7 +255,7 @@ fn check_ord_partial_ord<'tcx>(
then { then {
// Look for the PartialOrd implementations for `ty` // Look for the PartialOrd implementations for `ty`
cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| { cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
let partial_ord_is_automatically_derived = is_automatically_derived(cx.tcx.get_attrs(impl_id)); let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
if partial_ord_is_automatically_derived == ord_is_automatically_derived { if partial_ord_is_automatically_derived == ord_is_automatically_derived {
return; return;

View file

@ -13,13 +13,13 @@ use clippy_utils::attrs::is_proc_macro;
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_must_use_ty; use clippy_utils::ty::is_must_use_ty;
use clippy_utils::{match_def_path, must_use_attr, return_ty, trait_ref_of_method}; use clippy_utils::{match_def_path, return_ty, trait_ref_of_method};
use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id()); let attrs = cx.tcx.hir().attrs(item.hir_id());
let attr = must_use_attr(attrs); let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind { if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind {
let is_public = cx.access_levels.is_exported(item.def_id); let is_public = cx.access_levels.is_exported(item.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@ -44,7 +44,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
let is_public = cx.access_levels.is_exported(item.def_id); let is_public = cx.access_levels.is_exported(item.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir().attrs(item.hir_id()); let attrs = cx.tcx.hir().attrs(item.hir_id());
let attr = must_use_attr(attrs); let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
if let Some(attr) = attr { if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
} else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id).is_none() { } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id).is_none() {
@ -67,7 +67,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir().attrs(item.hir_id()); let attrs = cx.tcx.hir().attrs(item.hir_id());
let attr = must_use_attr(attrs); let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
if let Some(attr) = attr { if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr); check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
} else if let hir::TraitFn::Provided(eid) = *eid { } else if let hir::TraitFn::Provided(eid) = *eid {

View file

@ -1,4 +1,3 @@
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use clippy_utils::{is_lint_allowed, meets_msrv, msrvs}; use clippy_utils::{is_lint_allowed, meets_msrv, msrvs};
@ -161,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
let id = cx.tcx.hir().local_def_id(v.id); let id = cx.tcx.hir().local_def_id(v.id);
(matches!(v.data, hir::VariantData::Unit(_)) (matches!(v.data, hir::VariantData::Unit(_))
&& v.ident.as_str().starts_with('_') && v.ident.as_str().starts_with('_')
&& is_doc_hidden(cx.tcx.get_attrs(id.to_def_id()))) && cx.tcx.is_doc_hidden(id.to_def_id()))
.then(|| (id, v.span)) .then(|| (id, v.span))
}); });
if let Some((id, span)) = iter.next() if let Some((id, span)) = iter.next()

View file

@ -193,6 +193,5 @@ impl<'a> CommonPrefixSearcher<'a> {
} }
fn is_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool { fn is_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool {
let attrs = cx.tcx.get_attrs(variant_def.def_id); cx.tcx.is_doc_hidden(variant_def.def_id) || cx.tcx.has_attr(variant_def.def_id, sym::unstable)
clippy_utils::attrs::is_doc_hidden(attrs) || clippy_utils::attrs::is_unstable(attrs)
} }

View file

@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
// can't be implemented for unsafe new // can't be implemented for unsafe new
return; return;
} }
if clippy_utils::is_doc_hidden(cx.tcx.hir().attrs(id)) { if cx.tcx.is_doc_hidden(impl_item.def_id) {
// shouldn't be implemented when it is hidden in docs // shouldn't be implemented when it is hidden in docs
return; return;
} }

View file

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_hir; use clippy_utils::diagnostics::span_lint_hir;
use clippy_utils::is_automatically_derived;
use if_chain::if_chain; use if_chain::if_chain;
use rustc_hir::{Impl, Item, ItemKind}; use rustc_hir::{Impl, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
@ -37,8 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if_chain! { if_chain! {
if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind; if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind;
let attrs = cx.tcx.hir().attrs(item.hir_id()); if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
if !is_automatically_derived(attrs);
if let Some(eq_trait) = cx.tcx.lang_items().eq_trait(); if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
if trait_ref.path.res.def_id() == eq_trait; if trait_ref.path.res.def_id() == eq_trait;
then { then {

View file

@ -290,7 +290,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
fn has_sig_drop_attr(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { fn has_sig_drop_attr(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
if let Some(adt) = ty.ty_adt_def() { if let Some(adt) = ty.ty_adt_def() {
if get_attr(cx.sess(), cx.tcx.get_attrs(adt.did()), "has_significant_drop").count() > 0 { if get_attr(cx.sess(), cx.tcx.get_attrs_unchecked(adt.did()), "has_significant_drop").count() > 0 {
return true; return true;
} }
} }

View file

@ -1,6 +1,7 @@
use rustc_ast::{ast, attr}; use rustc_ast::ast;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_session::Session; use rustc_session::Session;
use rustc_ast::attr;
use rustc_span::sym; use rustc_span::sym;
use std::str::FromStr; use std::str::FromStr;
@ -158,7 +159,3 @@ pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
.any(|l| attr::list_contains_name(&l, sym::hidden)) .any(|l| attr::list_contains_name(&l, sym::hidden))
} }
/// Return true if the attributes contain `#[unstable]`
pub fn is_unstable(attrs: &[ast::Attribute]) -> bool {
attrs.iter().any(|attr| attr.has_name(sym::unstable))
}

View file

@ -66,7 +66,7 @@ use std::lazy::SyncOnceCell;
use std::sync::{Mutex, MutexGuard}; use std::sync::{Mutex, MutexGuard};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast::{self, Attribute, LitKind}; use rustc_ast::ast::{self, LitKind};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unhash::UnhashMap; use rustc_data_structures::unhash::UnhashMap;
use rustc_hir as hir; use rustc_hir as hir;
@ -1472,12 +1472,6 @@ pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>
} }
} }
/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
/// implementations have.
pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
has_attr(attrs, sym::automatically_derived)
}
pub fn is_self(slf: &Param<'_>) -> bool { pub fn is_self(slf: &Param<'_>) -> bool {
if let PatKind::Binding(.., name, _) = slf.pat.kind { if let PatKind::Binding(.., name, _) = slf.pat.kind {
name.name == kw::SelfLower name.name == kw::SelfLower
@ -1724,11 +1718,6 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t
None None
} }
// Finds the `#[must_use]` attribute, if any
pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
attrs.iter().find(|a| a.has_name(sym::must_use))
}
// check if expr is calling method or function with #[must_use] attribute // check if expr is calling method or function with #[must_use] attribute
pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let did = match expr.kind { let did = match expr.kind {
@ -1745,7 +1734,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
_ => None, _ => None,
}; };
did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some()) did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use))
} }
/// Checks if an expression represents the identity function /// Checks if an expression represents the identity function

View file

@ -22,7 +22,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::query::normalize::AtExt; use rustc_trait_selection::traits::query::normalize::AtExt;
use std::iter; use std::iter;
use crate::{match_def_path, must_use_attr, path_res, paths}; use crate::{match_def_path, path_res, paths};
// Checks if the given type implements copy. // Checks if the given type implements copy.
pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
@ -178,18 +178,18 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
// Returns whether the type has #[must_use] attribute // Returns whether the type has #[must_use] attribute
pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
match ty.kind() { match ty.kind() {
ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did())).is_some(), ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use),
ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(), ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use),
ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
// for the Array case we don't need to care for the len == 0 case // for the Array case we don't need to care for the len == 0 case
// because we don't want to lint functions returning empty arrays // because we don't want to lint functions returning empty arrays
is_must_use_ty(cx, *ty) is_must_use_ty(cx, *ty)
}, },
ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)),
ty::Opaque(ref def_id, _) => { ty::Opaque(def_id, _) => {
for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
if let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() { if let ty::PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
return true; return true;
} }
} }
@ -199,7 +199,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
ty::Dynamic(binder, _) => { ty::Dynamic(binder, _) => {
for predicate in binder.iter() { for predicate in binder.iter() {
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
if must_use_attr(cx.tcx.get_attrs(trait_ref.def_id)).is_some() { if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) {
return true; return true;
} }
} }