From ee4f17f9fa356e27259c82dc9575c5a78bb865a6 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Wed, 9 Sep 2026 00:17:36 +0800 Subject: [PATCH 1/7] move check_naked() from check_attr.rs to codegen_attrs.rs Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast/src/ast.rs | 19 ++++++++ .../src/attributes/codegen_attrs.rs | 46 +++++++++++++++++++ compiler/rustc_passes/src/check_attr.rs | 2 +- 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 6a86e9af71826..47a25e8fd704d 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3781,6 +3781,25 @@ impl Extern { Extern::Implicit(span) | Extern::Explicit(_, span) => Some(span), } } + + /// An ABI "like Rust" + /// + /// These ABIs are fully controlled by the Rust compiler, which means they + /// - support unwinding with `-Cpanic=unwind`, unlike `extern "C"` + /// - often diverge from the C ABI + /// - are subject to change between compiler versions + pub fn is_rustic_abi(self) -> bool { + match self { + Extern::None => true, + Extern::Implicit(_) => false, + Extern::Explicit(name, _) => { + matches!( + name.symbol_unescaped.as_str(), + "Rust" | "rust-call" | "rust-cold" | "rust-preserve-none" | "rust-tail" + ) + } + } + } } /// A function header. diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 2553829f8c5ce..b27f3b1c63626 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,3 +1,4 @@ +use rustc_ast::ItemKind; use rustc_attr_ir::{ CoverageAttrKind, InstrumentFnAttr, OptimizeAttr, RtsanSetting, UsedBy, find_attr, }; @@ -8,6 +9,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 +329,50 @@ 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 Some(item) = cx.target_item else { + return; + }; + + let ItemKind::Fn(fn_item) = &item.kind else { + return; + }; + + let fn_sig = &fn_item.sig; + let abi = fn_sig.header.ext; + + if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { + let abi_type = match abi { + rustc_ast::ast::Extern::None => "Rust".into(), + rustc_ast::ast::Extern::Explicit(name, _) => { + name.symbol_unescaped.to_string() + } + rustc_ast::ast::Extern::Implicit(_) => unreachable!(), + }; + feature_err( + cx.sess(), + sym::naked_functions_rustic_abi, + fn_sig.span, + format!( + "`#[naked]` is currently unstable on `extern \"{}\"` functions", + abi_type + ), + ) + .emit(); + } + } + _ => {} + }, + self.span?, + )) + } } pub(crate) struct TrackCallerParser; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index bea48e553d236..15a2e5052bd98 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; @@ -275,6 +274,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::MoveSizeLimit { .. } => (), AttributeKind::MustNotSupend { .. } => (), AttributeKind::MustUse { .. } => (), + AttributeKind::Naked(..) => (), AttributeKind::NeedsAllocator => (), AttributeKind::NeedsPanicRuntime => (), AttributeKind::NoBuiltins => (), From c916833aa02c3698e1a681c7aa66d6c9d8fc0ab6 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Fri, 11 Sep 2026 21:45:10 +0800 Subject: [PATCH 2/7] also consider associate item Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/block.rs | 2 +- compiler/rustc_ast_lowering/src/contract.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 21 ++++++--- .../rustc_ast_lowering/src/expr/closure.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 20 ++++++--- compiler/rustc_ast_lowering/src/lib.rs | 20 ++++++--- compiler/rustc_ast_lowering/src/pat.rs | 2 +- .../src/attributes/codegen_attrs.rs | 45 ++++++++++++++++--- compiler/rustc_attr_parsing/src/context.rs | 4 ++ compiler/rustc_attr_parsing/src/interface.rs | 3 ++ compiler/rustc_passes/src/check_attr.rs | 27 ----------- compiler/rustc_resolve/src/def_collector.rs | 1 + 12 files changed, 93 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index b2cb1718b86a3..4e1b36c01f5af 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -104,7 +104,7 @@ 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, None); 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..2958b65131502 100644 --- a/compiler/rustc_ast_lowering/src/contract.rs +++ b/compiler/rustc_ast_lowering/src/contract.rs @@ -352,7 +352,7 @@ 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, None); 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..272cc0600b2a1 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -231,7 +231,14 @@ 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), + None, + None, + ) .into_iter() .chain(old_attrs.iter().cloned()); let new_attrs = &*self.arena.alloc_from_iter(new_attrs); @@ -255,7 +262,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, Target::from_expr(e)); + self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e), None); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -795,7 +802,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, None); 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 +1666,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, Target::ExprField); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField, None); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1926,7 +1933,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, Target::from_expr(e)); + self.lower_attrs(expr.hir_id, &e.attrs, e.span, Target::from_expr(e), None); expr } @@ -1974,7 +1981,7 @@ 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, None); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr, try_span) }; @@ -2016,7 +2023,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, Target::Expression); + self.lower_attrs(ret_expr.hir_id, &attrs, span, Target::Expression, None); 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..53e0347433162 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -20,7 +20,7 @@ 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), None); 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..bb89b8510c5e8 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -166,6 +166,7 @@ impl<'hir> LoweringContext<'_, 'hir> { i.span, Target::from_ast_item(i), Some(i), + None, &extra_hir_attributes, ); @@ -607,8 +608,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), + None, + ); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { let fdec = &sig.decl; @@ -678,7 +684,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, None); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -765,7 +771,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, None); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -793,6 +799,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), + Some(i), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1050,6 +1057,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), + Some(i), ); let (ident, (generics, kind)) = match &i.kind { @@ -1216,7 +1224,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, Target::Param); + self.lower_attrs(hir_id, ¶m.attrs, param.span, Target::Param, None); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1914,7 +1922,7 @@ 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, None); 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 4b6e897da4c87..22b33f3cf0f74 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1137,8 +1137,9 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, + target_assoc_item: Option<&ast::AssocItem>, ) -> &'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, None, target_assoc_item, &[]) } fn lower_attrs_with_extra( @@ -1148,13 +1149,20 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target: Target, target_item: Option<&ast::Item>, + target_assoc_item: Option<&ast::AssocItem>, 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); + let mut lowered_attrs = self.lower_attrs_vec( + attrs, + self.lower_span(target_span), + id, + target, + target_item, + target_assoc_item, + ); lowered_attrs.extend(extra_hir_attributes.iter().cloned()); assert_eq!(id.owner, self.curr_owner.owner_id()); @@ -1182,6 +1190,7 @@ impl<'hir> LoweringContext<'_, 'hir> { target_hir_id: HirId, target: Target, target_item: Option<&ast::Item>, + target_assoc_item: Option<&ast::AssocItem>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( @@ -1189,6 +1198,7 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span, target, target_item, + target_assoc_item, |s| l.lower(s), |lint_id, span, kind| { self.curr_owner.delayed_lints.push(DelayedLint { @@ -2251,7 +2261,7 @@ 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)); + self.lower_attrs(hir_id, param_attrs, param_span, Target::from(¶m), None); param } @@ -2857,7 +2867,7 @@ 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, None); 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..c7a7f81a5b4d7 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -92,7 +92,7 @@ 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, None); hir::PatField { hir_id, diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index b27f3b1c63626..d3f48c46a79d2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,4 +1,4 @@ -use rustc_ast::ItemKind; +use rustc_ast::{AssocItemKind, ItemKind}; use rustc_attr_ir::{ CoverageAttrKind, InstrumentFnAttr, OptimizeAttr, RtsanSetting, UsedBy, find_attr, }; @@ -333,16 +333,47 @@ impl AttributeParser for NakedParser { 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, - ) => { + Target::Fn => { let Some(item) = cx.target_item else { - return; + panic!("expected struct AST target item for {:?}", cx.target); }; let ItemKind::Fn(fn_item) = &item.kind else { - return; + panic!("expected struct AST target item for {:?}", cx.target); + }; + + let fn_sig = &fn_item.sig; + let abi = fn_sig.header.ext; + + if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { + let abi_type = match abi { + rustc_ast::ast::Extern::None => "Rust".into(), + rustc_ast::ast::Extern::Explicit(name, _) => { + name.symbol_unescaped.to_string() + } + rustc_ast::ast::Extern::Implicit(_) => unreachable!(), + }; + feature_err( + cx.sess(), + sym::naked_functions_rustic_abi, + fn_sig.span, + format!( + "`#[naked]` is currently unstable on `extern \"{}\"` functions", + abi_type + ), + ) + .emit(); + } + } + Target::Method( + MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, + ) => { + let Some(assoc_item) = cx.target_assoc_item else { + panic!("expected struct AST target associated item for {:?}", cx.target); + }; + + let AssocItemKind::Fn(fn_item) = &assoc_item.kind else { + panic!("expected struct AST target associated item for {:?}", cx.target); }; let fn_sig = &fn_item.sig; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 72839643b4dc3..38eee10b28384 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -838,6 +838,10 @@ pub(crate) struct FinalizeCheckContext<'p, 'sess> { /// 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 associated item these attributes were applied to, when the target is an associated item. + /// Used by `finalize_check` to inspect associated item structure that is not encoded in [`Target`]. + pub(crate) target_assoc_item: Option<&'p rustc_ast::ast::AssocItem>, } 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 95412c34be371..0a1d17c25aa03 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -162,6 +162,7 @@ impl<'sess> AttributeParser<'sess> { target_span, target, None, + None, std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) @@ -317,6 +318,7 @@ impl<'sess> AttributeParser<'sess> { target_span: Span, target: Target, target_item: Option<&ast::Item>, + target_assoc_item: Option<&ast::AssocItem>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -525,6 +527,7 @@ impl<'sess> AttributeParser<'sess> { all_attrs: &attr_paths, parsed_attrs: &attributes, target_item, + target_assoc_item, }, attr_span, ); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 15a2e5052bd98..22c25292e6c72 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -200,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::RustcLegacyConstGenerics { attr_span, fn_indexes } => { self.check_rustc_legacy_const_generics(item, *attr_span, fn_indexes) @@ -734,32 +733,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..4f834d768b486 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -184,6 +184,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { i.span, Target::MacroDef, None, + None, std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly From 3967c94e4ee6ecc5e08da0295847401be7bfe260 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Sat, 12 Sep 2026 21:55:29 +0800 Subject: [PATCH 3/7] wrap target_item & target_assoc_item into an enum Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast/src/ast.rs | 6 ++ compiler/rustc_ast_lowering/src/expr.rs | 9 +-- compiler/rustc_ast_lowering/src/item.rs | 7 +-- compiler/rustc_ast_lowering/src/lib.rs | 16 ++--- .../src/attributes/codegen_attrs.rs | 59 ++++++------------- .../src/attributes/non_exhaustive.rs | 29 +++++---- compiler/rustc_attr_parsing/src/context.rs | 9 +-- compiler/rustc_attr_parsing/src/interface.rs | 7 +-- compiler/rustc_resolve/src/def_collector.rs | 1 - 9 files changed, 56 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 47a25e8fd704d..4583664588de9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3704,6 +3704,12 @@ impl VariantData { } } +#[derive(Clone, Copy, Debug)] +pub enum AstItemKind<'a> { + Item(&'a Item), + AssocItem(&'a Item), +} + /// An item definition. #[derive(Clone, Encodable, Decodable, Debug)] pub struct Item { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 272cc0600b2a1..6d07a71e13901 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -231,14 +231,7 @@ 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, - None, - ) + .lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e), None) .into_iter() .chain(old_attrs.iter().cloned()); let new_attrs = &*self.arena.alloc_from_iter(new_attrs); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index bb89b8510c5e8..88334a3165f86 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -165,8 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - Some(i), - None, + Some(ast::AstItemKind::Item(i)), &extra_hir_attributes, ); @@ -799,7 +798,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), - Some(i), + Some(ast::AstItemKind::AssocItem(i)), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1057,7 +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 }), - Some(i), + Some(ast::AstItemKind::AssocItem(i)), ); let (ident, (generics, kind)) = match &i.kind { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 22b33f3cf0f74..143a0bd15f03b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1137,9 +1137,9 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - target_assoc_item: Option<&ast::AssocItem>, + ast_target_item: Option>, ) -> &'hir [rustc_attr_ir::Attribute] { - self.lower_attrs_with_extra(id, attrs, target_span, target, None, target_assoc_item, &[]) + self.lower_attrs_with_extra(id, attrs, target_span, target, ast_target_item, &[]) } fn lower_attrs_with_extra( @@ -1148,8 +1148,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - target_item: Option<&ast::Item>, - target_assoc_item: Option<&ast::AssocItem>, + ast_target_item: Option>, extra_hir_attributes: &[rustc_attr_ir::Attribute], ) -> &'hir [rustc_attr_ir::Attribute] { if attrs.is_empty() && extra_hir_attributes.is_empty() { @@ -1160,8 +1159,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_span(target_span), id, target, - target_item, - target_assoc_item, + ast_target_item, ); lowered_attrs.extend(extra_hir_attributes.iter().cloned()); @@ -1189,16 +1187,14 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target_hir_id: HirId, target: Target, - target_item: Option<&ast::Item>, - target_assoc_item: Option<&ast::AssocItem>, + ast_target_item: Option>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( attrs, target_span, target, - target_item, - target_assoc_item, + ast_target_item, |s| l.lower(s), |lint_id, span, kind| { self.curr_owner.delayed_lints.push(DelayedLint { diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index d3f48c46a79d2..128cb38c9762e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -333,50 +333,29 @@ impl AttributeParser for NakedParser { fn deferred_finalize_check(&self) -> Option<(FinalizeCheckFn, Span)> { Some(( |cx, _| match cx.target { - Target::Fn => { - let Some(item) = cx.target_item else { - panic!("expected struct AST target item for {:?}", cx.target); - }; - - let ItemKind::Fn(fn_item) = &item.kind else { - panic!("expected struct AST target item for {:?}", cx.target); - }; - - let fn_sig = &fn_item.sig; - let abi = fn_sig.header.ext; - - if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { - let abi_type = match abi { - rustc_ast::ast::Extern::None => "Rust".into(), - rustc_ast::ast::Extern::Explicit(name, _) => { - name.symbol_unescaped.to_string() - } - rustc_ast::ast::Extern::Implicit(_) => unreachable!(), - }; - feature_err( - cx.sess(), - sym::naked_functions_rustic_abi, - fn_sig.span, - format!( - "`#[naked]` is currently unstable on `extern \"{}\"` functions", - abi_type - ), - ) - .emit(); - } - } - Target::Method( + Target::Fn + | Target::Method( MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, ) => { - let Some(assoc_item) = cx.target_assoc_item else { - panic!("expected struct AST target associated item for {:?}", cx.target); - }; - - let AssocItemKind::Fn(fn_item) = &assoc_item.kind else { - panic!("expected struct AST target associated item for {:?}", cx.target); + let fn_sig = match cx.ast_target_item { + Some(rustc_ast::ast::AstItemKind::Item(ast_item)) => { + let ItemKind::Fn(fn_item) = &ast_item.kind else { + panic!("expected struct AST target item for {:?}", ast_item); + }; + &fn_item.sig + } + Some(rustc_ast::ast::AstItemKind::AssocItem(assoc_item)) => { + let AssocItemKind::Fn(fn_item) = &assoc_item.kind else { + panic!( + "expected struct AST target associated item for {:?}", + assoc_item + ); + }; + &fn_item.sig + } + _ => panic!("expected enum AST target kind for {:?}", cx.ast_target_item), }; - let fn_sig = &fn_item.sig; let abi = fn_sig.header.ext; if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 2acba84956e67..75c8e68868948 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -1,4 +1,4 @@ -use rustc_ast::{ItemKind, VariantData}; +use rustc_ast::{AstItemKind, ItemKind, VariantData}; use rustc_feature::AttributeStability; use super::prelude::*; @@ -26,17 +26,22 @@ 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, - }); + let item = cx.ast_target_item.expect("missing AST target item for Target::Struct"); + match item { + AstItemKind::Item(ast_item) => { + let ItemKind::Struct(_, _, data) = &ast_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, + }); + } + } + _ => {} } } } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 38eee10b28384..d8c6bdfd384d2 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -835,13 +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 associated item these attributes were applied to, when the target is an associated item. - /// Used by `finalize_check` to inspect associated item structure that is not encoded in [`Target`]. - pub(crate) target_assoc_item: Option<&'p rustc_ast::ast::AssocItem>, + /// The AST item these attributes were applied to. + pub(crate) ast_target_item: Option>, } 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 0a1d17c25aa03..0432dc72ac281 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -162,7 +162,6 @@ impl<'sess> AttributeParser<'sess> { target_span, target, None, - None, std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) @@ -317,8 +316,7 @@ impl<'sess> AttributeParser<'sess> { attrs: &[ast::Attribute], target_span: Span, target: Target, - target_item: Option<&ast::Item>, - target_assoc_item: Option<&ast::AssocItem>, + ast_target_item: Option>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -526,8 +524,7 @@ impl<'sess> AttributeParser<'sess> { }, all_attrs: &attr_paths, parsed_attrs: &attributes, - target_item, - target_assoc_item, + ast_target_item, }, attr_span, ); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 4f834d768b486..f3329c3d0398e 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -184,7 +184,6 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { i.span, Target::MacroDef, None, - None, std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly From 7a74f01f6b01a35c8728af5e58d51b54f7f5933f Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Sun, 13 Sep 2026 09:28:08 +0800 Subject: [PATCH 4/7] addressing review comments Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast/src/ast.rs | 25 --------- compiler/rustc_ast_lowering/src/item.rs | 7 +-- compiler/rustc_ast_lowering/src/lib.rs | 20 +++---- compiler/rustc_attr_ir/src/target.rs | 53 ++++++++++++++++++- .../src/attributes/codegen_attrs.rs | 35 +++--------- .../src/attributes/non_exhaustive.rs | 6 +-- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_attr_parsing/src/interface.rs | 4 +- 8 files changed, 78 insertions(+), 74 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4583664588de9..6a86e9af71826 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3704,12 +3704,6 @@ impl VariantData { } } -#[derive(Clone, Copy, Debug)] -pub enum AstItemKind<'a> { - Item(&'a Item), - AssocItem(&'a Item), -} - /// An item definition. #[derive(Clone, Encodable, Decodable, Debug)] pub struct Item { @@ -3787,25 +3781,6 @@ impl Extern { Extern::Implicit(span) | Extern::Explicit(_, span) => Some(span), } } - - /// An ABI "like Rust" - /// - /// These ABIs are fully controlled by the Rust compiler, which means they - /// - support unwinding with `-Cpanic=unwind`, unlike `extern "C"` - /// - often diverge from the C ABI - /// - are subject to change between compiler versions - pub fn is_rustic_abi(self) -> bool { - match self { - Extern::None => true, - Extern::Implicit(_) => false, - Extern::Explicit(name, _) => { - matches!( - name.symbol_unescaped.as_str(), - "Rust" | "rust-call" | "rust-cold" | "rust-preserve-none" | "rust-tail" - ) - } - } - } } /// A function header. diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 88334a3165f86..29d1523814cbc 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,6 +1,7 @@ use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; +use rustc_attr_ir::target::AstTarget; use rustc_attr_ir::target::Target; use rustc_attr_ir::{AttributeKind, EiiImplResolution, find_attr}; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; @@ -165,7 +166,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - Some(ast::AstItemKind::Item(i)), + Some(AstTarget::Item(i)), &extra_hir_attributes, ); @@ -798,7 +799,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), - Some(ast::AstItemKind::AssocItem(i)), + Some(AstTarget::AssocItem(i)), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1056,7 +1057,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), - Some(ast::AstItemKind::AssocItem(i)), + Some(AstTarget::AssocItem(i)), ); let (ident, (generics, kind)) = match &i.kind { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 143a0bd15f03b..c6a207a1daf59 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -48,6 +48,7 @@ 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; use rustc_attr_parsing::{AttributeParser, Recovery, ShouldEmit}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedMap; @@ -1137,9 +1138,9 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - ast_target_item: Option>, + ast_target: Option>, ) -> &'hir [rustc_attr_ir::Attribute] { - self.lower_attrs_with_extra(id, attrs, target_span, target, ast_target_item, &[]) + self.lower_attrs_with_extra(id, attrs, target_span, target, ast_target, &[]) } fn lower_attrs_with_extra( @@ -1148,19 +1149,14 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - ast_target_item: Option>, + ast_target: Option>, 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, - ast_target_item, - ); + let mut lowered_attrs = + 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()); @@ -1187,14 +1183,14 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target_hir_id: HirId, target: Target, - ast_target_item: Option>, + ast_target: Option>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( attrs, target_span, target, - ast_target_item, + ast_target, |s| l.lower(s), |lint_id, span, kind| { self.curr_owner.delayed_lints.push(DelayedLint { diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index c41e78c4a96e0..57875d915e047 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -2,10 +2,19 @@ use std::fmt::{self, Display}; +use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; -use rustc_ast::{AssocItemKind, ForeignItemKind, ast}; +use rustc_ast::{AssocItemKind, ForeignItemKind, Item, ast}; use rustc_macros::StableHash; +// This enum lists all possible types of AST items. +// FIXME: Currently, this enum only lists `Item` and `AssocItem`, but in the future, be exhaustive. +#[derive(Clone, Copy, Debug)] +pub enum AstTarget<'a> { + Item(&'a Item), + AssocItem(&'a Item), +} + #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] pub enum MethodKind { /// Method in a `trait Trait` block @@ -65,6 +74,48 @@ pub enum Target { Break, } +impl AstTarget<'_> { + pub fn get_abi(&self) -> Option { + let ext = match self { + AstTarget::Item(item) => { + let ast::ItemKind::Fn(fn_item) = &item.kind else { + return None; + }; + fn_item.sig.header.ext + } + AstTarget::AssocItem(assoc_item) => { + let ast::AssocItemKind::Fn(fn_item) = &assoc_item.kind else { + return None; + }; + fn_item.sig.header.ext + } + }; + + 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::Item(item) => { + let ast::ItemKind::Fn(fn_item) = &item.kind else { + return None; + }; + Some(&fn_item.sig) + } + AstTarget::AssocItem(assoc_item) => { + let ast::AssocItemKind::Fn(fn_item) = &assoc_item.kind else { + return None; + }; + Some(&fn_item.sig) + } + } + } +} + 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 128cb38c9762e..2d74a289b0857 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,4 +1,3 @@ -use rustc_ast::{AssocItemKind, ItemKind}; use rustc_attr_ir::{ CoverageAttrKind, InstrumentFnAttr, OptimizeAttr, RtsanSetting, UsedBy, find_attr, }; @@ -337,42 +336,24 @@ impl AttributeParser for NakedParser { | Target::Method( MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, ) => { - let fn_sig = match cx.ast_target_item { - Some(rustc_ast::ast::AstItemKind::Item(ast_item)) => { - let ItemKind::Fn(fn_item) = &ast_item.kind else { - panic!("expected struct AST target item for {:?}", ast_item); - }; - &fn_item.sig - } - Some(rustc_ast::ast::AstItemKind::AssocItem(assoc_item)) => { - let AssocItemKind::Fn(fn_item) = &assoc_item.kind else { - panic!( - "expected struct AST target associated item for {:?}", - assoc_item - ); - }; - &fn_item.sig - } - _ => panic!("expected enum AST target kind for {:?}", cx.ast_target_item), + let Some(ast_target) = cx.ast_target else { + panic!("missing AST target for {:?}", cx.target); }; - let abi = fn_sig.header.ext; + let fn_sig = + ast_target.get_fn_sig().expect("missing fn signature for AST target"); + let Some(abi) = ast_target.get_abi() else { + return; + }; if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { - let abi_type = match abi { - rustc_ast::ast::Extern::None => "Rust".into(), - rustc_ast::ast::Extern::Explicit(name, _) => { - name.symbol_unescaped.to_string() - } - rustc_ast::ast::Extern::Implicit(_) => unreachable!(), - }; feature_err( cx.sess(), sym::naked_functions_rustic_abi, fn_sig.span, format!( "`#[naked]` is currently unstable on `extern \"{}\"` functions", - abi_type + abi.as_str() ), ) .emit(); diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 75c8e68868948..3c8afaefa3953 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -1,4 +1,4 @@ -use rustc_ast::{AstItemKind, ItemKind, VariantData}; +use rustc_ast::{ItemKind, VariantData}; use rustc_feature::AttributeStability; use super::prelude::*; @@ -26,9 +26,9 @@ impl NoArgsAttributeParser for NonExhaustiveParser { return; } - let item = cx.ast_target_item.expect("missing AST target item for Target::Struct"); + let item = cx.ast_target.expect("missing AST target item for Target::Struct"); match item { - AstItemKind::Item(ast_item) => { + rustc_attr_ir::target::AstTarget::Item(ast_item) => { let ItemKind::Struct(_, _, data) = &ast_item.kind else { panic!("expected struct AST target item for Target::Struct"); }; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d8c6bdfd384d2..6f8a5c359990a 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -836,7 +836,7 @@ pub(crate) struct FinalizeCheckContext<'p, 'sess> { pub(crate) parsed_attrs: &'p [Attribute], /// The AST item these attributes were applied to. - pub(crate) ast_target_item: Option>, + pub(crate) ast_target: Option>, } 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 0432dc72ac281..902188ffa783f 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -316,7 +316,7 @@ impl<'sess> AttributeParser<'sess> { attrs: &[ast::Attribute], target_span: Span, target: Target, - ast_target_item: Option>, + ast_target: Option>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -524,7 +524,7 @@ impl<'sess> AttributeParser<'sess> { }, all_attrs: &attr_paths, parsed_attrs: &attributes, - ast_target_item, + ast_target, }, attr_span, ); From b8412c32a5ca69680ebd9e13525c0b5ffddcbb91 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Tue, 15 Sep 2026 13:31:59 +0800 Subject: [PATCH 5/7] exhaust all possible types of AST Target (obtained from grepping all functions calling lower_attrs() Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/block.rs | 8 +++- compiler/rustc_ast_lowering/src/contract.rs | 8 +++- compiler/rustc_ast_lowering/src/expr.rs | 34 +++++++++++++---- .../rustc_ast_lowering/src/expr/closure.rs | 8 +++- compiler/rustc_ast_lowering/src/item.rs | 25 +++++++----- compiler/rustc_ast_lowering/src/lib.rs | 37 +++++++++++++----- compiler/rustc_ast_lowering/src/pat.rs | 8 +++- compiler/rustc_attr_ir/src/target.rs | 38 +++++++++++++++++-- .../src/attributes/codegen_attrs.rs | 8 +--- .../src/attributes/non_exhaustive.rs | 3 +- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_attr_parsing/src/interface.rs | 4 +- compiler/rustc_resolve/src/def_collector.rs | 2 +- 13 files changed, 138 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 4e1b36c01f5af..0ebc9c1533b2f 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, None); + self.lower_attrs( + hir_id, + &l.attrs, + l.span, + Target::Statement, + rustc_attr_ir::target::AstTarget::Local(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 2958b65131502..a7663d49e0a4a 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, None); + self.lower_attrs( + contract_check.hir_id, + &attrs, + span, + Target::Expression, + rustc_attr_ir::target::AstTarget::None, + ); 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 6d07a71e13901..bf0f819865343 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::None, + ) .into_iter() .chain(old_attrs.iter().cloned()); let new_attrs = &*self.arena.alloc_from_iter(new_attrs); @@ -255,7 +261,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, Target::from_expr(e), None); + self.lower_attrs(expr_hir_id, &e.attrs, e.span, Target::from_expr(e), AstTarget::Expr(e)); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -795,7 +801,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, None); + self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm, AstTarget::Arm(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 +1665,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, Target::ExprField, None); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField, AstTarget::ExprField(f)); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1926,7 +1932,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, Target::from_expr(e), None); + self.lower_attrs(expr.hir_id, &e.attrs, e.span, Target::from_expr(e), AstTarget::Expr(e)); expr } @@ -1974,7 +1980,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, None); + self.lower_attrs( + val_expr.hir_id, + &attrs, + span, + Target::Expression, + AstTarget::Expr(sub_expr), + ); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr, try_span) }; @@ -2016,7 +2028,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, None); + self.lower_attrs( + ret_expr.hir_id, + &attrs, + span, + Target::Expression, + AstTarget::Expr(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 53e0347433162..eaf89c7bf1098 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), None); + let attrs = self.lower_attrs( + expr_hir_id, + &e.attrs, + e.span, + Target::from_expr(e), + rustc_attr_ir::target::AstTarget::Closure(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 29d1523814cbc..a9a1950548f53 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,8 +1,7 @@ use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; -use rustc_attr_ir::target::AstTarget; -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}; @@ -166,7 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - Some(AstTarget::Item(i)), + AstTarget::Item(i), &extra_hir_attributes, ); @@ -613,7 +612,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_foreign_item_kind(&i.kind), - None, + AstTarget::ForeignItem(i), ); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { @@ -684,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, None); + self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant, AstTarget::Variant(v)); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -771,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, None); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field, AstTarget::FieldDef(f)); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -799,7 +798,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), - Some(AstTarget::AssocItem(i)), + AstTarget::AssocItem(i), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1057,7 +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 }), - Some(AstTarget::AssocItem(i)), + AstTarget::AssocItem(i), ); let (ident, (generics, kind)) = match &i.kind { @@ -1224,7 +1223,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, Target::Param, None); + self.lower_attrs(hir_id, ¶m.attrs, param.span, Target::Param, AstTarget::Param(param)); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1922,7 +1921,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, None); + self.lower_attrs( + hir_id, + &pred.attrs, + span, + Target::WherePredicate, + AstTarget::WherePredicate(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 c6a207a1daf59..53988ce34251f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -47,8 +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; +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; @@ -756,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(c), + ); hir::OwnerNode::Crate(module) }), AstOwner::Item(item) => { @@ -1138,7 +1143,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - ast_target: Option>, + ast_target: AstTarget<'_>, ) -> &'hir [rustc_attr_ir::Attribute] { self.lower_attrs_with_extra(id, attrs, target_span, target, ast_target, &[]) } @@ -1149,7 +1154,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - ast_target: Option>, + ast_target: AstTarget<'_>, extra_hir_attributes: &[rustc_attr_ir::Attribute], ) -> &'hir [rustc_attr_ir::Attribute] { if attrs.is_empty() && extra_hir_attributes.is_empty() { @@ -1183,7 +1188,7 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target_hir_id: HirId, target: Target, - ast_target: Option>, + ast_target: AstTarget<'_>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( @@ -2243,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, @@ -2253,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), None); - param + self.lower_attrs( + hir_id, + param_attrs, + param_span, + Target::from(¶m_hir), + AstTarget::GenericParam(param), + ); + param_hir } fn lower_generic_param_kind( @@ -2859,7 +2870,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, None); + self.lower_attrs( + hir_id, + &f.attrs, + f.span, + Target::ExprField, + AstTarget::Expr(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 c7a7f81a5b4d7..2f2c5d7747269 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, None); + self.lower_attrs( + hir_id, + &f.attrs, + f.span, + Target::PatField, + rustc_attr_ir::target::AstTarget::Pat(pattern), + ); hir::PatField { hir_id, diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index 57875d915e047..1ebe105203b14 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -4,15 +4,33 @@ use std::fmt::{self, Display}; use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; -use rustc_ast::{AssocItemKind, ForeignItemKind, Item, ast}; +use rustc_ast::{ + Arm, AssocItemKind, Closure, Crate, Expr, ExprField, FieldDef, ForeignItemKind, GenericParam, + Item, Local, Param, Pat, Variant, WherePredicate, ast, +}; use rustc_macros::StableHash; // This enum lists all possible types of AST items. -// FIXME: Currently, this enum only lists `Item` and `AssocItem`, but in the future, be exhaustive. #[derive(Clone, Copy, Debug)] pub enum AstTarget<'a> { - Item(&'a Item), AssocItem(&'a Item), + ForeignItem(&'a Item), + Item(&'a Item), + + Arm(&'a Arm), + Closure(&'a Closure), + Crate(&'a Crate), + Expr(&'a Expr), + ExprField(&'a ExprField), + FieldDef(&'a FieldDef), + GenericParam(&'a GenericParam), + Local(&'a Local), + Param(&'a Param), + Pat(&'a Pat), + Variant(&'a Variant), + WherePredicate(&'a WherePredicate), + + None, // Used when it is not possible to get detailed information about the target. } #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] @@ -89,6 +107,13 @@ impl AstTarget<'_> { }; fn_item.sig.header.ext } + AstTarget::ForeignItem(foreign_item) => { + let ast::ForeignItemKind::Fn(fn_item) = &foreign_item.kind else { + return None; + }; + fn_item.sig.header.ext + } + _ => return None, }; match ext { @@ -112,6 +137,13 @@ impl AstTarget<'_> { }; Some(&fn_item.sig) } + AstTarget::ForeignItem(foreign_item) => { + let ast::ForeignItemKind::Fn(fn_item) = &foreign_item.kind else { + return None; + }; + Some(&fn_item.sig) + } + _ => None, } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 2d74a289b0857..0feca7c1941b7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -336,13 +336,9 @@ impl AttributeParser for NakedParser { | Target::Method( MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, ) => { - let Some(ast_target) = cx.ast_target else { - panic!("missing AST target for {:?}", cx.target); - }; - let fn_sig = - ast_target.get_fn_sig().expect("missing fn signature for AST target"); - let Some(abi) = ast_target.get_abi() else { + cx.ast_target.get_fn_sig().expect("missing fn signature for AST target"); + let Some(abi) = cx.ast_target.get_abi() else { return; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 3c8afaefa3953..d85c37953103d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -26,8 +26,7 @@ impl NoArgsAttributeParser for NonExhaustiveParser { return; } - let item = cx.ast_target.expect("missing AST target item for Target::Struct"); - match item { + match cx.ast_target { rustc_attr_ir::target::AstTarget::Item(ast_item) => { let ItemKind::Struct(_, _, data) = &ast_item.kind else { panic!("expected struct AST target item for Target::Struct"); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 6f8a5c359990a..4aaa06c54fa2b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -836,7 +836,7 @@ pub(crate) struct FinalizeCheckContext<'p, 'sess> { pub(crate) parsed_attrs: &'p [Attribute], /// The AST item these attributes were applied to. - pub(crate) ast_target: Option>, + 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 902188ffa783f..ff069adfacbec 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::None, 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, - ast_target: Option>, + ast_target: rustc_attr_ir::target::AstTarget<'_>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index f3329c3d0398e..2611e2607627f 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::Item(i), std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly From 54827f01806a55eca3f58d21a550b0d137bbfdd1 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Sun, 27 Sep 2026 10:29:57 +0800 Subject: [PATCH 6/7] addressing comments & fixing code after 0929 rebase Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/item.rs | 8 +-- compiler/rustc_attr_ir/src/target.rs | 55 +++++-------------- .../src/attributes/codegen_attrs.rs | 3 +- .../src/attributes/link_attrs.rs | 37 ++++++------- .../src/attributes/non_exhaustive.rs | 7 +-- compiler/rustc_resolve/src/def_collector.rs | 2 +- 6 files changed, 40 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a9a1950548f53..6f91f52b3e4d6 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -165,7 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - AstTarget::Item(i), + AstTarget::Item(&i.kind), &extra_hir_attributes, ); @@ -612,7 +612,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_foreign_item_kind(&i.kind), - AstTarget::ForeignItem(i), + AstTarget::ForeignItem(&i.kind), ); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { @@ -798,7 +798,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), - AstTarget::AssocItem(i), + AstTarget::AssocItem(&i.kind), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1056,7 +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::AssocItem(i), + AstTarget::AssocItem(&i.kind), ); let (ident, (generics, kind)) = match &i.kind { diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index 1ebe105203b14..7be670b20b2ca 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -6,16 +6,16 @@ use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; use rustc_ast::{ Arm, AssocItemKind, Closure, Crate, Expr, ExprField, FieldDef, ForeignItemKind, GenericParam, - Item, Local, Param, Pat, Variant, WherePredicate, ast, + ItemKind, Local, Param, Pat, Variant, WherePredicate, ast, }; use rustc_macros::StableHash; -// This enum lists all possible types of AST items. +/// This enum lists all possible types of AST items. #[derive(Clone, Copy, Debug)] pub enum AstTarget<'a> { - AssocItem(&'a Item), - ForeignItem(&'a Item), - Item(&'a Item), + AssocItem(&'a AssocItemKind), + ForeignItem(&'a ForeignItemKind), + Item(&'a ItemKind), Arm(&'a Arm), Closure(&'a Closure), @@ -30,7 +30,8 @@ pub enum AstTarget<'a> { Variant(&'a Variant), WherePredicate(&'a WherePredicate), - None, // Used when it is not possible to get detailed information about the target. + /// Used when it is not possible to get detailed information about the target. + None, } #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] @@ -95,24 +96,9 @@ pub enum Target { impl AstTarget<'_> { pub fn get_abi(&self) -> Option { let ext = match self { - AstTarget::Item(item) => { - let ast::ItemKind::Fn(fn_item) = &item.kind else { - return None; - }; - fn_item.sig.header.ext - } - AstTarget::AssocItem(assoc_item) => { - let ast::AssocItemKind::Fn(fn_item) = &assoc_item.kind else { - return None; - }; - fn_item.sig.header.ext - } - AstTarget::ForeignItem(foreign_item) => { - let ast::ForeignItemKind::Fn(fn_item) = &foreign_item.kind else { - return None; - }; - fn_item.sig.header.ext - } + AstTarget::Item(ast::ItemKind::Fn(fn_item)) => fn_item.sig.header.ext, + AstTarget::AssocItem(ast::AssocItemKind::Fn(fn_item)) => fn_item.sig.header.ext, + AstTarget::ForeignItem(ast::ForeignItemKind::Fn(fn_item)) => fn_item.sig.header.ext, _ => return None, }; @@ -125,24 +111,9 @@ impl AstTarget<'_> { pub fn get_fn_sig(&self) -> Option<&rustc_ast::ast::FnSig> { match self { - AstTarget::Item(item) => { - let ast::ItemKind::Fn(fn_item) = &item.kind else { - return None; - }; - Some(&fn_item.sig) - } - AstTarget::AssocItem(assoc_item) => { - let ast::AssocItemKind::Fn(fn_item) = &assoc_item.kind else { - return None; - }; - Some(&fn_item.sig) - } - AstTarget::ForeignItem(foreign_item) => { - let ast::ForeignItemKind::Fn(fn_item) = &foreign_item.kind else { - return None; - }; - Some(&fn_item.sig) - } + AstTarget::Item(ast::ItemKind::Fn(fn_item)) => Some(&fn_item.sig), + AstTarget::AssocItem(ast::AssocItemKind::Fn(fn_item)) => Some(&fn_item.sig), + AstTarget::ForeignItem(ast::ForeignItemKind::Fn(fn_item)) => Some(&fn_item.sig), _ => None, } } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 0feca7c1941b7..e8ee8ed9f6581 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -348,8 +348,7 @@ impl AttributeParser for NakedParser { sym::naked_functions_rustic_abi, fn_sig.span, format!( - "`#[naked]` is currently unstable on `extern \"{}\"` functions", - abi.as_str() + "`#[naked]` is currently unstable on `extern {abi}` functions", ), ) .emit(); diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index ed911a63eb7fe..ba9f6be111f47 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -262,25 +262,24 @@ 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::Item(ast_item) + if let ItemKind::ForeignMod(fm) = &ast_item => + { + 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 d85c37953103d..1a3db27763577 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -27,10 +27,9 @@ impl NoArgsAttributeParser for NonExhaustiveParser { } match cx.ast_target { - rustc_attr_ir::target::AstTarget::Item(ast_item) => { - let ItemKind::Struct(_, _, data) = &ast_item.kind else { - panic!("expected struct AST target item for Target::Struct"); - }; + rustc_attr_ir::target::AstTarget::Item(ast_item) + if let ItemKind::Struct(_, _, data) = &ast_item => + { if let VariantData::Struct { fields, .. } = data && fields.iter().any(|f| f.default_value().is_some()) { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 2611e2607627f..27bfc53cb4bdc 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, - rustc_attr_ir::target::AstTarget::Item(i), + rustc_attr_ir::target::AstTarget::Item(&i.kind), std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly From fc91755e51f0856b1cda872d6540ae70bf02d8f0 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Thu, 1 Oct 2026 15:42:45 +0800 Subject: [PATCH 7/7] make AstTarget map 1-1 with Target Signed-off-by: Richard Tjokroutomo --- compiler/rustc_ast_lowering/src/block.rs | 2 +- compiler/rustc_ast_lowering/src/contract.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 32 ++- .../rustc_ast_lowering/src/expr/closure.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 22 +- compiler/rustc_ast_lowering/src/lib.rs | 6 +- compiler/rustc_ast_lowering/src/pat.rs | 2 +- compiler/rustc_attr_ir/src/target.rs | 216 ++++++++++++++++-- .../src/attributes/codegen_attrs.rs | 3 + .../src/attributes/link_attrs.rs | 5 +- .../src/attributes/macro_attrs.rs | 20 +- .../src/attributes/non_exhaustive.rs | 5 +- compiler/rustc_attr_parsing/src/interface.rs | 2 +- compiler/rustc_resolve/src/def_collector.rs | 2 +- 14 files changed, 259 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 0ebc9c1533b2f..cffd17bc16cee 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -109,7 +109,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &l.attrs, l.span, Target::Statement, - rustc_attr_ir::target::AstTarget::Local(l), + 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 a7663d49e0a4a..804fbf718bd13 100644 --- a/compiler/rustc_ast_lowering/src/contract.rs +++ b/compiler/rustc_ast_lowering/src/contract.rs @@ -357,7 +357,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &attrs, span, Target::Expression, - rustc_attr_ir::target::AstTarget::None, + rustc_attr_ir::target::AstTarget::from(Target::Expression), ); let ret_block = self.block_all(span, arena_vec![self; ret_stmt], Some(contract_check)); diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index bf0f819865343..9012df0448cf7 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -236,7 +236,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e.span, ex.hir_id, Target::from_expr(e), - AstTarget::None, + AstTarget::from(Target::from_expr(e)), ) .into_iter() .chain(old_attrs.iter().cloned()); @@ -261,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), AstTarget::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)), @@ -801,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, AstTarget::Arm(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). @@ -1665,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, AstTarget::ExprField(f)); + 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), @@ -1932,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), AstTarget::Expr(e)); + self.lower_attrs( + expr.hir_id, + &e.attrs, + e.span, + Target::from_expr(e), + AstTarget::Expression(Some(e)), + ); expr } @@ -1985,7 +2003,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &attrs, span, Target::Expression, - AstTarget::Expr(sub_expr), + AstTarget::Expression(Some(sub_expr)), ); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr, try_span) @@ -2033,7 +2051,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &attrs, span, Target::Expression, - AstTarget::Expr(sub_expr), + AstTarget::Expression(Some(sub_expr)), ); let break_pat = self.pat_cf_break(try_span, residual_local); diff --git a/compiler/rustc_ast_lowering/src/expr/closure.rs b/compiler/rustc_ast_lowering/src/expr/closure.rs index eaf89c7bf1098..d70c1bef65ab9 100644 --- a/compiler/rustc_ast_lowering/src/expr/closure.rs +++ b/compiler/rustc_ast_lowering/src/expr/closure.rs @@ -25,7 +25,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &e.attrs, e.span, Target::from_expr(e), - rustc_attr_ir::target::AstTarget::Closure(closure), + rustc_attr_ir::target::AstTarget::Closure(Some(closure)), ); match closure.coroutine_marker { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 6f91f52b3e4d6..ef821e5da4037 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -165,7 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - AstTarget::Item(&i.kind), + AstTarget::from_ast_item(&i.kind), &extra_hir_attributes, ); @@ -612,7 +612,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_foreign_item_kind(&i.kind), - AstTarget::ForeignItem(&i.kind), + AstTarget::from_foreign_item_kind(&i.kind), ); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { @@ -683,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, AstTarget::Variant(v)); + 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), @@ -770,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, AstTarget::FieldDef(f)); + 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, @@ -798,7 +798,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), - AstTarget::AssocItem(&i.kind), + AstTarget::from_assoc_item_kind(&i.kind), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1056,7 +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::AssocItem(&i.kind), + AstTarget::from_assoc_item_kind(&i.kind), ); let (ident, (generics, kind)) = match &i.kind { @@ -1223,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, AstTarget::Param(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), @@ -1926,7 +1932,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &pred.attrs, span, Target::WherePredicate, - AstTarget::WherePredicate(pred), + AstTarget::WherePredicate(Some(pred)), ); let kind = self.arena.alloc(match &pred.kind { WherePredicateKind::BoundPredicate(WhereBoundPredicate { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 53988ce34251f..f66993e878c2c 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -760,7 +760,7 @@ fn lower_to_hir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::MaybeOwner<'_> { &c.attrs, c.spans.inner_span, Target::Crate, - AstTarget::Crate(c), + AstTarget::Crate(Some(c)), ); hir::OwnerNode::Crate(module) }), @@ -2263,7 +2263,7 @@ impl<'hir> LoweringContext<'_, 'hir> { param_attrs, param_span, Target::from(¶m_hir), - AstTarget::GenericParam(param), + AstTarget::GenericParam(Some(param)), ); param_hir } @@ -2875,7 +2875,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &f.attrs, f.span, Target::ExprField, - AstTarget::Expr(expr), + AstTarget::Expression(Some(expr)), ); let expr = self.lower_expr_to_const_arg_direct(&f.expr, None); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 2f2c5d7747269..d854b4db64d37 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -97,7 +97,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &f.attrs, f.span, Target::PatField, - rustc_attr_ir::target::AstTarget::Pat(pattern), + rustc_attr_ir::target::AstTarget::Pat(Some(pattern)), ); hir::PatField { diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index 7be670b20b2ca..6216de0c5eaf0 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -5,33 +5,82 @@ use std::fmt::{self, Display}; use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; use rustc_ast::{ - Arm, AssocItemKind, Closure, Crate, Expr, ExprField, FieldDef, ForeignItemKind, GenericParam, - ItemKind, Local, Param, Pat, Variant, WherePredicate, 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), - ForeignItem(&'a ForeignItemKind), Item(&'a ItemKind), +} - Arm(&'a Arm), - Closure(&'a Closure), - Crate(&'a Crate), - Expr(&'a Expr), - ExprField(&'a ExprField), - FieldDef(&'a FieldDef), - GenericParam(&'a GenericParam), - Local(&'a Local), - Param(&'a Param), - Pat(&'a Pat), - Variant(&'a Variant), - WherePredicate(&'a WherePredicate), - - /// Used when it is not possible to get detailed information about the target. - None, +#[derive(Clone, Copy, Debug)] +pub enum MacroCallAstTarget<'a> { + AssocItem(&'a AssocItemKind), + ForeignItem(&'a ForeignItemKind), + Item(&'a ItemKind), } #[derive(Copy, Clone, PartialEq, Debug, Eq, StableHash)] @@ -47,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, @@ -93,12 +144,12 @@ pub enum Target { Break, } -impl AstTarget<'_> { +impl<'a> AstTarget<'a> { pub fn get_abi(&self) -> Option { let ext = match self { - AstTarget::Item(ast::ItemKind::Fn(fn_item)) => fn_item.sig.header.ext, - AstTarget::AssocItem(ast::AssocItemKind::Fn(fn_item)) => fn_item.sig.header.ext, - AstTarget::ForeignItem(ast::ForeignItemKind::Fn(fn_item)) => fn_item.sig.header.ext, + 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, }; @@ -111,12 +162,127 @@ impl AstTarget<'_> { pub fn get_fn_sig(&self) -> Option<&rustc_ast::ast::FnSig> { match self { - AstTarget::Item(ast::ItemKind::Fn(fn_item)) => Some(&fn_item.sig), - AstTarget::AssocItem(ast::AssocItemKind::Fn(fn_item)) => Some(&fn_item.sig), - AstTarget::ForeignItem(ast::ForeignItemKind::Fn(fn_item)) => Some(&fn_item.sig), + 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 { diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index e8ee8ed9f6581..234e217d9f2c8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -330,6 +330,9 @@ impl AttributeParser for NakedParser { } fn deferred_finalize_check(&self) -> Option<(FinalizeCheckFn, Span)> { + // FIXME(rtjkro): Currently, we're enum matching on `cx.target` instead of `cx.ast_target` + // because `AstTarget::Method` doesn't contain `MethodKind` yet. In the future, when this field is available to `AstTarget::Method`, + // update this check to use `cx.ast_target` instead of `cx.target`. Some(( |cx, _| match cx.target { Target::Fn diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index ba9f6be111f47..a122713ce1930 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -263,8 +263,9 @@ impl CombineAttributeParser for LinkParser { fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { match cx.ast_target { - rustc_attr_ir::target::AstTarget::Item(ast_item) - if let ItemKind::ForeignMod(fm) = &ast_item => + 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(|_| { diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 8bb5e6b7fc270..5e2e0db135961 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,4 +1,5 @@ use rustc_ast::ItemKind; +use rustc_attr_ir::target::AstTarget; use rustc_attr_ir::{MacroUseArgs, find_attr}; use rustc_feature::AttributeStability; use rustc_lint_defs::builtin::{INVALID_MACRO_EXPORT_ARGUMENTS, UNUSED_ATTRIBUTES}; @@ -181,15 +182,16 @@ impl SingleAttributeParser for MacroExportParser { } fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { - if cx.target != Target::MacroDef { - return; - } - - let item = cx.target_item.unwrap(); - if let ItemKind::MacroDef(_, macro_def) = &item.kind - && !macro_def.macro_rules - { - cx.emit_lint(UNUSED_ATTRIBUTES, MacroExport::OnDeclMacro, attr_span); + match cx.ast_target { + AstTarget::MacroDef(item_kind) => { + if let ItemKind::MacroDef(_, macro_def) = + item_kind.expect("AstTarget::MacroDef should always have an ItemKind::MacroDef") + && !macro_def.macro_rules + { + cx.emit_lint(UNUSED_ATTRIBUTES, MacroExport::OnDeclMacro, 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 1a3db27763577..c4ff1f220f581 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -27,8 +27,9 @@ impl NoArgsAttributeParser for NonExhaustiveParser { } match cx.ast_target { - rustc_attr_ir::target::AstTarget::Item(ast_item) - if let ItemKind::Struct(_, _, data) = &ast_item => + 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()) diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index ff069adfacbec..ac2b5423e2f60 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, - rustc_attr_ir::target::AstTarget::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) diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 27bfc53cb4bdc..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, - rustc_attr_ir::target::AstTarget::Item(&i.kind), + rustc_attr_ir::target::AstTarget::from_ast_item(&i.kind), std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly