EII ast changes

This commit is contained in:
Jana Dönszelmann 2025-07-28 10:40:21 +02:00
parent 615acd8b4d
commit 2de02ac86e
No known key found for this signature in database
14 changed files with 110 additions and 11 deletions

View file

@ -2109,6 +2109,19 @@ pub struct MacroDef {
pub body: Box<DelimArgs>,
/// `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<EiiExternTarget>,
}
#[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<Box<FnContract>>,
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
pub body: Option<Box<Block>>,
/// 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<EiiImpl>,
}
#[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);

View file

@ -393,6 +393,7 @@ macro_rules! common_visitor_and_walkers {
ThinVec<Pat>,
ThinVec<Box<Ty>>,
ThinVec<TyPat>,
ThinVec<EiiImpl>,
);
// 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),

View file

@ -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) => {

View file

@ -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 {

View file

@ -865,6 +865,17 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
sp: Span,
print_visibility: impl FnOnce(&mut Self),
) {
if let Some(eii_extern_target) = &macro_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);
}

View file

@ -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);

View file

@ -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)];

View file

@ -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)));

View file

@ -1092,6 +1092,7 @@ impl<'a> MethodDef<'a> {
contract: None,
body: Some(body_block),
define_opaque: None,
eii_impls: ThinVec::new(),
})),
tokens: None,
})

View file

@ -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)

View file

@ -345,6 +345,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box<ast::Item> {
contract: None,
body: Some(main_body),
define_opaque: None,
eii_impls: ThinVec::new(),
}));
let main = Box::new(ast::Item {

View file

@ -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!(),
}

View file

@ -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.

View file

@ -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)