1
Fork 0

Auto merge of #131808 - jdonszelmann:hir-attributes, r=oli-obk,petrochenkov

Hir attributes

This PR needs some explanation, it's somewhat large.

- This is step one as described in https://github.com/rust-lang/compiler-team/issues/796. I've added a new `hir::Attribute` which is a lowered version of `ast::Attribute`. Right now, this has few concrete effects, however every place that after this PR parses a `hir::Attribute` should later get a pre-parsed attribute as described in https://github.com/rust-lang/compiler-team/issues/796 and transitively https://github.com/rust-lang/rust/issues/131229.
- an extension trait `AttributeExt` is added, which is implemented for both `ast::Attribute` and `hir::Atribute`. This makes `hir::Attributes` mostly compatible with code that used to parse `ast::Attribute`. All its methods are also added as inherent methods to avoid having to import the trait everywhere in the compiler.
  - Incremental can not not hash `ast::Attribute` at all.
This commit is contained in:
bors 2024-12-15 22:05:33 +00:00
commit f2b91ccbc2
89 changed files with 1153 additions and 717 deletions

View file

@ -3521,6 +3521,7 @@ dependencies = [
"rustc_fluent_macro", "rustc_fluent_macro",
"rustc_fs_util", "rustc_fs_util",
"rustc_hir", "rustc_hir",
"rustc_hir_pretty",
"rustc_incremental", "rustc_incremental",
"rustc_index", "rustc_index",
"rustc_macros", "rustc_macros",
@ -3786,6 +3787,7 @@ dependencies = [
"rustc_span", "rustc_span",
"rustc_target", "rustc_target",
"smallvec", "smallvec",
"thin-vec",
"tracing", "tracing",
] ]
@ -4454,9 +4456,9 @@ version = "0.0.0"
dependencies = [ dependencies = [
"rustc_abi", "rustc_abi",
"rustc_ast", "rustc_ast",
"rustc_ast_pretty",
"rustc_data_structures", "rustc_data_structures",
"rustc_hir", "rustc_hir",
"rustc_hir_pretty",
"rustc_middle", "rustc_middle",
"rustc_session", "rustc_session",
"rustc_span", "rustc_span",

View file

@ -19,7 +19,7 @@
//! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators. //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators.
use std::borrow::Cow; use std::borrow::Cow;
use std::{cmp, fmt, mem}; use std::{cmp, fmt};
pub use GenericArgs::*; pub use GenericArgs::*;
pub use UnsafeSource::*; pub use UnsafeSource::*;
@ -1758,53 +1758,16 @@ pub enum AttrArgs {
Eq { Eq {
/// Span of the `=` token. /// Span of the `=` token.
eq_span: Span, eq_span: Span,
expr: P<Expr>,
value: AttrArgsEq,
}, },
} }
// The RHS of an `AttrArgs::Eq` starts out as an expression. Once macro
// expansion is completed, all cases end up either as a meta item literal,
// which is the form used after lowering to HIR, or as an error.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum AttrArgsEq {
Ast(P<Expr>),
Hir(MetaItemLit),
}
impl AttrArgsEq {
pub fn span(&self) -> Span {
match self {
AttrArgsEq::Ast(p) => p.span,
AttrArgsEq::Hir(lit) => lit.span,
}
}
pub fn unwrap_ast(&self) -> &Expr {
match self {
AttrArgsEq::Ast(p) => p,
AttrArgsEq::Hir(lit) => {
unreachable!("in literal form when getting inner tokens: {lit:?}")
}
}
}
pub fn unwrap_ast_mut(&mut self) -> &mut P<Expr> {
match self {
AttrArgsEq::Ast(p) => p,
AttrArgsEq::Hir(lit) => {
unreachable!("in literal form when getting inner tokens: {lit:?}")
}
}
}
}
impl AttrArgs { impl AttrArgs {
pub fn span(&self) -> Option<Span> { pub fn span(&self) -> Option<Span> {
match self { match self {
AttrArgs::Empty => None, AttrArgs::Empty => None,
AttrArgs::Delimited(args) => Some(args.dspan.entire()), AttrArgs::Delimited(args) => Some(args.dspan.entire()),
AttrArgs::Eq { eq_span, value } => Some(eq_span.to(value.span())), AttrArgs::Eq { eq_span, expr } => Some(eq_span.to(expr.span)),
} }
} }
@ -1814,27 +1777,7 @@ impl AttrArgs {
match self { match self {
AttrArgs::Empty => TokenStream::default(), AttrArgs::Empty => TokenStream::default(),
AttrArgs::Delimited(args) => args.tokens.clone(), AttrArgs::Delimited(args) => args.tokens.clone(),
AttrArgs::Eq { value, .. } => TokenStream::from_ast(value.unwrap_ast()), AttrArgs::Eq { expr, .. } => TokenStream::from_ast(expr),
}
}
}
impl<CTX> HashStable<CTX> for AttrArgs
where
CTX: crate::HashStableContext,
{
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
mem::discriminant(self).hash_stable(ctx, hasher);
match self {
AttrArgs::Empty => {}
AttrArgs::Delimited(args) => args.hash_stable(ctx, hasher),
AttrArgs::Eq { value: AttrArgsEq::Ast(expr), .. } => {
unreachable!("hash_stable {:?}", expr);
}
AttrArgs::Eq { eq_span, value: AttrArgsEq::Hir(lit) } => {
eq_span.hash_stable(ctx, hasher);
lit.hash_stable(ctx, hasher);
}
} }
} }
} }
@ -3051,7 +2994,7 @@ impl NormalAttr {
} }
} }
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] #[derive(Clone, Encodable, Decodable, Debug)]
pub struct AttrItem { pub struct AttrItem {
pub unsafety: Safety, pub unsafety: Safety,
pub path: Path, pub path: Path,

View file

@ -1,5 +1,6 @@
//! Functions dealing with attributes and meta items. //! Functions dealing with attributes and meta items.
use std::fmt::Debug;
use std::iter; use std::iter;
use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::atomic::{AtomicU32, Ordering};
@ -10,9 +11,9 @@ use smallvec::{SmallVec, smallvec};
use thin_vec::{ThinVec, thin_vec}; use thin_vec::{ThinVec, thin_vec};
use crate::ast::{ use crate::ast::{
AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs,
DelimArgs, Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
NormalAttr, Path, PathSegment, Safety, PathSegment, Safety,
}; };
use crate::ptr::P; use crate::ptr::P;
use crate::token::{self, CommentKind, Delimiter, Token}; use crate::token::{self, CommentKind, Delimiter, Token};
@ -66,11 +67,27 @@ impl Attribute {
AttrKind::DocComment(..) => panic!("unexpected doc comment"), AttrKind::DocComment(..) => panic!("unexpected doc comment"),
} }
} }
}
impl AttributeExt for Attribute {
fn id(&self) -> AttrId {
self.id
}
fn value_span(&self) -> Option<Span> {
match &self.kind {
AttrKind::Normal(normal) => match &normal.item.args {
AttrArgs::Eq { expr, .. } => Some(expr.span),
_ => None,
},
AttrKind::DocComment(..) => None,
}
}
/// Returns `true` if it is a sugared doc comment (`///` or `//!` for example). /// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
/// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not /// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
/// a doc comment) will return `false`. /// a doc comment) will return `false`.
pub fn is_doc_comment(&self) -> bool { fn is_doc_comment(&self) -> bool {
match self.kind { match self.kind {
AttrKind::Normal(..) => false, AttrKind::Normal(..) => false,
AttrKind::DocComment(..) => true, AttrKind::DocComment(..) => true,
@ -78,7 +95,7 @@ impl Attribute {
} }
/// For a single-segment attribute, returns its name; otherwise, returns `None`. /// For a single-segment attribute, returns its name; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> { fn ident(&self) -> Option<Ident> {
match &self.kind { match &self.kind {
AttrKind::Normal(normal) => { AttrKind::Normal(normal) => {
if let [ident] = &*normal.item.path.segments { if let [ident] = &*normal.item.path.segments {
@ -91,28 +108,14 @@ impl Attribute {
} }
} }
pub fn name_or_empty(&self) -> Symbol { fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
self.ident().unwrap_or_else(Ident::empty).name
}
pub fn path(&self) -> SmallVec<[Symbol; 1]> {
match &self.kind { match &self.kind {
AttrKind::Normal(normal) => { AttrKind::Normal(p) => Some(p.item.path.segments.iter().map(|i| i.ident).collect()),
normal.item.path.segments.iter().map(|s| s.ident.name).collect() AttrKind::DocComment(_, _) => None,
}
AttrKind::DocComment(..) => smallvec![sym::doc],
} }
} }
#[inline] fn path_matches(&self, name: &[Symbol]) -> bool {
pub fn has_name(&self, name: Symbol) -> bool {
match &self.kind {
AttrKind::Normal(normal) => normal.item.path == name,
AttrKind::DocComment(..) => false,
}
}
pub fn path_matches(&self, name: &[Symbol]) -> bool {
match &self.kind { match &self.kind {
AttrKind::Normal(normal) => { AttrKind::Normal(normal) => {
normal.item.path.segments.len() == name.len() normal.item.path.segments.len() == name.len()
@ -128,7 +131,11 @@ impl Attribute {
} }
} }
pub fn is_word(&self) -> bool { fn span(&self) -> Span {
self.span
}
fn is_word(&self) -> bool {
if let AttrKind::Normal(normal) = &self.kind { if let AttrKind::Normal(normal) = &self.kind {
matches!(normal.item.args, AttrArgs::Empty) matches!(normal.item.args, AttrArgs::Empty)
} else { } else {
@ -143,7 +150,7 @@ impl Attribute {
/// #[attr = ""] // Returns `None`. /// #[attr = ""] // Returns `None`.
/// #[attr] // Returns `None`. /// #[attr] // Returns `None`.
/// ``` /// ```
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> { fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
match &self.kind { match &self.kind {
AttrKind::Normal(normal) => normal.item.meta_item_list(), AttrKind::Normal(normal) => normal.item.meta_item_list(),
AttrKind::DocComment(..) => None, AttrKind::DocComment(..) => None,
@ -165,7 +172,7 @@ impl Attribute {
/// ```text /// ```text
/// #[attr("value")] /// #[attr("value")]
/// ``` /// ```
pub fn value_str(&self) -> Option<Symbol> { fn value_str(&self) -> Option<Symbol> {
match &self.kind { match &self.kind {
AttrKind::Normal(normal) => normal.item.value_str(), AttrKind::Normal(normal) => normal.item.value_str(),
AttrKind::DocComment(..) => None, AttrKind::DocComment(..) => None,
@ -177,7 +184,7 @@ impl Attribute {
/// * `/** doc */` returns `Some(("doc", CommentKind::Block))`. /// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
/// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`. /// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
/// * `#[doc(...)]` returns `None`. /// * `#[doc(...)]` returns `None`.
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
match &self.kind { match &self.kind {
AttrKind::DocComment(kind, data) => Some((*data, *kind)), AttrKind::DocComment(kind, data) => Some((*data, *kind)),
AttrKind::Normal(normal) if normal.item.path == sym::doc => { AttrKind::Normal(normal) if normal.item.path == sym::doc => {
@ -191,7 +198,7 @@ impl Attribute {
/// * `///doc` returns `Some("doc")`. /// * `///doc` returns `Some("doc")`.
/// * `#[doc = "doc"]` returns `Some("doc")`. /// * `#[doc = "doc"]` returns `Some("doc")`.
/// * `#[doc(...)]` returns `None`. /// * `#[doc(...)]` returns `None`.
pub fn doc_str(&self) -> Option<Symbol> { fn doc_str(&self) -> Option<Symbol> {
match &self.kind { match &self.kind {
AttrKind::DocComment(.., data) => Some(*data), AttrKind::DocComment(.., data) => Some(*data),
AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(), AttrKind::Normal(normal) if normal.item.path == sym::doc => normal.item.value_str(),
@ -199,16 +206,16 @@ impl Attribute {
} }
} }
fn style(&self) -> AttrStyle {
self.style
}
}
impl Attribute {
pub fn may_have_doc_links(&self) -> bool { pub fn may_have_doc_links(&self) -> bool {
self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str())) self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
} }
pub fn is_proc_macro_attr(&self) -> bool {
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
.iter()
.any(|kind| self.has_name(*kind))
}
/// Extracts the MetaItem from inside this Attribute. /// Extracts the MetaItem from inside this Attribute.
pub fn meta(&self) -> Option<MetaItem> { pub fn meta(&self) -> Option<MetaItem> {
match &self.kind { match &self.kind {
@ -268,7 +275,12 @@ impl AttrItem {
/// ``` /// ```
fn value_str(&self) -> Option<Symbol> { fn value_str(&self) -> Option<Symbol> {
match &self.args { match &self.args {
AttrArgs::Eq { value, .. } => value.value_str(), AttrArgs::Eq { expr, .. } => match expr.kind {
ExprKind::Lit(token_lit) => {
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
}
_ => None,
},
AttrArgs::Delimited(_) | AttrArgs::Empty => None, AttrArgs::Delimited(_) | AttrArgs::Empty => None,
} }
} }
@ -287,20 +299,6 @@ impl AttrItem {
} }
} }
impl AttrArgsEq {
fn value_str(&self) -> Option<Symbol> {
match self {
AttrArgsEq::Ast(expr) => match expr.kind {
ExprKind::Lit(token_lit) => {
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
}
_ => None,
},
AttrArgsEq::Hir(lit) => lit.kind.str(),
}
}
}
impl MetaItem { impl MetaItem {
/// For a single-segment meta item, returns its name; otherwise, returns `None`. /// For a single-segment meta item, returns its name; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> { pub fn ident(&self) -> Option<Ident> {
@ -439,7 +437,8 @@ impl MetaItem {
} }
impl MetaItemKind { impl MetaItemKind {
fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> { // public because it can be called in the hir
pub fn list_from_tokens(tokens: TokenStream) -> Option<ThinVec<MetaItemInner>> {
let mut tokens = tokens.trees().peekable(); let mut tokens = tokens.trees().peekable();
let mut result = ThinVec::new(); let mut result = ThinVec::new();
while tokens.peek().is_some() { while tokens.peek().is_some() {
@ -492,7 +491,7 @@ impl MetaItemKind {
MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List) MetaItemKind::list_from_tokens(tokens.clone()).map(MetaItemKind::List)
} }
AttrArgs::Delimited(..) => None, AttrArgs::Delimited(..) => None,
AttrArgs::Eq { value: AttrArgsEq::Ast(expr), .. } => match expr.kind { AttrArgs::Eq { expr, .. } => match expr.kind {
ExprKind::Lit(token_lit) => { ExprKind::Lit(token_lit) => {
// Turn failures to `None`, we'll get parse errors elsewhere. // Turn failures to `None`, we'll get parse errors elsewhere.
MetaItemLit::from_token_lit(token_lit, expr.span) MetaItemLit::from_token_lit(token_lit, expr.span)
@ -501,9 +500,6 @@ impl MetaItemKind {
} }
_ => None, _ => None,
}, },
AttrArgs::Eq { value: AttrArgsEq::Hir(lit), .. } => {
Some(MetaItemKind::NameValue(lit.clone()))
}
} }
} }
} }
@ -704,26 +700,175 @@ pub fn mk_attr_name_value_str(
tokens: None, tokens: None,
}); });
let path = Path::from_ident(Ident::new(name, span)); let path = Path::from_ident(Ident::new(name, span));
let args = AttrArgs::Eq { eq_span: span, value: AttrArgsEq::Ast(expr) }; let args = AttrArgs::Eq { eq_span: span, expr };
mk_attr(g, style, unsafety, path, args, span) mk_attr(g, style, unsafety, path, args, span)
} }
pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> { pub fn filter_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> impl Iterator<Item = &A> {
attrs.iter().filter(move |attr| attr.has_name(name)) attrs.iter().filter(move |attr| attr.has_name(name))
} }
pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> { pub fn find_by_name<A: AttributeExt>(attrs: &[A], name: Symbol) -> Option<&A> {
filter_by_name(attrs, name).next() filter_by_name(attrs, name).next()
} }
pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> { pub fn first_attr_value_str_by_name(attrs: &[impl AttributeExt], name: Symbol) -> Option<Symbol> {
find_by_name(attrs, name).and_then(|attr| attr.value_str()) find_by_name(attrs, name).and_then(|attr| attr.value_str())
} }
pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { pub fn contains_name(attrs: &[impl AttributeExt], name: Symbol) -> bool {
find_by_name(attrs, name).is_some() find_by_name(attrs, name).is_some()
} }
pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool { pub fn list_contains_name(items: &[MetaItemInner], name: Symbol) -> bool {
items.iter().any(|item| item.has_name(name)) items.iter().any(|item| item.has_name(name))
} }
impl MetaItemLit {
pub fn value_str(&self) -> Option<Symbol> {
LitKind::from_token_lit(self.as_token_lit()).ok().and_then(|lit| lit.str())
}
}
pub trait AttributeExt: Debug {
fn id(&self) -> AttrId;
fn name_or_empty(&self) -> Symbol {
self.ident().unwrap_or_else(Ident::empty).name
}
/// Get the meta item list, `#[attr(meta item list)]`
fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
/// Gets the value literal, as string, when using `#[attr = value]`
fn value_str(&self) -> Option<Symbol>;
/// Gets the span of the value literal, as string, when using `#[attr = value]`
fn value_span(&self) -> Option<Span>;
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
fn ident(&self) -> Option<Ident>;
/// Checks whether the path of this attribute matches the name.
///
/// Matches one segment of the path to each element in `name`
fn path_matches(&self, name: &[Symbol]) -> bool;
/// Returns `true` if it is a sugared doc comment (`///` or `//!` for example).
/// So `#[doc = "doc"]` (which is a doc comment) and `#[doc(...)]` (which is not
/// a doc comment) will return `false`.
fn is_doc_comment(&self) -> bool;
#[inline]
fn has_name(&self, name: Symbol) -> bool {
self.ident().map(|x| x.name == name).unwrap_or(false)
}
/// get the span of the entire attribute
fn span(&self) -> Span;
fn is_word(&self) -> bool;
fn path(&self) -> SmallVec<[Symbol; 1]> {
self.ident_path()
.map(|i| i.into_iter().map(|i| i.name).collect())
.unwrap_or(smallvec![sym::doc])
}
/// Returns None for doc comments
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>>;
/// Returns the documentation if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some("doc")`.
/// * `#[doc = "doc"]` returns `Some("doc")`.
/// * `#[doc(...)]` returns `None`.
fn doc_str(&self) -> Option<Symbol>;
fn is_proc_macro_attr(&self) -> bool {
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
.iter()
.any(|kind| self.has_name(*kind))
}
/// Returns the documentation and its kind if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some(("doc", CommentKind::Line))`.
/// * `/** doc */` returns `Some(("doc", CommentKind::Block))`.
/// * `#[doc = "doc"]` returns `Some(("doc", CommentKind::Line))`.
/// * `#[doc(...)]` returns `None`.
fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)>;
fn style(&self) -> AttrStyle;
}
// FIXME(fn_delegation): use function delegation instead of manually forwarding
impl Attribute {
pub fn id(&self) -> AttrId {
AttributeExt::id(self)
}
pub fn name_or_empty(&self) -> Symbol {
AttributeExt::name_or_empty(self)
}
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
AttributeExt::meta_item_list(self)
}
pub fn value_str(&self) -> Option<Symbol> {
AttributeExt::value_str(self)
}
pub fn value_span(&self) -> Option<Span> {
AttributeExt::value_span(self)
}
pub fn ident(&self) -> Option<Ident> {
AttributeExt::ident(self)
}
pub fn path_matches(&self, name: &[Symbol]) -> bool {
AttributeExt::path_matches(self, name)
}
pub fn is_doc_comment(&self) -> bool {
AttributeExt::is_doc_comment(self)
}
#[inline]
pub fn has_name(&self, name: Symbol) -> bool {
AttributeExt::has_name(self, name)
}
pub fn span(&self) -> Span {
AttributeExt::span(self)
}
pub fn is_word(&self) -> bool {
AttributeExt::is_word(self)
}
pub fn path(&self) -> SmallVec<[Symbol; 1]> {
AttributeExt::path(self)
}
pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
AttributeExt::ident_path(self)
}
pub fn doc_str(&self) -> Option<Symbol> {
AttributeExt::doc_str(self)
}
pub fn is_proc_macro_attr(&self) -> bool {
AttributeExt::is_proc_macro_attr(self)
}
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
AttributeExt::doc_str_and_comment_kind(self)
}
pub fn style(&self) -> AttrStyle {
AttributeExt::style(self)
}
}

View file

@ -1,7 +1,7 @@
use rustc_span::Symbol; use rustc_span::Symbol;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use crate::{Attribute, attr}; use crate::attr::{self, AttributeExt};
#[derive(Debug)] #[derive(Debug)]
pub enum EntryPointType { pub enum EntryPointType {
@ -37,7 +37,7 @@ pub enum EntryPointType {
} }
pub fn entry_point_type( pub fn entry_point_type(
attrs: &[Attribute], attrs: &[impl AttributeExt],
at_root: bool, at_root: bool,
name: Option<Symbol>, name: Option<Symbol>,
) -> EntryPointType { ) -> EntryPointType {

View file

@ -44,20 +44,10 @@ pub mod token;
pub mod tokenstream; pub mod tokenstream;
pub mod visit; pub mod visit;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
pub use self::ast::*; pub use self::ast::*;
pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasTokens}; pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasTokens};
/// Requirements for a `StableHashingContext` to be used in this crate. /// Requirements for a `StableHashingContext` to be used in this crate.
/// This is a hack to allow using the `HashStable_Generic` derive macro /// This is a hack to allow using the `HashStable_Generic` derive macro
/// instead of implementing everything in `rustc_middle`. /// instead of implementing everything in `rustc_middle`.
pub trait HashStableContext: rustc_span::HashStableContext { pub trait HashStableContext: rustc_span::HashStableContext {}
fn hash_attr(&mut self, _: &ast::Attribute, hasher: &mut StableHasher);
}
impl<AstCtx: crate::HashStableContext> HashStable<AstCtx> for ast::Attribute {
fn hash_stable(&self, hcx: &mut AstCtx, hasher: &mut StableHasher) {
hcx.hash_attr(self, hasher)
}
}

View file

@ -451,8 +451,8 @@ fn visit_attr_args<T: MutVisitor>(vis: &mut T, args: &mut AttrArgs) {
match args { match args {
AttrArgs::Empty => {} AttrArgs::Empty => {}
AttrArgs::Delimited(args) => visit_delim_args(vis, args), AttrArgs::Delimited(args) => visit_delim_args(vis, args),
AttrArgs::Eq { eq_span, value } => { AttrArgs::Eq { eq_span, expr } => {
vis.visit_expr(value.unwrap_ast_mut()); vis.visit_expr(expr);
vis.visit_span(eq_span); vis.visit_span(eq_span);
} }
} }

View file

@ -1287,7 +1287,7 @@ pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) -
match args { match args {
AttrArgs::Empty => {} AttrArgs::Empty => {}
AttrArgs::Delimited(_args) => {} AttrArgs::Delimited(_args) => {}
AttrArgs::Eq { value, .. } => try_visit!(visitor.visit_expr(value.unwrap_ast())), AttrArgs::Eq { expr, .. } => try_visit!(visitor.visit_expr(expr)),
} }
V::Result::output() V::Result::output()
} }

View file

@ -176,7 +176,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
id: NodeId, id: NodeId,
hir_id: hir::HirId, hir_id: hir::HirId,
ident: &mut Ident, ident: &mut Ident,
attrs: &'hir [Attribute], attrs: &'hir [hir::Attribute],
vis_span: Span, vis_span: Span,
i: &ItemKind, i: &ItemKind,
) -> hir::ItemKind<'hir> { ) -> hir::ItemKind<'hir> {
@ -467,7 +467,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
id: NodeId, id: NodeId,
vis_span: Span, vis_span: Span,
ident: &mut Ident, ident: &mut Ident,
attrs: &'hir [Attribute], attrs: &'hir [hir::Attribute],
) -> hir::ItemKind<'hir> { ) -> hir::ItemKind<'hir> {
let path = &tree.prefix; let path = &tree.prefix;
let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect(); let segments = prefix.segments.iter().chain(path.segments.iter()).cloned().collect();
@ -1392,7 +1392,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
} }
} }
pub(super) fn lower_safety(&mut self, s: Safety, default: hir::Safety) -> hir::Safety { pub(super) fn lower_safety(&self, s: Safety, default: hir::Safety) -> hir::Safety {
match s { match s {
Safety::Unsafe(_) => hir::Safety::Unsafe, Safety::Unsafe(_) => hir::Safety::Unsafe,
Safety::Default => default, Safety::Default => default,

View file

@ -41,7 +41,6 @@
// tidy-alphabetical-end // tidy-alphabetical-end
use rustc_ast::node_id::NodeMap; use rustc_ast::node_id::NodeMap;
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, *}; use rustc_ast::{self as ast, *};
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
@ -96,7 +95,7 @@ struct LoweringContext<'a, 'hir> {
/// Bodies inside the owner being lowered. /// Bodies inside the owner being lowered.
bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>, bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
/// Attributes inside the owner being lowered. /// Attributes inside the owner being lowered.
attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>, attrs: SortedMap<hir::ItemLocalId, &'hir [hir::Attribute]>,
/// Collect items that were created by lowering the current owner. /// Collect items that were created by lowering the current owner.
children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>, children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>,
@ -847,7 +846,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ret ret
} }
fn lower_attrs(&mut self, id: HirId, attrs: &[Attribute]) -> &'hir [Attribute] { fn lower_attrs(&mut self, id: HirId, attrs: &[Attribute]) -> &'hir [hir::Attribute] {
if attrs.is_empty() { if attrs.is_empty() {
&[] &[]
} else { } else {
@ -859,25 +858,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
} }
fn lower_attr(&self, attr: &Attribute) -> Attribute { fn lower_attr(&self, attr: &Attribute) -> hir::Attribute {
// Note that we explicitly do not walk the path. Since we don't really // Note that we explicitly do not walk the path. Since we don't really
// lower attributes (we use the AST version) there is nowhere to keep // lower attributes (we use the AST version) there is nowhere to keep
// the `HirId`s. We don't actually need HIR version of attributes anyway. // the `HirId`s. We don't actually need HIR version of attributes anyway.
// Tokens are also not needed after macro expansion and parsing. // Tokens are also not needed after macro expansion and parsing.
let kind = match attr.kind { let kind = match attr.kind {
AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr { AttrKind::Normal(ref normal) => hir::AttrKind::Normal(Box::new(hir::AttrItem {
item: AttrItem { unsafety: self.lower_safety(normal.item.unsafety, hir::Safety::Safe),
unsafety: normal.item.unsafety, path: hir::AttrPath {
path: normal.item.path.clone(), segments: normal
args: self.lower_attr_args(&normal.item.args), .item
tokens: None, .path
.segments
.iter()
.map(|i| i.ident)
.collect::<Vec<_>>()
.into_boxed_slice(),
span: normal.item.path.span,
}, },
tokens: None, args: self.lower_attr_args(&normal.item.args),
})), })),
AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data), AttrKind::DocComment(comment_kind, data) => {
hir::AttrKind::DocComment(comment_kind, data)
}
}; };
Attribute { kind, id: attr.id, style: attr.style, span: self.lower_span(attr.span) } hir::Attribute { kind, id: attr.id, style: attr.style, span: self.lower_span(attr.span) }
} }
fn alias_attrs(&mut self, id: HirId, target_id: HirId) { fn alias_attrs(&mut self, id: HirId, target_id: HirId) {
@ -889,15 +896,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
} }
fn lower_attr_args(&self, args: &AttrArgs) -> AttrArgs { fn lower_attr_args(&self, args: &AttrArgs) -> hir::AttrArgs {
match args { match args {
AttrArgs::Empty => AttrArgs::Empty, AttrArgs::Empty => hir::AttrArgs::Empty,
AttrArgs::Delimited(args) => AttrArgs::Delimited(self.lower_delim_args(args)), AttrArgs::Delimited(args) => hir::AttrArgs::Delimited(self.lower_delim_args(args)),
// This is an inert key-value attribute - it will never be visible to macros // This is an inert key-value attribute - it will never be visible to macros
// after it gets lowered to HIR. Therefore, we can extract literals to handle // after it gets lowered to HIR. Therefore, we can extract literals to handle
// nonterminals in `#[doc]` (e.g. `#[doc = $e]`). // nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
&AttrArgs::Eq { eq_span, ref value } => { &AttrArgs::Eq { eq_span, ref expr } => {
let expr = value.unwrap_ast();
// In valid code the value always ends up as a single literal. Otherwise, a dummy // In valid code the value always ends up as a single literal. Otherwise, a dummy
// literal suffices because the error is handled elsewhere. // literal suffices because the error is handled elsewhere.
let lit = if let ExprKind::Lit(token_lit) = expr.kind let lit = if let ExprKind::Lit(token_lit) = expr.kind
@ -913,7 +919,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: DUMMY_SP, span: DUMMY_SP,
} }
}; };
AttrArgs::Eq { eq_span, value: AttrArgsEq::Hir(lit) } hir::AttrArgs::Eq { eq_span, expr: lit }
} }
} }
} }
@ -2201,7 +2207,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn stmt_let_pat( fn stmt_let_pat(
&mut self, &mut self,
attrs: Option<&'hir [Attribute]>, attrs: Option<&'hir [hir::Attribute]>,
span: Span, span: Span,
init: Option<&'hir hir::Expr<'hir>>, init: Option<&'hir hir::Expr<'hir>>,
pat: &'hir hir::Pat<'hir>, pat: &'hir hir::Pat<'hir>,

View file

@ -342,7 +342,7 @@ impl<'a> AstValidator<'a> {
sym::forbid, sym::forbid,
sym::warn, sym::warn,
]; ];
!arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(attr) !arr.contains(&attr.name_or_empty()) && rustc_attr::is_builtin_attr(*attr)
}) })
.for_each(|attr| { .for_each(|attr| {
if attr.is_doc_comment() { if attr.is_doc_comment() {

View file

@ -17,9 +17,9 @@ use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
use rustc_ast::util::classify; use rustc_ast::util::classify;
use rustc_ast::util::comments::{Comment, CommentStyle}; use rustc_ast::util::comments::{Comment, CommentStyle};
use rustc_ast::{ use rustc_ast::{
self as ast, AttrArgs, AttrArgsEq, BindingMode, BlockCheckMode, ByRef, DelimArgs, GenericArg, self as ast, AttrArgs, BindingMode, BlockCheckMode, ByRef, DelimArgs, GenericArg, GenericBound,
GenericBound, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, PatKind,
InlineAsmTemplatePiece, PatKind, RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr, RangeEnd, RangeSyntax, Safety, SelfKind, Term, attr,
}; };
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
@ -359,7 +359,7 @@ fn binop_to_string(op: BinOpToken) -> &'static str {
} }
} }
fn doc_comment_to_string( pub fn doc_comment_to_string(
comment_kind: CommentKind, comment_kind: CommentKind,
attr_style: ast::AttrStyle, attr_style: ast::AttrStyle,
data: Symbol, data: Symbol,
@ -648,20 +648,13 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
AttrArgs::Empty => { AttrArgs::Empty => {
self.print_path(&item.path, false, 0); self.print_path(&item.path, false, 0);
} }
AttrArgs::Eq { value: AttrArgsEq::Ast(expr), .. } => { AttrArgs::Eq { expr, .. } => {
self.print_path(&item.path, false, 0); self.print_path(&item.path, false, 0);
self.space(); self.space();
self.word_space("="); self.word_space("=");
let token_str = self.expr_to_string(expr); let token_str = self.expr_to_string(expr);
self.word(token_str); self.word(token_str);
} }
AttrArgs::Eq { value: AttrArgsEq::Hir(lit), .. } => {
self.print_path(&item.path, false, 0);
self.space();
self.word_space("=");
let token_str = self.meta_item_lit_to_string(lit);
self.word(token_str);
}
} }
match item.unsafety { match item.unsafety {
ast::Safety::Unsafe(_) => self.pclose(), ast::Safety::Unsafe(_) => self.pclose(),

View file

@ -3,10 +3,8 @@
use std::num::NonZero; use std::num::NonZero;
use rustc_abi::Align; use rustc_abi::Align;
use rustc_ast::{ use rustc_ast::attr::AttributeExt;
self as ast, Attribute, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId, use rustc_ast::{self as ast, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId};
attr,
};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_feature::{Features, GatedCfg, find_gated_cfg, is_builtin_attr_name}; use rustc_feature::{Features, GatedCfg, find_gated_cfg, is_builtin_attr_name};
@ -20,8 +18,8 @@ use rustc_span::Span;
use rustc_span::hygiene::Transparency; use rustc_span::hygiene::Transparency;
use rustc_span::symbol::{Symbol, kw, sym}; use rustc_span::symbol::{Symbol, kw, sym};
use crate::fluent_generated;
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
use crate::{filter_by_name, first_attr_value_str_by_name, fluent_generated};
/// The version placeholder that recently stabilized features contain inside the /// The version placeholder that recently stabilized features contain inside the
/// `since` field of the `#[stable]` attribute. /// `since` field of the `#[stable]` attribute.
@ -29,7 +27,7 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591). /// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION"; pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
pub fn is_builtin_attr(attr: &Attribute) -> bool { pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
} }
@ -215,7 +213,7 @@ impl UnstableReason {
/// attributes in `attrs`. Returns `None` if no stability attributes are found. /// attributes in `attrs`. Returns `None` if no stability attributes are found.
pub fn find_stability( pub fn find_stability(
sess: &Session, sess: &Session,
attrs: &[Attribute], attrs: &[impl AttributeExt],
item_sp: Span, item_sp: Span,
) -> Option<(Stability, Span)> { ) -> Option<(Stability, Span)> {
let mut stab: Option<(Stability, Span)> = None; let mut stab: Option<(Stability, Span)> = None;
@ -226,23 +224,25 @@ pub fn find_stability(
sym::rustc_allowed_through_unstable_modules => allowed_through_unstable_modules = true, sym::rustc_allowed_through_unstable_modules => allowed_through_unstable_modules = true,
sym::unstable => { sym::unstable => {
if stab.is_some() { if stab.is_some() {
sess.dcx() sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels {
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); span: attr.span(),
});
break; break;
} }
if let Some((feature, level)) = parse_unstability(sess, attr) { if let Some((feature, level)) = parse_unstability(sess, attr) {
stab = Some((Stability { level, feature }, attr.span)); stab = Some((Stability { level, feature }, attr.span()));
} }
} }
sym::stable => { sym::stable => {
if stab.is_some() { if stab.is_some() {
sess.dcx() sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels {
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); span: attr.span(),
});
break; break;
} }
if let Some((feature, level)) = parse_stability(sess, attr) { if let Some((feature, level)) = parse_stability(sess, attr) {
stab = Some((Stability { level, feature }, attr.span)); stab = Some((Stability { level, feature }, attr.span()));
} }
} }
_ => {} _ => {}
@ -272,7 +272,7 @@ pub fn find_stability(
/// attributes in `attrs`. Returns `None` if no stability attributes are found. /// attributes in `attrs`. Returns `None` if no stability attributes are found.
pub fn find_const_stability( pub fn find_const_stability(
sess: &Session, sess: &Session,
attrs: &[Attribute], attrs: &[impl AttributeExt],
item_sp: Span, item_sp: Span,
) -> Option<(ConstStability, Span)> { ) -> Option<(ConstStability, Span)> {
let mut const_stab: Option<(ConstStability, Span)> = None; let mut const_stab: Option<(ConstStability, Span)> = None;
@ -285,8 +285,9 @@ pub fn find_const_stability(
sym::rustc_const_stable_indirect => const_stable_indirect = true, sym::rustc_const_stable_indirect => const_stable_indirect = true,
sym::rustc_const_unstable => { sym::rustc_const_unstable => {
if const_stab.is_some() { if const_stab.is_some() {
sess.dcx() sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels {
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); span: attr.span(),
});
break; break;
} }
@ -298,14 +299,15 @@ pub fn find_const_stability(
const_stable_indirect: false, const_stable_indirect: false,
promotable: false, promotable: false,
}, },
attr.span, attr.span(),
)); ));
} }
} }
sym::rustc_const_stable => { sym::rustc_const_stable => {
if const_stab.is_some() { if const_stab.is_some() {
sess.dcx() sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels {
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); span: attr.span(),
});
break; break;
} }
if let Some((feature, level)) = parse_stability(sess, attr) { if let Some((feature, level)) = parse_stability(sess, attr) {
@ -316,7 +318,7 @@ pub fn find_const_stability(
const_stable_indirect: false, const_stable_indirect: false,
promotable: false, promotable: false,
}, },
attr.span, attr.span(),
)); ));
} }
} }
@ -361,7 +363,7 @@ pub fn find_const_stability(
/// without the `staged_api` feature. /// without the `staged_api` feature.
pub fn unmarked_crate_const_stab( pub fn unmarked_crate_const_stab(
_sess: &Session, _sess: &Session,
attrs: &[Attribute], attrs: &[impl AttributeExt],
regular_stab: Stability, regular_stab: Stability,
) -> ConstStability { ) -> ConstStability {
assert!(regular_stab.level.is_unstable()); assert!(regular_stab.level.is_unstable());
@ -381,7 +383,7 @@ pub fn unmarked_crate_const_stab(
/// Returns `None` if no stability attributes are found. /// Returns `None` if no stability attributes are found.
pub fn find_body_stability( pub fn find_body_stability(
sess: &Session, sess: &Session,
attrs: &[Attribute], attrs: &[impl AttributeExt],
) -> Option<(DefaultBodyStability, Span)> { ) -> Option<(DefaultBodyStability, Span)> {
let mut body_stab: Option<(DefaultBodyStability, Span)> = None; let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
@ -389,12 +391,12 @@ pub fn find_body_stability(
if attr.has_name(sym::rustc_default_body_unstable) { if attr.has_name(sym::rustc_default_body_unstable) {
if body_stab.is_some() { if body_stab.is_some() {
sess.dcx() sess.dcx()
.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span }); .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span() });
break; break;
} }
if let Some((feature, level)) = parse_unstability(sess, attr) { if let Some((feature, level)) = parse_unstability(sess, attr) {
body_stab = Some((DefaultBodyStability { level, feature }, attr.span)); body_stab = Some((DefaultBodyStability { level, feature }, attr.span()));
} }
} }
} }
@ -420,9 +422,8 @@ fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -
/// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and /// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and
/// its stability information. /// its stability information.
fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> { fn parse_stability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol, StabilityLevel)> {
let meta = attr.meta()?; let metas = attr.meta_item_list()?;
let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
let mut feature = None; let mut feature = None;
let mut since = None; let mut since = None;
@ -454,9 +455,9 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
let feature = match feature { let feature = match feature {
Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
Some(_bad_feature) => { Some(_bad_feature) => {
Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span })) Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span() }))
} }
None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span })), None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span() })),
}; };
let since = if let Some(since) = since { let since = if let Some(since) = since {
@ -465,11 +466,11 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
} else if let Some(version) = parse_version(since) { } else if let Some(version) = parse_version(since) {
StableSince::Version(version) StableSince::Version(version)
} else { } else {
sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span }); sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span() });
StableSince::Err StableSince::Err
} }
} else { } else {
sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span }); sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span() });
StableSince::Err StableSince::Err
}; };
@ -484,9 +485,8 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` /// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
/// attribute, and return the feature name and its stability information. /// attribute, and return the feature name and its stability information.
fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, StabilityLevel)> { fn parse_unstability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol, StabilityLevel)> {
let meta = attr.meta()?; let metas = attr.meta_item_list()?;
let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
let mut feature = None; let mut feature = None;
let mut reason = None; let mut reason = None;
@ -553,13 +553,14 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
let feature = match feature { let feature = match feature {
Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
Some(_bad_feature) => { Some(_bad_feature) => {
Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span })) Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span() }))
} }
None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span })), None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span() })),
}; };
let issue = issue let issue = issue.ok_or_else(|| {
.ok_or_else(|| sess.dcx().emit_err(session_diagnostics::MissingIssue { span: attr.span })); sess.dcx().emit_err(session_diagnostics::MissingIssue { span: attr.span() })
});
match (feature, issue) { match (feature, issue) {
(Ok(feature), Ok(_)) => { (Ok(feature), Ok(_)) => {
@ -575,8 +576,8 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
} }
} }
pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> { pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option<Symbol> {
attr::first_attr_value_str_by_name(attrs, sym::crate_name) first_attr_value_str_by_name(attrs, sym::crate_name)
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -884,7 +885,7 @@ impl Deprecation {
pub fn find_deprecation( pub fn find_deprecation(
sess: &Session, sess: &Session,
features: &Features, features: &Features,
attrs: &[Attribute], attrs: &[impl AttributeExt],
) -> Option<(Deprecation, Span)> { ) -> Option<(Deprecation, Span)> {
let mut depr: Option<(Deprecation, Span)> = None; let mut depr: Option<(Deprecation, Span)> = None;
let is_rustc = features.staged_api(); let is_rustc = features.staged_api();
@ -894,16 +895,16 @@ pub fn find_deprecation(
continue; continue;
} }
let Some(meta) = attr.meta() else {
continue;
};
let mut since = None; let mut since = None;
let mut note = None; let mut note = None;
let mut suggestion = None; let mut suggestion = None;
match &meta.kind {
MetaItemKind::Word => {} if attr.is_doc_comment() {
MetaItemKind::NameValue(..) => note = meta.value_str(), continue;
MetaItemKind::List(list) => { } else if attr.is_word() {
} else if let Some(value) = attr.value_str() {
note = Some(value)
} else if let Some(list) = attr.meta_item_list() {
let get = |meta: &MetaItem, item: &mut Option<Symbol>| { let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
if item.is_some() { if item.is_some() {
sess.dcx().emit_err(session_diagnostics::MultipleItem { sess.dcx().emit_err(session_diagnostics::MultipleItem {
@ -924,16 +925,14 @@ pub fn find_deprecation(
start_point_span: sess.source_map().start_point(lit.span), start_point_span: sess.source_map().start_point(lit.span),
}); });
} else { } else {
sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem { sess.dcx()
span: meta.span, .emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
});
} }
false false
} }
}; };
for meta in list { for meta in &list {
match meta { match meta {
MetaItemInner::MetaItem(mi) => match mi.name_or_empty() { MetaItemInner::MetaItem(mi) => match mi.name_or_empty() {
sym::since => { sym::since => {
@ -985,7 +984,8 @@ pub fn find_deprecation(
} }
} }
} }
} } else {
continue;
} }
let since = if let Some(since) = since { let since = if let Some(since) = since {
@ -996,22 +996,22 @@ pub fn find_deprecation(
} else if let Some(version) = parse_version(since) { } else if let Some(version) = parse_version(since) {
DeprecatedSince::RustcVersion(version) DeprecatedSince::RustcVersion(version)
} else { } else {
sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span }); sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span() });
DeprecatedSince::Err DeprecatedSince::Err
} }
} else if is_rustc { } else if is_rustc {
sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span }); sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span() });
DeprecatedSince::Err DeprecatedSince::Err
} else { } else {
DeprecatedSince::Unspecified DeprecatedSince::Unspecified
}; };
if is_rustc && note.is_none() { if is_rustc && note.is_none() {
sess.dcx().emit_err(session_diagnostics::MissingNote { span: attr.span }); sess.dcx().emit_err(session_diagnostics::MissingNote { span: attr.span() });
continue; continue;
} }
depr = Some((Deprecation { since, note, suggestion }, attr.span)); depr = Some((Deprecation { since, note, suggestion }, attr.span()));
} }
depr depr
@ -1054,11 +1054,11 @@ impl IntType {
/// the same discriminant size that the corresponding C enum would or C /// the same discriminant size that the corresponding C enum would or C
/// 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: &impl AttributeExt) -> Vec<ReprAttr> {
if attr.has_name(sym::repr) { parse_repr_attr(sess, attr) } else { Vec::new() } 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> { pub fn parse_repr_attr(sess: &Session, attr: &impl AttributeExt) -> Vec<ReprAttr> {
assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}"); assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}");
use ReprAttr::*; use ReprAttr::*;
let mut acc = Vec::new(); let mut acc = Vec::new();
@ -1238,7 +1238,7 @@ pub enum TransparencyError {
} }
pub fn find_transparency( pub fn find_transparency(
attrs: &[Attribute], attrs: &[impl AttributeExt],
macro_rules: bool, macro_rules: bool,
) -> (Transparency, Option<TransparencyError>) { ) -> (Transparency, Option<TransparencyError>) {
let mut transparency = None; let mut transparency = None;
@ -1246,7 +1246,7 @@ pub fn find_transparency(
for attr in attrs { for attr in attrs {
if attr.has_name(sym::rustc_macro_transparency) { if attr.has_name(sym::rustc_macro_transparency) {
if let Some((_, old_span)) = transparency { if let Some((_, old_span)) = transparency {
error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span)); error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span()));
break; break;
} else if let Some(value) = attr.value_str() { } else if let Some(value) = attr.value_str() {
transparency = Some(( transparency = Some((
@ -1255,11 +1255,12 @@ pub fn find_transparency(
sym::semitransparent => Transparency::SemiTransparent, sym::semitransparent => Transparency::SemiTransparent,
sym::opaque => Transparency::Opaque, sym::opaque => Transparency::Opaque,
_ => { _ => {
error = Some(TransparencyError::UnknownTransparency(value, attr.span)); error =
Some(TransparencyError::UnknownTransparency(value, attr.span()));
continue; continue;
} }
}, },
attr.span, attr.span(),
)); ));
} }
} }
@ -1270,29 +1271,29 @@ pub fn find_transparency(
pub fn allow_internal_unstable<'a>( pub fn allow_internal_unstable<'a>(
sess: &'a Session, sess: &'a Session,
attrs: &'a [Attribute], attrs: &'a [impl AttributeExt],
) -> impl Iterator<Item = Symbol> + 'a { ) -> impl Iterator<Item = Symbol> + 'a {
allow_unstable(sess, attrs, sym::allow_internal_unstable) allow_unstable(sess, attrs, sym::allow_internal_unstable)
} }
pub fn rustc_allow_const_fn_unstable<'a>( pub fn rustc_allow_const_fn_unstable<'a>(
sess: &'a Session, sess: &'a Session,
attrs: &'a [Attribute], attrs: &'a [impl AttributeExt],
) -> impl Iterator<Item = Symbol> + 'a { ) -> impl Iterator<Item = Symbol> + 'a {
allow_unstable(sess, attrs, sym::rustc_allow_const_fn_unstable) allow_unstable(sess, attrs, sym::rustc_allow_const_fn_unstable)
} }
fn allow_unstable<'a>( fn allow_unstable<'a>(
sess: &'a Session, sess: &'a Session,
attrs: &'a [Attribute], attrs: &'a [impl AttributeExt],
symbol: Symbol, symbol: Symbol,
) -> impl Iterator<Item = Symbol> + 'a { ) -> impl Iterator<Item = Symbol> + 'a {
let attrs = attr::filter_by_name(attrs, symbol); let attrs = filter_by_name(attrs, symbol);
let list = attrs let list = attrs
.filter_map(move |attr| { .filter_map(move |attr| {
attr.meta_item_list().or_else(|| { attr.meta_item_list().or_else(|| {
sess.dcx().emit_err(session_diagnostics::ExpectsFeatureList { sess.dcx().emit_err(session_diagnostics::ExpectsFeatureList {
span: attr.span, span: attr.span(),
name: symbol.to_ident_string(), name: symbol.to_ident_string(),
}); });
None None
@ -1332,9 +1333,8 @@ pub fn parse_alignment(node: &ast::LitKind) -> Result<Align, &'static str> {
} }
/// Read the content of a `rustc_confusables` attribute, and return the list of candidate names. /// Read the content of a `rustc_confusables` attribute, and return the list of candidate names.
pub fn parse_confusables(attr: &Attribute) -> Option<Vec<Symbol>> { pub fn parse_confusables(attr: &impl AttributeExt) -> Option<Vec<Symbol>> {
let meta = attr.meta()?; let metas = attr.meta_item_list()?;
let MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else { return None };
let mut candidates = Vec::new(); let mut candidates = Vec::new();

View file

@ -23,6 +23,7 @@ rustc_errors = { path = "../rustc_errors" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_fs_util = { path = "../rustc_fs_util" } rustc_fs_util = { path = "../rustc_fs_util" }
rustc_hir = { path = "../rustc_hir" } rustc_hir = { path = "../rustc_hir" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_incremental = { path = "../rustc_incremental" } rustc_incremental = { path = "../rustc_incremental" }
rustc_index = { path = "../rustc_index" } rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" } rustc_macros = { path = "../rustc_macros" }

View file

@ -26,9 +26,9 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt; use std::fmt;
use rustc_ast as ast;
use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_errors::{DiagArgValue, IntoDiagArg};
use rustc_hir as hir;
use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::mir::mono::CodegenUnitNameBuilder; use rustc_middle::mir::mono::CodegenUnitNameBuilder;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
@ -77,7 +77,7 @@ struct AssertModuleSource<'tcx> {
} }
impl<'tcx> AssertModuleSource<'tcx> { impl<'tcx> AssertModuleSource<'tcx> {
fn check_attr(&mut self, attr: &ast::Attribute) { fn check_attr(&mut self, attr: &hir::Attribute) {
let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) { let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) {
(CguReuse::PreLto, ComparisonKind::AtLeast) (CguReuse::PreLto, ComparisonKind::AtLeast)
} else if attr.has_name(sym::rustc_partition_codegened) { } else if attr.has_name(sym::rustc_partition_codegened) {
@ -158,7 +158,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
); );
} }
fn field(&self, attr: &ast::Attribute, name: Symbol) -> Symbol { fn field(&self, attr: &hir::Attribute, name: Symbol) -> Symbol {
for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
if item.has_name(name) { if item.has_name(name) {
if let Some(value) = item.value_str() { if let Some(value) = item.value_str() {
@ -177,7 +177,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
/// Scan for a `cfg="foo"` attribute and check whether we have a /// Scan for a `cfg="foo"` attribute and check whether we have a
/// cfg flag called `foo`. /// cfg flag called `foo`.
fn check_config(&self, attr: &ast::Attribute) -> bool { fn check_config(&self, attr: &hir::Attribute) -> bool {
let config = &self.tcx.sess.psess.config; let config = &self.tcx.sess.psess.config;
let value = self.field(attr, sym::cfg); let value = self.field(attr, sym::cfg);
debug!("check_config(config={:?}, value={:?})", config, value); debug!("check_config(config={:?}, value={:?})", config, value);

View file

@ -1,4 +1,4 @@
use rustc_ast::{MetaItemInner, MetaItemKind, ast, attr}; use rustc_ast::{MetaItemInner, attr};
use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_name}; use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_name};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::codes::*; use rustc_errors::codes::*;
@ -6,7 +6,7 @@ use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err};
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
use rustc_hir::{HirId, LangItem, lang_items}; use rustc_hir::{self as hir, HirId, LangItem, lang_items};
use rustc_middle::middle::codegen_fn_attrs::{ use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
}; };
@ -525,13 +525,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
if !attr.has_name(sym::inline) { if !attr.has_name(sym::inline) {
return ia; return ia;
} }
match attr.meta_kind() { if attr.is_word() {
Some(MetaItemKind::Word) => InlineAttr::Hint, InlineAttr::Hint
Some(MetaItemKind::List(ref items)) => { } else if let Some(ref items) = attr.meta_item_list() {
inline_span = Some(attr.span); inline_span = Some(attr.span);
if items.len() != 1 { if items.len() != 1 {
struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument") struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit();
.emit();
InlineAttr::None InlineAttr::None
} else if list_contains_name(items, sym::always) { } else if list_contains_name(items, sym::always) {
InlineAttr::Always InlineAttr::Always
@ -544,9 +543,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
InlineAttr::None InlineAttr::None
} }
} } else {
Some(MetaItemKind::NameValue(_)) => ia, ia
None => ia,
} }
}); });
@ -562,12 +560,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
return ia; return ia;
} }
let err = |sp, s| struct_span_code_err!(tcx.dcx(), sp, E0722, "{}", s).emit(); let err = |sp, s| struct_span_code_err!(tcx.dcx(), sp, E0722, "{}", s).emit();
match attr.meta_kind() { if attr.is_word() {
Some(MetaItemKind::Word) => {
err(attr.span, "expected one argument"); err(attr.span, "expected one argument");
ia ia
} } else if let Some(ref items) = attr.meta_item_list() {
Some(MetaItemKind::List(ref items)) => {
inline_span = Some(attr.span); inline_span = Some(attr.span);
if items.len() != 1 { if items.len() != 1 {
err(attr.span, "expected one argument"); err(attr.span, "expected one argument");
@ -580,9 +576,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
err(items[0].span(), "invalid argument"); err(items[0].span(), "invalid argument");
OptimizeAttr::None OptimizeAttr::None
} }
} } else {
Some(MetaItemKind::NameValue(_)) => ia, OptimizeAttr::None
None => ia,
} }
}); });
@ -730,7 +725,7 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
false false
} }
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> { fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option<u16> {
use rustc_ast::{LitIntType, LitKind, MetaItemLit}; use rustc_ast::{LitIntType, LitKind, MetaItemLit};
let meta_item_list = attr.meta_item_list(); let meta_item_list = attr.meta_item_list();
let meta_item_list = meta_item_list.as_deref(); let meta_item_list = meta_item_list.as_deref();
@ -795,7 +790,7 @@ struct MixedExportNameAndNoMangleState<'a> {
export_name: Option<Span>, export_name: Option<Span>,
hir_id: Option<HirId>, hir_id: Option<HirId>,
no_mangle: Option<Span>, no_mangle: Option<Span>,
no_mangle_attr: Option<&'a ast::Attribute>, no_mangle_attr: Option<&'a hir::Attribute>,
} }
impl<'a> MixedExportNameAndNoMangleState<'a> { impl<'a> MixedExportNameAndNoMangleState<'a> {
@ -803,7 +798,7 @@ impl<'a> MixedExportNameAndNoMangleState<'a> {
self.export_name = Some(span); self.export_name = Some(span);
} }
fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: &'a ast::Attribute) { fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: &'a hir::Attribute) {
self.no_mangle = Some(span); self.no_mangle = Some(span);
self.hir_id = Some(hir_id); self.hir_id = Some(hir_id);
self.no_mangle_attr = Some(attr_name); self.no_mangle_attr = Some(attr_name);
@ -824,7 +819,7 @@ impl<'a> MixedExportNameAndNoMangleState<'a> {
no_mangle, no_mangle,
errors::MixedExportNameAndNoMangle { errors::MixedExportNameAndNoMangle {
no_mangle, no_mangle,
no_mangle_attr: rustc_ast_pretty::pprust::attribute_to_string(no_mangle_attr), no_mangle_attr: rustc_hir_pretty::attribute_to_string(&tcx, no_mangle_attr),
export_name, export_name,
removal_span: no_mangle, removal_span: no_mangle,
}, },

View file

@ -1,8 +1,8 @@
use rustc_ast::ast;
use rustc_attr::InstructionSetAttr; use rustc_attr::InstructionSetAttr;
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
@ -19,7 +19,7 @@ use crate::errors;
/// Enabled target features are added to `target_features`. /// Enabled target features are added to `target_features`.
pub(crate) fn from_target_feature_attr( pub(crate) fn from_target_feature_attr(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
attr: &ast::Attribute, attr: &hir::Attribute,
rust_target_features: &UnordMap<String, target_features::StabilityComputed>, rust_target_features: &UnordMap<String, target_features::StabilityComputed>,
target_features: &mut Vec<TargetFeature>, target_features: &mut Vec<TargetFeature>,
) { ) {

View file

@ -4,7 +4,7 @@ use std::path::Component::Prefix;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc; use std::rc::Rc;
use rustc_ast::attr::MarkedAttrs; use rustc_ast::attr::{AttributeExt, MarkedAttrs};
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::Nonterminal; use rustc_ast::token::Nonterminal;
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
@ -782,10 +782,12 @@ impl SyntaxExtension {
} }
} }
fn collapse_debuginfo_by_name(attr: &Attribute) -> Result<CollapseMacroDebuginfo, Span> { fn collapse_debuginfo_by_name(
attr: &impl AttributeExt,
) -> Result<CollapseMacroDebuginfo, Span> {
let list = attr.meta_item_list(); let list = attr.meta_item_list();
let Some([MetaItemInner::MetaItem(item)]) = list.as_deref() else { let Some([MetaItemInner::MetaItem(item)]) = list.as_deref() else {
return Err(attr.span); return Err(attr.span());
}; };
if !item.is_word() { if !item.is_word() {
return Err(item.span); return Err(item.span);
@ -805,7 +807,7 @@ impl SyntaxExtension {
/// | (unspecified) | no | if-ext | if-ext | yes | /// | (unspecified) | no | if-ext | if-ext | yes |
/// | external | no | if-ext | if-ext | yes | /// | external | no | if-ext | if-ext | yes |
/// | yes | yes | yes | yes | yes | /// | yes | yes | yes | yes | yes |
fn get_collapse_debuginfo(sess: &Session, attrs: &[ast::Attribute], ext: bool) -> bool { fn get_collapse_debuginfo(sess: &Session, attrs: &[impl AttributeExt], ext: bool) -> bool {
let flag = sess.opts.cg.collapse_macro_debuginfo; let flag = sess.opts.cg.collapse_macro_debuginfo;
let attr = attr::find_by_name(attrs, sym::collapse_debuginfo) let attr = attr::find_by_name(attrs, sym::collapse_debuginfo)
.and_then(|attr| { .and_then(|attr| {
@ -842,11 +844,11 @@ impl SyntaxExtension {
helper_attrs: Vec<Symbol>, helper_attrs: Vec<Symbol>,
edition: Edition, edition: Edition,
name: Symbol, name: Symbol,
attrs: &[ast::Attribute], attrs: &[impl AttributeExt],
is_local: bool, is_local: bool,
) -> SyntaxExtension { ) -> SyntaxExtension {
let allow_internal_unstable = let allow_internal_unstable =
attr::allow_internal_unstable(sess, attrs).collect::<Vec<Symbol>>(); rustc_attr::allow_internal_unstable(sess, attrs).collect::<Vec<Symbol>>();
let allow_internal_unsafe = attr::contains_name(attrs, sym::allow_internal_unsafe); let allow_internal_unsafe = attr::contains_name(attrs, sym::allow_internal_unsafe);
let local_inner_macros = attr::find_by_name(attrs, sym::macro_export) let local_inner_macros = attr::find_by_name(attrs, sym::macro_export)
@ -1305,7 +1307,7 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe
pub fn parse_macro_name_and_helper_attrs( pub fn parse_macro_name_and_helper_attrs(
dcx: DiagCtxtHandle<'_>, dcx: DiagCtxtHandle<'_>,
attr: &Attribute, attr: &impl AttributeExt,
macro_type: &str, macro_type: &str,
) -> Option<(Symbol, Vec<Symbol>)> { ) -> Option<(Symbol, Vec<Symbol>)> {
// Once we've located the `#[proc_macro_derive]` attribute, verify // Once we've located the `#[proc_macro_derive]` attribute, verify
@ -1313,7 +1315,7 @@ pub fn parse_macro_name_and_helper_attrs(
// `#[proc_macro_derive(Foo, attributes(A, ..))]` // `#[proc_macro_derive(Foo, attributes(A, ..))]`
let list = attr.meta_item_list()?; let list = attr.meta_item_list()?;
let ([trait_attr] | [trait_attr, _]) = list.as_slice() else { let ([trait_attr] | [trait_attr, _]) = list.as_slice() else {
dcx.emit_err(errors::AttrNoArguments { span: attr.span }); dcx.emit_err(errors::AttrNoArguments { span: attr.span() });
return None; return None;
}; };
let Some(trait_attr) = trait_attr.meta_item() else { let Some(trait_attr) = trait_attr.meta_item() else {

View file

@ -9,7 +9,7 @@ use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, TransparencyError}; use rustc_attr::{self as attr, AttributeExt, TransparencyError};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::{Applicability, ErrorGuaranteed}; use rustc_errors::{Applicability, ErrorGuaranteed};
use rustc_feature::Features; use rustc_feature::Features;
@ -371,7 +371,7 @@ pub fn compile_declarative_macro(
features: &Features, features: &Features,
macro_def: &ast::MacroDef, macro_def: &ast::MacroDef,
ident: Ident, ident: Ident,
attrs: &[ast::Attribute], attrs: &[impl AttributeExt],
span: Span, span: Span,
node_id: NodeId, node_id: NodeId,
edition: Edition, edition: Edition,

View file

@ -16,5 +16,6 @@ rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" } rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" } rustc_target = { path = "../rustc_target" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
thin-vec = "0.2.12"
tracing = "0.1" tracing = "0.1"
# tidy-alphabetical-end # tidy-alphabetical-end

View file

@ -6,7 +6,7 @@ macro_rules! arena_types {
$macro!([ $macro!([
// HIR types // HIR types
[] asm_template: rustc_ast::InlineAsmTemplatePiece, [] asm_template: rustc_ast::InlineAsmTemplatePiece,
[] attribute: rustc_ast::Attribute, [] attribute: rustc_hir::Attribute,
[] owner_info: rustc_hir::OwnerInfo<'tcx>, [] owner_info: rustc_hir::OwnerInfo<'tcx>,
[] use_path: rustc_hir::UsePath<'tcx>, [] use_path: rustc_hir::UsePath<'tcx>,
[] lit: rustc_hir::Lit, [] lit: rustc_hir::Lit,

View file

@ -1,10 +1,13 @@
use std::fmt; use std::fmt;
use rustc_abi::ExternAbi; use rustc_abi::ExternAbi;
// ignore-tidy-filelength
use rustc_ast::attr::AttributeExt;
use rustc_ast::token::CommentKind;
use rustc_ast::util::parser::{AssocOp, ExprPrecedence}; use rustc_ast::util::parser::{AssocOp, ExprPrecedence};
use rustc_ast::{ use rustc_ast::{
self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, self as ast, AttrId, AttrStyle, DelimArgs, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece,
LitKind, TraitObjectSyntax, UintTy, IntTy, Label, LitKind, MetaItemInner, MetaItemLit, TraitObjectSyntax, UintTy,
}; };
pub use rustc_ast::{ pub use rustc_ast::{
BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
@ -21,6 +24,7 @@ use rustc_span::symbol::{Ident, Symbol, kw, sym};
use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Span}; use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Span};
use rustc_target::asm::InlineAsmRegOrRegClass; use rustc_target::asm::InlineAsmRegOrRegClass;
use smallvec::SmallVec; use smallvec::SmallVec;
use thin_vec::ThinVec;
use tracing::debug; use tracing::debug;
use crate::LangItem; use crate::LangItem;
@ -937,6 +941,250 @@ pub struct ParentedNode<'tcx> {
pub node: Node<'tcx>, pub node: Node<'tcx>,
} }
/// Arguments passed to an attribute macro.
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
pub enum AttrArgs {
/// No arguments: `#[attr]`.
Empty,
/// Delimited arguments: `#[attr()/[]/{}]`.
Delimited(DelimArgs),
/// Arguments of a key-value attribute: `#[attr = "value"]`.
Eq {
/// Span of the `=` token.
eq_span: Span,
/// The "value".
expr: MetaItemLit,
},
}
#[derive(Clone, Debug, Encodable, Decodable)]
pub enum AttrKind {
/// A normal attribute.
Normal(Box<AttrItem>),
/// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`).
/// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal`
/// variant (which is much less compact and thus more expensive).
DocComment(CommentKind, Symbol),
}
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
pub struct AttrPath {
pub segments: Box<[Ident]>,
pub span: Span,
}
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
pub struct AttrItem {
pub unsafety: Safety,
// Not lowered to hir::Path because we have no NodeId to resolve to.
pub path: AttrPath,
pub args: AttrArgs,
}
#[derive(Clone, Debug, Encodable, Decodable)]
pub struct Attribute {
pub kind: AttrKind,
pub id: AttrId,
/// Denotes if the attribute decorates the following construct (outer)
/// or the construct this attribute is contained within (inner).
pub style: AttrStyle,
pub span: Span,
}
impl Attribute {
pub fn get_normal_item(&self) -> &AttrItem {
match &self.kind {
AttrKind::Normal(normal) => &normal,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
pub fn unwrap_normal_item(self) -> AttrItem {
match self.kind {
AttrKind::Normal(normal) => *normal,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
pub fn value_lit(&self) -> Option<&MetaItemLit> {
match &self.kind {
AttrKind::Normal(n) => match n.as_ref() {
AttrItem { args: AttrArgs::Eq { expr, .. }, .. } => Some(expr),
_ => None,
},
_ => None,
}
}
}
impl AttributeExt for Attribute {
fn id(&self) -> AttrId {
self.id
}
fn meta_item_list(&self) -> Option<ThinVec<ast::MetaItemInner>> {
match &self.kind {
AttrKind::Normal(n) => match n.as_ref() {
AttrItem { args: AttrArgs::Delimited(d), .. } => {
ast::MetaItemKind::list_from_tokens(d.tokens.clone())
}
_ => None,
},
_ => None,
}
}
fn value_str(&self) -> Option<Symbol> {
self.value_lit().and_then(|x| x.value_str())
}
fn value_span(&self) -> Option<Span> {
self.value_lit().map(|i| i.span)
}
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
fn ident(&self) -> Option<Ident> {
match &self.kind {
AttrKind::Normal(n) => {
if let [ident] = n.path.segments.as_ref() {
Some(*ident)
} else {
None
}
}
AttrKind::DocComment(..) => None,
}
}
fn path_matches(&self, name: &[Symbol]) -> bool {
match &self.kind {
AttrKind::Normal(n) => {
n.path.segments.len() == name.len()
&& n.path.segments.iter().zip(name).all(|(s, n)| s.name == *n)
}
AttrKind::DocComment(..) => false,
}
}
fn is_doc_comment(&self) -> bool {
matches!(self.kind, AttrKind::DocComment(..))
}
fn span(&self) -> Span {
self.span
}
fn is_word(&self) -> bool {
match &self.kind {
AttrKind::Normal(n) => {
matches!(n.args, AttrArgs::Empty)
}
AttrKind::DocComment(..) => false,
}
}
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
match &self.kind {
AttrKind::Normal(n) => Some(n.path.segments.iter().copied().collect()),
AttrKind::DocComment(..) => None,
}
}
fn doc_str(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::DocComment(.., data) => Some(*data),
AttrKind::Normal(_) if self.has_name(sym::doc) => self.value_str(),
_ => None,
}
}
fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
match &self.kind {
AttrKind::DocComment(kind, data) => Some((*data, *kind)),
AttrKind::Normal(_) if self.name_or_empty() == sym::doc => {
self.value_str().map(|s| (s, CommentKind::Line))
}
_ => None,
}
}
fn style(&self) -> AttrStyle {
self.style
}
}
// FIXME(fn_delegation): use function delegation instead of manually forwarding
impl Attribute {
pub fn id(&self) -> AttrId {
AttributeExt::id(self)
}
pub fn name_or_empty(&self) -> Symbol {
AttributeExt::name_or_empty(self)
}
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
AttributeExt::meta_item_list(self)
}
pub fn value_str(&self) -> Option<Symbol> {
AttributeExt::value_str(self)
}
pub fn value_span(&self) -> Option<Span> {
AttributeExt::value_span(self)
}
pub fn ident(&self) -> Option<Ident> {
AttributeExt::ident(self)
}
pub fn path_matches(&self, name: &[Symbol]) -> bool {
AttributeExt::path_matches(self, name)
}
pub fn is_doc_comment(&self) -> bool {
AttributeExt::is_doc_comment(self)
}
#[inline]
pub fn has_name(&self, name: Symbol) -> bool {
AttributeExt::has_name(self, name)
}
pub fn span(&self) -> Span {
AttributeExt::span(self)
}
pub fn is_word(&self) -> bool {
AttributeExt::is_word(self)
}
pub fn path(&self) -> SmallVec<[Symbol; 1]> {
AttributeExt::path(self)
}
pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
AttributeExt::ident_path(self)
}
pub fn doc_str(&self) -> Option<Symbol> {
AttributeExt::doc_str(self)
}
pub fn is_proc_macro_attr(&self) -> bool {
AttributeExt::is_proc_macro_attr(self)
}
pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
AttributeExt::doc_str_and_comment_kind(self)
}
pub fn style(&self) -> AttrStyle {
AttributeExt::style(self)
}
}
/// Attributes owned by a HIR owner. /// Attributes owned by a HIR owner.
#[derive(Debug)] #[derive(Debug)]
pub struct AttributeMap<'tcx> { pub struct AttributeMap<'tcx> {

View file

@ -64,8 +64,8 @@
//! This order consistency is required in a few places in rustc, for //! This order consistency is required in a few places in rustc, for
//! example coroutine inference, and possibly also HIR borrowck. //! example coroutine inference, and possibly also HIR borrowck.
use rustc_ast::Label;
use rustc_ast::visit::{VisitorResult, try_visit, visit_opt, walk_list}; use rustc_ast::visit::{VisitorResult, try_visit, visit_opt, walk_list};
use rustc_ast::{Attribute, Label};
use rustc_span::Span; use rustc_span::Span;
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::{Ident, Symbol}; use rustc_span::symbol::{Ident, Symbol};

View file

@ -7,7 +7,7 @@
//! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`.
//! * Functions called by the compiler itself. //! * Functions called by the compiler itself.
use rustc_ast as ast; use rustc_ast::attr::AttributeExt;
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_macros::{Decodable, Encodable, HashStable_Generic};
@ -153,11 +153,11 @@ impl<CTX> HashStable<CTX> for LangItem {
/// Extracts the first `lang = "$name"` out of a list of attributes. /// Extracts the first `lang = "$name"` out of a list of attributes.
/// The `#[panic_handler]` attribute is also extracted out when found. /// The `#[panic_handler]` attribute is also extracted out when found.
pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { pub fn extract(attrs: &[impl AttributeExt]) -> Option<(Symbol, Span)> {
attrs.iter().find_map(|attr| { attrs.iter().find_map(|attr| {
Some(match attr { Some(match attr {
_ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span), _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span()),
_ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span), _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span()),
_ => return None, _ => return None,
}) })
}) })

View file

@ -2,7 +2,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHas
use rustc_span::def_id::DefPathHash; use rustc_span::def_id::DefPathHash;
use crate::hir::{ use crate::hir::{
AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, Attribute, AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes,
TraitItemId,
}; };
use crate::hir_id::{HirId, ItemLocalId}; use crate::hir_id::{HirId, ItemLocalId};
@ -12,6 +13,7 @@ use crate::hir_id::{HirId, ItemLocalId};
pub trait HashStableContext: pub trait HashStableContext:
rustc_ast::HashStableContext + rustc_target::HashStableContext rustc_ast::HashStableContext + rustc_target::HashStableContext
{ {
fn hash_attr(&mut self, _: &Attribute, hasher: &mut StableHasher);
} }
impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId { impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
@ -113,3 +115,9 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> {
opt_hir_hash.unwrap().hash_stable(hcx, hasher) opt_hir_hash.unwrap().hash_stable(hcx, hasher)
} }
} }
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Attribute {
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
hcx.hash_attr(self, hasher)
}
}

View file

@ -11,16 +11,18 @@ use std::vec;
use rustc_abi::ExternAbi; use rustc_abi::ExternAbi;
use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity}; use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity};
use rustc_ast::{DUMMY_NODE_ID, DelimArgs};
use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pp::{self, Breaks};
use rustc_ast_pretty::pprust::state::MacHeader;
use rustc_ast_pretty::pprust::{Comments, PrintState}; use rustc_ast_pretty::pprust::{Comments, PrintState};
use rustc_hir::{ use rustc_hir::{
BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
}; };
use rustc_span::FileName;
use rustc_span::source_map::SourceMap; use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_span::symbol::{Ident, Symbol, kw};
use rustc_span::{FileName, Span};
use {rustc_ast as ast, rustc_hir as hir}; use {rustc_ast as ast, rustc_hir as hir};
pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: HirId) -> String { pub fn id_to_string(map: &dyn rustc_hir::intravisit::Map<'_>, hir_id: HirId) -> String {
@ -68,15 +70,115 @@ impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> {
pub struct State<'a> { pub struct State<'a> {
pub s: pp::Printer, pub s: pp::Printer,
comments: Option<Comments<'a>>, comments: Option<Comments<'a>>,
attrs: &'a dyn Fn(HirId) -> &'a [ast::Attribute], attrs: &'a dyn Fn(HirId) -> &'a [hir::Attribute],
ann: &'a (dyn PpAnn + 'a), ann: &'a (dyn PpAnn + 'a),
} }
impl<'a> State<'a> { impl<'a> State<'a> {
fn attrs(&self, id: HirId) -> &'a [ast::Attribute] { fn attrs(&self, id: HirId) -> &'a [hir::Attribute] {
(self.attrs)(id) (self.attrs)(id)
} }
fn print_inner_attributes(&mut self, attrs: &[hir::Attribute]) -> bool {
self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
}
fn print_outer_attributes(&mut self, attrs: &[hir::Attribute]) -> bool {
self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
}
fn print_either_attributes(
&mut self,
attrs: &[hir::Attribute],
kind: ast::AttrStyle,
is_inline: bool,
trailing_hardbreak: bool,
) -> bool {
let mut printed = false;
for attr in attrs {
if attr.style == kind {
self.print_attribute_inline(attr, is_inline);
if is_inline {
self.nbsp();
}
printed = true;
}
}
if printed && trailing_hardbreak && !is_inline {
self.hardbreak_if_not_bol();
}
printed
}
fn print_attribute_inline(&mut self, attr: &hir::Attribute, is_inline: bool) {
if !is_inline {
self.hardbreak_if_not_bol();
}
self.maybe_print_comment(attr.span.lo());
match &attr.kind {
hir::AttrKind::Normal(normal) => {
match attr.style {
ast::AttrStyle::Inner => self.word("#!["),
ast::AttrStyle::Outer => self.word("#["),
}
if normal.unsafety == hir::Safety::Unsafe {
self.word("unsafe(");
}
self.print_attr_item(&normal, attr.span);
if normal.unsafety == hir::Safety::Unsafe {
self.word(")");
}
self.word("]");
}
hir::AttrKind::DocComment(comment_kind, data) => {
self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string(
*comment_kind,
attr.style,
*data,
));
self.hardbreak()
}
}
}
fn print_attr_item(&mut self, item: &hir::AttrItem, span: Span) {
self.ibox(0);
let path = ast::Path {
span,
segments: item
.path
.segments
.iter()
.map(|i| ast::PathSegment { ident: *i, args: None, id: DUMMY_NODE_ID })
.collect(),
tokens: None,
};
match &item.args {
hir::AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self
.print_mac_common(
Some(MacHeader::Path(&path)),
false,
None,
*delim,
tokens,
true,
span,
),
hir::AttrArgs::Empty => {
PrintState::print_path(self, &path, false, 0);
}
hir::AttrArgs::Eq { eq_span: _, expr } => {
PrintState::print_path(self, &path, false, 0);
self.space();
self.word_space("=");
let token_str = self.meta_item_lit_to_string(expr);
self.word(token_str);
}
}
self.end();
}
fn print_node(&mut self, node: Node<'_>) { fn print_node(&mut self, node: Node<'_>) {
match node { match node {
Node::Param(a) => self.print_param(a), Node::Param(a) => self.print_param(a),
@ -164,7 +266,7 @@ pub fn print_crate<'a>(
krate: &hir::Mod<'_>, krate: &hir::Mod<'_>,
filename: FileName, filename: FileName,
input: String, input: String,
attrs: &'a dyn Fn(HirId) -> &'a [ast::Attribute], attrs: &'a dyn Fn(HirId) -> &'a [hir::Attribute],
ann: &'a dyn PpAnn, ann: &'a dyn PpAnn,
) -> String { ) -> String {
let mut s = State { let mut s = State {
@ -191,6 +293,10 @@ where
printer.s.eof() printer.s.eof()
} }
pub fn attribute_to_string(ann: &dyn PpAnn, attr: &hir::Attribute) -> String {
to_string(ann, |s| s.print_attribute_inline(attr, false))
}
pub fn ty_to_string(ann: &dyn PpAnn, ty: &hir::Ty<'_>) -> String { pub fn ty_to_string(ann: &dyn PpAnn, ty: &hir::Ty<'_>) -> String {
to_string(ann, |s| s.print_type(ty)) to_string(ann, |s| s.print_type(ty))
} }
@ -242,7 +348,7 @@ impl<'a> State<'a> {
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span); self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span);
} }
fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[ast::Attribute]) { fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[hir::Attribute]) {
self.print_inner_attributes(attrs); self.print_inner_attributes(attrs);
for &item_id in _mod.item_ids { for &item_id in _mod.item_ids {
self.ann.nested(self, Nested::Item(item_id)); self.ann.nested(self, Nested::Item(item_id));
@ -926,14 +1032,14 @@ impl<'a> State<'a> {
self.print_block_maybe_unclosed(blk, &[], false) self.print_block_maybe_unclosed(blk, &[], false)
} }
fn print_block_with_attrs(&mut self, blk: &hir::Block<'_>, attrs: &[ast::Attribute]) { fn print_block_with_attrs(&mut self, blk: &hir::Block<'_>, attrs: &[hir::Attribute]) {
self.print_block_maybe_unclosed(blk, attrs, true) self.print_block_maybe_unclosed(blk, attrs, true)
} }
fn print_block_maybe_unclosed( fn print_block_maybe_unclosed(
&mut self, &mut self,
blk: &hir::Block<'_>, blk: &hir::Block<'_>,
attrs: &[ast::Attribute], attrs: &[hir::Attribute],
close_box: bool, close_box: bool,
) { ) {
match blk.rules { match blk.rules {

View file

@ -50,7 +50,7 @@ use rustc_middle::{bug, span_bug};
use rustc_span::Span; use rustc_span::Span;
use rustc_span::symbol::{Symbol, sym}; use rustc_span::symbol::{Symbol, sym};
use tracing::debug; use tracing::debug;
use {rustc_ast as ast, rustc_graphviz as dot, rustc_hir as hir}; use {rustc_graphviz as dot, rustc_hir as hir};
use crate::errors; use crate::errors;
@ -106,7 +106,7 @@ struct IfThisChanged<'tcx> {
} }
impl<'tcx> IfThisChanged<'tcx> { impl<'tcx> IfThisChanged<'tcx> {
fn argument(&self, attr: &ast::Attribute) -> Option<Symbol> { fn argument(&self, attr: &hir::Attribute) -> Option<Symbol> {
let mut value = None; let mut value = None;
for list_item in attr.meta_item_list().unwrap_or_default() { for list_item in attr.meta_item_list().unwrap_or_default() {
match list_item.ident() { match list_item.ident() {

View file

@ -19,11 +19,13 @@
//! Errors are reported if we are in the suitable configuration but //! Errors are reported if we are in the suitable configuration but
//! the required condition is not met. //! the required condition is not met.
use rustc_ast::{self as ast, Attribute, MetaItemInner}; use rustc_ast::{self as ast, MetaItemInner};
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::unord::UnordSet; use rustc_data_structures::unord::UnordSet;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_hir::{ImplItemKind, ItemKind as HirItem, Node as HirNode, TraitItemKind, intravisit}; use rustc_hir::{
Attribute, ImplItemKind, ItemKind as HirItem, Node as HirNode, TraitItemKind, intravisit,
};
use rustc_middle::dep_graph::{DepNode, DepNodeExt, label_strs}; use rustc_middle::dep_graph::{DepNode, DepNodeExt, label_strs};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;

View file

@ -387,7 +387,7 @@ pub struct MissingDoc;
impl_lint_pass!(MissingDoc => [MISSING_DOCS]); impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
fn has_doc(attr: &ast::Attribute) -> bool { fn has_doc(attr: &hir::Attribute) -> bool {
if attr.is_doc_comment() { if attr.is_doc_comment() {
return true; return true;
} }
@ -1012,7 +1012,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN
impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
let attrs = cx.tcx.hir().attrs(it.hir_id()); let attrs = cx.tcx.hir().attrs(it.hir_id());
let check_no_mangle_on_generic_fn = |no_mangle_attr: &ast::Attribute, let check_no_mangle_on_generic_fn = |no_mangle_attr: &hir::Attribute,
impl_generics: Option<&hir::Generics<'_>>, impl_generics: Option<&hir::Generics<'_>>,
generics: &hir::Generics<'_>, generics: &hir::Generics<'_>,
span| { span| {
@ -1176,7 +1176,7 @@ declare_lint_pass!(
); );
impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &hir::Attribute) {
if attr.has_name(sym::feature) if attr.has_name(sym::feature)
&& let Some(items) = attr.meta_item_list() && let Some(items) = attr.meta_item_list()
{ {

View file

@ -1,4 +1,5 @@
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_attr::AttributeExt;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
use rustc_feature::{Features, GateIssue}; use rustc_feature::{Features, GateIssue};
@ -371,7 +372,7 @@ impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> {
/// FIXME(blyxyas): In a future revision, we should also graph #![allow]s, /// FIXME(blyxyas): In a future revision, we should also graph #![allow]s,
/// but that is handled with more care /// but that is handled with more care
fn visit_attribute(&mut self, attribute: &'tcx ast::Attribute) { fn visit_attribute(&mut self, attribute: &'tcx hir::Attribute) {
if matches!( if matches!(
Level::from_attr(attribute), Level::from_attr(attribute),
Some( Some(
@ -383,10 +384,9 @@ impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> {
) )
) { ) {
let store = unerased_lint_store(self.tcx.sess); let store = unerased_lint_store(self.tcx.sess);
let Some(meta) = attribute.meta() else { return };
// Lint attributes are always a metalist inside a // Lint attributes are always a metalist inside a
// metalist (even with just one lint). // metalist (even with just one lint).
let Some(meta_item_list) = meta.meta_item_list() else { return }; let Some(meta_item_list) = attribute.meta_item_list() else { return };
for meta_list in meta_item_list { for meta_list in meta_item_list {
// Convert Path to String // Convert Path to String
@ -686,7 +686,12 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
}; };
} }
fn add(&mut self, attrs: &[ast::Attribute], is_crate_node: bool, source_hir_id: Option<HirId>) { fn add(
&mut self,
attrs: &[impl AttributeExt],
is_crate_node: bool,
source_hir_id: Option<HirId>,
) {
let sess = self.sess; let sess = self.sess;
for (attr_index, attr) in attrs.iter().enumerate() { for (attr_index, attr) in attrs.iter().enumerate() {
if attr.has_name(sym::automatically_derived) { if attr.has_name(sym::automatically_derived) {
@ -910,7 +915,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
let src = LintLevelSource::Node { name, span: sp, reason }; let src = LintLevelSource::Node { name, span: sp, reason };
for &id in ids { for &id in ids {
if self.check_gated_lint(id, attr.span, false) { if self.check_gated_lint(id, attr.span(), false) {
self.insert_spec(id, (level, src)); self.insert_spec(id, (level, src));
} }
} }

View file

@ -1,7 +1,7 @@
use rustc_abi::ExternAbi; use rustc_abi::ExternAbi;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
use rustc_hir::{GenericParamKind, PatKind}; use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatKind};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_session::config::CrateType; use rustc_session::config::CrateType;
use rustc_session::{declare_lint, declare_lint_pass}; use rustc_session::{declare_lint, declare_lint_pass};
@ -342,11 +342,13 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
Some(Ident::from_str(name)) Some(Ident::from_str(name))
} else { } else {
attr::find_by_name(cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name) attr::find_by_name(cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name).and_then(
.and_then(|attr| attr.meta()) |attr| {
.and_then(|meta| { if let AttrKind::Normal(n) = &attr.kind
meta.name_value_literal().and_then(|lit| { && let AttrItem { args: AttrArgs::Eq { eq_span: _, expr: ref lit }, .. } =
if let ast::LitKind::Str(name, ..) = lit.kind { n.as_ref()
&& let ast::LitKind::Str(name, ..) = lit.kind
{
// Discard the double quotes surrounding the literal. // Discard the double quotes surrounding the literal.
let sp = cx let sp = cx
.sess() .sess()
@ -355,8 +357,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
.ok() .ok()
.and_then(|snippet| { .and_then(|snippet| {
let left = snippet.find('"')?; let left = snippet.find('"')?;
let right = let right = snippet.rfind('"').map(|pos| snippet.len() - pos)?;
snippet.rfind('"').map(|pos| snippet.len() - pos)?;
Some( Some(
lit.span lit.span
@ -370,8 +371,8 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
} else { } else {
None None
} }
}) },
}) )
}; };
if let Some(ident) = &crate_ident { if let Some(ident) = &crate_ident {

View file

@ -42,9 +42,9 @@ macro_rules! late_lint_methods {
fn check_field_def(a: &'tcx rustc_hir::FieldDef<'tcx>); fn check_field_def(a: &'tcx rustc_hir::FieldDef<'tcx>);
fn check_variant(a: &'tcx rustc_hir::Variant<'tcx>); fn check_variant(a: &'tcx rustc_hir::Variant<'tcx>);
fn check_path(a: &rustc_hir::Path<'tcx>, b: rustc_hir::HirId); fn check_path(a: &rustc_hir::Path<'tcx>, b: rustc_hir::HirId);
fn check_attribute(a: &'tcx rustc_ast::Attribute); fn check_attribute(a: &'tcx rustc_hir::Attribute);
fn check_attributes(a: &'tcx [rustc_ast::Attribute]); fn check_attributes(a: &'tcx [rustc_hir::Attribute]);
fn check_attributes_post(a: &'tcx [rustc_ast::Attribute]); fn check_attributes_post(a: &'tcx [rustc_hir::Attribute]);
]); ]);
) )
} }

View file

@ -3,8 +3,9 @@
// tidy-alphabetical-end // tidy-alphabetical-end
use rustc_abi::ExternAbi; use rustc_abi::ExternAbi;
use rustc_ast::AttrId;
use rustc_ast::attr::AttributeExt;
use rustc_ast::node_id::NodeId; use rustc_ast::node_id::NodeId;
use rustc_ast::{AttrId, Attribute};
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::stable_hasher::{ use rustc_data_structures::stable_hasher::{
HashStable, StableCompare, StableHasher, ToStableHashKey, HashStable, StableCompare, StableHasher, ToStableHashKey,
@ -221,8 +222,8 @@ impl Level {
} }
/// Converts an `Attribute` to a level. /// Converts an `Attribute` to a level.
pub fn from_attr(attr: &Attribute) -> Option<Self> { pub fn from_attr(attr: &impl AttributeExt) -> Option<Self> {
Self::from_symbol(attr.name_or_empty(), Some(attr.id)) Self::from_symbol(attr.name_or_empty(), Some(attr.id()))
} }
/// Converts a `Symbol` to a level. /// Converts a `Symbol` to a level.

View file

@ -17,6 +17,7 @@ use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard};
use rustc_errors::DiagCtxtHandle; use rustc_errors::DiagCtxtHandle;
use rustc_expand::base::SyntaxExtension; use rustc_expand::base::SyntaxExtension;
use rustc_fs_util::try_canonicalize; use rustc_fs_util::try_canonicalize;
use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE, LocalDefId, StableCrateId}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE, LocalDefId, StableCrateId};
use rustc_hir::definitions::Definitions; use rustc_hir::definitions::Definitions;
use rustc_index::IndexVec; use rustc_index::IndexVec;
@ -97,7 +98,13 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
} }
pub enum LoadedMacro { pub enum LoadedMacro {
MacroDef { def: MacroDef, ident: Ident, attrs: AttrVec, span: Span, edition: Edition }, MacroDef {
def: MacroDef,
ident: Ident,
attrs: Vec<hir::Attribute>,
span: Span,
edition: Edition,
},
ProcMacro(SyntaxExtension), ProcMacro(SyntaxExtension),
} }

View file

@ -1369,7 +1369,7 @@ impl<'a> CrateMetadataRef<'a> {
self, self,
id: DefIndex, id: DefIndex,
sess: &'a Session, sess: &'a Session,
) -> impl Iterator<Item = ast::Attribute> + 'a { ) -> impl Iterator<Item = hir::Attribute> + 'a {
self.root self.root
.tables .tables
.attributes .attributes

View file

@ -344,7 +344,7 @@ provide! { tcx, def_id, other, cdata,
} }
associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) } associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) }
inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } attrs_for_def => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
is_mir_available => { cdata.is_item_mir_available(def_id.index) } is_mir_available => { cdata.is_item_mir_available(def_id.index) }
is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) } is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
cross_crate_inlinable => { table_direct } cross_crate_inlinable => { table_direct }

View file

@ -4,7 +4,7 @@ use std::fs::File;
use std::io::{Read, Seek, Write}; use std::io::{Read, Seek, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use rustc_ast::Attribute; use rustc_ast::attr::AttributeExt;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::memmap::{Mmap, MmapMut};
use rustc_data_structures::sync::{Lrc, join, par_for_each_in}; use rustc_data_structures::sync::{Lrc, join, par_for_each_in};
@ -814,7 +814,7 @@ struct AnalyzeAttrState<'a> {
/// visibility: this is a piece of data that can be computed once per defid, and not once per /// visibility: this is a piece of data that can be computed once per defid, and not once per
/// attribute. Some attributes would only be usable downstream if they are public. /// attribute. Some attributes would only be usable downstream if they are public.
#[inline] #[inline]
fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState<'_>) -> bool { fn analyze_attr(attr: &impl AttributeExt, state: &mut AnalyzeAttrState<'_>) -> bool {
let mut should_encode = false; let mut should_encode = false;
if !rustc_feature::encode_cross_crate(attr.name_or_empty()) { if !rustc_feature::encode_cross_crate(attr.name_or_empty()) {
// Attributes not marked encode-cross-crate don't need to be encoded for downstream crates. // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates.
@ -1354,7 +1354,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
.hir() .hir()
.attrs(tcx.local_def_id_to_hir_id(def_id)) .attrs(tcx.local_def_id_to_hir_id(def_id))
.iter() .iter()
.filter(|attr| analyze_attr(attr, &mut state)); .filter(|attr| analyze_attr(*attr, &mut state));
record_array!(self.tables.attributes[def_id.to_def_id()] <- attr_iter); record_array!(self.tables.attributes[def_id.to_def_id()] <- attr_iter);

View file

@ -403,7 +403,7 @@ define_tables! {
cross_crate_inlinable: Table<DefIndex, bool>, cross_crate_inlinable: Table<DefIndex, bool>,
- optional: - optional:
attributes: Table<DefIndex, LazyArray<ast::Attribute>>, attributes: Table<DefIndex, LazyArray<hir::Attribute>>,
// For non-reexported names in a module every name is associated with a separate `DefId`, // For non-reexported names in a module every name is associated with a separate `DefId`,
// so we can take their names, visibilities etc from other encoded tables. // so we can take their names, visibilities etc from other encoded tables.
module_children_non_reexports: Table<DefIndex, LazyArray<DefIndex>>, module_children_non_reexports: Table<DefIndex, LazyArray<DefIndex>>,

View file

@ -85,7 +85,7 @@ macro_rules! arena_types {
[] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>, [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
[] dyn_compatibility_violations: rustc_middle::traits::DynCompatibilityViolation, [] dyn_compatibility_violations: rustc_middle::traits::DynCompatibilityViolation,
[] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>, [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>,
[decode] attribute: rustc_ast::Attribute, [decode] attribute: rustc_hir::Attribute,
[] name_set: rustc_data_structures::unord::UnordSet<rustc_span::symbol::Symbol>, [] name_set: rustc_data_structures::unord::UnordSet<rustc_span::symbol::Symbol>,
[] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::symbol::Symbol>, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::symbol::Symbol>,
[] pats: rustc_middle::ty::PatternKind<'tcx>, [] pats: rustc_middle::ty::PatternKind<'tcx>,

View file

@ -9,11 +9,11 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
use rustc_hir::intravisit::Visitor; use rustc_hir::intravisit::Visitor;
use rustc_hir::*; use rustc_hir::*;
use rustc_hir_pretty as pprust_hir;
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_span::def_id::StableCrateId; use rustc_span::def_id::StableCrateId;
use rustc_span::symbol::{Ident, Symbol, kw, sym}; use rustc_span::symbol::{Ident, Symbol, kw, sym};
use rustc_span::{ErrorGuaranteed, Span}; use rustc_span::{ErrorGuaranteed, Span};
use {rustc_ast as ast, rustc_hir_pretty as pprust_hir};
use crate::hir::ModuleItems; use crate::hir::ModuleItems;
use crate::middle::debugger_visualizer::DebuggerVisualizerFile; use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
@ -381,7 +381,7 @@ impl<'hir> Map<'hir> {
/// Gets the attributes on the crate. This is preferable to /// Gets the attributes on the crate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter /// invoking `krate.attrs` because it registers a tighter
/// dep-graph access. /// dep-graph access.
pub fn krate_attrs(self) -> &'hir [ast::Attribute] { pub fn krate_attrs(self) -> &'hir [Attribute] {
self.attrs(CRATE_HIR_ID) self.attrs(CRATE_HIR_ID)
} }
@ -792,7 +792,7 @@ impl<'hir> Map<'hir> {
/// Given a node ID, gets a list of attributes associated with the AST /// Given a node ID, gets a list of attributes associated with the AST
/// corresponding to the node-ID. /// corresponding to the node-ID.
pub fn attrs(self, id: HirId) -> &'hir [ast::Attribute] { pub fn attrs(self, id: HirId) -> &'hir [Attribute] {
self.tcx.hir_attrs(id.owner).get(id.local_id) self.tcx.hir_attrs(id.owner).get(id.local_id)
} }

View file

@ -151,7 +151,7 @@ impl<'tcx> TyCtxt<'tcx> {
self, self,
node: OwnerNode<'_>, node: OwnerNode<'_>,
bodies: &SortedMap<ItemLocalId, &Body<'_>>, bodies: &SortedMap<ItemLocalId, &Body<'_>>,
attrs: &SortedMap<ItemLocalId, &[rustc_ast::Attribute]>, attrs: &SortedMap<ItemLocalId, &[Attribute]>,
) -> (Option<Fingerprint>, Option<Fingerprint>) { ) -> (Option<Fingerprint>, Option<Fingerprint>) {
if self.needs_crate_hash() { if self.needs_crate_hash() {
self.with_stable_hashing_context(|mut hcx| { self.with_stable_hashing_context(|mut hcx| {

View file

@ -10,7 +10,7 @@
use std::num::IntErrorKind; use std::num::IntErrorKind;
use rustc_ast::Attribute; use rustc_ast::attr::AttributeExt;
use rustc_session::{Limit, Limits, Session}; use rustc_session::{Limit, Limits, Session};
use rustc_span::symbol::{Symbol, sym}; use rustc_span::symbol::{Symbol, sym};
@ -35,32 +35,36 @@ pub fn provide(providers: &mut Providers) {
} }
} }
pub fn get_recursion_limit(krate_attrs: &[Attribute], sess: &Session) -> Limit { pub fn get_recursion_limit(krate_attrs: &[impl AttributeExt], sess: &Session) -> Limit {
get_limit(krate_attrs, sess, sym::recursion_limit, 128) get_limit(krate_attrs, sess, sym::recursion_limit, 128)
} }
fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: usize) -> Limit { fn get_limit(
krate_attrs: &[impl AttributeExt],
sess: &Session,
name: Symbol,
default: usize,
) -> Limit {
match get_limit_size(krate_attrs, sess, name) { match get_limit_size(krate_attrs, sess, name) {
Some(size) => Limit::new(size), Some(size) => Limit::new(size),
None => Limit::new(default), None => Limit::new(default),
} }
} }
pub fn get_limit_size(krate_attrs: &[Attribute], sess: &Session, name: Symbol) -> Option<usize> { pub fn get_limit_size(
krate_attrs: &[impl AttributeExt],
sess: &Session,
name: Symbol,
) -> Option<usize> {
for attr in krate_attrs { for attr in krate_attrs {
if !attr.has_name(name) { if !attr.has_name(name) {
continue; continue;
} }
if let Some(s) = attr.value_str() { if let Some(sym) = attr.value_str() {
match s.as_str().parse() { match sym.as_str().parse() {
Ok(n) => return Some(n), Ok(n) => return Some(n),
Err(e) => { Err(e) => {
let value_span = attr
.meta()
.and_then(|meta| meta.name_value_literal_span())
.unwrap_or(attr.span);
let error_str = match e.kind() { let error_str = match e.kind() {
IntErrorKind::PosOverflow => "`limit` is too large", IntErrorKind::PosOverflow => "`limit` is too large",
IntErrorKind::Empty => "`limit` must be a non-negative integer", IntErrorKind::Empty => "`limit` must be a non-negative integer",
@ -71,7 +75,11 @@ pub fn get_limit_size(krate_attrs: &[Attribute], sess: &Session, name: Symbol) -
IntErrorKind::Zero => bug!("zero is a valid `limit`"), IntErrorKind::Zero => bug!("zero is a valid `limit`"),
kind => bug!("unimplemented IntErrorKind variant: {:?}", kind), kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
}; };
sess.dcx().emit_err(LimitInvalid { span: attr.span, value_span, error_str }); sess.dcx().emit_err(LimitInvalid {
span: attr.span(),
value_span: attr.value_span().unwrap(),
error_str,
});
} }
} }
} }

View file

@ -1267,7 +1267,7 @@ rustc_queries! {
/// Returns the attributes on the item at `def_id`. /// Returns the attributes on the item at `def_id`.
/// ///
/// Do not use this directly, use `tcx.get_attrs` instead. /// Do not use this directly, use `tcx.get_attrs` instead.
query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] { query attrs_for_def(def_id: DefId) -> &'tcx [hir::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

@ -798,7 +798,7 @@ macro_rules! impl_ref_decoder {
impl_ref_decoder! {<'tcx> impl_ref_decoder! {<'tcx>
Span, Span,
rustc_ast::Attribute, rustc_hir::Attribute,
rustc_span::symbol::Ident, rustc_span::symbol::Ident,
ty::Variance, ty::Variance,
rustc_span::def_id::DefId, rustc_span::def_id::DefId,

View file

@ -13,7 +13,7 @@ use std::ops::{Bound, Deref};
use std::{fmt, iter, mem}; use std::{fmt, iter, mem};
use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx}; use rustc_abi::{ExternAbi, FieldIdx, Layout, LayoutData, TargetDataLayout, VariantIdx};
use rustc_ast::{self as ast, attr}; use rustc_ast as ast;
use rustc_data_structures::defer; use rustc_data_structures::defer;
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
@ -29,13 +29,12 @@ use rustc_data_structures::unord::UnordSet;
use rustc_errors::{ use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan,
}; };
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::definitions::Definitions; use rustc_hir::definitions::Definitions;
use rustc_hir::intravisit::Visitor; use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_hir::{HirId, Node, TraitCandidate}; use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate};
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_macros::{HashStable, TyDecodable, TyEncodable};
use rustc_query_system::cache::WithDepNode; use rustc_query_system::cache::WithDepNode;
@ -3239,12 +3238,16 @@ pub fn provide(providers: &mut Providers) {
providers.extern_mod_stmt_cnum = providers.extern_mod_stmt_cnum =
|tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned(); |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
providers.is_panic_runtime = providers.is_panic_runtime =
|tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime); |tcx, LocalCrate| contains_name(tcx.hir().krate_attrs(), sym::panic_runtime);
providers.is_compiler_builtins = providers.is_compiler_builtins =
|tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins); |tcx, LocalCrate| contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins);
providers.has_panic_handler = |tcx, LocalCrate| { providers.has_panic_handler = |tcx, LocalCrate| {
// We want to check if the panic handler was defined in this crate // We want to check if the panic handler was defined in this crate
tcx.lang_items().panic_impl().is_some_and(|did| did.is_local()) tcx.lang_items().panic_impl().is_some_and(|did| did.is_local())
}; };
providers.source_span = |tcx, def_id| tcx.untracked.source_span.get(def_id).unwrap_or(DUMMY_SP); providers.source_span = |tcx, def_id| tcx.untracked.source_span.get(def_id).unwrap_or(DUMMY_SP);
} }
pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
attrs.iter().any(|x| x.has_name(name))
}

View file

@ -277,7 +277,7 @@ impl<'tcx> InstanceKind<'tcx> {
&self, &self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
attr: Symbol, attr: Symbol,
) -> impl Iterator<Item = &'tcx rustc_ast::Attribute> { ) -> impl Iterator<Item = &'tcx hir::Attribute> {
tcx.get_attrs(self.def_id(), attr) tcx.get_attrs(self.def_id(), attr)
} }

View file

@ -1745,11 +1745,11 @@ impl<'tcx> TyCtxt<'tcx> {
} }
// FIXME(@lcnr): Remove this function. // FIXME(@lcnr): Remove this function.
pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [ast::Attribute] { pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [hir::Attribute] {
if let Some(did) = did.as_local() { if let Some(did) = did.as_local() {
self.hir().attrs(self.local_def_id_to_hir_id(did)) self.hir().attrs(self.local_def_id_to_hir_id(did))
} else { } else {
self.item_attrs(did) self.attrs_for_def(did)
} }
} }
@ -1758,14 +1758,14 @@ impl<'tcx> TyCtxt<'tcx> {
self, self,
did: impl Into<DefId>, did: impl Into<DefId>,
attr: Symbol, attr: Symbol,
) -> impl Iterator<Item = &'tcx ast::Attribute> { ) -> impl Iterator<Item = &'tcx hir::Attribute> {
let did: DefId = did.into(); let did: DefId = did.into();
let filter_fn = move |a: &&ast::Attribute| a.has_name(attr); let filter_fn = move |a: &&hir::Attribute| a.has_name(attr);
if let Some(did) = did.as_local() { if let Some(did) = did.as_local() {
self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn)
} else { } else {
debug_assert!(rustc_feature::encode_cross_crate(attr)); debug_assert!(rustc_feature::encode_cross_crate(attr));
self.item_attrs(did).iter().filter(filter_fn) self.attrs_for_def(did).iter().filter(filter_fn)
} }
} }
@ -1781,7 +1781,7 @@ impl<'tcx> TyCtxt<'tcx> {
self, self,
did: impl Into<DefId>, did: impl Into<DefId>,
attr: Symbol, attr: Symbol,
) -> Option<&'tcx ast::Attribute> { ) -> Option<&'tcx hir::Attribute> {
let did: DefId = did.into(); let did: DefId = did.into();
if did.as_local().is_some() { if did.as_local().is_some() {
// it's a crate local item, we need to check feature flags // it's a crate local item, we need to check feature flags
@ -1794,7 +1794,7 @@ impl<'tcx> TyCtxt<'tcx> {
// we filter out unstable diagnostic attributes before // we filter out unstable diagnostic attributes before
// encoding attributes // encoding attributes
debug_assert!(rustc_feature::encode_cross_crate(attr)); debug_assert!(rustc_feature::encode_cross_crate(attr));
self.item_attrs(did) self.attrs_for_def(did)
.iter() .iter()
.find(|a| matches!(a.path().as_ref(), [sym::diagnostic, a] if *a == attr)) .find(|a| matches!(a.path().as_ref(), [sym::diagnostic, a] if *a == attr))
} }
@ -1804,19 +1804,19 @@ impl<'tcx> TyCtxt<'tcx> {
self, self,
did: DefId, did: DefId,
attr: &'attr [Symbol], attr: &'attr [Symbol],
) -> impl Iterator<Item = &'tcx ast::Attribute> + 'attr ) -> impl Iterator<Item = &'tcx hir::Attribute> + 'attr
where where
'tcx: 'attr, 'tcx: 'attr,
{ {
let filter_fn = move |a: &&ast::Attribute| a.path_matches(attr); let filter_fn = move |a: &&hir::Attribute| a.path_matches(attr);
if let Some(did) = did.as_local() { if let Some(did) = did.as_local() {
self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn)
} else { } else {
self.item_attrs(did).iter().filter(filter_fn) self.attrs_for_def(did).iter().filter(filter_fn)
} }
} }
pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx ast::Attribute> { pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx hir::Attribute> {
if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) { if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
let did: DefId = did.into(); let did: DefId = did.into();
bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr); bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr);

View file

@ -111,6 +111,7 @@ trivially_parameterized_over_tcx! {
rustc_span::hygiene::SyntaxContextData, rustc_span::hygiene::SyntaxContextData,
rustc_span::symbol::Ident, rustc_span::symbol::Ident,
rustc_type_ir::Variance, rustc_type_ir::Variance,
rustc_hir::Attribute,
} }
// HACK(compiler-errors): This macro rule can only take a fake path, // HACK(compiler-errors): This macro rule can only take a fake path,
@ -140,5 +141,5 @@ parameterized_over_tcx! {
ty::Predicate, ty::Predicate,
ty::Clause, ty::Clause,
ty::ClauseKind, ty::ClauseKind,
ty::ImplTraitHeader ty::ImplTraitHeader,
} }

View file

@ -17,10 +17,9 @@
//! terminators, and everything below can be found in the `parse::instruction` submodule. //! terminators, and everything below can be found in the `parse::instruction` submodule.
//! //!
use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir::HirId;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{Attribute, HirId};
use rustc_index::{IndexSlice, IndexVec}; use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::span_bug; use rustc_middle::span_bug;

View file

@ -1,6 +1,5 @@
use rustc_ast as ast;
use rustc_ast::attr;
use rustc_ast::token::{self, Delimiter}; use rustc_ast::token::{self, Delimiter};
use rustc_ast::{self as ast, Attribute, attr};
use rustc_errors::codes::*; use rustc_errors::codes::*;
use rustc_errors::{Diag, PResult}; use rustc_errors::{Diag, PResult};
use rustc_span::symbol::kw; use rustc_span::symbol::kw;
@ -48,7 +47,7 @@ impl<'a> Parser<'a> {
let start_pos = self.num_bump_calls; let start_pos = self.num_bump_calls;
loop { loop {
let attr = if self.check(&token::Pound) { let attr = if self.check(&token::Pound) {
let prev_outer_attr_sp = outer_attrs.last().map(|attr| attr.span); let prev_outer_attr_sp = outer_attrs.last().map(|attr: &Attribute| attr.span);
let inner_error_reason = if just_parsed_doc_comment { let inner_error_reason = if just_parsed_doc_comment {
Some(InnerAttrForbiddenReason::AfterOuterDocComment { Some(InnerAttrForbiddenReason::AfterOuterDocComment {

View file

@ -29,9 +29,9 @@ use rustc_ast::tokenstream::{
}; };
use rustc_ast::util::case::Case; use rustc_ast::util::case::Case;
use rustc_ast::{ use rustc_ast::{
self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID,
DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit,
Safety, StrLit, Visibility, VisibilityKind, Visibility, VisibilityKind,
}; };
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
@ -1376,7 +1376,7 @@ impl<'a> Parser<'a> {
AttrArgs::Delimited(args) AttrArgs::Delimited(args)
} else if self.eat(&token::Eq) { } else if self.eat(&token::Eq) {
let eq_span = self.prev_token.span; let eq_span = self.prev_token.span;
AttrArgs::Eq { eq_span, value: AttrArgsEq::Ast(self.parse_expr_force_collect()?) } AttrArgs::Eq { eq_span, expr: self.parse_expr_force_collect()? }
} else { } else {
AttrArgs::Empty AttrArgs::Empty
}) })

View file

@ -3,8 +3,7 @@
use rustc_ast::token::Delimiter; use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan; use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{ use rustc_ast::{
self as ast, AttrArgs, AttrArgsEq, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety,
Safety,
}; };
use rustc_errors::{Applicability, FatalError, PResult}; use rustc_errors::{Applicability, FatalError, PResult};
use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
@ -70,7 +69,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met
parse_in(psess, tokens.clone(), "meta list", |p| p.parse_meta_seq_top())?; parse_in(psess, tokens.clone(), "meta list", |p| p.parse_meta_seq_top())?;
MetaItemKind::List(nmis) MetaItemKind::List(nmis)
} }
AttrArgs::Eq { value: AttrArgsEq::Ast(expr), .. } => { AttrArgs::Eq { expr, .. } => {
if let ast::ExprKind::Lit(token_lit) = expr.kind { if let ast::ExprKind::Lit(token_lit) = expr.kind {
let res = ast::MetaItemLit::from_token_lit(token_lit, expr.span); let res = ast::MetaItemLit::from_token_lit(token_lit, expr.span);
let res = match res { let res = match res {
@ -116,9 +115,6 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met
return Err(err); return Err(err);
} }
} }
AttrArgs::Eq { value: AttrArgsEq::Hir(lit), .. } => {
MetaItemKind::NameValue(lit.clone())
}
}, },
}) })
} }

View file

@ -1,4 +1,4 @@
use rustc_ast::Attribute; use rustc_hir::Attribute;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_middle::span_bug; use rustc_middle::span_bug;

View file

@ -7,17 +7,15 @@
use std::cell::Cell; use std::cell::Cell;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use rustc_ast::{ use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast};
AttrKind, AttrStyle, Attribute, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast,
};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
use rustc_hir::def_id::LocalModDefId; use rustc_hir::def_id::LocalModDefId;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{ use rustc_hir::{
self as hir, self, AssocItemKind, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, HirId, self as hir, self, AssocItemKind, AttrKind, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig,
Item, ItemKind, MethodKind, Safety, Target, TraitItem, ForeignItem, HirId, Item, ItemKind, MethodKind, Safety, Target, TraitItem,
}; };
use rustc_macros::LintDiagnostic; use rustc_macros::LintDiagnostic;
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
@ -1176,10 +1174,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
specified_inline: &mut Option<(bool, Span)>, specified_inline: &mut Option<(bool, Span)>,
aliases: &mut FxHashMap<String, Span>, aliases: &mut FxHashMap<String, Span>,
) { ) {
if let Some(mi) = attr.meta() if let Some(list) = attr.meta_item_list() {
&& let Some(list) = mi.meta_item_list() for meta in &list {
{
for meta in list {
if let Some(i_meta) = meta.meta_item() { if let Some(i_meta) = meta.meta_item() {
match i_meta.name_or_empty() { match i_meta.name_or_empty() {
sym::alias => { sym::alias => {
@ -1279,7 +1275,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
AttrStyle::Inner => "!", AttrStyle::Inner => "!",
AttrStyle::Outer => "", AttrStyle::Outer => "",
}, },
sugg: (attr.meta().unwrap().span, applicability), sugg: (attr.span, applicability),
}, },
); );
} else if i_meta.has_name(sym::passes) } else if i_meta.has_name(sym::passes)
@ -2141,10 +2137,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
fn check_confusables(&self, attr: &Attribute, target: Target) { fn check_confusables(&self, attr: &Attribute, target: Target) {
match target { match target {
Target::Method(MethodKind::Inherent) => { Target::Method(MethodKind::Inherent) => {
let Some(meta) = attr.meta() else { let Some(metas) = attr.meta_item_list() else {
return;
};
let ast::MetaItem { kind: MetaItemKind::List(ref metas), .. } = meta else {
return; return;
}; };
@ -2602,7 +2595,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
if let AttrKind::Normal(ref p) = attr.kind { if let AttrKind::Normal(ref p) = attr.kind {
tcx.dcx().try_steal_replace_and_emit_err( tcx.dcx().try_steal_replace_and_emit_err(
p.item.path.span, p.path.span,
StashKey::UndeterminedMacroResolution, StashKey::UndeterminedMacroResolution,
err, err,
); );

View file

@ -9,9 +9,8 @@
//! //!
//! * Compiler internal types like `Ty` and `TyCtxt` //! * Compiler internal types like `Ty` and `TyCtxt`
use rustc_ast as ast;
use rustc_hir::OwnerId;
use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_hir::{Attribute, OwnerId};
use rustc_middle::query::{LocalCrate, Providers}; use rustc_middle::query::{LocalCrate, Providers};
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::def_id::{DefId, LOCAL_CRATE};
@ -55,7 +54,7 @@ fn report_duplicate_item(
} }
/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes. /// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.
fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> { fn extract(attrs: &[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

@ -500,7 +500,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
hir_visit::walk_assoc_item_constraint(self, constraint) hir_visit::walk_assoc_item_constraint(self, constraint)
} }
fn visit_attribute(&mut self, attr: &'v ast::Attribute) { fn visit_attribute(&mut self, attr: &'v hir::Attribute) {
self.record("Attribute", None, attr); self.record("Attribute", None, attr);
} }

View file

@ -1,5 +1,5 @@
use rustc_abi::{HasDataLayout, TargetDataLayout}; use rustc_abi::{HasDataLayout, TargetDataLayout};
use rustc_ast::Attribute; use rustc_hir::Attribute;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_middle::span_bug; use rustc_middle::span_bug;

View file

@ -4,8 +4,8 @@
//! but are not declared in one single location (unlike lang features), which means we need to //! but are not declared in one single location (unlike lang features), which means we need to
//! collect them instead. //! collect them instead.
use rustc_ast::Attribute;
use rustc_attr::VERSION_PLACEHOLDER; use rustc_attr::VERSION_PLACEHOLDER;
use rustc_hir::Attribute;
use rustc_hir::intravisit::Visitor; use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};

View file

@ -1,18 +1,17 @@
//! This module contains `HashStable` implementations for various data types //! This module contains `HashStable` implementations for various data types
//! from `rustc_ast` in no particular order. //! from various crates in no particular order.
use std::assert_matches::assert_matches;
use rustc_ast as ast;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir as hir;
use rustc_span::SourceFile; use rustc_span::SourceFile;
use smallvec::SmallVec; use smallvec::SmallVec;
use crate::ich::StableHashingContext; use crate::ich::StableHashingContext;
impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {} impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {}
impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> {}
impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] { impl<'a> HashStable<StableHashingContext<'a>> for [hir::Attribute] {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
if self.is_empty() { if self.is_empty() {
self.len().hash_stable(hcx, hasher); self.len().hash_stable(hcx, hasher);
@ -20,7 +19,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
} }
// Some attributes are always ignored during hashing. // Some attributes are always ignored during hashing.
let filtered: SmallVec<[&ast::Attribute; 8]> = self let filtered: SmallVec<[&hir::Attribute; 8]> = self
.iter() .iter()
.filter(|attr| { .filter(|attr| {
!attr.is_doc_comment() !attr.is_doc_comment()
@ -35,30 +34,23 @@ impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
} }
} }
impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> { impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
fn hash_attr(&mut self, attr: &ast::Attribute, hasher: &mut StableHasher) { fn hash_attr(&mut self, attr: &hir::Attribute, hasher: &mut StableHasher) {
// Make sure that these have been filtered out. // Make sure that these have been filtered out.
debug_assert!(!attr.ident().is_some_and(|ident| self.is_ignored_attr(ident.name))); debug_assert!(!attr.ident().is_some_and(|ident| self.is_ignored_attr(ident.name)));
debug_assert!(!attr.is_doc_comment()); debug_assert!(!attr.is_doc_comment());
let ast::Attribute { kind, id: _, style, span } = attr; let hir::Attribute { kind, id: _, style, span } = attr;
if let ast::AttrKind::Normal(normal) = kind { if let hir::AttrKind::Normal(item) = kind {
normal.item.hash_stable(self, hasher); item.hash_stable(self, hasher);
style.hash_stable(self, hasher); style.hash_stable(self, hasher);
span.hash_stable(self, hasher); span.hash_stable(self, hasher);
assert_matches!(
normal.tokens.as_ref(),
None,
"Tokens should have been removed during lowering!"
);
} else { } else {
unreachable!(); unreachable!();
} }
} }
} }
impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {}
impl<'a> HashStable<StableHashingContext<'a>> for SourceFile { impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let SourceFile { let SourceFile {

View file

@ -7,7 +7,7 @@ use std::mem;
use rustc_ast::expand::StrippedCfgItem; use rustc_ast::expand::StrippedCfgItem;
use rustc_ast::{self as ast, Crate, Inline, ItemKind, ModKind, NodeId, attr}; use rustc_ast::{self as ast, Crate, Inline, ItemKind, ModKind, NodeId, attr};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_attr::StabilityLevel; use rustc_attr::{AttributeExt, StabilityLevel};
use rustc_data_structures::intern::Interned; use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, StashKey}; use rustc_errors::{Applicability, StashKey};
@ -1126,7 +1126,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
&mut self, &mut self,
macro_def: &ast::MacroDef, macro_def: &ast::MacroDef,
ident: Ident, ident: Ident,
attrs: &[ast::Attribute], attrs: &[impl AttributeExt],
span: Span, span: Span,
node_id: NodeId, node_id: NodeId,
edition: Edition, edition: Edition,

View file

@ -6,6 +6,7 @@ use pulldown_cmark::{
}; };
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::util::comments::beautify_doc_string; use rustc_ast::util::comments::beautify_doc_string;
use rustc_attr::AttributeExt;
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
@ -192,19 +193,24 @@ pub fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
} }
} }
pub fn attrs_to_doc_fragments<'a>( pub fn attrs_to_doc_fragments<'a, A: AttributeExt + Clone + 'a>(
attrs: impl Iterator<Item = (&'a ast::Attribute, Option<DefId>)>, attrs: impl Iterator<Item = (&'a A, Option<DefId>)>,
doc_only: bool, doc_only: bool,
) -> (Vec<DocFragment>, ast::AttrVec) { ) -> (Vec<DocFragment>, Vec<A>) {
let mut doc_fragments = Vec::new(); let mut doc_fragments = Vec::new();
let mut other_attrs = ast::AttrVec::new(); let mut other_attrs = Vec::<A>::new();
for (attr, item_id) in attrs { for (attr, item_id) in attrs {
if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() { if let Some((doc_str, comment_kind)) = attr.doc_str_and_comment_kind() {
let doc = beautify_doc_string(doc_str, comment_kind); let doc = beautify_doc_string(doc_str, comment_kind);
let (span, kind) = if attr.is_doc_comment() { let (span, kind) = if attr.is_doc_comment() {
(attr.span, DocFragmentKind::SugaredDoc) (attr.span(), DocFragmentKind::SugaredDoc)
} else { } else {
(span_for_value(attr), DocFragmentKind::RawDoc) (
attr.value_span()
.map(|i| i.with_ctxt(attr.span().ctxt()))
.unwrap_or(attr.span()),
DocFragmentKind::RawDoc,
)
}; };
let fragment = DocFragment { span, doc, kind, item_id, indent: 0 }; let fragment = DocFragment { span, doc, kind, item_id, indent: 0 };
doc_fragments.push(fragment); doc_fragments.push(fragment);
@ -218,16 +224,6 @@ pub fn attrs_to_doc_fragments<'a>(
(doc_fragments, other_attrs) (doc_fragments, other_attrs)
} }
fn span_for_value(attr: &ast::Attribute) -> Span {
if let ast::AttrKind::Normal(normal) = &attr.kind
&& let ast::AttrArgs::Eq { value, .. } = &normal.item.args
{
value.span().with_ctxt(attr.span.ctxt())
} else {
attr.span
}
}
/// Return the doc-comments on this item, grouped by the module they came from. /// Return the doc-comments on this item, grouped by the module they came from.
/// The module can be different if this is a re-export with added documentation. /// The module can be different if this is a re-export with added documentation.
/// ///
@ -353,12 +349,15 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen
/// ///
//// If there are no doc-comments, return true. //// If there are no doc-comments, return true.
/// FIXME(#78591): Support both inner and outer attributes on the same item. /// FIXME(#78591): Support both inner and outer attributes on the same item.
pub fn inner_docs(attrs: &[ast::Attribute]) -> bool { pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool {
attrs.iter().find(|a| a.doc_str().is_some()).map_or(true, |a| a.style == ast::AttrStyle::Inner) attrs
.iter()
.find(|a| a.doc_str().is_some())
.map_or(true, |a| a.style() == ast::AttrStyle::Inner)
} }
/// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`. /// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`.
pub fn has_primitive_or_keyword_docs(attrs: &[ast::Attribute]) -> bool { pub fn has_primitive_or_keyword_docs(attrs: &[impl AttributeExt]) -> bool {
for attr in attrs { for attr in attrs {
if attr.has_name(sym::rustc_doc_primitive) { if attr.has_name(sym::rustc_doc_primitive) {
return true; return true;
@ -408,7 +407,7 @@ pub fn may_be_doc_link(link_type: LinkType) -> bool {
/// Simplified version of `preprocessed_markdown_links` from rustdoc. /// Simplified version of `preprocessed_markdown_links` from rustdoc.
/// Must return at least the same links as it, but may add some more links on top of that. /// Must return at least the same links as it, but may add some more links on top of that.
pub(crate) fn attrs_to_preprocessed_links(attrs: &[ast::Attribute]) -> Vec<Box<str>> { pub(crate) fn attrs_to_preprocessed_links<A: AttributeExt + Clone>(attrs: &[A]) -> Vec<Box<str>> {
let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true); let (doc_fragments, _) = attrs_to_doc_fragments(attrs.iter().map(|attr| (attr, None)), true);
let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap(); let doc = prepare_to_doc_link_resolution(&doc_fragments).into_values().next().unwrap();

View file

@ -7,9 +7,9 @@ edition = "2021"
# tidy-alphabetical-start # tidy-alphabetical-start
rustc_abi = { path = "../rustc_abi" } rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" } rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" }
rustc_hir = { path = "../rustc_hir" } rustc_hir = { path = "../rustc_hir" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_middle = { path = "../rustc_middle" } rustc_middle = { path = "../rustc_middle" }
rustc_session = { path = "../rustc_session" } rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" } rustc_span = { path = "../rustc_span" }

View file

@ -255,7 +255,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
attr.iter().map(|seg| rustc_span::symbol::Symbol::intern(&seg)).collect(); attr.iter().map(|seg| rustc_span::symbol::Symbol::intern(&seg)).collect();
tcx.get_attrs_by_path(did, &attr_name) tcx.get_attrs_by_path(did, &attr_name)
.map(|attribute| { .map(|attribute| {
let attr_str = rustc_ast_pretty::pprust::attribute_to_string(attribute); let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute);
let span = attribute.span; let span = attribute.span;
stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables))
}) })
@ -266,17 +266,16 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
let mut tables = self.0.borrow_mut(); let mut tables = self.0.borrow_mut();
let tcx = tables.tcx; let tcx = tables.tcx;
let did = tables[def_id]; let did = tables[def_id];
let filter_fn = move |a: &&rustc_ast::ast::Attribute| { let filter_fn =
matches!(a.kind, rustc_ast::ast::AttrKind::Normal(_)) move |a: &&rustc_hir::Attribute| matches!(a.kind, rustc_hir::AttrKind::Normal(_));
};
let attrs_iter = if let Some(did) = did.as_local() { let attrs_iter = if let Some(did) = did.as_local() {
tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter().filter(filter_fn) tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter().filter(filter_fn)
} else { } else {
tcx.item_attrs(did).iter().filter(filter_fn) tcx.attrs_for_def(did).iter().filter(filter_fn)
}; };
attrs_iter attrs_iter
.map(|attribute| { .map(|attribute| {
let attr_str = rustc_ast_pretty::pprust::attribute_to_string(attribute); let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute);
let span = attribute.span; let span = attribute.span;
stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables))
}) })

View file

@ -1,11 +1,12 @@
use std::iter; use std::iter;
use std::path::PathBuf; use std::path::PathBuf;
use rustc_ast::{AttrArgs, AttrKind, Attribute, MetaItemInner}; use rustc_ast::MetaItemInner;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::codes::*; use rustc_errors::codes::*;
use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{AttrArgs, AttrKind, Attribute};
use rustc_macros::LintDiagnostic; use rustc_macros::LintDiagnostic;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::print::PrintTraitRefExt as _;
@ -639,7 +640,7 @@ impl<'tcx> OnUnimplementedDirective {
let report_span = match &item.args { let report_span = match &item.args {
AttrArgs::Empty => item.path.span, AttrArgs::Empty => item.path.span,
AttrArgs::Delimited(args) => args.dspan.entire(), AttrArgs::Delimited(args) => args.dspan.entire(),
AttrArgs::Eq { eq_span, value } => eq_span.to(value.span()), AttrArgs::Eq { eq_span, expr } => eq_span.to(expr.span),
}; };
if let Some(item_def_id) = item_def_id.as_local() { if let Some(item_def_id) = item_def_id.as_local() {
@ -654,7 +655,7 @@ impl<'tcx> OnUnimplementedDirective {
} }
} else if is_diagnostic_namespace_variant { } else if is_diagnostic_namespace_variant {
match &attr.kind { match &attr.kind {
AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => { AttrKind::Normal(p) if !matches!(p.args, AttrArgs::Empty) => {
if let Some(item_def_id) = item_def_id.as_local() { if let Some(item_def_id) = item_def_id.as_local() {
tcx.emit_node_span_lint( tcx.emit_node_span_lint(
UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,

View file

@ -4,6 +4,7 @@ use std::iter::once;
use std::sync::Arc; use std::sync::Arc;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::Mutability; use rustc_hir::Mutability;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LocalModDefId}; use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LocalModDefId};
@ -15,7 +16,6 @@ use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{Symbol, sym}; use rustc_span::symbol::{Symbol, sym};
use thin_vec::{ThinVec, thin_vec}; use thin_vec::{ThinVec, thin_vec};
use tracing::{debug, trace}; use tracing::{debug, trace};
use {rustc_ast as ast, rustc_hir as hir};
use super::Item; use super::Item;
use crate::clean::{ use crate::clean::{
@ -43,7 +43,7 @@ pub(crate) fn try_inline(
cx: &mut DocContext<'_>, cx: &mut DocContext<'_>,
res: Res, res: Res,
name: Symbol, name: Symbol,
attrs: Option<(&[ast::Attribute], Option<LocalDefId>)>, attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
visited: &mut DefIdSet, visited: &mut DefIdSet,
) -> Option<Vec<clean::Item>> { ) -> Option<Vec<clean::Item>> {
let did = res.opt_def_id()?; let did = res.opt_def_id()?;
@ -206,7 +206,7 @@ pub(crate) fn try_inline_glob(
} }
} }
pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> &'hir [ast::Attribute] { pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> &'hir [hir::Attribute] {
cx.tcx.get_attrs_unchecked(did) cx.tcx.get_attrs_unchecked(did)
} }
@ -360,7 +360,7 @@ fn build_type_alias(
pub(crate) fn build_impls( pub(crate) fn build_impls(
cx: &mut DocContext<'_>, cx: &mut DocContext<'_>,
did: DefId, did: DefId,
attrs: Option<(&[ast::Attribute], Option<LocalDefId>)>, attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
ret: &mut Vec<clean::Item>, ret: &mut Vec<clean::Item>,
) { ) {
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls"); let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls");
@ -392,8 +392,8 @@ pub(crate) fn build_impls(
pub(crate) fn merge_attrs( pub(crate) fn merge_attrs(
cx: &mut DocContext<'_>, cx: &mut DocContext<'_>,
old_attrs: &[ast::Attribute], old_attrs: &[hir::Attribute],
new_attrs: Option<(&[ast::Attribute], Option<LocalDefId>)>, new_attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
) -> (clean::Attributes, Option<Arc<clean::cfg::Cfg>>) { ) -> (clean::Attributes, Option<Arc<clean::cfg::Cfg>>) {
// NOTE: If we have additional attributes (from a re-export), // NOTE: If we have additional attributes (from a re-export),
// always insert them first. This ensure that re-export // always insert them first. This ensure that re-export
@ -404,14 +404,14 @@ pub(crate) fn merge_attrs(
both.extend_from_slice(old_attrs); both.extend_from_slice(old_attrs);
( (
if let Some(item_id) = item_id { if let Some(item_id) = item_id {
Attributes::from_ast_with_additional(old_attrs, (inner, item_id.to_def_id())) Attributes::from_hir_with_additional(old_attrs, (inner, item_id.to_def_id()))
} else { } else {
Attributes::from_ast(&both) Attributes::from_hir(&both)
}, },
both.cfg(cx.tcx, &cx.cache.hidden_cfg), both.cfg(cx.tcx, &cx.cache.hidden_cfg),
) )
} else { } else {
(Attributes::from_ast(old_attrs), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg)) (Attributes::from_hir(old_attrs), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg))
} }
} }
@ -419,7 +419,7 @@ pub(crate) fn merge_attrs(
pub(crate) fn build_impl( pub(crate) fn build_impl(
cx: &mut DocContext<'_>, cx: &mut DocContext<'_>,
did: DefId, did: DefId,
attrs: Option<(&[ast::Attribute], Option<LocalDefId>)>, attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
ret: &mut Vec<clean::Item>, ret: &mut Vec<clean::Item>,
) { ) {
if !cx.inlined.insert(did.into()) { if !cx.inlined.insert(did.into()) {
@ -629,7 +629,7 @@ fn build_module_items(
visited: &mut DefIdSet, visited: &mut DefIdSet,
inlined_names: &mut FxHashSet<(ItemType, Symbol)>, inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
allowed_def_ids: Option<&DefIdSet>, allowed_def_ids: Option<&DefIdSet>,
attrs: Option<(&[ast::Attribute], Option<LocalDefId>)>, attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
) -> Vec<clean::Item> { ) -> Vec<clean::Item> {
let mut items = Vec::new(); let mut items = Vec::new();

View file

@ -201,7 +201,7 @@ fn generate_item_with_correct_attrs(
}; };
let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg); let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
let attrs = Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false); let attrs = Attributes::from_hir_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false);
let name = renamed.or(Some(name)); let name = renamed.or(Some(name));
let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, cfg); let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, cfg);
@ -1036,7 +1036,7 @@ fn clean_fn_or_proc_macro<'tcx>(
/// This is needed to make it more "readable" when documenting functions using /// This is needed to make it more "readable" when documenting functions using
/// `rustc_legacy_const_generics`. More information in /// `rustc_legacy_const_generics`. More information in
/// <https://github.com/rust-lang/rust/issues/83167>. /// <https://github.com/rust-lang/rust/issues/83167>.
fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attribute]) { fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attribute]) {
for meta_item_list in attrs for meta_item_list in attrs
.iter() .iter()
.filter(|a| a.has_name(sym::rustc_legacy_const_generics)) .filter(|a| a.has_name(sym::rustc_legacy_const_generics))
@ -2578,7 +2578,7 @@ fn get_all_import_attributes<'hir>(
import_def_id: LocalDefId, import_def_id: LocalDefId,
target_def_id: DefId, target_def_id: DefId,
is_inline: bool, is_inline: bool,
) -> Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)> { ) -> Vec<(Cow<'hir, hir::Attribute>, Option<DefId>)> {
let mut attrs = Vec::new(); let mut attrs = Vec::new();
let mut first = true; let mut first = true;
for def_id in reexport_chain(cx.tcx, import_def_id, target_def_id) for def_id in reexport_chain(cx.tcx, import_def_id, target_def_id)
@ -2631,9 +2631,9 @@ fn filter_doc_attr_ident(ident: Symbol, is_inline: bool) -> bool {
/// Remove attributes from `normal` that should not be inherited by `use` re-export. /// Remove attributes from `normal` that should not be inherited by `use` re-export.
/// Before calling this function, make sure `normal` is a `#[doc]` attribute. /// Before calling this function, make sure `normal` is a `#[doc]` attribute.
fn filter_doc_attr(normal: &mut ast::NormalAttr, is_inline: bool) { fn filter_doc_attr(args: &mut hir::AttrArgs, is_inline: bool) {
match normal.item.args { match args {
ast::AttrArgs::Delimited(ref mut args) => { hir::AttrArgs::Delimited(ref mut args) => {
let tokens = filter_tokens_from_list(&args.tokens, |token| { let tokens = filter_tokens_from_list(&args.tokens, |token| {
!matches!( !matches!(
token, token,
@ -2651,7 +2651,7 @@ fn filter_doc_attr(normal: &mut ast::NormalAttr, is_inline: bool) {
}); });
args.tokens = TokenStream::new(tokens); args.tokens = TokenStream::new(tokens);
} }
ast::AttrArgs::Empty | ast::AttrArgs::Eq { .. } => {} hir::AttrArgs::Empty | hir::AttrArgs::Eq { .. } => {}
} }
} }
@ -2676,23 +2676,23 @@ fn filter_doc_attr(normal: &mut ast::NormalAttr, is_inline: bool) {
/// * `doc(no_inline)` /// * `doc(no_inline)`
/// * `doc(hidden)` /// * `doc(hidden)`
fn add_without_unwanted_attributes<'hir>( fn add_without_unwanted_attributes<'hir>(
attrs: &mut Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)>, attrs: &mut Vec<(Cow<'hir, hir::Attribute>, Option<DefId>)>,
new_attrs: &'hir [ast::Attribute], new_attrs: &'hir [hir::Attribute],
is_inline: bool, is_inline: bool,
import_parent: Option<DefId>, import_parent: Option<DefId>,
) { ) {
for attr in new_attrs { for attr in new_attrs {
if matches!(attr.kind, ast::AttrKind::DocComment(..)) { if matches!(attr.kind, hir::AttrKind::DocComment(..)) {
attrs.push((Cow::Borrowed(attr), import_parent)); attrs.push((Cow::Borrowed(attr), import_parent));
continue; continue;
} }
let mut attr = attr.clone(); let mut attr = attr.clone();
match attr.kind { match attr.kind {
ast::AttrKind::Normal(ref mut normal) => { hir::AttrKind::Normal(ref mut normal) => {
if let [ident] = &*normal.item.path.segments { if let [ident] = &*normal.path.segments {
let ident = ident.ident.name; let ident = ident.name;
if ident == sym::doc { if ident == sym::doc {
filter_doc_attr(normal, is_inline); filter_doc_attr(&mut normal.args, is_inline);
attrs.push((Cow::Owned(attr), import_parent)); attrs.push((Cow::Owned(attr), import_parent));
} else if is_inline || ident != sym::cfg { } else if is_inline || ident != sym::cfg {
// If it's not a `cfg()` attribute, we keep it. // If it's not a `cfg()` attribute, we keep it.

View file

@ -6,8 +6,6 @@ use std::{fmt, iter};
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use rustc_abi::{ExternAbi, VariantIdx}; use rustc_abi::{ExternAbi, VariantIdx};
use rustc_ast::MetaItemInner;
use rustc_ast_pretty::pprust;
use rustc_attr::{ConstStability, Deprecation, Stability, StableSince}; use rustc_attr::{ConstStability, Deprecation, Stability, StableSince};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def::{CtorKind, DefKind, Res};
@ -454,14 +452,14 @@ impl Item {
kind: ItemKind, kind: ItemKind,
cx: &mut DocContext<'_>, cx: &mut DocContext<'_>,
) -> Item { ) -> Item {
let ast_attrs = cx.tcx.get_attrs_unchecked(def_id); let hir_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,
name, name,
kind, kind,
Attributes::from_ast(ast_attrs), Attributes::from_hir(hir_attrs),
ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg), hir_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
) )
} }
@ -742,10 +740,10 @@ impl Item {
.iter() .iter()
.filter_map(|attr| { .filter_map(|attr| {
if keep_as_is { if keep_as_is {
Some(pprust::attribute_to_string(attr)) Some(rustc_hir_pretty::attribute_to_string(&tcx, attr))
} else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
Some( Some(
pprust::attribute_to_string(attr) rustc_hir_pretty::attribute_to_string(&tcx, attr)
.replace("\\\n", "") .replace("\\\n", "")
.replace('\n', "") .replace('\n', "")
.replace(" ", " "), .replace(" ", " "),
@ -955,7 +953,7 @@ pub(crate) trait AttributesExt {
type AttributeIterator<'a>: Iterator<Item = ast::MetaItemInner> type AttributeIterator<'a>: Iterator<Item = ast::MetaItemInner>
where where
Self: 'a; Self: 'a;
type Attributes<'a>: Iterator<Item = &'a ast::Attribute> type Attributes<'a>: Iterator<Item = &'a hir::Attribute>
where where
Self: 'a; Self: 'a;
@ -1009,7 +1007,7 @@ pub(crate) trait AttributesExt {
// #[doc] // #[doc]
if attr.doc_str().is_none() && attr.has_name(sym::doc) { if attr.doc_str().is_none() && attr.has_name(sym::doc) {
// #[doc(...)] // #[doc(...)]
if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) { if let Some(list) = attr.meta_item_list() {
for item in list { for item in list {
// #[doc(hidden)] // #[doc(hidden)]
if !item.has_name(sym::cfg) { if !item.has_name(sym::cfg) {
@ -1042,7 +1040,7 @@ pub(crate) trait AttributesExt {
let mut meta = attr.meta_item().unwrap().clone(); let mut meta = attr.meta_item().unwrap().clone();
meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature));
if let Ok(feat_cfg) = Cfg::parse(&MetaItemInner::MetaItem(meta)) { if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) {
cfg &= feat_cfg; cfg &= feat_cfg;
} }
} }
@ -1053,14 +1051,14 @@ pub(crate) trait AttributesExt {
} }
} }
impl AttributesExt for [ast::Attribute] { impl AttributesExt for [hir::Attribute] {
type AttributeIterator<'a> = impl Iterator<Item = ast::MetaItemInner> + 'a; type AttributeIterator<'a> = impl Iterator<Item = ast::MetaItemInner> + 'a;
type Attributes<'a> = impl Iterator<Item = &'a ast::Attribute> + 'a; type Attributes<'a> = impl Iterator<Item = &'a hir::Attribute> + 'a;
fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> { fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> {
self.iter() self.iter()
.filter(move |attr| attr.has_name(name)) .filter(move |attr| attr.has_name(name))
.filter_map(ast::Attribute::meta_item_list) .filter_map(ast::attr::AttributeExt::meta_item_list)
.flatten() .flatten()
} }
@ -1069,20 +1067,20 @@ impl AttributesExt for [ast::Attribute] {
} }
} }
impl AttributesExt for [(Cow<'_, ast::Attribute>, Option<DefId>)] { impl AttributesExt for [(Cow<'_, hir::Attribute>, Option<DefId>)] {
type AttributeIterator<'a> type AttributeIterator<'a>
= impl Iterator<Item = ast::MetaItemInner> + 'a = impl Iterator<Item = ast::MetaItemInner> + 'a
where where
Self: 'a; Self: 'a;
type Attributes<'a> type Attributes<'a>
= impl Iterator<Item = &'a ast::Attribute> + 'a = impl Iterator<Item = &'a hir::Attribute> + 'a
where where
Self: 'a; Self: 'a;
fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> { fn lists(&self, name: Symbol) -> Self::AttributeIterator<'_> {
AttributesExt::iter(self) AttributesExt::iter(self)
.filter(move |attr| attr.has_name(name)) .filter(move |attr| attr.has_name(name))
.filter_map(ast::Attribute::meta_item_list) .filter_map(hir::Attribute::meta_item_list)
.flatten() .flatten()
} }
@ -1152,7 +1150,7 @@ pub struct RenderedLink {
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub(crate) struct Attributes { pub(crate) struct Attributes {
pub(crate) doc_strings: Vec<DocFragment>, pub(crate) doc_strings: Vec<DocFragment>,
pub(crate) other_attrs: ast::AttrVec, pub(crate) other_attrs: Vec<hir::Attribute>,
} }
impl Attributes { impl Attributes {
@ -1180,22 +1178,22 @@ impl Attributes {
self.has_doc_flag(sym::hidden) self.has_doc_flag(sym::hidden)
} }
pub(crate) fn from_ast(attrs: &[ast::Attribute]) -> Attributes { pub(crate) fn from_hir(attrs: &[hir::Attribute]) -> Attributes {
Attributes::from_ast_iter(attrs.iter().map(|attr| (attr, None)), false) Attributes::from_hir_iter(attrs.iter().map(|attr| (attr, None)), false)
} }
pub(crate) fn from_ast_with_additional( pub(crate) fn from_hir_with_additional(
attrs: &[ast::Attribute], attrs: &[hir::Attribute],
(additional_attrs, def_id): (&[ast::Attribute], DefId), (additional_attrs, def_id): (&[hir::Attribute], DefId),
) -> Attributes { ) -> Attributes {
// Additional documentation should be shown before the original documentation. // Additional documentation should be shown before the original documentation.
let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id))); let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
let attrs2 = attrs.iter().map(|attr| (attr, None)); let attrs2 = attrs.iter().map(|attr| (attr, None));
Attributes::from_ast_iter(attrs1.chain(attrs2), false) Attributes::from_hir_iter(attrs1.chain(attrs2), false)
} }
pub(crate) fn from_ast_iter<'a>( pub(crate) fn from_hir_iter<'a>(
attrs: impl Iterator<Item = (&'a ast::Attribute, Option<DefId>)>, attrs: impl Iterator<Item = (&'a hir::Attribute, Option<DefId>)>,
doc_only: bool, doc_only: bool,
) -> Attributes { ) -> Attributes {
let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only); let (doc_strings, other_attrs) = attrs_to_doc_fragments(attrs, doc_only);

View file

@ -578,7 +578,7 @@ pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool {
} }
pub(crate) fn attrs_have_doc_flag<'a>( pub(crate) fn attrs_have_doc_flag<'a>(
mut attrs: impl Iterator<Item = &'a ast::Attribute>, mut attrs: impl Iterator<Item = &'a hir::Attribute>,
flag: Symbol, flag: Symbol,
) -> bool { ) -> bool {
attrs attrs

View file

@ -13,10 +13,10 @@ use std::{panic, str};
pub(crate) use make::DocTestBuilder; pub(crate) use make::DocTestBuilder;
pub(crate) use markdown::test as test_markdown; pub(crate) use markdown::test as test_markdown;
use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::emitter::HumanReadableErrorType;
use rustc_errors::{ColorConfig, DiagCtxtHandle}; use rustc_errors::{ColorConfig, DiagCtxtHandle};
use rustc_hir as hir;
use rustc_hir::CRATE_HIR_ID; use rustc_hir::CRATE_HIR_ID;
use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::def_id::LOCAL_CRATE;
use rustc_interface::interface; use rustc_interface::interface;
@ -325,7 +325,7 @@ pub(crate) fn run_tests(
// Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade. // Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade.
fn scrape_test_config( fn scrape_test_config(
crate_name: String, crate_name: String,
attrs: &[ast::Attribute], attrs: &[hir::Attribute],
args_file: PathBuf, args_file: PathBuf,
) -> GlobalTestOptions { ) -> GlobalTestOptions {
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;

View file

@ -110,7 +110,7 @@ impl HirCollector<'_> {
// The collapse-docs pass won't combine sugared/raw doc attributes, or included files with // The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
// anything else, this will combine them for us. // anything else, this will combine them for us.
let attrs = Attributes::from_ast(ast_attrs); let attrs = Attributes::from_hir(ast_attrs);
if let Some(doc) = attrs.opt_doc_value() { if let Some(doc) = attrs.opt_doc_value() {
let span = span_of_fragments(&attrs.doc_strings).unwrap_or(sp); let span = span_of_fragments(&attrs.doc_strings).unwrap_or(sp);
self.collector.position = if span.edition().at_least_rust_2024() { self.collector.position = if span.edition().at_least_rust_2024() {

View file

@ -1,7 +1,7 @@
use super::INLINE_ALWAYS; use super::INLINE_ALWAYS;
use super::utils::is_word; use super::utils::is_word;
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use rustc_ast::Attribute; use rustc_hir::Attribute;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_span::{Span, sym}; use rustc_span::{Span, sym};

View file

@ -2,14 +2,14 @@ use super::{Attribute, SHOULD_PANIC_WITHOUT_EXPECT};
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::token::{Token, TokenKind}; use rustc_ast::token::{Token, TokenKind};
use rustc_ast::tokenstream::TokenTree; use rustc_ast::tokenstream::TokenTree;
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind}; use rustc_ast::{AttrArgs, AttrKind};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::EarlyContext; use rustc_lint::EarlyContext;
use rustc_span::sym; use rustc_span::sym;
pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) { pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute) {
if let AttrKind::Normal(normal_attr) = &attr.kind { if let AttrKind::Normal(normal_attr) = &attr.kind {
if let AttrArgs::Eq { value: AttrArgsEq::Ast(_), .. } = &normal_attr.item.args { if let AttrArgs::Eq { .. } = &normal_attr.item.args {
// `#[should_panic = ".."]` found, good // `#[should_panic = ".."]` found, good
return; return;
} }

View file

@ -5,9 +5,8 @@ use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn}; use clippy_utils::{LimitStack, get_async_fn_body, is_async_fn};
use core::ops::ControlFlow; use core::ops::ControlFlow;
use rustc_ast::ast::Attribute;
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, Expr, ExprKind, FnDecl}; use rustc_hir::{Attribute, Body, Expr, ExprKind, FnDecl};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;

View file

@ -2,10 +2,10 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{SpanRangeExt, snippet_indent}; use clippy_utils::source::{SpanRangeExt, snippet_indent};
use clippy_utils::tokenize_with_text; use clippy_utils::tokenize_with_text;
use itertools::Itertools; use itertools::Itertools;
use rustc_ast::AttrStyle;
use rustc_ast::token::CommentKind; use rustc_ast::token::CommentKind;
use rustc_ast::{AttrKind, AttrStyle, Attribute};
use rustc_errors::{Applicability, Diag, SuggestionStyle}; use rustc_errors::{Applicability, Diag, SuggestionStyle};
use rustc_hir::{ItemKind, Node}; use rustc_hir::{AttrKind, Attribute, ItemKind, Node};
use rustc_lexer::TokenKind; use rustc_lexer::TokenKind;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::{BytePos, ExpnKind, InnerSpan, Span, SpanData}; use rustc_span::{BytePos, ExpnKind, InnerSpan, Span, SpanData};

View file

@ -1,18 +1,18 @@
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, AttrStyle, Attribute}; use rustc_ast::{AttrStyle};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::sym; use rustc_hir::{Attribute, AttrKind, AttrArgs};
use super::DOC_INCLUDE_WITHOUT_CFG; use super::DOC_INCLUDE_WITHOUT_CFG;
pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) {
for attr in attrs { for attr in attrs {
if !attr.span.from_expansion() if !attr.span.from_expansion()
&& let AttrKind::Normal(ref normal) = attr.kind && let AttrKind::Normal(ref item) = attr.kind
&& normal.item.path == sym::doc && attr.doc_str().is_some()
&& let AttrArgs::Eq { value: AttrArgsEq::Hir(ref meta), .. } = normal.item.args && let AttrArgs::Eq { expr: meta, .. } = &item.args
&& !attr.span.contains(meta.span) && !attr.span.contains(meta.span)
// Since the `include_str` is already expanded at this point, we can only take the // Since the `include_str` is already expanded at this point, we can only take the
// whole attribute snippet and then modify for our suggestion. // whole attribute snippet and then modify for our suggestion.

View file

@ -16,10 +16,9 @@ use pulldown_cmark::Event::{
}; };
use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph}; use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph};
use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd}; use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd};
use rustc_ast::ast::Attribute;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AnonConst, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind}; use rustc_hir::{AnonConst, Attribute, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;

View file

@ -1,7 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use rustc_ast::AttrStyle;
use rustc_ast::token::CommentKind; use rustc_ast::token::CommentKind;
use rustc_ast::{AttrKind, AttrStyle, Attribute};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::Attribute;
use rustc_lint::LateContext; use rustc_lint::LateContext;
use rustc_span::Span; use rustc_span::Span;
@ -35,7 +36,7 @@ fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> {
attrs attrs
.iter() .iter()
.filter_map(|attr| { .filter_map(|attr| {
if let AttrKind::DocComment(com_kind, sym) = attr.kind if let Some((sym, com_kind)) = attr.doc_str_and_comment_kind()
&& let AttrStyle::Outer = attr.style && let AttrStyle::Outer = attr.style
&& let Some(com) = sym.as_str().strip_prefix('!') && let Some(com) = sym.as_str().strip_prefix('!')
{ {

View file

@ -1,6 +1,5 @@
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind}; use rustc_hir::{Attribute, Item, ItemKind};
use rustc_lint::LateContext; use rustc_lint::LateContext;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;

View file

@ -1,9 +1,8 @@
use hir::FnSig; use hir::FnSig;
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::def_id::DefIdSet; use rustc_hir::def_id::DefIdSet;
use rustc_hir::{self as hir, QPath}; use rustc_hir::{self as hir, Attribute, QPath};
use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::{LateContext, LintContext}; use rustc_lint::{LateContext, LintContext};
use rustc_middle::lint::in_external_macro; use rustc_middle::lint::in_external_macro;

View file

@ -2,8 +2,8 @@ use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::source::snippet_opt; use clippy_utils::source::snippet_opt;
use rustc_ast::{AttrArgs, AttrArgsEq, AttrKind, Attribute, LitKind}; use rustc_ast::{LitKind};
use rustc_hir::{Expr, ExprKind}; use rustc_hir::{Expr, ExprKind, Attribute, AttrArgs, AttrKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
use rustc_span::{Span, sym}; use rustc_span::{Span, sym};
@ -93,10 +93,10 @@ impl LateLintPass<'_> for LargeIncludeFile {
if !attr.span.from_expansion() if !attr.span.from_expansion()
// Currently, rustc limits the usage of macro at the top-level of attributes, // Currently, rustc limits the usage of macro at the top-level of attributes,
// so we don't need to recurse into each level. // so we don't need to recurse into each level.
&& let AttrKind::Normal(ref normal) = attr.kind && let AttrKind::Normal(ref item) = attr.kind
&& let Some(doc) = attr.doc_str() && let Some(doc) = attr.doc_str()
&& doc.as_str().len() as u64 > self.max_file_size && doc.as_str().len() as u64 > self.max_file_size
&& let AttrArgs::Eq { value: AttrArgsEq::Hir(ref meta), .. } = normal.item.args && let AttrArgs::Eq { expr: meta, .. } = &item.args
&& !attr.span.contains(meta.span) && !attr.span.contains(meta.span)
// Since the `include_str` is already expanded at this point, we can only take the // Since the `include_str` is already expanded at this point, we can only take the
// whole attribute snippet and then modify for our suggestion. // whole attribute snippet and then modify for our suggestion.

View file

@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use hir::def::{DefKind, Res}; use hir::def::{DefKind, Res};
use rustc_ast::ast;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir as hir; use rustc_hir as hir;
@ -104,7 +103,7 @@ impl LateLintPass<'_> for MacroUseImports {
self.push_unique_macro_pat_ty(cx, item.span); self.push_unique_macro_pat_ty(cx, item.span);
} }
} }
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &hir::Attribute) {
if attr.span.from_expansion() { if attr.span.from_expansion() {
self.push_unique_macro(cx, attr.span); self.push_unique_macro(cx, attr.span);
} }

View file

@ -2,9 +2,9 @@ use super::REDUNDANT_PATTERN_MATCHING;
use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability; use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment}; use clippy_utils::{is_lint_allowed, is_wild, span_contains_comment};
use rustc_ast::{Attribute, LitKind}; use rustc_ast::LitKind;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Pat, PatKind, QPath}; use rustc_hir::{Arm, Attribute, BorrowKind, Expr, ExprKind, Pat, PatKind, QPath};
use rustc_lint::{LateContext, LintContext}; use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty; use rustc_middle::ty;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;

View file

@ -10,8 +10,9 @@ use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::is_from_proc_macro; use clippy_utils::is_from_proc_macro;
use clippy_utils::source::SpanRangeExt; use clippy_utils::source::SpanRangeExt;
use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_ast::ast::MetaItemInner;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::Attribute;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
@ -67,9 +68,8 @@ impl MissingDoc {
*self.doc_hidden_stack.last().expect("empty doc_hidden_stack") *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
} }
fn has_include(meta: Option<MetaItem>) -> bool { fn has_include(meta: Option<&[MetaItemInner]>) -> bool {
if let Some(meta) = meta if let Some(list) = meta
&& let MetaItemKind::List(list) = meta.kind
&& let Some(meta) = list.first() && let Some(meta) = list.first()
&& let Some(name) = meta.ident() && let Some(name) = meta.ident()
{ {
@ -83,7 +83,7 @@ impl MissingDoc {
&self, &self,
cx: &LateContext<'_>, cx: &LateContext<'_>,
def_id: LocalDefId, def_id: LocalDefId,
attrs: &[ast::Attribute], attrs: &[Attribute],
sp: Span, sp: Span,
article: &'static str, article: &'static str,
desc: &'static str, desc: &'static str,
@ -129,7 +129,7 @@ impl MissingDoc {
let has_doc = attrs let has_doc = attrs
.iter() .iter()
.any(|a| a.doc_str().is_some() || Self::has_include(a.meta())) .any(|a| a.doc_str().is_some() || Self::has_include(a.meta_item_list().as_deref()))
|| matches!(self.search_span(sp), Some(span) if span_to_snippet_contains_docs(cx, span)); || matches!(self.search_span(sp), Some(span) if span_to_snippet_contains_docs(cx, span));
if !has_doc { if !has_doc {
@ -172,12 +172,12 @@ impl MissingDoc {
impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]); impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]);
impl<'tcx> LateLintPass<'tcx> for MissingDoc { impl<'tcx> LateLintPass<'tcx> for MissingDoc {
fn check_attributes(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) { fn check_attributes(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
let doc_hidden = self.doc_hidden() || is_doc_hidden(attrs); let doc_hidden = self.doc_hidden() || is_doc_hidden(attrs);
self.doc_hidden_stack.push(doc_hidden); self.doc_hidden_stack.push(doc_hidden);
} }
fn check_attributes_post(&mut self, _: &LateContext<'tcx>, _: &'tcx [ast::Attribute]) { fn check_attributes_post(&mut self, _: &LateContext<'tcx>, _: &'tcx [Attribute]) {
self.doc_hidden_stack.pop().expect("empty doc_hidden_stack"); self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
} }

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::Attribute;
use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::AssocItemContainer; use rustc_middle::ty::AssocItemContainer;
use rustc_session::declare_lint_pass; use rustc_session::declare_lint_pass;
@ -63,7 +63,7 @@ declare_clippy_lint! {
"detects missing `#[inline]` attribute for public callables (functions, trait methods, methods...)" "detects missing `#[inline]` attribute for public callables (functions, trait methods, methods...)"
} }
fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) { fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[Attribute], sp: Span, desc: &'static str) {
let has_inline = attrs.iter().any(|a| a.has_name(sym::inline)); let has_inline = attrs.iter().any(|a| a.has_name(sym::inline));
if !has_inline { if !has_inline {
span_lint( span_lint(

View file

@ -5,12 +5,11 @@ use clippy_utils::source::{SpanRangeExt, snippet};
use clippy_utils::ty::{ use clippy_utils::ty::{
implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
}; };
use rustc_ast::ast::Attribute;
use rustc_errors::{Applicability, Diag}; use rustc_errors::{Applicability, Diag};
use rustc_hir::intravisit::FnKind; use rustc_hir::intravisit::FnKind;
use rustc_hir::{ use rustc_hir::{
BindingMode, Body, FnDecl, GenericArg, HirId, HirIdSet, Impl, ItemKind, LangItem, Mutability, Node, PatKind, QPath, Attribute, BindingMode, Body, FnDecl, GenericArg, HirId, HirIdSet, Impl, ItemKind, LangItem, Mutability, Node,
TyKind, PatKind, QPath, TyKind,
}; };
use rustc_hir_typeck::expr_use_visitor as euv; use rustc_hir_typeck::expr_use_visitor as euv;
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};

View file

@ -872,8 +872,7 @@ pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool {
match (l, r) { match (l, r) {
(Empty, Empty) => true, (Empty, Empty) => true,
(Delimited(la), Delimited(ra)) => eq_delim_args(la, ra), (Delimited(la), Delimited(ra)) => eq_delim_args(la, ra),
(Eq { value: AttrArgsEq::Ast(le), .. }, Eq{ value: AttrArgsEq::Ast(re), .. }) => eq_expr(le, re), (Eq { eq_span: _, expr: le }, Eq { eq_span: _, expr: re }) => eq_expr(le, re),
(Eq { value: AttrArgsEq::Hir(ll), .. }, Eq{ value: AttrArgsEq::Hir(rl), .. }) => ll.kind == rl.kind,
_ => false, _ => false,
} }
} }

View file

@ -1,4 +1,5 @@
use rustc_ast::{ast, attr}; use rustc_ast::attr;
use rustc_ast::attr::AttributeExt;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_lexer::TokenKind; use rustc_lexer::TokenKind;
use rustc_lint::LateContext; use rustc_lint::LateContext;
@ -51,33 +52,31 @@ impl LimitStack {
pub fn limit(&self) -> u64 { pub fn limit(&self) -> u64 {
*self.stack.last().expect("there should always be a value in the stack") *self.stack.last().expect("there should always be a value in the stack")
} }
pub fn push_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { pub fn push_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) {
let stack = &mut self.stack; let stack = &mut self.stack;
parse_attrs(sess, attrs, name, |val| stack.push(val)); parse_attrs(sess, attrs, name, |val| stack.push(val));
} }
pub fn pop_attrs(&mut self, sess: &Session, attrs: &[ast::Attribute], name: &'static str) { pub fn pop_attrs(&mut self, sess: &Session, attrs: &[impl AttributeExt], name: &'static str) {
let stack = &mut self.stack; let stack = &mut self.stack;
parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val))); parse_attrs(sess, attrs, name, |val| assert_eq!(stack.pop(), Some(val)));
} }
} }
pub fn get_attr<'a>( pub fn get_attr<'a, A: AttributeExt + 'a>(
sess: &'a Session, sess: &'a Session,
attrs: &'a [ast::Attribute], attrs: &'a [A],
name: &'static str, name: &'static str,
) -> impl Iterator<Item = &'a ast::Attribute> { ) -> impl Iterator<Item = &'a A> {
attrs.iter().filter(move |attr| { attrs.iter().filter(move |attr| {
let attr = if let ast::AttrKind::Normal(ref normal) = attr.kind { let Some(attr_segments) = attr.ident_path() else {
&normal.item
} else {
return false; return false;
}; };
let attr_segments = &attr.path.segments;
if attr_segments.len() == 2 && attr_segments[0].ident.name == sym::clippy { if attr_segments.len() == 2 && attr_segments[0].name == sym::clippy {
BUILTIN_ATTRIBUTES BUILTIN_ATTRIBUTES
.iter() .iter()
.find_map(|&(builtin_name, ref deprecation_status)| { .find_map(|&(builtin_name, ref deprecation_status)| {
if attr_segments[1].ident.name.as_str() == builtin_name { if attr_segments[1].name.as_str() == builtin_name {
Some(deprecation_status) Some(deprecation_status)
} else { } else {
None None
@ -85,14 +84,13 @@ pub fn get_attr<'a>(
}) })
.map_or_else( .map_or_else(
|| { || {
sess.dcx() sess.dcx().span_err(attr_segments[1].span, "usage of unknown attribute");
.span_err(attr_segments[1].ident.span, "usage of unknown attribute");
false false
}, },
|deprecation_status| { |deprecation_status| {
let mut diag = sess let mut diag = sess
.dcx() .dcx()
.struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute"); .struct_span_err(attr_segments[1].span, "usage of deprecated attribute");
match *deprecation_status { match *deprecation_status {
DeprecationStatus::Deprecated => { DeprecationStatus::Deprecated => {
diag.emit(); diag.emit();
@ -100,7 +98,7 @@ pub fn get_attr<'a>(
}, },
DeprecationStatus::Replaced(new_name) => { DeprecationStatus::Replaced(new_name) => {
diag.span_suggestion( diag.span_suggestion(
attr_segments[1].ident.span, attr_segments[1].span,
"consider using", "consider using",
new_name, new_name,
Applicability::MachineApplicable, Applicability::MachineApplicable,
@ -110,7 +108,7 @@ pub fn get_attr<'a>(
}, },
DeprecationStatus::None => { DeprecationStatus::None => {
diag.cancel(); diag.cancel();
attr_segments[1].ident.name.as_str() == name attr_segments[1].as_str() == name
}, },
} }
}, },
@ -121,31 +119,31 @@ pub fn get_attr<'a>(
}) })
} }
fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'static str, mut f: F) { fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[impl AttributeExt], name: &'static str, mut f: F) {
for attr in get_attr(sess, attrs, name) { for attr in get_attr(sess, attrs, name) {
if let Some(ref value) = attr.value_str() { if let Some(ref value) = attr.value_str() {
if let Ok(value) = FromStr::from_str(value.as_str()) { if let Ok(value) = FromStr::from_str(value.as_str()) {
f(value); f(value);
} else { } else {
sess.dcx().span_err(attr.span, "not a number"); sess.dcx().span_err(attr.span(), "not a number");
} }
} else { } else {
sess.dcx().span_err(attr.span, "bad clippy attribute"); sess.dcx().span_err(attr.span(), "bad clippy attribute");
} }
} }
} }
pub fn get_unique_attr<'a>( pub fn get_unique_attr<'a, A: AttributeExt>(
sess: &'a Session, sess: &'a Session,
attrs: &'a [ast::Attribute], attrs: &'a [A],
name: &'static str, name: &'static str,
) -> Option<&'a ast::Attribute> { ) -> Option<&'a A> {
let mut unique_attr: Option<&ast::Attribute> = None; let mut unique_attr: Option<&A> = None;
for attr in get_attr(sess, attrs, name) { for attr in get_attr(sess, attrs, name) {
if let Some(duplicate) = unique_attr { if let Some(duplicate) = unique_attr {
sess.dcx() sess.dcx()
.struct_span_err(attr.span, format!("`{name}` is defined multiple times")) .struct_span_err(attr.span(), format!("`{name}` is defined multiple times"))
.with_span_note(duplicate.span, "first definition found here") .with_span_note(duplicate.span(), "first definition found here")
.emit(); .emit();
} else { } else {
unique_attr = Some(attr); unique_attr = Some(attr);
@ -156,16 +154,16 @@ pub fn get_unique_attr<'a>(
/// Returns true if the attributes contain any of `proc_macro`, /// Returns true if the attributes contain any of `proc_macro`,
/// `proc_macro_derive` or `proc_macro_attribute`, false otherwise /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool { pub fn is_proc_macro(attrs: &[impl AttributeExt]) -> bool {
attrs.iter().any(rustc_ast::Attribute::is_proc_macro_attr) attrs.iter().any(AttributeExt::is_proc_macro_attr)
} }
/// Returns true if the attributes contain `#[doc(hidden)]` /// Returns true if the attributes contain `#[doc(hidden)]`
pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool { pub fn is_doc_hidden(attrs: &[impl AttributeExt]) -> bool {
attrs attrs
.iter() .iter()
.filter(|attr| attr.has_name(sym::doc)) .filter(|attr| attr.has_name(sym::doc))
.filter_map(ast::Attribute::meta_item_list) .filter_map(AttributeExt::meta_item_list)
.any(|l| attr::list_contains_name(&l, sym::hidden)) .any(|l| attr::list_contains_name(&l, sym::hidden))
} }

View file

@ -135,13 +135,24 @@ use rustc_middle::hir::nested_filter;
#[macro_export] #[macro_export]
macro_rules! extract_msrv_attr { macro_rules! extract_msrv_attr {
($context:ident) => { (LateContext) => {
fn check_attributes(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { fn check_attributes(&mut self, cx: &rustc_lint::LateContext<'_>, attrs: &[rustc_hir::Attribute]) {
let sess = rustc_lint::LintContext::sess(cx); let sess = rustc_lint::LintContext::sess(cx);
self.msrv.check_attributes(sess, attrs); self.msrv.check_attributes(sess, attrs);
} }
fn check_attributes_post(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) { fn check_attributes_post(&mut self, cx: &rustc_lint::LateContext<'_>, attrs: &[rustc_hir::Attribute]) {
let sess = rustc_lint::LintContext::sess(cx);
self.msrv.check_attributes_post(sess, attrs);
}
};
(EarlyContext) => {
fn check_attributes(&mut self, cx: &rustc_lint::EarlyContext<'_>, attrs: &[rustc_ast::Attribute]) {
let sess = rustc_lint::LintContext::sess(cx);
self.msrv.check_attributes(sess, attrs);
}
fn check_attributes_post(&mut self, cx: &rustc_lint::EarlyContext<'_>, attrs: &[rustc_ast::Attribute]) {
let sess = rustc_lint::LintContext::sess(cx); let sess = rustc_lint::LintContext::sess(cx);
self.msrv.check_attributes_post(sess, attrs); self.msrv.check_attributes_post(sess, attrs);
} }
@ -1912,7 +1923,7 @@ pub fn clip(tcx: TyCtxt<'_>, u: u128, ity: UintTy) -> u128 {
(u << amt) >> amt (u << amt) >> amt
} }
pub fn has_attr(attrs: &[ast::Attribute], symbol: Symbol) -> bool { pub fn has_attr(attrs: &[hir::Attribute], symbol: Symbol) -> bool {
attrs.iter().any(|attr| attr.has_name(symbol)) attrs.iter().any(|attr| attr.has_name(symbol))
} }
@ -2263,21 +2274,13 @@ pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> {
pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool { pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| { cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
if let ast::AttrKind::Normal(ref normal) = attr.kind { attr.name_or_empty() == sym::no_std
normal.item.path == sym::no_std
} else {
false
}
}) })
} }
pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| { cx.tcx.hir().attrs(hir::CRATE_HIR_ID).iter().any(|attr| {
if let ast::AttrKind::Normal(ref normal) = attr.kind { attr.name_or_empty() == sym::no_core
normal.item.path == sym::no_core
} else {
false
}
}) })
} }

View file

@ -1,4 +1,4 @@
use rustc_ast::Attribute; use rustc_attr::AttributeExt;
use rustc_attr::parse_version; use rustc_attr::parse_version;
use rustc_session::{RustcVersion, Session}; use rustc_session::{RustcVersion, Session};
use rustc_span::{Symbol, sym}; use rustc_span::{Symbol, sym};
@ -124,15 +124,15 @@ impl Msrv {
self.current().is_none_or(|msrv| msrv >= required) self.current().is_none_or(|msrv| msrv >= required)
} }
fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> { fn parse_attr(sess: &Session, attrs: &[impl AttributeExt]) -> Option<RustcVersion> {
let sym_msrv = Symbol::intern("msrv"); let sym_msrv = Symbol::intern("msrv");
let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv])); let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv]));
if let Some(msrv_attr) = msrv_attrs.next() { if let Some(msrv_attr) = msrv_attrs.next() {
if let Some(duplicate) = msrv_attrs.last() { if let Some(duplicate) = msrv_attrs.last() {
sess.dcx() sess.dcx()
.struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times") .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times")
.with_span_note(msrv_attr.span, "first definition found here") .with_span_note(msrv_attr.span(), "first definition found here")
.emit(); .emit();
} }
@ -142,22 +142,22 @@ impl Msrv {
} }
sess.dcx() sess.dcx()
.span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version")); .span_err(msrv_attr.span(), format!("`{msrv}` is not a valid Rust version"));
} else { } else {
sess.dcx().span_err(msrv_attr.span, "bad clippy attribute"); sess.dcx().span_err(msrv_attr.span(), "bad clippy attribute");
} }
} }
None None
} }
pub fn check_attributes(&mut self, sess: &Session, attrs: &[Attribute]) { pub fn check_attributes(&mut self, sess: &Session, attrs: &[impl AttributeExt]) {
if let Some(version) = Self::parse_attr(sess, attrs) { if let Some(version) = Self::parse_attr(sess, attrs) {
self.stack.push(version); self.stack.push(version);
} }
} }
pub fn check_attributes_post(&mut self, sess: &Session, attrs: &[Attribute]) { pub fn check_attributes_post(&mut self, sess: &Session, attrs: &[impl AttributeExt]) {
if Self::parse_attr(sess, attrs).is_some() { if Self::parse_attr(sess, attrs).is_some() {
self.stack.pop(); self.stack.pop();
} }

View file

@ -7,9 +7,7 @@ extern crate std;
// issue#97006 // issue#97006
macro_rules! m { ($attr_path: path) => { #[$attr_path] fn f() {} } } macro_rules! m { ($attr_path: path) => { #[$attr_path] fn f() {} } }
#[ #[inline]
inline]
fn f() { } fn f() { }
fn main() { } fn main() { }