From 3eb39d42ee4aa86a69319e4cacc9280dc199ad8c Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Wed, 9 Sep 2026 00:17:36 +0800 Subject: [PATCH 1/6] 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 ed5f6a83c06c1..748e9358fb152 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; @@ -277,6 +276,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::MoveSizeLimit { .. } => (), AttributeKind::MustNotSupend { .. } => (), AttributeKind::MustUse { .. } => (), + AttributeKind::Naked(..) => (), AttributeKind::NeedsAllocator => (), AttributeKind::NeedsPanicRuntime => (), AttributeKind::NoBuiltins => (), From 0ebaa7434d38bef546ad7f86dc88b0fd3b014129 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Fri, 11 Sep 2026 21:45:10 +0800 Subject: [PATCH 2/6] 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 e30fdfcebfdb8..78bfaab455365 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 } @@ -2842,7 +2852,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 df89ffe57b9a0..931e9746cb79b 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 { @@ -524,6 +526,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 748e9358fb152..fc4a5e3c67cdd 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::MacroExport { span, .. } => { self.check_macro_export(hir_id, *span, target) @@ -736,32 +735,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[naked]` is applied to a function definition. - fn check_naked(&self, hir_id: HirId, target: Target) { - match target { - Target::Fn - | Target::Method( - MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, - ) => { - let fn_sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); - let abi = fn_sig.header.abi; - if abi.is_rustic_abi() && !self.tcx.features().naked_functions_rustic_abi() { - feature_err( - &self.tcx.sess, - sym::naked_functions_rustic_abi, - fn_sig.span, - format!( - "`#[naked]` is currently unstable on `extern \"{}\"` functions", - abi.as_str() - ), - ) - .emit(); - } - } - _ => {} - } - } - fn check_doc_alias_value(&self, span: Span, hir_id: HirId, target: Target, alias: Symbol) { if let Some(location) = match target { Target::AssocTy(_) => { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index f3329c3d0398e..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 dc57a91579e68bea7ddae7693ebbe80880486a83 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Sat, 12 Sep 2026 21:55:29 +0800 Subject: [PATCH 3/6] 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 78bfaab455365..487757d8e2ae1 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 931e9746cb79b..e51d096cb4a3b 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 { @@ -525,8 +523,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 e44609e35103c14fcf45bfa983c48e782dc108d1 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Sun, 13 Sep 2026 09:28:08 +0800 Subject: [PATCH 4/6] 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 487757d8e2ae1..c30f808d818a7 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 e51d096cb4a3b..347bc15d1a091 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 { @@ -523,7 +523,7 @@ impl<'sess> AttributeParser<'sess> { }, all_attrs: &attr_paths, parsed_attrs: &attributes, - ast_target_item, + ast_target, }, attr_span, ); From 4c8de2dde812bea213588ee731b1501104ff48b9 Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Tue, 15 Sep 2026 13:31:59 +0800 Subject: [PATCH 5/6] 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 c30f808d818a7..a28269e58e0c7 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( @@ -2844,7 +2855,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME(mgca): This might result in lowering attributes that // then go unused as the `Target::ExprField` is not actually // corresponding to `Node::ExprField`. - self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField, 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 347bc15d1a091..4208d849643a4 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 02a5ea5a456c87b4354292fd1698df49a4ad028a Mon Sep 17 00:00:00 2001 From: Richard Tjokroutomo Date: Sun, 27 Sep 2026 10:29:57 +0800 Subject: [PATCH 6/6] 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 f4d0fa35e3f47..4b6ef2fba7498 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