diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index c3222b79e55c9..5079f7d8bc76f 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -1,4 +1,5 @@ use rustc_ast::{Block, BlockCheckMode, Local, LocalKind, Stmt, StmtKind}; +use rustc_attr_parsing::AttrTarget; use rustc_hir as hir; use rustc_span::sym; use smallvec::SmallVec; @@ -109,7 +110,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs(hir_id, &l.attrs, l.span); + self.lower_attrs(hir_id, &l.attrs, l.span, AttrTarget::Let); self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 8747e624a4a9e..420d4331fa74f 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -5,6 +5,7 @@ use rustc_ast::ptr::P as AstP; use rustc_ast::*; use rustc_ast_pretty::pprust::expr_to_string; use rustc_attr_data_structures::{AttributeKind, find_attr}; +use rustc_attr_parsing::AttrTarget; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::HirId; @@ -14,7 +15,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{Spanned, respan}; use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; -use thin_vec::{ThinVec, thin_vec}; +use thin_vec::ThinVec; use visit::{Visitor, walk_expr}; use super::errors::{ @@ -75,7 +76,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if !e.attrs.is_empty() { let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); let new_attrs = self - .lower_attrs_vec(&e.attrs, e.span, ex.hir_id) + .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, AttrTarget::from_expr(e)) .into_iter() .chain(old_attrs.iter().cloned()); let new_attrs = &*self.arena.alloc_from_iter(new_attrs); @@ -98,7 +99,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span); + self.lower_attrs(expr_hir_id, &e.attrs, e.span, AttrTarget::from_expr(e)); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -674,7 +675,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs, arm.span); + self.lower_attrs(hir_id, &arm.attrs, arm.span, AttrTarget::Arm); let is_never_pattern = pat.is_never_pattern(); // We need to lower the body even if it's unneeded for never pattern in match, // ensure that we can get HirId for DefId if need (issue #137708). @@ -825,6 +826,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, outer_hir_id: HirId, inner_hir_id: HirId, + target: AttrTarget<'_>, ) { if self.tcx.features().async_fn_track_caller() && let Some(attrs) = self.attrs.get(&outer_hir_id.local_id) @@ -847,6 +849,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: unstable_span, }], span, + target, ); } } @@ -1218,7 +1221,12 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::CoroutineSource::Closure, ); - this.maybe_forward_track_caller(body.span, closure_hir_id, expr.hir_id); + this.maybe_forward_track_caller( + body.span, + closure_hir_id, + expr.hir_id, + AttrTarget::from_expr(body), + ); (parameters, expr) }); @@ -1687,7 +1695,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, AttrTarget::ExprField); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1943,7 +1951,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // Also, add the attributes to the outer returned expr node. let expr = self.expr_drop_temps_mut(for_span, match_expr); - self.lower_attrs(expr.hir_id, &e.attrs, e.span); + self.lower_attrs(expr.hir_id, &e.attrs, e.span, AttrTarget::from_expr(e)); expr } @@ -1985,22 +1993,21 @@ impl<'hir> LoweringContext<'_, 'hir> { }; // `#[allow(unreachable_code)]` - let attr = attr::mk_attr_nested_word( + let attrs = &[attr::mk_attr_nested_word( &self.tcx.sess.psess.attr_id_generator, AttrStyle::Outer, Safety::Default, sym::allow, sym::unreachable_code, try_span, - ); - let attrs: AttrVec = thin_vec![attr]; + )]; // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,` let continue_arm = { let val_ident = Ident::with_dummy_span(sym::val); let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); let val_expr = self.expr_ident(span, val_ident, val_pat_nid); - self.lower_attrs(val_expr.hir_id, &attrs, span); + self.lower_attrs(val_expr.hir_id, attrs, span, AttrTarget::Expression { kind: None }); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr) }; @@ -2031,7 +2038,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ret_expr = self.checked_return(Some(from_residual_expr)); self.arena.alloc(self.expr(try_span, ret_expr)) }; - self.lower_attrs(ret_expr.hir_id, &attrs, span); + self.lower_attrs(ret_expr.hir_id, attrs, span, AttrTarget::Expression { kind: None }); let break_pat = self.pat_cf_break(try_span, residual_local); self.arm(break_pat, ret_expr) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 8acb510577302..2f4e667078b3f 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -2,6 +2,7 @@ use rustc_abi::ExternAbi; use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; +use rustc_attr_parsing::{AttrTarget, Position}; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def::{DefKind, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; @@ -83,7 +84,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); // FIXME(jdonszelman): is dummy span ever a problem here? - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP); + lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP, AttrTarget::Crate); hir::OwnerNode::Crate(module) }) } @@ -139,7 +140,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> { let vis_span = self.lower_span(i.vis.span); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, AttrTarget::from_item(&i.kind)); let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind); let item = hir::Item { owner_id: hir_id.expect_owner(), @@ -229,6 +230,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body.as_deref(), attrs, contract.as_deref(), + AttrTarget::from_item(i), ); let itctx = ImplTraitContext::Universal; @@ -642,7 +644,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, AttrTarget::from_foreign(i)); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(box Fn { sig, ident, generics, define_opaque, .. }) => { let fdec = &sig.decl; @@ -717,7 +719,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_variant(&mut self, item_kind: &ItemKind, v: &Variant) -> hir::Variant<'hir> { let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span); + self.lower_attrs(hir_id, &v.attrs, v.span, AttrTarget::EnumVariant); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -800,7 +802,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::FieldDef<'hir> { let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, AttrTarget::Field); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -819,7 +821,8 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let target = AttrTarget::from_trait_item(i); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, target); let trait_item_def_id = hir_id.expect_owner(); let (ident, generics, kind, has_default) = match &i.kind { @@ -902,6 +905,7 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(body), attrs, contract.as_deref(), + target, ); let (generics, sig) = self.lower_method_sig( generics, @@ -1013,7 +1017,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + + let target = AttrTarget::from_impl_item( + if is_in_trait_impl { Position::TraitImpl } else { Position::Impl }, + i, + ); + + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, target); let (ident, (generics, kind)) = match &i.kind { AssocItemKind::Const(box ConstItem { @@ -1056,6 +1066,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body.as_deref(), attrs, contract.as_deref(), + target, ); let (generics, sig) = self.lower_method_sig( generics, @@ -1207,7 +1218,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span); + self.lower_attrs(hir_id, ¶m.attrs, param.span, AttrTarget::Param); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1335,6 +1346,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body: Option<&Block>, attrs: &'hir [hir::Attribute], contract: Option<&FnContract>, + target: AttrTarget<'_>, ) -> hir::BodyId { let Some(body) = body else { // Functions without a body are an error, except if this is an intrinsic. For those we @@ -1382,7 +1394,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME(async_fn_track_caller): Can this be moved above? let hir_id = expr.hir_id; - this.maybe_forward_track_caller(body.span, fn_id, hir_id); + this.maybe_forward_track_caller(body.span, fn_id, hir_id, target); (parameters, expr) }) @@ -1936,7 +1948,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> { let hir_id = self.lower_node_id(pred.id); let span = self.lower_span(pred.span); - self.lower_attrs(hir_id, &pred.attrs, span); + self.lower_attrs(hir_id, &pred.attrs, span, AttrTarget::WherePredicate); let kind = self.arena.alloc(match &pred.kind { WherePredicateKind::BoundPredicate(WhereBoundPredicate { bound_generic_params, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 26d7c0cd6d38f..c2a12a3edfc16 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -42,7 +42,7 @@ use std::sync::Arc; use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, *}; -use rustc_attr_parsing::{AttributeParser, OmitDoc}; +use rustc_attr_parsing::{AttrTarget, AttributeParser, OmitDoc}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -912,11 +912,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: HirId, attrs: &[Attribute], target_span: Span, + target: AttrTarget<'_>, ) -> &'hir [hir::Attribute] { if attrs.is_empty() { &[] } else { - let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id); + let lowered_attrs = + self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target); assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(lowered_attrs); @@ -941,12 +943,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { attrs: &[Attribute], target_span: Span, target_hir_id: HirId, + target: AttrTarget<'_>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( attrs, target_span, target_hir_id, + target, OmitDoc::Lower, |s| l.lower(s), |l| { @@ -1899,7 +1903,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span()); + self.lower_attrs(hir_id, ¶m.attrs, param.span(), AttrTarget::from_generic(param)); hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index e444062104813..bb6043de5c17f 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -2,6 +2,7 @@ use std::sync::Arc; use rustc_ast::ptr::P; use rustc_ast::*; +use rustc_attr_parsing::AttrTarget; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{self as hir, LangItem}; @@ -94,7 +95,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, AttrTarget::PatField); hir::PatField { hir_id, diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 4651cf504fa5a..eeec2d9dbfb64 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -297,7 +297,7 @@ pub enum AttributeKind { RustcLayoutScalarValidRangeStart(Box, Span), /// Represents `#[rustc_skip_during_method_dispatch]`. - SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span }, + SkipDuringMethodDispatch { array: bool, boxed_slice: bool }, /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`. Stability { diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 9ad46a83f5084..9e68da76b7279 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -110,6 +110,10 @@ attr_parsing_rustc_allowed_unstable_pairing = attr_parsing_rustc_promotable_pairing = `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute +attr_parsing_should_be_applied_to_trait = + attribute should be applied to a trait + .label = not a trait + attr_parsing_soft_no_args = `soft` should not have any arguments diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index 83a98c53c7f74..fcd446901c364 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -4,9 +4,11 @@ use rustc_attr_data_structures::AttributeKind; use rustc_feature::{AttributeTemplate, template}; use rustc_span::{Symbol, sym}; +use crate::AttrTarget; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; +use crate::session_diagnostics::AttrShouldBeAppliedToTrait; pub(crate) struct SkipDuringMethodDispatchParser; @@ -18,6 +20,14 @@ impl SingleAttributeParser for SkipDuringMethodDispatchParser { const TEMPLATE: AttributeTemplate = template!(List: "array, boxed_slice"); fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + if !matches!(cx.target, AttrTarget::Trait { .. }) { + cx.dcx().emit_err(AttrShouldBeAppliedToTrait { + attr_span: cx.attr_span, + defn_span: cx.target_span, + }); + return None; + } + let mut array = false; let mut boxed_slice = false; let Some(args) = args.list() else { @@ -49,6 +59,6 @@ impl SingleAttributeParser for SkipDuringMethodDispatchParser { cx.duplicate_key(arg.span(), key); } } - Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span }) + Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice }) } } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6a03cde3a53a8..a7b3baf909c36 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -14,6 +14,7 @@ use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirI use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; +use crate::AttrTarget; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::codegen_attrs::{ ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser, @@ -205,6 +206,9 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { /// The name of the attribute we're currently accepting. pub(crate) attr_path: AttrPath, + + /// The thing the attribute is on. + pub(crate) target: AttrTarget<'f>, } impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { @@ -514,6 +518,7 @@ impl<'sess> AttributeParser<'sess, Early> { sym: Symbol, target_span: Span, target_node_id: NodeId, + target: AttrTarget<'_>, ) -> Option { let mut p = Self { features: None, @@ -526,6 +531,7 @@ impl<'sess> AttributeParser<'sess, Early> { attrs, target_span, target_node_id, + target, OmitDoc::Skip, std::convert::identity, |_lint| { @@ -564,8 +570,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attrs: &[ast::Attribute], target_span: Span, target_id: S::Id, + target: AttrTarget<'_>, omit_doc: OmitDoc, - lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(AttributeLint), ) -> Vec { @@ -633,6 +639,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { attr_span: lower_span(attr.span), template, attr_path: path.get_attribute_path(), + target, }; accept(&mut cx, args) diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 47eeb63bad3db..a95a94e9e1c4f 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -89,6 +89,7 @@ pub(crate) mod context; mod lints; pub mod parser; mod session_diagnostics; +mod target; pub use attributes::cfg::*; pub use attributes::util::{ @@ -96,5 +97,6 @@ pub use attributes::util::{ }; pub use context::{AttributeParser, Early, Late, OmitDoc}; pub use lints::emit_attribute_lint; +pub use target::*; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index a815aa8c7a8ae..15729d07bc343 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -631,3 +631,12 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag } } + +#[derive(Diagnostic)] +#[diag(attr_parsing_should_be_applied_to_trait)] +pub(crate) struct AttrShouldBeAppliedToTrait { + #[primary_span] + pub attr_span: Span, + #[label] + pub defn_span: Span, +} diff --git a/compiler/rustc_attr_parsing/src/target.rs b/compiler/rustc_attr_parsing/src/target.rs new file mode 100644 index 0000000000000..9da58adb0490a --- /dev/null +++ b/compiler/rustc_attr_parsing/src/target.rs @@ -0,0 +1,255 @@ +use rustc_ast as ast; + +/// Describes what context an [`AttrTarget`] is in, like a trait implementation for example. +#[derive(Copy, Clone, Debug)] +pub enum Position { + Free, + Trait, + TraitImpl, + Impl, + Extern, +} + +/// Enumeration of things that an attribute can be on. Used during attribute parsing. +#[derive(Copy, Clone, Debug)] +pub enum AttrTarget<'ast> { + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// fn function(){} + /// ``` + Function { pos: Position, f: &'ast ast::Fn }, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// const X: u32 = 42; + /// ``` + Const { pos: Position }, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// type X = Y; + /// ``` + TypeAlias { pos: Position }, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// static X: u32 = 42; + /// ``` + Static { pos: Position }, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// reuse this::that + /// ``` + Delegation { pos: Position }, + /// ```rust,ignore (pseudo-Rust) + /// struct Foo { + /// #[attr] + /// field: u32, + /// } + /// ``` + Field, + /// A field in a struct expression. + /// ```rust,ignore (pseudo-Rust) + /// Foo { #[attr] field: value } + /// ``` + ExprField, + /// A field in a struct pattern. + /// ```rust,ignore (pseudo-Rust) + /// Foo { #[attr] field } + /// ``` + PatField, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// enum Foo { + /// Variant, + /// } + /// ``` + Enum, + /// ```rust,ignore (pseudo-Rust) + /// enum Foo { + /// #[attr] + /// Variant, + /// } + /// ``` + EnumVariant, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// struct Foo { + /// field: u32, + /// } + /// ``` + Struct, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// union Foo { + /// field: u32, + /// } + /// ``` + Union, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// extern crate foo; + /// ``` + ExternCrate, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// use std::vec::Vec; + /// ``` + Use, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// mod foo; + /// //or + /// #[attr] + /// mod bar {}; + /// ``` + Module, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// extern "C" { .. } + /// ``` + ExternBlock, + /// ```rust,ignore (pseudo-Rust) + /// struct Foo<#[attr] 'a, #[attr] T, #[attr] const N: usize> { + /// field: &'a [T; N], + /// } + /// ``` + GenericParam { kind: &'ast ast::GenericParamKind }, + /// ```rust,ignore (pseudo-Rust) + /// #![feature(where_clause_attrs)] + /// + /// struct A + /// where + /// #[attr] + /// T: Iterator, + /// { + /// f: T, + /// } + /// ``` + WherePredicate, + /// Expressions, like `#[attr] || {}`, `#[attr][a, b, c]` or `#[attr] { ... }`; + Expression { + /// The ast of this expression, if it exists (or not, if it is the result of a desugaring for example). + kind: Option<&'ast ast::ExprKind>, + }, + /// A `let` statement, like `#[attr] let x = 42;`; + Let, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// trait Foo {} + /// ``` + Trait { trait_: &'ast ast::Trait }, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// macro_rules! identity { + /// ( $($tokens:tt)* ) => { $($tokens)* } + /// } + /// ``` + Macro, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// trait Bar = Foo + Sync; + /// ``` + TraitAlias, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// impl Foo { .. } + /// ``` + Impl, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// impl Trait for Foo { } + /// ``` + TraitImpl, + /// ```rust,ignore (pseudo-Rust) + /// #[attr] + /// core::arch::global_asm!("/* {} */", const 0); + /// ``` + GlobalAsm, + /// ```rust,ignore (pseudo-Rust) + /// match 123 { + /// #[attr] + /// 0..=10 => { println!("match!") }, + /// _ => { println!("no match!") }, + /// } + /// ``` + Arm, + /// The crate: + /// ```rust,ignore (pseudo-Rust) + /// #![attr] + /// ``` + Crate, + /// ```rust,ignore (pseudo-Rust) + /// fn function(#[attr] x: usize){} + /// ``` + Param, +} + +impl AttrTarget<'_> { + pub fn from_expr(expr: &ast::Expr) -> AttrTarget<'_> { + AttrTarget::Expression { kind: Some(&expr.kind) } + } + + pub fn from_item(item: &ast::ItemKind) -> AttrTarget<'_> { + use rustc_ast::ItemKind; + let pos = Position::Free; + match item { + ItemKind::ExternCrate(..) => AttrTarget::ExternCrate, + ItemKind::Use(..) => AttrTarget::Use, + ItemKind::Static(..) => AttrTarget::Static { pos }, + ItemKind::Const(..) => AttrTarget::Const { pos }, + ItemKind::Fn(f) => AttrTarget::Function { pos, f }, + ItemKind::Mod(..) => AttrTarget::Module, + ItemKind::ForeignMod(..) => AttrTarget::ExternBlock, + ItemKind::GlobalAsm(..) => AttrTarget::GlobalAsm, + ItemKind::TyAlias(..) => AttrTarget::TypeAlias { pos }, + ItemKind::Enum(..) => AttrTarget::Enum, + ItemKind::Struct(..) => AttrTarget::Struct, + ItemKind::Union(..) => AttrTarget::Union, + ItemKind::Trait(trait_) => AttrTarget::Trait { trait_ }, + ItemKind::TraitAlias(..) => AttrTarget::TraitAlias, + ItemKind::MacroDef(..) => AttrTarget::Macro, + ItemKind::Impl { .. } => AttrTarget::Impl, + ItemKind::Delegation(..) => AttrTarget::Delegation { pos }, + ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => { + unreachable!("macros have been expanded") + } + } + } + + pub fn from_generic(generic: &ast::GenericParam) -> AttrTarget<'_> { + AttrTarget::GenericParam { kind: &generic.kind } + } + + pub fn from_impl_item(pos: Position, item: &ast::AssocItem) -> AttrTarget<'_> { + use ast::AssocItemKind::*; + match &item.kind { + Const(_) => AttrTarget::Const { pos }, + Fn(f) => AttrTarget::Function { pos, f }, + Type(_) => AttrTarget::TypeAlias { pos }, + Delegation(_) => AttrTarget::Delegation { pos }, + MacCall(_) | DelegationMac(_) => unreachable!("macros have been expanded"), + } + } + + pub fn from_trait_item(item: &ast::AssocItem) -> AttrTarget<'_> { + let pos = Position::Trait; + use ast::AssocItemKind::*; + match &item.kind { + Const(_) => AttrTarget::Const { pos }, + Fn(f) => AttrTarget::Function { pos, f }, + Type(_) => AttrTarget::TypeAlias { pos }, + Delegation(_) => AttrTarget::Delegation { pos }, + MacCall(_) | DelegationMac(_) => unreachable!("macros have been expanded"), + } + } + + pub fn from_foreign(param: &ast::ForeignItem) -> AttrTarget<'_> { + use ast::ForeignItemKind::*; + + let pos = Position::Extern; + match ¶m.kind { + Static(_) => AttrTarget::Const { pos }, + Fn(f) => AttrTarget::Function { pos, f }, + TyAlias(_) => AttrTarget::TypeAlias { pos }, + MacCall(_) => unreachable!("macros have been expanded"), + } + } +} diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index d642851bb77bf..4239411e2d241 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -186,7 +186,7 @@ use rustc_ast::{ Generics, Mutability, PatKind, VariantData, }; use rustc_attr_data_structures::{AttributeKind, ReprPacked}; -use rustc_attr_parsing::AttributeParser; +use rustc_attr_parsing::{AttrTarget, AttributeParser}; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_hir::Attribute; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -484,7 +484,7 @@ impl<'a> TraitDef<'a> { match item { Annotatable::Item(item) => { let is_packed = matches!( - AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id), + AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, AttrTarget::from_item(&item.kind)), Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..))) ); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 3ee39fb71b24d..a27b4959ccb54 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1021,7 +1021,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let [skip_array_during_method_dispatch, skip_boxed_slice_during_method_dispatch] = find_attr!( tcx.get_all_attrs(def_id), - AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span:_ } => [*array, *boxed_slice] + AttributeKind::SkipDuringMethodDispatch { array, boxed_slice } => [*array, *boxed_slice] ) .unwrap_or([false; 2]); diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 97e627f2eb29c..5bfed4d690c8d 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,6 +1,6 @@ use rustc_abi::ExternAbi; use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr}; -use rustc_attr_parsing::AttributeParser; +use rustc_attr_parsing::{AttrTarget, AttributeParser}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -167,7 +167,7 @@ impl NonCamelCaseTypes { impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = matches!( - AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id), + AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id, AttrTarget::from_item(&it.kind)), Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(r, _)| r == &ReprAttr::ReprC) ); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4bc48cb6aca6f..e080ad5c21824 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -120,12 +120,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { for attr in attrs { let mut style = None; match attr { - Attribute::Parsed(AttributeKind::SkipDuringMethodDispatch { - span: attr_span, - .. - }) => { - self.check_must_be_applied_to_trait(*attr_span, span, target); - } Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => { self.check_confusables(*first_span, target); } @@ -193,7 +187,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect - | AttributeKind::MacroTransparency(_), + | AttributeKind::MacroTransparency(_) + | AttributeKind::SkipDuringMethodDispatch { .. }, ) => { /* do nothing */ } Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 1e345b11c1466..615563a30c6bf 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -2,7 +2,7 @@ use std::mem; use rustc_ast::visit::FnKind; use rustc_ast::*; -use rustc_attr_parsing::{AttributeParser, Early, OmitDoc}; +use rustc_attr_parsing::{AttrTarget, AttributeParser, Early, OmitDoc}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; @@ -137,6 +137,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, i.id, + AttrTarget::Macro, OmitDoc::Skip, std::convert::identity, |_l| {