diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index b2cb1718b86a3..cffd17bc16cee 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -104,7 +104,13 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs(hir_id, &l.attrs, l.span, Target::Statement); + self.lower_attrs( + hir_id, + &l.attrs, + l.span, + Target::Statement, + rustc_attr_ir::target::AstTarget::Local(Some(l)), + ); self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/contract.rs b/compiler/rustc_ast_lowering/src/contract.rs index cbfeda33040e7..804fbf718bd13 100644 --- a/compiler/rustc_ast_lowering/src/contract.rs +++ b/compiler/rustc_ast_lowering/src/contract.rs @@ -352,7 +352,13 @@ impl<'hir> LoweringContext<'_, 'hir> { )); let attrs: rustc_ast::AttrVec = thin_vec![self.unreachable_code_attr(span)]; - self.lower_attrs(contract_check.hir_id, &attrs, span, Target::Expression); + self.lower_attrs( + contract_check.hir_id, + &attrs, + span, + Target::Expression, + rustc_attr_ir::target::AstTarget::from(Target::Expression), + ); let ret_block = self.block_all(span, arena_vec![self; ret_stmt], Some(contract_check)); self.arena.alloc(self.expr_block(self.arena.alloc(ret_block))) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index f4bfec24e3b1b..9012df0448cf7 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -6,7 +6,7 @@ use rustc_ast::node_id::NodeMap; use rustc_ast::visit::{Visitor, walk_expr}; use rustc_ast::*; use rustc_attr_ir::lang_items::LangItem; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_errors::msg; use rustc_hir as hir; use rustc_hir::HirId; @@ -231,7 +231,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let old_attrs = self.curr_owner.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); let new_attrs = self - .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e), None) + .lower_attrs_vec( + &e.attrs, + e.span, + ex.hir_id, + Target::from_expr(e), + AstTarget::from(Target::from_expr(e)), + ) .into_iter() .chain(old_attrs.iter().cloned()); let new_attrs = &*self.arena.alloc_from_iter(new_attrs); @@ -255,7 +261,13 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e)); + self.lower_attrs( + expr_hir_id, + &e.attrs, + e.span, + Target::from_expr(e), + AstTarget::Expression(Some(e)), + ); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -795,7 +807,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm); + self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm, AstTarget::Arm(Some(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). @@ -1659,7 +1671,13 @@ 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, Target::ExprField); + self.lower_attrs( + hir_id, + &f.attrs, + f.span, + Target::ExprField, + AstTarget::ExprField(Some(f)), + ); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1926,7 +1944,13 @@ 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, Target::from_expr(e)); + self.lower_attrs( + expr.hir_id, + &e.attrs, + e.span, + Target::from_expr(e), + AstTarget::Expression(Some(e)), + ); expr } @@ -1974,7 +1998,13 @@ impl<'hir> LoweringContext<'_, 'hir> { 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, Target::Expression); + self.lower_attrs( + val_expr.hir_id, + &attrs, + span, + Target::Expression, + AstTarget::Expression(Some(sub_expr)), + ); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr, try_span) }; @@ -2016,7 +2046,13 @@ 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, Target::Expression); + self.lower_attrs( + ret_expr.hir_id, + &attrs, + span, + Target::Expression, + AstTarget::Expression(Some(sub_expr)), + ); let break_pat = self.pat_cf_break(try_span, residual_local); self.arm(break_pat, ret_expr, try_span) diff --git a/compiler/rustc_ast_lowering/src/expr/closure.rs b/compiler/rustc_ast_lowering/src/expr/closure.rs index c72956545b7c8..d70c1bef65ab9 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -20,7 +20,13 @@ impl<'hir> LoweringContext<'_, 'hir> { closure: &Closure, ) -> hir::Expr<'hir> { let expr_hir_id = self.lower_node_id(e.id); - let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e)); + let attrs = self.lower_attrs( + expr_hir_id, + &e.attrs, + e.span, + Target::from_expr(e), + rustc_attr_ir::target::AstTarget::Closure(Some(closure)), + ); match closure.coroutine_marker { Some(coroutine_marker) => self.lower_expr_coroutine_closure_with_move_exprs( diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 6ec5903c5fb3b..ef821e5da4037 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,7 +1,7 @@ use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_attr_ir::{AttributeKind, EiiImplResolution, find_attr}; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def::{DefKind, Res}; @@ -165,7 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - Some(i), + AstTarget::from_ast_item(&i.kind), &extra_hir_attributes, ); @@ -607,8 +607,13 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let owner_id = self.curr_owner.owner_id(); let hir_id: HirId = owner_id.into(); - let attrs = - self.lower_attrs(hir_id, &i.attrs, i.span, Target::from_foreign_item_kind(&i.kind)); + let attrs = self.lower_attrs( + hir_id, + &i.attrs, + i.span, + Target::from_foreign_item_kind(&i.kind), + AstTarget::from_foreign_item_kind(&i.kind), + ); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { let fdec = &sig.decl; @@ -678,7 +683,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().span_fatal(v.span, "unnamed enum variants are not yet implemented"); } let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant); + self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant, AstTarget::Variant(Some(v))); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -765,7 +770,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field, AstTarget::Field(Some(f))); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -793,6 +798,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), + AstTarget::from_assoc_item_kind(&i.kind), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1050,6 +1056,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), + AstTarget::from_assoc_item_kind(&i.kind), ); let (ident, (generics, kind)) = match &i.kind { @@ -1216,7 +1223,13 @@ 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, Target::Param); + self.lower_attrs( + hir_id, + ¶m.attrs, + param.span, + Target::Param, + AstTarget::Param(Some(param)), + ); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1914,7 +1927,13 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> 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, Target::WherePredicate); + self.lower_attrs( + hir_id, + &pred.attrs, + span, + Target::WherePredicate, + AstTarget::WherePredicate(Some(pred)), + ); 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 e30fdfcebfdb8..f88b9454e4ebd 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -47,7 +47,7 @@ use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, *}; use rustc_attr_ir::find_attr; use rustc_attr_ir::lang_items::LangItem; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_attr_parsing::{AttributeParser, Recovery, ShouldEmit}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedMap; @@ -755,7 +755,13 @@ fn lower_to_hir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::MaybeOwner<'_> { AstOwner::Crate(c) => with_lctx(tcx, &*resolver, CRATE_NODE_ID, |lctx| { debug_assert_eq!(lctx.curr_owner.owner_id(), CRATE_OWNER_ID); let module = lctx.lower_mod(&c.items, &c.spans); - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, c.spans.inner_span, Target::Crate); + lctx.lower_attrs( + hir::CRATE_HIR_ID, + &c.attrs, + c.spans.inner_span, + Target::Crate, + AstTarget::Crate(Some(c)), + ); hir::OwnerNode::Crate(module) }), AstOwner::Item(item) => { @@ -1137,8 +1143,9 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, + ast_target: AstTarget<'_>, ) -> &'hir [rustc_attr_ir::Attribute] { - self.lower_attrs_with_extra(id, attrs, target_span, target, None, &[]) + self.lower_attrs_with_extra(id, attrs, target_span, target, ast_target, &[]) } fn lower_attrs_with_extra( @@ -1147,14 +1154,14 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - target_item: Option<&ast::Item>, + ast_target: AstTarget<'_>, extra_hir_attributes: &[rustc_attr_ir::Attribute], ) -> &'hir [rustc_attr_ir::Attribute] { if attrs.is_empty() && extra_hir_attributes.is_empty() { &[] } else { let mut lowered_attrs = - self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target, target_item); + self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target, ast_target); lowered_attrs.extend(extra_hir_attributes.iter().cloned()); assert_eq!(id.owner, self.curr_owner.owner_id()); @@ -1181,14 +1188,14 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target_hir_id: HirId, target: Target, - target_item: Option<&ast::Item>, + ast_target: AstTarget<'_>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( attrs, target_span, target, - target_item, + ast_target, |s| l.lower(s), |lint_id, span, kind| { self.curr_owner.delayed_lints.push(DelayedLint { @@ -2241,7 +2248,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let hir_id = self.lower_node_id(param.id); let param_attrs = ¶m.attrs; let param_span = param.span(); - let param = hir::GenericParam { + let param_hir = hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), name, @@ -2251,8 +2258,14 @@ impl<'hir> LoweringContext<'_, 'hir> { colon_span: param.colon_span.map(|s| self.lower_span(s)), source, }; - self.lower_attrs(hir_id, param_attrs, param_span, Target::from(¶m)); - param + self.lower_attrs( + hir_id, + param_attrs, + param_span, + Target::from(¶m_hir), + AstTarget::GenericParam(Some(param)), + ); + param_hir } fn lower_generic_param_kind( @@ -2842,7 +2855,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME(mgca): This might result in lowering attributes that // then go unused as the `Target::ExprField` is not actually // corresponding to `Node::ExprField`. - self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField); + self.lower_attrs( + hir_id, + &f.attrs, + f.span, + Target::ExprField, + AstTarget::Expression(Some(expr)), + ); let expr = self.lower_expr_to_const_arg_direct(&f.expr, None); &*self.arena.alloc(hir::ConstArgExprField { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index df3d7b1a3c0a6..d854b4db64d37 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -92,7 +92,13 @@ impl<'hir> LoweringContext<'_, '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, Target::PatField); + self.lower_attrs( + hir_id, + &f.attrs, + f.span, + Target::PatField, + rustc_attr_ir::target::AstTarget::Pat(Some(pattern)), + ); hir::PatField { hir_id, diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index c41e78c4a96e0..4452ec2b53542 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -2,10 +2,87 @@ use std::fmt::{self, Display}; +use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; -use rustc_ast::{AssocItemKind, ForeignItemKind, ast}; +use rustc_ast::{ + Arm, AssocItemKind, Closure, Crate, Expr, ExprField, FieldDef, ForLoop, ForeignItemKind, + GenericParam, ItemKind, Local, Param, Pat, PatField, Stmt, Variant, WherePredicate, ast, +}; use rustc_macros::StableHash; +/// This enum lists all possible types of AST items. +#[derive(Clone, Copy, Debug)] +pub enum AstTarget<'a> { + // Target types that may correspond to different kinds of items. + Delegation { target: Option>, mac: bool }, + MacroCall(Option>), + + // Target types that correspond exclusively to `AssocItem` kind. Mapping is obtained from `Target::from_assoc_item_kind`. + AssocConst(Option<&'a AssocItemKind>), + Method(Option<&'a AssocItemKind>), + AssocTy(Option<&'a AssocItemKind>), + + // Target types that correspond exclusively to `ForeignItem` kind. Mapping is obtained from `Target::from_foreign_item_kind`. + ForeignStatic(Option<&'a ForeignItemKind>), + ForeignFn(Option<&'a ForeignItemKind>), + ForeignTy(Option<&'a ForeignItemKind>), + + // Target types that correspond exclusively to `Item` kind. Mapping is obtained from `Target::from_ast_item`. + ExternCrate(Option<&'a ItemKind>), + Use(Option<&'a ItemKind>), + Static(Option<&'a ItemKind>), + Const(Option<&'a ItemKind>), + Fn(Option<&'a ItemKind>), + Mod(Option<&'a ItemKind>), + ForeignMod(Option<&'a ItemKind>), + GlobalAsm(Option<&'a ItemKind>), + TyAlias(Option<&'a ItemKind>), + Enum(Option<&'a ItemKind>), + Struct(Option<&'a ItemKind>), + Union(Option<&'a ItemKind>), + Trait(Option<&'a ItemKind>), + TraitAlias(Option<&'a ItemKind>), + Impl { item: Option<&'a ItemKind>, of_trait: bool }, + MacroDef(Option<&'a ItemKind>), + + // Target types that correspond exclusively to `Expr` kind. Mapping is obtained from `Target::from_expr`. + Closure(Option<&'a Closure>), + Expression(Option<&'a Expr>), + ForLoop(Option<&'a ForLoop>), + Loop, + While, + Break, + + Arm(Option<&'a Arm>), + ConstParam(Option<&'a GenericParam>), + Crate(Option<&'a Crate>), + ExprField(Option<&'a ExprField>), + Field(Option<&'a FieldDef>), + GenericParam(Option<&'a GenericParam>), + LifetimeParam(Option<&'a GenericParam>), + Local(Option<&'a Local>), + Param(Option<&'a Param>), + Pat(Option<&'a Pat>), + PatField(Option<&'a PatField>), + Statement(Option<&'a Stmt>), + TypeParam(Option<&'a GenericParam>), + Variant(Option<&'a Variant>), + WherePredicate(Option<&'a WherePredicate>), +} + +#[derive(Clone, Copy, Debug)] +pub enum DelegationAstTarget<'a> { + AssocItem(&'a AssocItemKind), + Item(&'a ItemKind), +} + +#[derive(Clone, Copy, Debug)] +pub enum MacroCallAstTarget<'a> { + AssocItem(&'a AssocItemKind), + ForeignItem(&'a ForeignItemKind), + Item(&'a ItemKind), +} + #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] pub enum MethodKind { /// Method in a `trait Trait` block @@ -19,6 +96,8 @@ pub enum MethodKind { Inherent, } +// FIXME (rtjkro): `AstTarget` has nearly one-to-one mapping with `Target`, barring the extra fields from `AssocConst`, `Method`, and `AssocTy`. +// In the future, remove `Target` and use `AstTarget` instead. #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] pub enum Target { ExternCrate, @@ -65,6 +144,147 @@ pub enum Target { Break, } +impl<'a> AstTarget<'a> { + pub fn get_abi(&self) -> Option { + let ext = match self { + AstTarget::Method(Some(ast::AssocItemKind::Fn(fn_item))) => fn_item.sig.header.ext, + AstTarget::Fn(Some(ast::ItemKind::Fn(fn_item))) => fn_item.sig.header.ext, + AstTarget::ForeignFn(Some(ast::ForeignItemKind::Fn(fn_item))) => fn_item.sig.header.ext, + _ => return None, + }; + + match ext { + ast::Extern::None => Some(ExternAbi::Rust), + ast::Extern::Implicit(_) => Some(ExternAbi::FALLBACK), + ast::Extern::Explicit(abi, _) => Some(abi.symbol_unescaped.as_str().parse().ok()?), + } + } + + pub fn get_fn_sig(&self) -> Option<&rustc_ast::ast::FnSig> { + match self { + AstTarget::Method(Some(ast::AssocItemKind::Fn(fn_item))) => Some(&fn_item.sig), + AstTarget::Fn(Some(ast::ItemKind::Fn(fn_item))) => Some(&fn_item.sig), + AstTarget::ForeignFn(Some(ast::ForeignItemKind::Fn(fn_item))) => Some(&fn_item.sig), + _ => None, + } + } + + pub fn from_foreign_item_kind(kind: &'a ast::ForeignItemKind) -> Self { + match kind { + ForeignItemKind::Static(_) => AstTarget::ForeignStatic(Some(kind)), + ForeignItemKind::Fn(_) => AstTarget::ForeignFn(Some(kind)), + ForeignItemKind::TyAlias(_) => AstTarget::ForeignTy(Some(kind)), + ForeignItemKind::MacCall(_) => { + AstTarget::MacroCall(Some(MacroCallAstTarget::ForeignItem(kind))) + } + } + } + + pub fn from_assoc_item_kind(kind: &'a ast::AssocItemKind) -> Self { + match kind { + AssocItemKind::Const(_) => AstTarget::AssocConst(Some(kind)), + AssocItemKind::Fn(_) => AstTarget::Method(Some(kind)), + AssocItemKind::Type(_) => AstTarget::AssocTy(Some(kind)), + AssocItemKind::Delegation(_) => AstTarget::Delegation { + target: Some(DelegationAstTarget::AssocItem(kind)), + mac: false, + }, + AssocItemKind::DelegationMac(_) => AstTarget::Delegation { + target: Some(DelegationAstTarget::AssocItem(kind)), + mac: true, + }, + AssocItemKind::MacCall(_) => { + AstTarget::MacroCall(Some(MacroCallAstTarget::AssocItem(kind))) + } + } + } + + pub fn from_ast_item(kind: &'a ast::ItemKind) -> Self { + match kind { + ast::ItemKind::ExternCrate(..) => AstTarget::ExternCrate(Some(kind)), + ast::ItemKind::Use(..) => AstTarget::Use(Some(kind)), + ast::ItemKind::Static { .. } => AstTarget::Static(Some(kind)), + ast::ItemKind::Const(..) => AstTarget::Const(Some(kind)), + ast::ItemKind::ConstBlock(..) => AstTarget::Const(Some(kind)), + ast::ItemKind::Fn { .. } => AstTarget::Fn(Some(kind)), + ast::ItemKind::Mod(..) => AstTarget::Mod(Some(kind)), + ast::ItemKind::ForeignMod { .. } => AstTarget::ForeignMod(Some(kind)), + ast::ItemKind::GlobalAsm { .. } => AstTarget::GlobalAsm(Some(kind)), + ast::ItemKind::TyAlias(..) => AstTarget::TyAlias(Some(kind)), + ast::ItemKind::Enum(..) => AstTarget::Enum(Some(kind)), + ast::ItemKind::Struct(..) => AstTarget::Struct(Some(kind)), + ast::ItemKind::Union(..) => AstTarget::Union(Some(kind)), + ast::ItemKind::Trait(..) => AstTarget::Trait(Some(kind)), + ast::ItemKind::TraitAlias(..) => AstTarget::TraitAlias(Some(kind)), + ast::ItemKind::Impl(i) => { + AstTarget::Impl { item: Some(kind), of_trait: i.of_trait.is_some() } + } + ast::ItemKind::MacCall(..) => { + AstTarget::MacroCall(Some(MacroCallAstTarget::Item(kind))) + } + ast::ItemKind::MacroDef(..) => AstTarget::MacroDef(Some(kind)), + ast::ItemKind::Delegation(..) => { + AstTarget::Delegation { target: Some(DelegationAstTarget::Item(kind)), mac: false } + } + ast::ItemKind::DelegationMac(..) => { + AstTarget::Delegation { target: Some(DelegationAstTarget::Item(kind)), mac: true } + } + ast::ItemKind::TestBinderConstraints(..) => { + AstTarget::MacroCall(Some(MacroCallAstTarget::Item(kind))) + } + } + } +} + +impl<'a> From for AstTarget<'a> { + fn from(target: Target) -> Self { + match target { + Target::ExternCrate => AstTarget::ExternCrate(None), + Target::Use => AstTarget::Use(None), + Target::Static => AstTarget::Static(None), + Target::Const => AstTarget::Const(None), + Target::Fn => AstTarget::Fn(None), + Target::Closure => AstTarget::Closure(None), + Target::Mod => AstTarget::Mod(None), + Target::ForeignMod => AstTarget::ForeignMod(None), + Target::GlobalAsm => AstTarget::GlobalAsm(None), + Target::TyAlias => AstTarget::TyAlias(None), + Target::Enum => AstTarget::Enum(None), + Target::Variant => AstTarget::Variant(None), + Target::Struct => AstTarget::Struct(None), + Target::Field => AstTarget::Field(None), + Target::Union => AstTarget::Union(None), + Target::Trait => AstTarget::Trait(None), + Target::TraitAlias => AstTarget::TraitAlias(None), + Target::Impl { of_trait } => AstTarget::Impl { item: None, of_trait }, + Target::Expression => AstTarget::Expression(None), + Target::Statement => AstTarget::Statement(None), + Target::Arm => AstTarget::Arm(None), + Target::AssocConst(_assoc_ctxt) => AstTarget::AssocConst(None), + Target::Method(_method_kind) => AstTarget::Method(None), + Target::AssocTy(_assoc_ctxt) => AstTarget::AssocTy(None), + Target::ForeignFn => AstTarget::ForeignFn(None), + Target::ForeignStatic => AstTarget::ForeignStatic(None), + Target::ForeignTy => AstTarget::ForeignTy(None), + Target::LifetimeParam => AstTarget::LifetimeParam(None), + Target::TypeParam => AstTarget::TypeParam(None), + Target::ConstParam => AstTarget::ConstParam(None), + Target::MacroDef => AstTarget::MacroDef(None), + Target::Param => AstTarget::Param(None), + Target::PatField => AstTarget::PatField(None), + Target::ExprField => AstTarget::ExprField(None), + Target::WherePredicate => AstTarget::WherePredicate(None), + Target::MacroCall => AstTarget::MacroCall(None), + Target::Crate => AstTarget::Crate(None), + Target::Delegation { mac } => AstTarget::Delegation { target: None, mac }, + Target::ForLoop => AstTarget::ForLoop(None), + Target::While => AstTarget::While, + Target::Loop => AstTarget::Loop, + Target::Break => AstTarget::Break, + } + } +} + impl Display for Target { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", Self::name(*self)) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 2553829f8c5ce..e8ee8ed9f6581 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -8,6 +8,7 @@ use rustc_structures::SanitizerSet; use super::prelude::*; use crate::attributes::AttributeSafety; +use crate::context::FinalizeCheckFn; use crate::diagnostics::{ EmptyExportName, EmptySection, NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector, NullOnSection, ObjcClassExpectedStringLiteral, @@ -327,6 +328,37 @@ impl AttributeParser for NakedParser { Some(AttributeKind::Naked(span)) } + + fn deferred_finalize_check(&self) -> Option<(FinalizeCheckFn, Span)> { + Some(( + |cx, _| match cx.target { + Target::Fn + | Target::Method( + MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, + ) => { + let fn_sig = + cx.ast_target.get_fn_sig().expect("missing fn signature for AST target"); + let Some(abi) = cx.ast_target.get_abi() else { + return; + }; + + if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { + feature_err( + cx.sess(), + sym::naked_functions_rustic_abi, + fn_sig.span, + format!( + "`#[naked]` is currently unstable on `extern {abi}` functions", + ), + ) + .emit(); + } + } + _ => {} + }, + self.span?, + )) + } } pub(crate) struct TrackCallerParser; diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index f4d0fa35e3f47..d498124750ee2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -262,25 +262,25 @@ impl CombineAttributeParser for LinkParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - if cx.target != Target::ForeignMod { - return; - } - - let item = cx.target_item.expect("missing AST target item for Target::ForeignMod"); - let ItemKind::ForeignMod(fm) = &item.kind else { - panic!("expected foreign module AST target item for Target::ForeignMod"); - }; - let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { - abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| { - cx.dcx().span_delayed_bug( - abi.span, - "LinkParser::finalize_check was unable to pre-detect the ABI, so it continues to use the recovery value solely to check for unused_attributes in the lint; a user error E0703 will be reported later in lower_abi", - ); - ExternAbi::Rust - }) - }); - if matches!(abi, ExternAbi::Rust) { - cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span); + match cx.ast_target { + rustc_attr_ir::target::AstTarget::ForeignMod(ast_item) + if let ItemKind::ForeignMod(fm) = + &ast_item.expect("missing AST target item for astTarget::ForeignMod") => + { + let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| { + abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| { + cx.dcx().span_delayed_bug( + abi.span, + "LinkParser::finalize_check was unable to pre-detect the ABI, so it continues to use the recovery value solely to check for unused_attributes in the lint; a user error E0703 will be reported later in lower_abi", + ); + ExternAbi::Rust + }) + }); + if matches!(abi, ExternAbi::Rust) { + cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span); + } + } + _ => {} } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 2acba84956e67..c4ff1f220f581 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -26,17 +26,21 @@ impl NoArgsAttributeParser for NonExhaustiveParser { return; } - let item = cx.target_item.expect("missing AST target item for Target::Struct"); - let ItemKind::Struct(_, _, data) = &item.kind else { - panic!("expected struct AST target item for Target::Struct"); - }; - if let VariantData::Struct { fields, .. } = data - && fields.iter().any(|f| f.default_value().is_some()) - { - cx.emit_err(NonExhaustiveWithDefaultFieldValues { - attr_span, - defn_span: cx.target_span, - }); + match cx.ast_target { + rustc_attr_ir::target::AstTarget::Struct(ast_item) + if let ItemKind::Struct(_, _, data) = + &ast_item.expect("missing AST target item for AstTarget::Struct") => + { + if let VariantData::Struct { fields, .. } = data + && fields.iter().any(|f| f.default_value().is_some()) + { + cx.emit_err(NonExhaustiveWithDefaultFieldValues { + attr_span, + defn_span: cx.target_span, + }); + } + } + _ => {} } } } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 72839643b4dc3..4aaa06c54fa2b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -835,9 +835,8 @@ pub(crate) struct FinalizeCheckContext<'p, 'sess> { /// Unlike [`all_attrs`](Self::all_attrs), this contains the fully parsed attributes. pub(crate) parsed_attrs: &'p [Attribute], - /// The AST item these attributes were applied to, when the target is an item. - /// Used by `finalize_check` to inspect item structure that is not encoded in [`Target`]. - pub(crate) target_item: Option<&'p rustc_ast::ast::Item>, + /// The AST item these attributes were applied to. + pub(crate) ast_target: rustc_attr_ir::target::AstTarget<'p>, } impl<'p, 'sess: 'p> Deref for FinalizeCheckContext<'p, 'sess> { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index df89ffe57b9a0..366971216f6b5 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -161,7 +161,7 @@ impl<'sess> AttributeParser<'sess> { attrs, target_span, target, - None, + rustc_attr_ir::target::AstTarget::from(target), std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) @@ -316,7 +316,7 @@ impl<'sess> AttributeParser<'sess> { attrs: &[ast::Attribute], target_span: Span, target: Target, - target_item: Option<&ast::Item>, + ast_target: rustc_attr_ir::target::AstTarget<'_>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -523,7 +523,7 @@ impl<'sess> AttributeParser<'sess> { }, all_attrs: &attr_paths, parsed_attrs: &attributes, - target_item, + ast_target, }, attr_span, ); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ed5f6a83c06c1..fc4a5e3c67cdd 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -38,7 +38,6 @@ use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt, TypingMode, Unnormalized}; -use rustc_session::diagnostics::feature_err; use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, bug, kw, span_bug, sym}; use rustc_structures::CrateType; @@ -201,7 +200,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcAllowConstFnUnstable(_, first_span) => { self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target) } - AttributeKind::Naked(..) => self.check_naked(hir_id, target), AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span), AttributeKind::MacroExport { span, .. } => { self.check_macro_export(hir_id, *span, target) @@ -277,6 +275,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::MoveSizeLimit { .. } => (), AttributeKind::MustNotSupend { .. } => (), AttributeKind::MustUse { .. } => (), + AttributeKind::Naked(..) => (), AttributeKind::NeedsAllocator => (), AttributeKind::NeedsPanicRuntime => (), AttributeKind::NoBuiltins => (), @@ -736,32 +735,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[naked]` is applied to a function definition. - fn check_naked(&self, hir_id: HirId, target: Target) { - match target { - Target::Fn - | Target::Method( - MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, - ) => { - let fn_sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); - let abi = fn_sig.header.abi; - if abi.is_rustic_abi() && !self.tcx.features().naked_functions_rustic_abi() { - feature_err( - &self.tcx.sess, - sym::naked_functions_rustic_abi, - fn_sig.span, - format!( - "`#[naked]` is currently unstable on `extern \"{}\"` functions", - abi.as_str() - ), - ) - .emit(); - } - } - _ => {} - } - } - fn check_doc_alias_value(&self, span: Span, hir_id: HirId, target: Target, alias: Symbol) { if let Some(location) = match target { Target::AssocTy(_) => { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index f3329c3d0398e..fb2eac959d292 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -183,7 +183,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { &i.attrs, i.span, Target::MacroDef, - None, + rustc_attr_ir::target::AstTarget::from_ast_item(&i.kind), std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly