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,177 +868,180 @@ impl IntType {
/// structure layout, `packed` to remove padding, and `transparent` to delegate representation
/// concerns to the only non-ZST field.
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 diagnostic = &sess.parse_sess.span_diagnostic;
if attr.has_name(sym::repr) {
if let Some(items) = attr.meta_item_list() {
for item in items {
let mut recognised = false;
if item.is_word() {
let hint = match item.name_or_empty() {
sym::C => Some(ReprC),
sym::packed => Some(ReprPacked(1)),
sym::simd => Some(ReprSimd),
sym::transparent => Some(ReprTransparent),
sym::no_niche => Some(ReprNoNiche),
sym::align => {
let mut err = struct_span_err!(
diagnostic,
item.span(),
E0589,
"invalid `repr(align)` attribute: `align` needs an argument"
);
err.span_suggestion(
item.span(),
"supply an argument here",
"align(...)".to_string(),
Applicability::HasPlaceholders,
);
err.emit();
recognised = true;
None
}
name => int_type_of_word(name).map(ReprInt),
};
if let Some(h) = hint {
if let Some(items) = attr.meta_item_list() {
for item in items {
let mut recognised = false;
if item.is_word() {
let hint = match item.name_or_empty() {
sym::C => Some(ReprC),
sym::packed => Some(ReprPacked(1)),
sym::simd => Some(ReprSimd),
sym::transparent => Some(ReprTransparent),
sym::no_niche => Some(ReprNoNiche),
sym::align => {
let mut err = struct_span_err!(
diagnostic,
item.span(),
E0589,
"invalid `repr(align)` attribute: `align` needs an argument"
);
err.span_suggestion(
item.span(),
"supply an argument here",
"align(...)".to_string(),
Applicability::HasPlaceholders,
);
err.emit();
recognised = true;
acc.push(h);
None
}
} else if let Some((name, value)) = item.name_value_literal() {
let mut literal_error = None;
if name == sym::align {
recognised = true;
match parse_alignment(&value.kind) {
Ok(literal) => acc.push(ReprAlign(literal)),
Err(message) => literal_error = Some(message),
};
} else if name == sym::packed {
recognised = true;
match parse_alignment(&value.kind) {
Ok(literal) => acc.push(ReprPacked(literal)),
Err(message) => literal_error = Some(message),
};
} else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche)
|| int_type_of_word(name).is_some()
{
recognised = true;
struct_span_err!(
name => int_type_of_word(name).map(ReprInt),
};
if let Some(h) = hint {
recognised = true;
acc.push(h);
}
} else if let Some((name, value)) = item.name_value_literal() {
let mut literal_error = None;
if name == sym::align {
recognised = true;
match parse_alignment(&value.kind) {
Ok(literal) => acc.push(ReprAlign(literal)),
Err(message) => literal_error = Some(message),
};
} else if name == sym::packed {
recognised = true;
match parse_alignment(&value.kind) {
Ok(literal) => acc.push(ReprPacked(literal)),
Err(message) => literal_error = Some(message),
};
} else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche)
|| int_type_of_word(name).is_some()
{
recognised = true;
struct_span_err!(
diagnostic,
item.span(),
E0552,
"invalid representation hint: `{}` does not take a parenthesized argument list",
name.to_ident_string(),
).emit();
}
if let Some(literal_error) = literal_error {
struct_span_err!(
}
if let Some(literal_error) = literal_error {
struct_span_err!(
diagnostic,
item.span(),
E0589,
"invalid `repr({})` attribute: {}",
name.to_ident_string(),
literal_error
)
.emit();
}
} else if let Some(meta_item) = item.meta_item() {
if let MetaItemKind::NameValue(ref value) = meta_item.kind {
if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
let name = meta_item.name_or_empty().to_ident_string();
recognised = true;
let mut err = struct_span_err!(
diagnostic,
item.span(),
E0589,
"invalid `repr({})` attribute: {}",
name.to_ident_string(),
literal_error
)
.emit();
}
} else if let Some(meta_item) = item.meta_item() {
if let MetaItemKind::NameValue(ref value) = meta_item.kind {
if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
let name = meta_item.name_or_empty().to_ident_string();
recognised = true;
let mut err = struct_span_err!(
diagnostic,
item.span(),
E0693,
"incorrect `repr({})` attribute format",
name,
);
match value.kind {
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
err.span_suggestion(
item.span(),
"use parentheses instead",
format!("{}({})", name, int),
Applicability::MachineApplicable,
);
}
ast::LitKind::Str(s, _) => {
err.span_suggestion(
item.span(),
"use parentheses instead",
format!("{}({})", name, s),
Applicability::MachineApplicable,
);
}
_ => {}
E0693,
"incorrect `repr({})` attribute format",
name,
);
match value.kind {
ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => {
err.span_suggestion(
item.span(),
"use parentheses instead",
format!("{}({})", name, int),
Applicability::MachineApplicable,
);
}
err.emit();
} else {
if matches!(
meta_item.name_or_empty(),
sym::C | sym::simd | sym::transparent | sym::no_niche
) || int_type_of_word(meta_item.name_or_empty()).is_some()
{
recognised = true;
struct_span_err!(
diagnostic,
meta_item.span,
E0552,
"invalid representation hint: `{}` does not take a value",
meta_item.name_or_empty().to_ident_string(),
)
.emit();
ast::LitKind::Str(s, _) => {
err.span_suggestion(
item.span(),
"use parentheses instead",
format!("{}({})", name, s),
Applicability::MachineApplicable,
);
}
_ => {}
}
} else if let MetaItemKind::List(_) = meta_item.kind {
if meta_item.has_name(sym::align) {
recognised = true;
struct_span_err!(
diagnostic,
meta_item.span,
E0693,
"incorrect `repr(align)` attribute format: \
`align` takes exactly one argument in parentheses"
)
.emit();
} else if meta_item.has_name(sym::packed) {
recognised = true;
struct_span_err!(
diagnostic,
meta_item.span,
E0552,
"incorrect `repr(packed)` attribute format: \
`packed` takes exactly one parenthesized argument, \
or no parentheses at all"
)
.emit();
} else if matches!(
err.emit();
} else {
if matches!(
meta_item.name_or_empty(),
sym::C | sym::simd | sym::transparent | sym::no_niche
) || int_type_of_word(meta_item.name_or_empty()).is_some()
{
recognised = true;
struct_span_err!(
diagnostic,
meta_item.span,
E0552,
"invalid representation hint: `{}` does not take a value",
meta_item.name_or_empty().to_ident_string(),
)
.emit();
}
}
} else if let MetaItemKind::List(_) = meta_item.kind {
if meta_item.has_name(sym::align) {
recognised = true;
struct_span_err!(
diagnostic,
meta_item.span,
E0693,
"incorrect `repr(align)` attribute format: \
`align` takes exactly one argument in parentheses"
)
.emit();
} else if meta_item.has_name(sym::packed) {
recognised = true;
struct_span_err!(
diagnostic,
meta_item.span,
E0552,
"incorrect `repr(packed)` attribute format: \
`packed` takes exactly one parenthesized argument, \
or no parentheses at all"
)
.emit();
} else if matches!(
meta_item.name_or_empty(),
sym::C | sym::simd | sym::transparent | sym::no_niche
) || int_type_of_word(meta_item.name_or_empty()).is_some()
{
recognised = true;
struct_span_err!(
diagnostic,
meta_item.span,
E0552,
"invalid representation hint: `{}` does not take a parenthesized argument list",
meta_item.name_or_empty().to_ident_string(),
).emit();
}
}
}
if !recognised {
// Not a word we recognize. This will be caught and reported by
// the `check_mod_attrs` pass, but this pass doesn't always run
// (e.g. if we only pretty-print the source), so we have to gate
// the `delay_span_bug` call as follows:
if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
}
}
if !recognised {
// Not a word we recognize. This will be caught and reported by
// the `check_mod_attrs` pass, but this pass doesn't always run
// (e.g. if we only pretty-print the source), so we have to gate
// the `delay_span_bug` call as follows:
if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
diagnostic.delay_span_bug(item.span(), "unrecognized representation hint");
}
}
}

View File

@ -6,6 +6,7 @@ use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::OptLevel;
use rustc_span::symbol::sym;
use rustc_target::spec::abi::Abi;
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
use smallvec::SmallVec;
@ -329,9 +330,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
) {
let span = cx
.tcx
.get_attrs(instance.def_id())
.iter()
.find(|a| a.has_name(rustc_span::sym::target_feature))
.get_attr(instance.def_id(), sym::target_feature)
.map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
let msg = format!(
"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) => {
let unstable_in_stable = self.ccx.is_const_stable_const_fn()
&& !super::rustc_allow_const_fn_unstable(
self.tcx,
self.def_id().to_def_id(),
gate,
);
&& !super::rustc_allow_const_fn_unstable(self.tcx, self.def_id(), gate);
if unstable_in_stable {
emit_unstable_in_stable_error(self.ccx, span, gate);
}
@ -713,7 +709,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
match &terminator.kind {
TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => {
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);
@ -797,7 +793,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// trait.
let callee_trait = tcx.trait_of_item(callee);
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)
// Can only call methods when it's `<Self as TheTrait>::f`.
&& 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 {
let attrs = tcx.get_attrs(def_id);
pub fn rustc_allow_const_fn_unstable(
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)
}

View File

@ -1,5 +1,6 @@
//! 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_hir as hir;
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`.
#[derive(Debug, Clone, Copy)]
pub struct FnCallNonConst<'tcx> {
pub caller: DefId,
pub caller: LocalDefId,
pub callee: DefId,
pub substs: SubstsRef<'tcx>,
pub span: Span,
@ -117,13 +118,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
match self_ty.kind() {
Param(param_ty) => {
debug!(?param_ty);
if let Some(generics) = caller
.as_local()
.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 caller_hir_id = tcx.hir().local_def_id_to_hir_id(caller);
if let Some(generics) = tcx.hir().get(caller_hir_id).generics() {
let constraint = with_no_trimmed_paths!(format!(
"~const {}",
trait_ref.print_only_trait_path()

View File

@ -147,6 +147,16 @@ pub enum AttributeDuplicates {
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.
/// E.g., `template!(Word, List: "description")` means that the attribute
/// supports forms `#[attr]` and `#[attr(description)]`.
@ -168,9 +178,10 @@ macro_rules! template {
}
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 {
name: sym::$attr,
only_local: or_default!(false, $($only_local)?),
type_: $typ,
template: $tpl,
gate: Ungated,
@ -180,18 +191,20 @@ macro_rules! ungated {
}
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 {
name: sym::$attr,
only_local: or_default!(false, $($only_local)?),
type_: $typ,
template: $tpl,
duplicates: $duplicates,
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 {
name: sym::$attr,
only_local: or_default!(false, $($only_local)?),
type_: $typ,
template: $tpl,
duplicates: $duplicates,
@ -201,12 +214,13 @@ macro_rules! gated {
}
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!(
$attr,
$typ,
$tpl,
$duplicate,
$(@only_local: $only_local,)?
concat!(
"the `#[",
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 {
name: sym::$attr,
only_local: or_default!(false, $($only_local)?),
type_: $typ,
template: $tpl,
duplicates: $duplicates,
@ -237,6 +252,10 @@ const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never b
pub struct BuiltinAttribute {
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 template: AttributeTemplate,
pub duplicates: AttributeDuplicates,
@ -295,7 +314,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(must_use, Normal, template!(Word, NameValueStr: "reason"), FutureWarnFollowing),
gated!(
must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing,
must_not_suspend, experimental!(must_not_suspend)
experimental!(must_not_suspend)
),
ungated!(
deprecated, Normal,
@ -324,8 +343,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk),
ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(no_mangle, Normal, template!(Word), WarnFollowing),
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing),
ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, @only_local: true),
// Limits:
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
// Code generation:
ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing),
ungated!(cold, Normal, template!(Word), WarnFollowing),
ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, @only_local: true),
ungated!(cold, Normal, template!(Word), WarnFollowing, @only_local: true),
ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing),
ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk),
ungated!(track_caller, Normal, template!(Word), WarnFollowing),
@ -385,7 +404,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
// 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!(
link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, raw_dylib,
experimental!(link_ordinal)
@ -394,6 +413,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Plugins:
BuiltinAttribute {
name: sym::plugin,
only_local: false,
type_: CrateLevel,
template: template!(List: "name"),
duplicates: DuplicatesOk,
@ -475,7 +495,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
// DuplicatesOk since it has its own validation
ungated!(
stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk
stable, Normal, template!(List: r#"feature = "name", since = "version""#), DuplicatesOk,
),
ungated!(
unstable, Normal,
@ -546,11 +566,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// ==========================================================================
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",
),
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:
// ==========================================================================
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",
),
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_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_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_attr!(
@ -656,6 +676,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
BuiltinAttribute {
name: sym::rustc_diagnostic_item,
// FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
only_local: false,
type_: Normal,
template: template!(NameValueStr: "name"),
duplicates: ErrorFollowing,
@ -676,7 +698,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"unboxed_closures are still evolving",
),
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 \
overflow checking behavior of several libcore functions that are inlined \
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()
}
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>> =
SyncLazy::new(|| {
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 builtin_attrs::AttributeDuplicates;
pub use builtin_attrs::{
deprecated_attributes, find_gated_cfg, is_builtin_attr_name, AttributeGate, AttributeTemplate,
AttributeType, BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
deprecated_attributes, find_gated_cfg, is_builtin_attr_name, is_builtin_only_local,
AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, GatedCfg,
BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP,
};
pub use removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};

View File

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

View File

@ -258,10 +258,7 @@ impl<'tcx> Queries<'tcx> {
/// an error.
fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
let Some((def_id, _)) = tcx.entry_fn(()) else { return };
let attrs = &*tcx.get_attrs(def_id);
let attrs = attrs.iter().filter(|attr| attr.has_name(sym::rustc_error));
for attr in attrs {
for attr in tcx.get_attrs(def_id, sym::rustc_error) {
match attr.meta_item_list() {
// Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`.
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);
if !has_doc {
cx.struct_span_lint(
@ -2738,11 +2738,7 @@ impl ClashingExternDeclarations {
// bottleneck, this does just fine.
(
overridden_link_name,
tcx.get_attrs(fi.def_id.to_def_id())
.iter()
.find(|at| at.has_name(sym::link_name))
.unwrap()
.span,
tcx.get_attr(fi.def_id.to_def_id(), 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 {
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

View File

@ -303,26 +303,25 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_pre_path: &str,
descr_post_path: &str,
) -> bool {
for attr in cx.tcx.get_attrs(def_id).iter() {
if attr.has_name(sym::must_use) {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let msg = format!(
"unused {}`{}`{} that must be used",
descr_pre_path,
cx.tcx.def_path_str(def_id),
descr_post_path
);
let mut err = lint.build(&msg);
// check for #[must_use = "..."]
if let Some(note) = attr.value_str() {
err.note(note.as_str());
}
err.emit();
});
return true;
}
if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let msg = format!(
"unused {}`{}`{} that must be used",
descr_pre_path,
cx.tcx.def_path_str(def_id),
descr_post_path
);
let mut err = lint.build(&msg);
// check for #[must_use = "..."]
if let Some(note) = attr.value_str() {
err.note(note.as_str());
}
err.emit();
});
true
} else {
false
}
false
}
}
}

View File

@ -985,11 +985,17 @@ fn should_encode_generics(def_kind: DefKind) -> bool {
}
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_attrs(&mut self, def_id: DefId) {
let attrs = self.tcx.get_attrs(def_id);
record!(self.tables.attributes[def_id] <- attrs);
if attrs.iter().any(|attr| attr.may_have_doc_links()) {
self.tables.may_have_doc_links.set(def_id.index, ());
fn encode_attrs(&mut self, def_id: LocalDefId) {
let mut attrs = self
.tcx
.hir()
.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 };
self.tables.opt_def_kind.set(def_id.index, def_kind);
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));
if def_kind.has_codegen_attrs() {
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);
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()));
if let Some(stability) = 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();
self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(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_ident_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) }
}
/// 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] {
desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) }
separate_provide_extern

View File

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

View File

@ -1148,9 +1148,8 @@ impl<'tcx> TyCtxt<'tcx> {
/// `rustc_layout_scalar_valid_range` attribute.
// 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>) {
let attrs = self.get_attrs(def_id);
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;
};
debug!("layout_scalar_valid_range: attr={:?}", attr);

View File

@ -568,11 +568,8 @@ impl<T> Trait<T> for X {
}
}
TargetFeatureCast(def_id) => {
let attrs = self.get_attrs(*def_id);
let target_spans = attrs
.iter()
.filter(|attr| attr.has_name(sym::target_feature))
.map(|attr| attr.span);
let target_spans =
self.get_attrs(*def_id, sym::target_feature).map(|attr| attr.span);
diag.note(
"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_macros::HashStable;
use rustc_middle::ty::normalize_erasing_regions::NormalizationError;
use rustc_span::Symbol;
use std::fmt;
@ -185,8 +186,8 @@ impl<'tcx> InstanceDef<'tcx> {
}
#[inline]
pub fn attrs(&self, tcx: TyCtxt<'tcx>) -> ty::Attributes<'tcx> {
tcx.get_attrs(self.def_id())
pub fn get_attrs(&self, tcx: TyCtxt<'tcx>, attr: Symbol) -> ty::Attributes<'tcx> {
tcx.get_attrs(self.def_id(), attr)
}
/// 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::IntVarValue::*;
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::middle::privacy::AccessLevels;
use crate::mir::{Body, GeneratorLayout};
@ -28,8 +22,12 @@ use crate::ty;
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
use crate::ty::util::Discr;
pub use adt::*;
pub use assoc::*;
pub use generics::*;
use rustc_ast as ast;
use rustc_attr as attr;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_data_structures::intern::{Interned, WithStableHash};
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::Span;
use rustc_target::abi::Align;
pub use vtable::*;
use std::fmt::Debug;
use std::hash::Hash;
@ -1818,8 +1817,8 @@ impl ReprOptions {
field_shuffle_seed ^= user_seed;
}
for attr in tcx.get_attrs(did).iter() {
for r in attr::find_repr_attrs(&tcx.sess, attr) {
for attr in tcx.get_attrs(did, sym::repr) {
for r in attr::parse_repr_attr(&tcx.sess, attr) {
flags.insert(match r {
attr::ReprC => ReprFlags::IS_C,
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)]
pub enum ImplOverlapKind {
/// These impls are always allowed to overlap.
@ -2186,8 +2184,8 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
/// Gets the attributes of a definition.
pub fn get_attrs(self, did: DefId) -> Attributes<'tcx> {
// FIXME(@lcnr): Remove this function.
pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [ast::Attribute] {
if let Some(did) = did.as_local() {
self.hir().attrs(self.hir().local_def_id_to_hir_id(did))
} 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.
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`.

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,3 @@
use rustc_ast::ast;
use rustc_span::symbol::sym;
use rustc_span::Span;
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));
}
let attributes = tcx.get_attrs(def_id);
let param_env = tcx.param_env(def_id);
let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
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)
.into_engine(tcx, body)
.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)
.into_engine(tcx, body)
.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)
.into_engine(tcx, body)
.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();
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");
}
}
@ -92,7 +89,6 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
pub fn sanity_check_via_rustc_peek<'tcx, A>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
_attributes: &[ast::Attribute],
results: &Results<'tcx, A>,
) where
A: RustcPeekAt<'tcx>,

View File

@ -197,7 +197,7 @@ fn emit_unused_generic_params_error<'tcx>(
unused_parameters: &FiniteBitSet<u32>,
) {
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;
}

View File

@ -170,7 +170,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
// If `def_id` is `None`, we don't need to consider stability attributes.
let def_id = match def_id {
Some(x) => x.to_def_id(),
Some(x) => x,
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
// 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;
}
// However, we cannot allow stable `const fn`s to use unstable features without an explicit
// opt-in via `rustc_allow_const_fn_unstable`.
attr::rustc_allow_const_fn_unstable(&tcx.sess, &tcx.get_attrs(def_id))
.any(|name| name == feature_gate)
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)
};
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> {
attrs.iter().find_map(|attr| {
if attr.has_name(sym::rustc_diagnostic_item) { attr.value_str() } else { None }

View File

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

View File

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

View File

@ -49,27 +49,26 @@ struct SymbolNamesTest<'tcx> {
impl SymbolNamesTest<'_> {
fn process_attrs(&mut self, def_id: LocalDefId) {
let tcx = self.tcx;
for attr in tcx.get_attrs(def_id.to_def_id()).iter() {
if attr.has_name(SYMBOL_NAME) {
let def_id = def_id.to_def_id();
let instance = Instance::new(
def_id,
tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)),
);
let mangled = tcx.symbol_name(instance);
tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled));
if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
}
} else if attr.has_name(DEF_PATH) {
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));
// 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.
for attr in tcx.get_attrs(def_id.to_def_id(), SYMBOL_NAME) {
let def_id = def_id.to_def_id();
let instance = Instance::new(
def_id,
tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def_id)),
);
let mangled = tcx.symbol_name(instance);
tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled));
if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
}
}
// (*) 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.
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()));
tcx.sess.span_err(attr.span, &format!("def-path({})", path));
}
}
}

View File

@ -175,9 +175,7 @@ impl<'tcx> OnUnimplementedDirective {
}
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.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) else {
let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else {
return Ok(None);
};

View File

@ -1156,9 +1156,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let ImplCandidate(def_id) = candidate {
if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
let attrs = tcx.get_attrs(def_id);
let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
let value = attr.and_then(|a| a.value_str());
let value = tcx
.get_attr(def_id, sym::rustc_reservation_impl)
.and_then(|a| a.value_str());
if let Some(value) = value {
debug!(
"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 {
let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
let attr_span = tcx
.get_attrs(impl_trait_ref.def_id)
.iter()
.find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
.get_attr(impl_trait_ref.def_id, sym::rustc_must_implement_one_of)
.map(|attr| attr.span);
missing_items_must_implement_one_of_err(tcx, impl_span, missing_items, attr_span);
@ -1158,20 +1156,20 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
let repr = def.repr();
if repr.packed() {
for attr in tcx.get_attrs(def.did()).iter() {
for r in attr::find_repr_attrs(&tcx.sess, attr) {
for attr in tcx.get_attrs(def.did(), sym::repr) {
for r in attr::parse_repr_attr(&tcx.sess, attr) {
if let attr::ReprPacked(pack) = r
&& let Some(repr_pack) = repr.pack
&& pack as u64 != repr_pack.bytes()
{
struct_span_err!(
tcx.sess,
sp,
E0634,
"type has conflicting packed representation hints"
)
.emit();
}
&& let Some(repr_pack) = repr.pack
&& pack as u64 != repr_pack.bytes()
{
struct_span_err!(
tcx.sess,
sp,
E0634,
"type has conflicting packed representation hints"
)
.emit();
}
}
}
if repr.align.is_some() {
@ -1321,8 +1319,7 @@ fn check_enum<'tcx>(
def.destructor(tcx); // force the destructor to be evaluated
if vs.is_empty() {
let attributes = tcx.get_attrs(def_id.to_def_id());
if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) {
if let Some(attr) = tcx.get_attr(def_id.to_def_id(), sym::repr) {
struct_span_err!(
tcx.sess,
attr.span,

View File

@ -407,8 +407,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.has_only_self_parameter(m)
&& self
.tcx
.get_attrs(m.def_id)
.iter()
// This special internal attribute is used to permit
// "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
// `as_mut`?
.any(|a| a.has_name(sym::rustc_conversion_suggestion))
.has_attr(m.def_id, sym::rustc_conversion_suggestion)
});
methods

View File

@ -609,44 +609,43 @@ fn check_must_not_suspend_def(
hir_id: HirId,
data: SuspendCheckData<'_, '_>,
) -> bool {
for attr in tcx.get_attrs(def_id).iter() {
if attr.has_name(sym::must_not_suspend) {
tcx.struct_span_lint_hir(
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
hir_id,
data.source_span,
|lint| {
let msg = format!(
"{}`{}`{} held across a suspend point, but should not be",
data.descr_pre,
tcx.def_path_str(def_id),
data.descr_post,
);
let mut err = lint.build(&msg);
if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
tcx.struct_span_lint_hir(
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
hir_id,
data.source_span,
|lint| {
let msg = format!(
"{}`{}`{} held across a suspend point, but should not be",
data.descr_pre,
tcx.def_path_str(def_id),
data.descr_post,
);
let mut err = lint.build(&msg);
// add span pointing to the offending yield/await
err.span_label(data.yield_span, "the value is held across this suspend point");
// add span pointing to the offending yield/await
err.span_label(data.yield_span, "the value is held across this suspend point");
// Add optional reason note
if let Some(note) = attr.value_str() {
// FIXME(guswynn): consider formatting this better
err.span_note(data.source_span, note.as_str());
}
// Add optional reason note
if let Some(note) = attr.value_str() {
// FIXME(guswynn): consider formatting this better
err.span_note(data.source_span, note.as_str());
}
// Add some quick suggestions on what to do
// FIXME: can `drop` work as a suggestion here as well?
err.span_help(
data.source_span,
"consider using a block (`{ ... }`) \
to shrink the value's scope, ending before the suspend point",
);
// Add some quick suggestions on what to do
// FIXME: can `drop` work as a suggestion here as well?
err.span_help(
data.source_span,
"consider using a block (`{ ... }`) \
to shrink the value's scope, ending before the suspend point",
);
err.emit();
},
);
err.emit();
},
);
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| {
// Removal suggestion span needs to include attributes (Issue #54400)
let span_with_attrs = tcx
.get_attrs(extern_crate.def_id)
.hir()
.attrs(id)
.iter()
.map(|attr| attr.span)
.fold(span, |acc, attr_span| acc.to(attr_span));
@ -166,13 +167,13 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
continue;
}
let id = tcx.hir().local_def_id_to_hir_id(def_id);
// If the extern crate has any attributes, they may have funky
// semantics we can't faithfully represent using `use` (most
// notably `#[macro_use]`). Ignore it.
if !tcx.get_attrs(extern_crate.def_id).is_empty() {
if !tcx.hir().attrs(id).is_empty() {
continue;
}
let id = tcx.hir().local_def_id_to_hir_id(def_id);
tcx.struct_span_lint_hir(lint, id, extern_crate.span, |lint| {
// Otherwise, we can convert it into a `use` of some kind.
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
};
let must_implement_one_of = tcx
.get_attrs(def_id)
.iter()
.find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
.get_attr(def_id, sym::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_then(|attr| match attr.meta_item_list() {

View File

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

View File

@ -22,7 +22,7 @@ use crate::clean::{
use crate::core::DocContext;
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.
///
@ -155,7 +155,7 @@ crate fn try_inline_glob(
}
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.
@ -691,7 +691,7 @@ crate fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
let trait_ = clean::TraitWithExtraInfo {
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.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
// external crate
let did = self.crate_num.as_def_id();
tcx.get_attrs(did)
.lists(sym::doc)
tcx.get_attrs(did, sym::doc)
.flat_map(|attr| attr.meta_item_list().unwrap_or_default())
.filter(|a| a.has_name(sym::html_root_url))
.filter_map(|a| a.value_str())
.map(to_remote)
@ -226,11 +226,13 @@ impl ExternalCrate {
let as_keyword = |res: Res<!>| {
if let Res::Def(DefKind::Mod, def_id) = res {
let attrs = tcx.get_attrs(def_id);
let mut keyword = None;
for attr in attrs.lists(sym::doc) {
if attr.has_name(sym::keyword) {
if let Some(v) = attr.value_str() {
let meta_items = tcx
.get_attrs(def_id, sym::doc)
.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);
break;
}
@ -288,11 +290,13 @@ impl ExternalCrate {
// rendering by delegating everything to a hash map.
let as_primitive = |res: Res<!>| {
if let Res::Def(DefKind::Mod, def_id) = res {
let attrs = tcx.get_attrs(def_id);
let mut prim = None;
for attr in attrs.lists(sym::doc) {
if let Some(v) = attr.value_str() {
if attr.has_name(sym::primitive) {
let meta_items = tcx
.get_attrs(def_id, sym::doc)
.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);
if prim.is_some() {
break;
@ -413,7 +417,10 @@ impl Item {
}
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 {
@ -464,7 +471,7 @@ impl Item {
kind: ItemKind,
cx: &mut DocContext<'_>,
) -> 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(
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
/// `clean::Attributes` method.
crate fn has_doc_flag(attrs: ty::Attributes<'_>, flag: Symbol) -> bool {
attrs.iter().any(|attr| {
attr.has_name(sym::doc)
&& attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag))
crate fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool {
tcx.get_attrs(did, sym::doc).any(|attr| {
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) => {
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));
// 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 {
attr_buf.extend(
cx.tcx
.get_attrs(did)
.iter()
.filter(|attr| attr.has_name(sym::doc))
.get_attrs(did, sym::doc)
.filter(|attr| {
if let Some([attr]) = attr.meta_item_list().as_deref() {
attr.has_name(sym::cfg)

View File

@ -1,5 +1,5 @@
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::{
def::{DefKind, Res},
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
@ -71,8 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
self_ty,
..
}) = item.kind;
if let attrs = cx.tcx.hir().attrs(item.hir_id());
if !is_automatically_derived(attrs);
if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
if !item.span.from_expansion();
if let Some(def_id) = trait_ref.trait_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 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 attrs = cx.tcx.hir().attrs(item.hir_id());
if !attrs.iter().any(|attr| attr.doc_str().is_some());
if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
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::paths;
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 rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
use rustc_hir::{
@ -171,8 +171,8 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
}) = item.kind
{
let ty = cx.tcx.type_of(item.def_id);
let attrs = cx.tcx.hir().attrs(item.hir_id());
let is_automatically_derived = is_automatically_derived(attrs);
let is_automatically_derived =
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_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
@ -201,7 +201,7 @@ fn check_hash_peq<'tcx>(
then {
// Look for the PartialEq implementations for `ty`
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 {
return;
@ -255,7 +255,7 @@ fn check_ord_partial_ord<'tcx>(
then {
// Look for the PartialOrd implementations for `ty`
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 {
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::source::snippet_opt;
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};
pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
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 {
let is_public = cx.access_levels.is_exported(item.def_id);
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 fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
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 {
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() {
@ -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 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 {
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
} 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::source::snippet_opt;
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);
(matches!(v.data, hir::VariantData::Unit(_))
&& 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))
});
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 {
let attrs = cx.tcx.get_attrs(variant_def.def_id);
clippy_utils::attrs::is_doc_hidden(attrs) || clippy_utils::attrs::is_unstable(attrs)
cx.tcx.is_doc_hidden(variant_def.def_id) || cx.tcx.has_attr(variant_def.def_id, sym::unstable)
}

View File

@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
// can't be implemented for unsafe new
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
return;
}

View File

@ -1,5 +1,4 @@
use clippy_utils::diagnostics::span_lint_hir;
use clippy_utils::is_automatically_derived;
use if_chain::if_chain;
use rustc_hir::{Impl, Item, ItemKind};
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<'_>) {
if_chain! {
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 !is_automatically_derived(attrs);
if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
if trait_ref.path.res.def_id() == eq_trait;
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 {
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;
}
}

View File

@ -1,6 +1,7 @@
use rustc_ast::{ast, attr};
use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_session::Session;
use rustc_ast::attr;
use rustc_span::sym;
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))
}
/// 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 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::unhash::UnhashMap;
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 {
if let PatKind::Binding(.., name, _) = slf.pat.kind {
name.name == kw::SelfLower
@ -1724,11 +1718,6 @@ pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'t
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
pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let did = match expr.kind {
@ -1745,7 +1734,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
_ => 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

View File

@ -22,7 +22,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::query::normalize::AtExt;
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.
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
pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
match ty.kind() {
ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did())).is_some(),
ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(),
ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use),
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, _) => {
// 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
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) {
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;
}
}
@ -199,7 +199,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
ty::Dynamic(binder, _) => {
for predicate in binder.iter() {
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;
}
}