Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2065,6 +2065,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)]
Expand Down Expand Up @@ -3713,6 +3726,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>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it a vec and not an option?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one function could be the implementation of multiple EIIs. A panic handler could also be the integer overflow handler simultaneously

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... Doesn't sound too compelling to support, but if the complexity is basically just in the collector/checker (where it's just a loop, so not a problem) and not in the macros or such, then it's ok.

Def needs tests tho. Also a test using the same eii attribute twice. Or one function defining two different eiis at the same time

}

#[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)]
Expand Down Expand Up @@ -4060,7 +4088,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);
Expand Down
9 changes: 6 additions & 3 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,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`
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -914,13 +917,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),
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
hir::ItemKind::TraitAlias(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);
Expand All @@ -444,7 +444,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) => {
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1079,11 +1079,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 {
Expand Down
26 changes: 26 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,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 {
Expand Down Expand Up @@ -2141,6 +2152,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) => {
Expand All @@ -2156,6 +2176,12 @@ impl<'a> State<'a> {
self.pclose();
}
}

match item.unsafety {
ast::Safety::Unsafe(_) => self.pclose(),
ast::Safety::Default | ast::Safety::Safe(_) => {}
}

self.end(ib);
}

Expand Down
20 changes: 17 additions & 3 deletions compiler/rustc_ast_pretty/src/pprust/state/item.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use ast::StaticItem;
use itertools::{Itertools, Position};
use rustc_ast as ast;
use rustc_ast::ModKind;
use rustc_ast::{self as ast, EiiImpl, ModKind, Safety};
use rustc_span::Ident;

use crate::pp::BoxMarker;
Expand Down Expand Up @@ -675,10 +674,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);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/alloc_error_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)];
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/autodiff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,7 @@ impl<'a> MethodDef<'a> {
contract: None,
body: Some(body_block),
define_opaque: None,
eii_impls: ThinVec::new(),
})),
tokens: None,
})
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/global_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/test_harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1521,7 +1521,7 @@ impl<'a> CrateMetadataRef<'a> {
let macro_rules = self.root.tables.is_macro_rules.get(self, id);
let body =
self.root.tables.macro_definition.get(self, id).unwrap().decode((self, sess));
ast::MacroDef { macro_rules, body: Box::new(body) }
ast::MacroDef { macro_rules, body: Box::new(body), eii_extern_target: None }
}
_ => bug!(),
}
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ impl<'a> Parser<'a> {
contract,
body,
define_opaque: None,
eii_impls: ThinVec::new(),
}))
} else if self.eat_keyword(exp!(Extern)) {
if self.eat_keyword(exp!(Crate)) {
Expand Down Expand Up @@ -2245,7 +2246,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?
Expand Down Expand Up @@ -2292,7 +2296,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.
Expand Down
6 changes: 6 additions & 0 deletions src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,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,
Expand All @@ -394,6 +395,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
contract: rc,
body: rb,
define_opaque: _,
eii_impls: _,
}),
) => {
eq_defaultness(*ld, *rd)
Expand Down Expand Up @@ -539,6 +541,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,
Expand All @@ -548,6 +551,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
contract: rc,
body: rb,
define_opaque: _,
eii_impls: _,
}),
) => {
eq_defaultness(*ld, *rd)
Expand Down Expand Up @@ -622,6 +626,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,
Expand All @@ -631,6 +636,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
contract: rc,
body: rb,
define_opaque: _,
eii_impls: _,
}),
) => {
eq_defaultness(*ld, *rd)
Expand Down