From bec7eadfdb161741cd70c0670ff3717f5ad2785c Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Thu, 17 Sep 2026 06:35:23 +0300 Subject: [PATCH 1/2] @RichardTjokroutomo changes, rebase after PR land --- 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 | 29 +++++-- compiler/rustc_ast_lowering/src/lib.rs | 41 ++++++--- compiler/rustc_ast_lowering/src/pat.rs | 8 +- compiler/rustc_attr_ir/src/target.rs | 85 ++++++++++++++++++- .../src/attributes/codegen_attrs.rs | 33 +++++++ .../src/attributes/non_exhaustive.rs | 26 +++--- compiler/rustc_attr_parsing/src/context.rs | 5 +- compiler/rustc_attr_parsing/src/interface.rs | 6 +- compiler/rustc_passes/src/check_attr.rs | 29 +------ compiler/rustc_resolve/src/def_collector.rs | 2 +- 14 files changed, 244 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index b2cb1718b86a3..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); + 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 cbfeda33040e7..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); + 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 f4bfec24e3b1b..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)); + 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); + 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); + 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)); + 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); + 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); + 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 c72956545b7c8..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)); + 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 6ec5903c5fb3b..a9a1950548f53 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1,7 +1,7 @@ use rustc_abi::ExternAbi; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_attr_ir::{AttributeKind, EiiImplResolution, find_attr}; use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def::{DefKind, Res}; @@ -165,7 +165,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_ast_item(i), - Some(i), + AstTarget::Item(i), &extra_hir_attributes, ); @@ -607,8 +607,13 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let owner_id = self.curr_owner.owner_id(); let hir_id: HirId = owner_id.into(); - let attrs = - self.lower_attrs(hir_id, &i.attrs, i.span, Target::from_foreign_item_kind(&i.kind)); + let attrs = self.lower_attrs( + hir_id, + &i.attrs, + i.span, + Target::from_foreign_item_kind(&i.kind), + AstTarget::ForeignItem(i), + ); let (ident, kind) = match &i.kind { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { let fdec = &sig.decl; @@ -678,7 +683,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().span_fatal(v.span, "unnamed enum variants are not yet implemented"); } let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant); + self.lower_attrs(hir_id, &v.attrs, v.span, Target::Variant, AstTarget::Variant(v)); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -765,7 +770,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ty = self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field); + self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field, AstTarget::FieldDef(f)); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -793,6 +798,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Trait), + AstTarget::AssocItem(i), ); let (ident, generics, kind, has_value) = match &i.kind { @@ -1050,6 +1056,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &i.attrs, i.span, Target::from_assoc_item_kind(&i.kind, AssocCtxt::Impl { of_trait: is_in_trait_impl }), + AstTarget::AssocItem(i), ); let (ident, (generics, kind)) = match &i.kind { @@ -1216,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); + self.lower_attrs(hir_id, ¶m.attrs, param.span, Target::Param, AstTarget::Param(param)); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1914,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); + 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 e30fdfcebfdb8..a28269e58e0c7 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -47,7 +47,7 @@ use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, *}; use rustc_attr_ir::find_attr; use rustc_attr_ir::lang_items::LangItem; -use rustc_attr_ir::target::Target; +use rustc_attr_ir::target::{AstTarget, Target}; use rustc_attr_parsing::{AttributeParser, Recovery, ShouldEmit}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedMap; @@ -755,7 +755,13 @@ fn lower_to_hir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::MaybeOwner<'_> { AstOwner::Crate(c) => with_lctx(tcx, &*resolver, CRATE_NODE_ID, |lctx| { debug_assert_eq!(lctx.curr_owner.owner_id(), CRATE_OWNER_ID); let module = lctx.lower_mod(&c.items, &c.spans); - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, c.spans.inner_span, Target::Crate); + lctx.lower_attrs( + hir::CRATE_HIR_ID, + &c.attrs, + c.spans.inner_span, + Target::Crate, + AstTarget::Crate(c), + ); hir::OwnerNode::Crate(module) }), AstOwner::Item(item) => { @@ -1137,8 +1143,9 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, + ast_target: AstTarget<'_>, ) -> &'hir [rustc_attr_ir::Attribute] { - self.lower_attrs_with_extra(id, attrs, target_span, target, None, &[]) + self.lower_attrs_with_extra(id, attrs, target_span, target, ast_target, &[]) } fn lower_attrs_with_extra( @@ -1147,14 +1154,14 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, - target_item: Option<&ast::Item>, + ast_target: AstTarget<'_>, extra_hir_attributes: &[rustc_attr_ir::Attribute], ) -> &'hir [rustc_attr_ir::Attribute] { if attrs.is_empty() && extra_hir_attributes.is_empty() { &[] } else { let mut lowered_attrs = - self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target, target_item); + self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target, ast_target); lowered_attrs.extend(extra_hir_attributes.iter().cloned()); assert_eq!(id.owner, self.curr_owner.owner_id()); @@ -1181,14 +1188,14 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target_hir_id: HirId, target: Target, - target_item: Option<&ast::Item>, + ast_target: AstTarget<'_>, ) -> Vec { let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( attrs, target_span, target, - target_item, + ast_target, |s| l.lower(s), |lint_id, span, kind| { self.curr_owner.delayed_lints.push(DelayedLint { @@ -2241,7 +2248,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let hir_id = self.lower_node_id(param.id); let param_attrs = ¶m.attrs; let param_span = param.span(); - let param = hir::GenericParam { + let param_hir = hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), name, @@ -2251,8 +2258,14 @@ impl<'hir> LoweringContext<'_, 'hir> { colon_span: param.colon_span.map(|s| self.lower_span(s)), source, }; - self.lower_attrs(hir_id, param_attrs, param_span, Target::from(¶m)); - param + self.lower_attrs( + hir_id, + param_attrs, + param_span, + Target::from(¶m_hir), + AstTarget::GenericParam(param), + ); + param_hir } fn lower_generic_param_kind( @@ -2842,7 +2855,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // FIXME(mgca): This might result in lowering attributes that // then go unused as the `Target::ExprField` is not actually // corresponding to `Node::ExprField`. - self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField); + self.lower_attrs( + hir_id, + &f.attrs, + f.span, + Target::ExprField, + AstTarget::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 df3d7b1a3c0a6..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); + 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 c41e78c4a96e0..1ebe105203b14 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -2,10 +2,37 @@ use std::fmt::{self, Display}; +use rustc_abi::ExternAbi; pub use rustc_ast::visit::AssocCtxt; -use rustc_ast::{AssocItemKind, ForeignItemKind, ast}; +use rustc_ast::{ + Arm, AssocItemKind, Closure, Crate, Expr, ExprField, FieldDef, ForeignItemKind, GenericParam, + Item, Local, Param, Pat, Variant, WherePredicate, ast, +}; use rustc_macros::StableHash; +// 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), + + 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)] pub enum MethodKind { /// Method in a `trait Trait` block @@ -65,6 +92,62 @@ 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 + } + 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 { + 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) + } + AstTarget::ForeignItem(foreign_item) => { + let ast::ForeignItemKind::Fn(fn_item) = &foreign_item.kind else { + return None; + }; + Some(&fn_item.sig) + } + _ => None, + } + } +} + impl Display for Target { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", Self::name(*self)) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 2553829f8c5ce..0feca7c1941b7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -8,6 +8,7 @@ use rustc_structures::SanitizerSet; use super::prelude::*; use crate::attributes::AttributeSafety; +use crate::context::FinalizeCheckFn; use crate::diagnostics::{ EmptyExportName, EmptySection, NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector, NullOnSection, ObjcClassExpectedStringLiteral, @@ -327,6 +328,38 @@ impl AttributeParser for NakedParser { Some(AttributeKind::Naked(span)) } + + fn deferred_finalize_check(&self) -> Option<(FinalizeCheckFn, Span)> { + Some(( + |cx, _| match cx.target { + Target::Fn + | Target::Method( + MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, + ) => { + let fn_sig = + cx.ast_target.get_fn_sig().expect("missing fn signature for AST target"); + let Some(abi) = cx.ast_target.get_abi() else { + return; + }; + + if abi.is_rustic_abi() && !cx.features().naked_functions_rustic_abi() { + feature_err( + cx.sess(), + sym::naked_functions_rustic_abi, + fn_sig.span, + format!( + "`#[naked]` is currently unstable on `extern \"{}\"` functions", + abi.as_str() + ), + ) + .emit(); + } + } + _ => {} + }, + self.span?, + )) + } } pub(crate) struct TrackCallerParser; diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 2acba84956e67..d85c37953103d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -26,17 +26,21 @@ impl NoArgsAttributeParser for NonExhaustiveParser { return; } - let item = cx.target_item.expect("missing AST target item for Target::Struct"); - let ItemKind::Struct(_, _, data) = &item.kind else { - panic!("expected struct AST target item for Target::Struct"); - }; - if let VariantData::Struct { fields, .. } = data - && fields.iter().any(|f| f.default_value().is_some()) - { - cx.emit_err(NonExhaustiveWithDefaultFieldValues { - attr_span, - defn_span: cx.target_span, - }); + match cx.ast_target { + rustc_attr_ir::target::AstTarget::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 72839643b4dc3..4aaa06c54fa2b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -835,9 +835,8 @@ pub(crate) struct FinalizeCheckContext<'p, 'sess> { /// Unlike [`all_attrs`](Self::all_attrs), this contains the fully parsed attributes. pub(crate) parsed_attrs: &'p [Attribute], - /// The AST item these attributes were applied to, when the target is an item. - /// Used by `finalize_check` to inspect item structure that is not encoded in [`Target`]. - pub(crate) target_item: Option<&'p rustc_ast::ast::Item>, + /// The AST item these attributes were applied to. + pub(crate) ast_target: rustc_attr_ir::target::AstTarget<'p>, } impl<'p, 'sess: 'p> Deref for FinalizeCheckContext<'p, 'sess> { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index df89ffe57b9a0..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, - target_item: Option<&ast::Item>, + ast_target: rustc_attr_ir::target::AstTarget<'_>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -523,7 +523,7 @@ impl<'sess> AttributeParser<'sess> { }, all_attrs: &attr_paths, parsed_attrs: &attributes, - target_item, + ast_target, }, attr_span, ); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ed5f6a83c06c1..fc4a5e3c67cdd 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -38,7 +38,6 @@ use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt, TypingMode, Unnormalized}; -use rustc_session::diagnostics::feature_err; use rustc_span::edition::Edition; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, bug, kw, span_bug, sym}; use rustc_structures::CrateType; @@ -201,7 +200,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcAllowConstFnUnstable(_, first_span) => { self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target) } - AttributeKind::Naked(..) => self.check_naked(hir_id, target), AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span), AttributeKind::MacroExport { span, .. } => { self.check_macro_export(hir_id, *span, target) @@ -277,6 +275,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::MoveSizeLimit { .. } => (), AttributeKind::MustNotSupend { .. } => (), AttributeKind::MustUse { .. } => (), + AttributeKind::Naked(..) => (), AttributeKind::NeedsAllocator => (), AttributeKind::NeedsPanicRuntime => (), AttributeKind::NoBuiltins => (), @@ -736,32 +735,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[naked]` is applied to a function definition. - fn check_naked(&self, hir_id: HirId, target: Target) { - match target { - Target::Fn - | Target::Method( - MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent, - ) => { - let fn_sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); - let abi = fn_sig.header.abi; - if abi.is_rustic_abi() && !self.tcx.features().naked_functions_rustic_abi() { - feature_err( - &self.tcx.sess, - sym::naked_functions_rustic_abi, - fn_sig.span, - format!( - "`#[naked]` is currently unstable on `extern \"{}\"` functions", - abi.as_str() - ), - ) - .emit(); - } - } - _ => {} - } - } - fn check_doc_alias_value(&self, span: Span, hir_id: HirId, target: Target, alias: Symbol) { if let Some(location) = match target { Target::AssocTy(_) => { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index f3329c3d0398e..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 b8b10f05f96b420c8f57b93083acf2bde4637de5 Mon Sep 17 00:00:00 2001 From: Obei Sideg Date: Thu, 17 Sep 2026 08:46:06 +0300 Subject: [PATCH 2/2] Use attribute parser for checking `#[may_dangle]` attribute --- compiler/rustc_ast_lowering/src/item.rs | 42 +++++++++++++------ compiler/rustc_ast_lowering/src/lib.rs | 42 ++++++++++++++++--- compiler/rustc_attr_ir/src/target.rs | 6 ++- .../src/attributes/link_attrs.rs | 34 ++++++++------- .../src/attributes/semantics.rs | 22 ++++++++++ compiler/rustc_attr_parsing/src/context.rs | 23 +++++++++- .../rustc_attr_parsing/src/diagnostics.rs | 7 ++++ compiler/rustc_attr_parsing/src/interface.rs | 10 ++++- compiler/rustc_attr_parsing/src/lib.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 34 ++------------- compiler/rustc_passes/src/diagnostics.rs | 7 ---- compiler/rustc_resolve/src/def_collector.rs | 1 + tests/ui/attributes/may_dangle.stderr | 36 ++++++++-------- 13 files changed, 172 insertions(+), 94 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a9a1950548f53..5c81e081ad59b 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -169,7 +169,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &extra_hir_attributes, ); - let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind); + let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind, Some(i)); let item = hir::Item { owner_id, kind, @@ -188,6 +188,7 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &'hir [rustc_attr_ir::Attribute], vis_span: Span, i: &ItemKind, + owner: Option<&Item>, ) -> hir::ItemKind<'hir> { match i { ItemKind::ExternCrate(orig_name, ident) => { @@ -225,6 +226,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, (ty, rhs)) = self.lower_generics( generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + owner, |this| { let ty = this.lower_ty_alloc( ty, @@ -277,7 +279,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); let itctx = ImplTraitContext::Universal; - let (generics, decl) = this.lower_generics(generics, itctx, |this| { + let (generics, decl) = this.lower_generics(generics, itctx, owner, |this| { this.lower_fn_decl(decl, id, FnDeclKind::Fn, coroutine_marker) }); let sig = hir::FnSig { @@ -332,6 +334,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, ty) = self.lower_generics( &generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + owner, |this| match ty { None => { let guar = this.dcx().span_delayed_bug( @@ -358,6 +361,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, variants) = self.lower_generics( generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + owner, |this| { this.arena.alloc_from_iter( enum_definition.variants.iter().map(|x| this.lower_variant(i, x)), @@ -371,6 +375,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, struct_def) = self.lower_generics( generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + owner, |this| this.lower_variant_data(hir_id, i, struct_def), ); hir::ItemKind::Struct(ident, generics, struct_def) @@ -380,6 +385,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, vdata) = self.lower_generics( generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + owner, |this| this.lower_variant_data(hir_id, i, vdata), ); hir::ItemKind::Union(ident, generics, vdata) @@ -406,7 +412,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // parent lifetime. let itctx = ImplTraitContext::Universal; let (generics, (of_trait, lowered_ty)) = - self.lower_generics(ast_generics, itctx, |this| { + self.lower_generics(ast_generics, itctx, owner, |this| { let of_trait = of_trait .as_deref() .map(|of_trait| this.lower_trait_impl_header(of_trait)); @@ -449,6 +455,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, (safety, items, bounds)) = self.lower_generics( generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + owner, |this| { let bounds = this.lower_param_bounds( bounds, @@ -479,6 +486,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, bounds) = self.lower_generics( generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + owner, |this| { this.lower_param_bounds( bounds, @@ -524,6 +532,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, body) = self.lower_generics( generics, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + owner, |this| this.lower_test_binder_body(body), ); hir::ItemKind::TestBinderConstraints { generics, body: self.arena.alloc(body) } @@ -618,13 +627,14 @@ impl<'hir> LoweringContext<'_, 'hir> { ForeignItemKind::Fn(Fn { sig, ident, generics, define_opaque, .. }) => { let fdec = &sig.decl; let itctx = ImplTraitContext::Universal; - let (generics, (decl, fn_args)) = self.lower_generics(generics, itctx, |this| { - ( - // Disallow `impl Trait` in foreign items. - this.lower_fn_decl(fdec, i.id, FnDeclKind::ExternFn, None), - this.lower_fn_params_to_idents(fdec), - ) - }); + let (generics, (decl, fn_args)) = + self.lower_generics(generics, itctx, None, |this| { + ( + // Disallow `impl Trait` in foreign items. + this.lower_fn_decl(fdec, i.id, FnDeclKind::ExternFn, None), + this.lower_fn_params_to_idents(fdec), + ) + }); // Unmarked safety in unsafe block defaults to unsafe. let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs); @@ -808,6 +818,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = self.lower_generics( generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + None, |this| { let ty = this.lower_ty_alloc( ty, @@ -909,6 +920,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, kind) = self.lower_generics( &generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + None, |this| { let ty = ty.as_ref().map(|x| { this.lower_ty_alloc( @@ -1067,6 +1079,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_generics( generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + None, |this| { let ty = this.lower_ty_alloc( ty, @@ -1111,6 +1124,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_generics( &generics, ImplTraitContext::Disallowed(ImplTraitPosition::Generic), + None, |this| match ty { None => { let guar = this.dcx().span_delayed_bug( @@ -1547,7 +1561,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header, hir::Safety::Safe, attrs); let itctx = ImplTraitContext::Universal; - let (generics, decl) = self.lower_generics(generics, itctx, |this| { + let (generics, decl) = self.lower_generics(generics, itctx, None, |this| { this.lower_fn_decl(&sig.decl, id, kind, coroutine_marker) }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) @@ -1750,6 +1764,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, generics: &Generics, itctx: ImplTraitContext, + owner: Option<&Item>, f: impl FnOnce(&mut Self) -> T, ) -> (&'hir hir::Generics<'hir>, T) { assert!(self.curr_owner.impl_trait_defs.is_empty()); @@ -1779,7 +1794,7 @@ impl<'hir> LoweringContext<'_, 'hir> { })); let mut params: SmallVec<[hir::GenericParam<'hir>; 4]> = self - .lower_generic_params_mut(&generics.params, hir::GenericParamSource::Generics) + .lower_generic_params_mut(&generics.params, hir::GenericParamSource::Generics, owner) .collect(); // Introduce extra lifetimes if late resolution tells us to. @@ -2005,6 +2020,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, body) = self.lower_generics( &forall.generics, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + None, |this| this.lower_test_binder_body(&forall.body), ); let assert_on_exit = forall.assert_on_exit.as_ref().map(|assert_on_exit| { @@ -2030,6 +2046,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: exists.span, }, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + None, |this| this.lower_test_binder_body(&exists.body), ); let params = generics.params; @@ -2102,6 +2119,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (generics, (lhs, rhs)) = self.lower_generics( &Generics { params: params.clone(), where_clause: Default::default(), span: *span }, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + None, |this| { let lhs = this .lower_ty_alloc(lhs, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index a28269e58e0c7..87c71f2cb8cfe 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -48,7 +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::{AstTarget, Target}; -use rustc_attr_parsing::{AttributeParser, Recovery, ShouldEmit}; +use rustc_attr_parsing::{AttrResolution, AttributeParser, Recovery, ShouldEmit}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hash::{StableHash, StableHasher}; @@ -393,6 +393,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } +struct LoweringAttrResolution<'a, 'hir> { + tcx: TyCtxt<'hir>, + resolver: &'a ResolverAstLowering<'hir>, + partial_res_overrides: &'a NodeMap, +} + +impl AttrResolution for LoweringAttrResolution<'_, '_> { + fn resolve_def_id(&self, id: NodeId) -> Option { + let partial = match self.partial_res_overrides.get(&id) { + Some(self_param_id) => PartialRes::new(Res::Local(*self_param_id)), + None => self.resolver.partial_res_map.get(&id).copied()?, + }; + partial.full_res()?.opt_def_id() + } + + fn is_lang_item(&self, def_id: DefId, item: LangItem) -> bool { + self.tcx.is_lang_item(def_id, item) + } +} + struct SpanLowerer { is_incremental: bool, def_id: LocalDefId, @@ -1098,7 +1118,7 @@ impl<'hir> LoweringContext<'_, 'hir> { .collect(); let arena = self.arena; let explicit_generic_params = - self.lower_generic_params_mut(generic_params, hir::GenericParamSource::Binder); + self.lower_generic_params_mut(generic_params, hir::GenericParamSource::Binder, None); arena.alloc_from_iter(explicit_generic_params.chain(extra_lifetimes.into_iter())) } @@ -1191,11 +1211,17 @@ impl<'hir> LoweringContext<'_, 'hir> { ast_target: AstTarget<'_>, ) -> Vec { let l = self.span_lowerer(); + let resolve = LoweringAttrResolution { + tcx: self.tcx, + resolver: self.resolver, + partial_res_overrides: &self.partial_res_overrides, + }; self.attribute_parser.parse_attribute_list( attrs, target_span, target, ast_target, + Some(&resolve), |s| l.lower(s), |lint_id, span, kind| { self.curr_owner.delayed_lints.push(DelayedLint { @@ -2225,8 +2251,9 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, params: &[GenericParam], source: hir::GenericParamSource, + owner: Option<&ast::Item>, ) -> impl Iterator> { - params.iter().map(move |param| self.lower_generic_param(param, source)) + params.iter().map(move |param| self.lower_generic_param(param, source, owner)) } fn lower_generic_params( @@ -2234,7 +2261,7 @@ impl<'hir> LoweringContext<'_, 'hir> { params: &[GenericParam], source: hir::GenericParamSource, ) -> &'hir [hir::GenericParam<'hir>] { - self.arena.alloc_from_iter(self.lower_generic_params_mut(params, source)) + self.arena.alloc_from_iter(self.lower_generic_params_mut(params, source, None)) } #[instrument(level = "trace", skip(self))] @@ -2242,6 +2269,7 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, param: &GenericParam, source: hir::GenericParamSource, + owner: Option<&ast::Item>, ) -> hir::GenericParam<'hir> { let (name, kind) = self.lower_generic_param_kind(param, source); @@ -2258,12 +2286,14 @@ impl<'hir> LoweringContext<'_, 'hir> { colon_span: param.colon_span.map(|s| self.lower_span(s)), source, }; - self.lower_attrs( + let owner = matches!(source, hir::GenericParamSource::Generics).then_some(owner).flatten(); + self.lower_attrs_with_extra( hir_id, param_attrs, param_span, Target::from(¶m_hir), - AstTarget::GenericParam(param), + AstTarget::GenericParam { param, owner }, + &[], ); param_hir } diff --git a/compiler/rustc_attr_ir/src/target.rs b/compiler/rustc_attr_ir/src/target.rs index 1ebe105203b14..f7c817bc928e6 100644 --- a/compiler/rustc_attr_ir/src/target.rs +++ b/compiler/rustc_attr_ir/src/target.rs @@ -23,7 +23,11 @@ pub enum AstTarget<'a> { Expr(&'a Expr), ExprField(&'a ExprField), FieldDef(&'a FieldDef), - GenericParam(&'a GenericParam), + /// `owner` is the item whose `<>` list this param belongs to. + GenericParam { + param: &'a GenericParam, + owner: Option<&'a Item>, + }, Local(&'a Local), Param(&'a Param), Pat(&'a Pat), diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index f4d0fa35e3f47..1423ccd190860 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -266,21 +266,25 @@ impl CombineAttributeParser for LinkParser { 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(item) => { + 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); + } + } + _ => {} } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs index 6c4cd5ef667c8..c2885f3c322d2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -1,6 +1,10 @@ +use rustc_ast::ItemKind; +use rustc_attr_ir::lang_items::LangItem; +use rustc_attr_ir::target::AstTarget; use rustc_feature::AttributeStability; use super::prelude::*; +use crate::diagnostics::InvalidMayDangle; pub(crate) struct MayDangleParser; impl NoArgsAttributeParser for MayDangleParser { @@ -9,6 +13,24 @@ impl NoArgsAttributeParser for MayDangleParser { AllowedTargets::AllowList(&[Allow(Target::TypeParam), Allow(Target::LifetimeParam)]); const STABILITY: AttributeStability = unstable!(dropck_eyepatch); const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle; + + fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) { + if matches!(cx.target, Target::TypeParam | Target::LifetimeParam) + && !matches!( + cx.ast_target, + AstTarget::GenericParam { owner: Some(item), .. } + if matches!( + &item.kind, + ItemKind::Impl(impl_) + if impl_.of_trait.as_deref().is_some_and(|header| { + cx.is_lang_item(header.trait_ref.ref_id, LangItem::Drop) + }) + ) + ) + { + cx.emit_err(InvalidMayDangle { attr_span }); + } + } } pub(crate) struct ComptimeParser; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 4aaa06c54fa2b..18e1dfba28d52 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -8,7 +8,8 @@ use std::sync::LazyLock; #[cfg(debug_assertions)] use std::sync::atomic::{AtomicBool, Ordering}; -use rustc_ast::{AttrStyle, MetaItemLit, Safety}; +use rustc_ast::{AttrStyle, MetaItemLit, NodeId, Safety}; +use rustc_attr_ir::lang_items::LangItem; use rustc_attr_ir::target::Target; use rustc_attr_ir::{AttrPath, Attribute, AttributeKind}; use rustc_data_structures::sync::{DynSend, DynSync}; @@ -18,6 +19,7 @@ use rustc_lint_defs::builtin::UNUSED_ATTRIBUTES; use rustc_lint_defs::{Lint, LintId}; use rustc_parse::parser::Recovery; use rustc_session::Session; +use rustc_span::def_id::DefId; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; // Glob imports to avoid big, bitrotty import lists @@ -782,6 +784,25 @@ pub struct SharedContext<'p, 'sess> { /// This is used for the arguments-used check. #[cfg(debug_assertions)] pub(crate) has_lint_been_emitted: AtomicBool, + + /// Resolution from AST lowering. Early parse leaves this unset. + pub(crate) resolve: Option<&'p dyn AttrResolution>, +} + +/// Name resolution and lang-item lookup for attribute parsers. +/// +/// Implemented by AST lowering; this crate cannot depend on `TyCtxt`. +pub trait AttrResolution { + fn resolve_def_id(&self, id: NodeId) -> Option; + fn is_lang_item(&self, def_id: DefId, item: LangItem) -> bool; +} + +impl SharedContext<'_, '_> { + pub(crate) fn is_lang_item(&self, id: NodeId, item: LangItem) -> bool { + self.resolve.is_some_and(|resolve| { + resolve.resolve_def_id(id).is_some_and(|def_id| resolve.is_lang_item(def_id, item)) + }) + } } /// Context given to every attribute parser during finalization. diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index fb4a32d864fbe..03d68a26131b0 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -903,6 +903,13 @@ pub(crate) struct InlineForceInlineConflict { )] pub(crate) struct InlineIgnoredForExported; +#[derive(Diagnostic)] +#[diag("`#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl")] +pub(crate) struct InvalidMayDangle { + #[primary_span] + pub attr_span: Span, +} + #[derive(Diagnostic)] #[diag("`#[ffi_const]` function cannot be `#[ffi_pure]`", code = E0757)] pub(crate) struct BothFfiConstAndPure { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 4208d849643a4..7a90623fb09f2 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -17,8 +17,8 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::AttributeSafety; use crate::context::{ - ATTRIBUTE_PARSERS, AcceptContext, FinalizeCheckContext, FinalizeCheckFn, FinalizeContext, - FinalizeFn, FinalizeOutput, SharedContext, + ATTRIBUTE_PARSERS, AcceptContext, AttrResolution, FinalizeCheckContext, FinalizeCheckFn, + FinalizeContext, FinalizeFn, FinalizeOutput, SharedContext, }; use crate::diagnostics::ParsedDescription; use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser}; @@ -162,6 +162,7 @@ impl<'sess> AttributeParser<'sess> { target_span, target, rustc_attr_ir::target::AstTarget::None, + None, std::convert::identity, |lint_id, span, kind| { sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0) @@ -256,6 +257,7 @@ impl<'sess> AttributeParser<'sess> { emit_lint: &mut emit_lint, #[cfg(debug_assertions)] has_lint_been_emitted: AtomicBool::new(false), + resolve: None, }, attr_span, inner_span, @@ -317,6 +319,7 @@ impl<'sess> AttributeParser<'sess> { target_span: Span, target: Target, ast_target: rustc_attr_ir::target::AstTarget<'_>, + resolve: Option<&dyn AttrResolution>, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -430,6 +433,7 @@ impl<'sess> AttributeParser<'sess> { emit_lint: &mut emit_lint, #[cfg(debug_assertions)] has_lint_been_emitted: AtomicBool::new(false), + resolve, }, attr_span, inner_span, @@ -497,6 +501,7 @@ impl<'sess> AttributeParser<'sess> { emit_lint: &mut emit_lint, #[cfg(debug_assertions)] has_lint_been_emitted: AtomicBool::new(false), + resolve, }, all_attrs: &attr_paths, }); @@ -520,6 +525,7 @@ impl<'sess> AttributeParser<'sess> { emit_lint: &mut emit_lint, #[cfg(debug_assertions)] has_lint_been_emitted: AtomicBool::new(false), + resolve, }, all_attrs: &attr_paths, parsed_attrs: &attributes, diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 3360791cdbc5f..264fe984e6ff1 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -116,7 +116,7 @@ pub use attributes::cfg::{ }; pub use attributes::cfg_select::*; pub use attributes::util::{is_builtin_attr, parse_version}; -pub use context::ShouldEmit; +pub use context::{AttrResolution, ShouldEmit}; pub use diagnostics::ParsedDescription; pub use interface::{AttributeParser, EmitAttribute}; pub use rustc_parse::parser::Recovery; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index fc4a5e3c67cdd..7d05ed1862956 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,6 @@ use std::slice; use rustc_ast::MetaItemKind; use rustc_attr_ir::diagnostic::Directive; -use rustc_attr_ir::lang_items::LangItem; use rustc_attr_ir::target::{AssocCtxt, MethodKind, Target}; use rustc_attr_ir::{ Attribute, AttributeKind, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution, @@ -24,8 +23,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ - self as hir, CRATE_HIR_ID, Constness, FnSig, ForeignItem, GenericParam, GenericParamKind, - HirId, Item, ItemKind, Mod, Node, ParamName, TraitItem, + self as hir, CRATE_HIR_ID, Constness, FnSig, ForeignItem, GenericParamKind, HirId, Item, + ItemKind, Mod, Node, ParamName, TraitItem, }; use rustc_lint_defs::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_ATTRIBUTES, @@ -200,7 +199,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcAllowConstFnUnstable(_, first_span) => { self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target) } - AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span), AttributeKind::MacroExport { span, .. } => { self.check_macro_export(hir_id, *span, target) } @@ -272,6 +270,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::MacroEscape => (), AttributeKind::MacroUse { .. } => (), AttributeKind::Marker => (), + AttributeKind::MayDangle(_) => (), AttributeKind::MoveSizeLimit { .. } => (), AttributeKind::MustNotSupend { .. } => (), AttributeKind::MustUse { .. } => (), @@ -1013,33 +1012,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl. - fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) { - let hir::Node::GenericParam( - param @ GenericParam { - kind: hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. }, - .. - }, - ) = self.tcx.hir_node(hir_id) - else { - self.dcx().delayed_bug("Checked in attr parser"); - return; - }; - - if matches!(param.source, hir::GenericParamSource::Generics) - && let parent_hir_id = self.tcx.parent_hir_id(hir_id) - && let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id) - && let hir::ItemKind::Impl(impl_) = item.kind - && let Some(of_trait) = impl_.of_trait - && let Some(def_id) = of_trait.trait_ref.trait_def_id() - && self.tcx.is_lang_item(def_id, LangItem::Drop) - { - return; - } - - self.dcx().emit_err(diagnostics::InvalidMayDangle { attr_span }); - } - /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument. fn check_rustc_legacy_const_generics( &self, diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index e8e53a7bbfa1b..cac70b3163b59 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -239,13 +239,6 @@ pub(crate) struct NonExportedMacroInvalidAttrs { pub attr_span: Span, } -#[derive(Diagnostic)] -#[diag("`#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl")] -pub(crate) struct InvalidMayDangle { - #[primary_span] - pub attr_span: Span, -} - #[derive(Diagnostic)] #[diag("`#[panic_handler]` function required, but not found")] pub(crate) struct MissingPanicHandler; diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 2611e2607627f..df29c3c0c47a8 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, rustc_attr_ir::target::AstTarget::Item(i), + None, std::convert::identity, |_lint_id, _span, _kind| { // FIXME(jdonszelmann): emit lints here properly diff --git a/tests/ui/attributes/may_dangle.stderr b/tests/ui/attributes/may_dangle.stderr index 5f560003a2238..6873d8fc8eb21 100644 --- a/tests/ui/attributes/may_dangle.stderr +++ b/tests/ui/attributes/may_dangle.stderr @@ -1,3 +1,15 @@ +error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl + --> $DIR/may_dangle.rs:8:13 + | +LL | unsafe impl<#[may_dangle] 'a, T, const N: usize> NotDrop for Implee1<'a, T, N> {} + | ^^^^^^^^^^^^^ + +error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl + --> $DIR/may_dangle.rs:11:17 + | +LL | unsafe impl<'a, #[may_dangle] T, const N: usize> NotDrop for Implee2<'a, T, N> {} + | ^^^^^^^^^^^^^ + error: the `may_dangle` attribute cannot be used on const parameters --> $DIR/may_dangle.rs:14:22 | @@ -6,6 +18,12 @@ LL | unsafe impl<'a, T, #[may_dangle] const N: usize> Drop for Implee1<'a, T, N> | = help: the `may_dangle` attribute can be applied to lifetime parameters and type parameters +error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl + --> $DIR/may_dangle.rs:36:17 + | +LL | unsafe impl<#[may_dangle] T> Drop for Implee { + | ^^^^^^^^^^^^^ + error: the `may_dangle` attribute cannot be used on structs --> $DIR/may_dangle.rs:42:3 | @@ -38,23 +56,5 @@ LL | #[may_dangle] | = help: the `may_dangle` attribute can be applied to lifetime parameters and type parameters -error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl - --> $DIR/may_dangle.rs:8:13 - | -LL | unsafe impl<#[may_dangle] 'a, T, const N: usize> NotDrop for Implee1<'a, T, N> {} - | ^^^^^^^^^^^^^ - -error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl - --> $DIR/may_dangle.rs:11:17 - | -LL | unsafe impl<'a, #[may_dangle] T, const N: usize> NotDrop for Implee2<'a, T, N> {} - | ^^^^^^^^^^^^^ - -error: `#[may_dangle]` must be applied to a lifetime or type generic parameter in `Drop` impl - --> $DIR/may_dangle.rs:36:17 - | -LL | unsafe impl<#[may_dangle] T> Drop for Implee { - | ^^^^^^^^^^^^^ - error: aborting due to 8 previous errors