From 2de02ac86e02eaf0b5979ecbb0531db68910d0c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 28 Jul 2025 10:40:21 +0200 Subject: [PATCH] EII ast changes --- compiler/rustc_ast/src/ast.rs | 30 ++++++++++++++++++- compiler/rustc_ast/src/visit.rs | 9 ++++-- compiler/rustc_ast_lowering/src/item.rs | 8 +++-- .../rustc_ast_passes/src/ast_validation.rs | 5 ++++ compiler/rustc_ast_pretty/src/pprust/state.rs | 26 ++++++++++++++++ .../rustc_ast_pretty/src/pprust/state/item.rs | 19 ++++++++++-- .../src/alloc_error_handler.rs | 1 + compiler/rustc_builtin_macros/src/autodiff.rs | 1 + .../src/deriving/generic/mod.rs | 1 + .../src/global_allocator.rs | 1 + .../rustc_builtin_macros/src/test_harness.rs | 1 + compiler/rustc_metadata/src/rmeta/decoder.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 11 +++++-- .../clippy/clippy_utils/src/ast_utils/mod.rs | 6 ++++ 14 files changed, 110 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e348cc1ab281..ae0ecaccea22 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2109,6 +2109,19 @@ pub struct MacroDef { pub body: Box, /// `true` if macro was defined with `macro_rules`. pub macro_rules: bool, + + /// If this is a macro used for externally implementable items, + /// it refers to an extern item which is its "target". This requires + /// name resolution so can't just be an attribute, so we store it in this field. + pub eii_extern_target: Option, +} + +#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)] +pub struct EiiExternTarget { + /// path to the extern item we're targetting + pub extern_item_path: Path, + pub impl_unsafe: bool, + pub span: Span, } #[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)] @@ -3748,6 +3761,21 @@ pub struct Fn { pub contract: Option>, pub define_opaque: Option>, pub body: Option>, + + /// This function is an implementation of an externally implementable item (EII). + /// This means, there was an EII declared somewhere and this function is the + /// implementation that should be run when the declaration is called. + pub eii_impls: ThinVec, +} + +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct EiiImpl { + pub node_id: NodeId, + pub eii_macro_path: Path, + pub impl_safety: Safety, + pub span: Span, + pub inner_span: Span, + pub is_default: bool, } #[derive(Clone, Encodable, Decodable, Debug, Walkable)] @@ -4114,7 +4142,7 @@ mod size_asserts { static_assert_size!(Block, 32); static_assert_size!(Expr, 72); static_assert_size!(ExprKind, 40); - static_assert_size!(Fn, 184); + static_assert_size!(Fn, 192); static_assert_size!(ForeignItem, 80); static_assert_size!(ForeignItemKind, 16); static_assert_size!(GenericArg, 24); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 7a0424d39575..c7156da84dec 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -393,6 +393,7 @@ macro_rules! common_visitor_and_walkers { ThinVec, ThinVec>, ThinVec, + ThinVec, ); // This macro generates `impl Visitable` and `impl MutVisitable` that forward to `Walkable` @@ -485,6 +486,8 @@ macro_rules! common_visitor_and_walkers { WhereEqPredicate, WhereRegionPredicate, YieldKind, + EiiExternTarget, + EiiImpl, ); /// Each method of this trait is a hook to be potentially @@ -919,13 +922,13 @@ macro_rules! common_visitor_and_walkers { _ctxt, // Visibility is visited as a part of the item. _vis, - Fn { defaultness, ident, sig, generics, contract, body, define_opaque }, + Fn { defaultness, ident, sig, generics, contract, body, define_opaque, eii_impls }, ) => { let FnSig { header, decl, span } = sig; visit_visitable!($($mut)? vis, defaultness, ident, header, generics, decl, - contract, body, span, define_opaque - ) + contract, body, span, define_opaque, eii_impls + ); } FnKind::Closure(binder, coroutine_kind, decl, body) => visit_visitable!($($mut)? vis, binder, coroutine_kind, decl, body), diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index f5b7065247a0..1db6a31e305d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -435,7 +435,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ItemKind::TraitAlias(constness, ident, generics, bounds) } - ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => { + ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_extern_target: _ }) => { let ident = self.lower_ident(*ident); let body = Box::new(self.lower_delim_args(body)); let def_id = self.local_def_id(id); @@ -446,7 +446,11 @@ impl<'hir> LoweringContext<'_, 'hir> { def_kind.descr(def_id.to_def_id()) ); }; - let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules }); + let macro_def = self.arena.alloc(ast::MacroDef { + body, + macro_rules: *macro_rules, + eii_extern_target: None, + }); hir::ItemKind::Macro(ident, macro_def, macro_kinds) } ItemKind::Delegation(box delegation) => { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ddb19f5e7915..0d34ba6c2ca8 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1179,11 +1179,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> { contract: _, body, define_opaque: _, + eii_impls, }, ) => { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.check_defaultness(item.span, *defaultness); + for EiiImpl { eii_macro_path, .. } in eii_impls { + self.visit_path(eii_macro_path); + } + let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)); if body.is_none() && !is_intrinsic && !self.is_sdylib_interface { self.dcx().emit_err(errors::FnWithoutBody { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 35e47fed9f7a..1aa08dfd3d5e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -865,6 +865,17 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere sp: Span, print_visibility: impl FnOnce(&mut Self), ) { + if let Some(eii_extern_target) = ¯o_def.eii_extern_target { + self.word("#[eii_extern_target("); + self.print_path(&eii_extern_target.extern_item_path, false, 0); + if eii_extern_target.impl_unsafe { + self.word(","); + self.space(); + self.word("unsafe"); + } + self.word(")]"); + self.hardbreak(); + } let (kw, has_bang) = if macro_def.macro_rules { ("macro_rules", true) } else { @@ -2162,6 +2173,15 @@ impl<'a> State<'a> { fn print_meta_item(&mut self, item: &ast::MetaItem) { let ib = self.ibox(INDENT_UNIT); + + match item.unsafety { + ast::Safety::Unsafe(_) => { + self.word("unsafe"); + self.popen(); + } + ast::Safety::Default | ast::Safety::Safe(_) => {} + } + match &item.kind { ast::MetaItemKind::Word => self.print_path(&item.path, false, 0), ast::MetaItemKind::NameValue(value) => { @@ -2177,6 +2197,12 @@ impl<'a> State<'a> { self.pclose(); } } + + match item.unsafety { + ast::Safety::Unsafe(_) => self.pclose(), + ast::Safety::Default | ast::Safety::Safe(_) => {} + } + self.end(ib); } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index c7cbf34dedb9..3233d8c2c251 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -1,6 +1,6 @@ use ast::StaticItem; use itertools::{Itertools, Position}; -use rustc_ast::{self as ast, ModKind, TraitAlias}; +use rustc_ast::{self as ast, EiiImpl, ModKind, Safety, TraitAlias}; use rustc_span::Ident; use crate::pp::BoxMarker; @@ -671,10 +671,25 @@ impl<'a> State<'a> { } fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], func: &ast::Fn) { - let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque } = func; + let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque, eii_impls } = + func; self.print_define_opaques(define_opaque.as_deref()); + for EiiImpl { eii_macro_path, impl_safety, .. } in eii_impls { + self.word("#["); + if let Safety::Unsafe(..) = impl_safety { + self.word("unsafe"); + self.popen(); + } + self.print_path(eii_macro_path, false, 0); + if let Safety::Unsafe(..) = impl_safety { + self.pclose(); + } + self.word("]"); + self.hardbreak(); + } + let body_cb_ib = body.as_ref().map(|body| (body, self.head(""))); self.print_visibility(vis); diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index e5d9d2080c08..12ccc4a6de04 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -90,6 +90,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span contract: None, body, define_opaque: None, + eii_impls: ThinVec::new(), })); let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)]; diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index ddc59bfe1414..7839a75636b6 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -346,6 +346,7 @@ mod llvm_enzyme { contract: None, body: Some(d_body), define_opaque: None, + eii_impls: ThinVec::new(), }); let mut rustc_ad_attr = Box::new(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff))); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index baffc525d95a..bb6557802ece 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1092,6 +1092,7 @@ impl<'a> MethodDef<'a> { contract: None, body: Some(body_block), define_opaque: None, + eii_impls: ThinVec::new(), })), tokens: None, }) diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index e69f0838f22e..bb031dafdcfd 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -84,6 +84,7 @@ impl AllocFnFactory<'_, '_> { contract: None, body, define_opaque: None, + eii_impls: ThinVec::new(), })); let item = self.cx.item(self.span, self.attrs(method), kind); self.cx.stmt_item(self.ty_span, item) diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 2a6ac5754bfa..8d6969b0ca12 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -345,6 +345,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box { contract: None, body: Some(main_body), define_opaque: None, + eii_impls: ThinVec::new(), })); let main = Box::new(ast::Item { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 65cbdc675962..76438f046dd5 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1530,7 +1530,7 @@ impl<'a> CrateMetadataRef<'a> { .get((self, tcx), id) .unwrap() .decode((self, tcx)); - ast::MacroDef { macro_rules, body: Box::new(body) } + ast::MacroDef { macro_rules, body: Box::new(body), eii_extern_target: None } } _ => bug!(), } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index abc0ffa87d3d..f9b95ba192d4 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -227,6 +227,7 @@ impl<'a> Parser<'a> { contract, body, define_opaque: None, + eii_impls: ThinVec::new(), })) } else if self.eat_keyword_case(exp!(Extern), case) { if self.eat_keyword_case(exp!(Crate), case) { @@ -2200,7 +2201,10 @@ impl<'a> Parser<'a> { }; self.psess.gated_spans.gate(sym::decl_macro, lo.to(self.prev_token.span)); - Ok(ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: false })) + Ok(ItemKind::MacroDef( + ident, + ast::MacroDef { body, macro_rules: false, eii_extern_target: None }, + )) } /// Is this a possibly malformed start of a `macro_rules! foo` item definition? @@ -2247,7 +2251,10 @@ impl<'a> Parser<'a> { self.eat_semi_for_macro_if_needed(&body); self.complain_if_pub_macro(vis, true); - Ok(ItemKind::MacroDef(ident, ast::MacroDef { body, macro_rules: true })) + Ok(ItemKind::MacroDef( + ident, + ast::MacroDef { body, macro_rules: true, eii_extern_target: None }, + )) } /// Item macro invocations or `macro_rules!` definitions need inherited visibility. diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 08663782a1d5..432d7a251a21 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -382,6 +382,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { contract: lc, body: lb, define_opaque: _, + eii_impls: _, }), Fn(box ast::Fn { defaultness: rd, @@ -391,6 +392,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { contract: rc, body: rb, define_opaque: _, + eii_impls: _, }), ) => { eq_defaultness(*ld, *rd) @@ -554,6 +556,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { contract: lc, body: lb, define_opaque: _, + eii_impls: _, }), Fn(box ast::Fn { defaultness: rd, @@ -563,6 +566,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { contract: rc, body: rb, define_opaque: _, + eii_impls: _, }), ) => { eq_defaultness(*ld, *rd) @@ -638,6 +642,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { contract: lc, body: lb, define_opaque: _, + eii_impls: _, }), Fn(box ast::Fn { defaultness: rd, @@ -647,6 +652,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { contract: rc, body: rb, define_opaque: _, + eii_impls: _, }), ) => { eq_defaultness(*ld, *rd)