Skip to content

Commit cfd6730

Browse files
Auto merge of #146348 - jdonszelmann:eiiv3, r=<try>
[DONT MERGE] externally implementable items
2 parents 2fcbda6 + c412bfb commit cfd6730

File tree

131 files changed

+3292
-53
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

131 files changed

+3292
-53
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2090,6 +2090,19 @@ pub struct MacroDef {
20902090
pub body: Box<DelimArgs>,
20912091
/// `true` if macro was defined with `macro_rules`.
20922092
pub macro_rules: bool,
2093+
2094+
/// If this is a macro used for externally implementable items,
2095+
/// it refers to an extern item which is its "target". This requires
2096+
/// name resolution so can't just be an attribute, so we store it in this field.
2097+
pub eii_extern_target: Option<EiiExternTarget>,
2098+
}
2099+
2100+
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
2101+
pub struct EiiExternTarget {
2102+
/// path to the extern item we're targetting
2103+
pub extern_item_path: Path,
2104+
pub impl_unsafe: bool,
2105+
pub span: Span,
20932106
}
20942107

20952108
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
@@ -3731,6 +3744,21 @@ pub struct Fn {
37313744
pub contract: Option<Box<FnContract>>,
37323745
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
37333746
pub body: Option<Box<Block>>,
3747+
3748+
/// This function is an implementation of an externally implementable item (EII).
3749+
/// This means, there was an EII declared somewhere and this function is the
3750+
/// implementation that should be run when the declaration is called.
3751+
pub eii_impls: ThinVec<EiiImpl>,
3752+
}
3753+
3754+
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
3755+
pub struct EiiImpl {
3756+
pub node_id: NodeId,
3757+
pub eii_macro_path: Path,
3758+
pub impl_safety: Safety,
3759+
pub span: Span,
3760+
pub inner_span: Span,
3761+
pub is_default: bool,
37343762
}
37353763

37363764
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
@@ -4097,7 +4125,7 @@ mod size_asserts {
40974125
static_assert_size!(Block, 32);
40984126
static_assert_size!(Expr, 72);
40994127
static_assert_size!(ExprKind, 40);
4100-
static_assert_size!(Fn, 184);
4128+
static_assert_size!(Fn, 192);
41014129
static_assert_size!(ForeignItem, 80);
41024130
static_assert_size!(ForeignItemKind, 16);
41034131
static_assert_size!(GenericArg, 24);

compiler/rustc_ast/src/visit.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ macro_rules! common_visitor_and_walkers {
393393
ThinVec<Pat>,
394394
ThinVec<Box<Ty>>,
395395
ThinVec<TyPat>,
396+
ThinVec<EiiImpl>,
396397
);
397398

398399
// This macro generates `impl Visitable` and `impl MutVisitable` that forward to `Walkable`
@@ -485,6 +486,8 @@ macro_rules! common_visitor_and_walkers {
485486
WhereEqPredicate,
486487
WhereRegionPredicate,
487488
YieldKind,
489+
EiiExternTarget,
490+
EiiImpl,
488491
);
489492

490493
/// Each method of this trait is a hook to be potentially
@@ -919,13 +922,13 @@ macro_rules! common_visitor_and_walkers {
919922
_ctxt,
920923
// Visibility is visited as a part of the item.
921924
_vis,
922-
Fn { defaultness, ident, sig, generics, contract, body, define_opaque },
925+
Fn { defaultness, ident, sig, generics, contract, body, define_opaque, eii_impls },
923926
) => {
924927
let FnSig { header, decl, span } = sig;
925928
visit_visitable!($($mut)? vis,
926929
defaultness, ident, header, generics, decl,
927-
contract, body, span, define_opaque
928-
)
930+
contract, body, span, define_opaque, eii_impls
931+
);
929932
}
930933
FnKind::Closure(binder, coroutine_kind, decl, body) =>
931934
visit_visitable!($($mut)? vis, binder, coroutine_kind, decl, body),

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 109 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
22
use rustc_ast::visit::AssocCtxt;
33
use rustc_ast::*;
44
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
5-
use rustc_hir::attrs::AttributeKind;
5+
use rustc_hir::attrs::{AttributeKind, EiiDecl};
66
use rustc_hir::def::{DefKind, PerNS, Res};
77
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
88
use rustc_hir::{
@@ -11,6 +11,7 @@ use rustc_hir::{
1111
use rustc_index::{IndexSlice, IndexVec};
1212
use rustc_middle::span_bug;
1313
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
14+
use rustc_span::def_id::DefId;
1415
use rustc_span::edit_distance::find_best_match_for_name;
1516
use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
1617
use smallvec::{SmallVec, smallvec};
@@ -133,17 +134,103 @@ impl<'hir> LoweringContext<'_, 'hir> {
133134
}
134135
}
135136

137+
fn generate_extra_attrs_for_item_kind(
138+
&mut self,
139+
id: NodeId,
140+
i: &ItemKind,
141+
) -> Vec<hir::Attribute> {
142+
match i {
143+
ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
144+
ItemKind::Fn(box Fn { eii_impls, .. }) => {
145+
vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
146+
eii_impls
147+
.iter()
148+
.flat_map(
149+
|EiiImpl {
150+
node_id,
151+
eii_macro_path,
152+
impl_safety,
153+
span,
154+
inner_span,
155+
is_default,
156+
}| {
157+
self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| {
158+
hir::attrs::EiiImpl {
159+
eii_macro: did,
160+
span: self.lower_span(*span),
161+
inner_span: self.lower_span(*inner_span),
162+
impl_marked_unsafe: self
163+
.lower_safety(*impl_safety, hir::Safety::Safe)
164+
.is_unsafe(),
165+
is_default: *is_default,
166+
}
167+
})
168+
},
169+
)
170+
.collect(),
171+
))]
172+
}
173+
ItemKind::MacroDef(
174+
_,
175+
MacroDef {
176+
eii_extern_target: Some(EiiExternTarget { extern_item_path, impl_unsafe, span }),
177+
..
178+
},
179+
) => self
180+
.lower_path_simple_eii(id, extern_item_path)
181+
.map(|did| {
182+
vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(EiiDecl {
183+
eii_extern_target: did,
184+
impl_unsafe: *impl_unsafe,
185+
span: self.lower_span(*span),
186+
}))]
187+
})
188+
.unwrap_or_default(),
189+
ItemKind::ExternCrate(..)
190+
| ItemKind::Use(..)
191+
| ItemKind::Static(..)
192+
| ItemKind::Const(..)
193+
| ItemKind::Mod(..)
194+
| ItemKind::ForeignMod(..)
195+
| ItemKind::GlobalAsm(..)
196+
| ItemKind::TyAlias(..)
197+
| ItemKind::Enum(..)
198+
| ItemKind::Struct(..)
199+
| ItemKind::Union(..)
200+
| ItemKind::Trait(..)
201+
| ItemKind::TraitAlias(..)
202+
| ItemKind::Impl(..)
203+
| ItemKind::MacCall(..)
204+
| ItemKind::MacroDef(..)
205+
| ItemKind::Delegation(..)
206+
| ItemKind::DelegationMac(..) => Vec::new(),
207+
}
208+
}
209+
136210
fn lower_item(&mut self, i: &Item) -> &'hir hir::Item<'hir> {
137211
let vis_span = self.lower_span(i.vis.span);
138212
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
139-
let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, Target::from_ast_item(i));
213+
214+
let extra_hir_attributes = self.generate_extra_attrs_for_item_kind(i.id, &i.kind);
215+
let attrs = self.lower_attrs_with_extra(
216+
hir_id,
217+
&i.attrs,
218+
i.span,
219+
Target::from_ast_item(i),
220+
&extra_hir_attributes,
221+
);
222+
140223
let kind = self.lower_item_kind(i.span, i.id, hir_id, attrs, vis_span, &i.kind);
141224
let item = hir::Item {
142225
owner_id: hir_id.expect_owner(),
143226
kind,
144227
vis_span,
145228
span: self.lower_span(i.span),
146229
has_delayed_lints: !self.delayed_lints.is_empty(),
230+
eii: find_attr!(
231+
attrs,
232+
AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..)
233+
),
147234
};
148235
self.arena.alloc(item)
149236
}
@@ -431,7 +518,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
431518
);
432519
hir::ItemKind::TraitAlias(constness, ident, generics, bounds)
433520
}
434-
ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => {
521+
ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_extern_target: _ }) => {
435522
let ident = self.lower_ident(*ident);
436523
let body = Box::new(self.lower_delim_args(body));
437524
let def_id = self.local_def_id(id);
@@ -442,7 +529,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
442529
def_kind.descr(def_id.to_def_id())
443530
);
444531
};
445-
let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
532+
let macro_def = self.arena.alloc(ast::MacroDef {
533+
body,
534+
macro_rules: *macro_rules,
535+
eii_extern_target: None,
536+
});
446537
hir::ItemKind::Macro(ident, macro_def, macro_kinds)
447538
}
448539
ItemKind::Delegation(box delegation) => {
@@ -461,6 +552,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
461552
}
462553
}
463554

555+
fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option<DefId> {
556+
let res = self.resolver.get_partial_res(id)?;
557+
let Some(did) = res.expect_full_res().opt_def_id() else {
558+
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
559+
return None;
560+
};
561+
562+
Some(did)
563+
}
564+
464565
#[instrument(level = "debug", skip(self))]
465566
fn lower_use_tree(
466567
&mut self,
@@ -569,6 +670,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
569670
vis_span,
570671
span: this.lower_span(use_tree.span),
571672
has_delayed_lints: !this.delayed_lints.is_empty(),
673+
eii: find_attr!(
674+
attrs,
675+
AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..)
676+
),
572677
};
573678
hir::OwnerNode::Item(this.arena.alloc(item))
574679
});

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -953,11 +953,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
953953
target_span: Span,
954954
target: Target,
955955
) -> &'hir [hir::Attribute] {
956-
if attrs.is_empty() {
956+
self.lower_attrs_with_extra(id, attrs, target_span, target, &[])
957+
}
958+
959+
fn lower_attrs_with_extra(
960+
&mut self,
961+
id: HirId,
962+
attrs: &[Attribute],
963+
target_span: Span,
964+
target: Target,
965+
extra_hir_attributes: &[hir::Attribute],
966+
) -> &'hir [hir::Attribute] {
967+
if attrs.is_empty() && extra_hir_attributes.is_empty() {
957968
&[]
958969
} else {
959-
let lowered_attrs =
970+
let mut lowered_attrs =
960971
self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target);
972+
lowered_attrs.extend(extra_hir_attributes.iter().cloned());
961973

962974
assert_eq!(id.owner, self.current_hir_id_owner);
963975
let ret = self.arena.alloc_from_iter(lowered_attrs);

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,11 +1133,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11331133
contract: _,
11341134
body,
11351135
define_opaque: _,
1136+
eii_impls,
11361137
},
11371138
) => {
11381139
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
11391140
self.check_defaultness(item.span, *defaultness);
11401141

1142+
for EiiImpl { eii_macro_path, .. } in eii_impls {
1143+
self.visit_path(eii_macro_path);
1144+
}
1145+
11411146
let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
11421147
if body.is_none() && !is_intrinsic && !self.is_sdylib_interface {
11431148
self.dcx().emit_err(errors::FnWithoutBody {

compiler/rustc_ast_pretty/src/pprust/state.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,17 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
852852
sp: Span,
853853
print_visibility: impl FnOnce(&mut Self),
854854
) {
855+
if let Some(eii_extern_target) = &macro_def.eii_extern_target {
856+
self.word("#[eii_extern_target(");
857+
self.print_path(&eii_extern_target.extern_item_path, false, 0);
858+
if eii_extern_target.impl_unsafe {
859+
self.word(",");
860+
self.space();
861+
self.word("unsafe");
862+
}
863+
self.word(")]");
864+
self.hardbreak();
865+
}
855866
let (kw, has_bang) = if macro_def.macro_rules {
856867
("macro_rules", true)
857868
} else {
@@ -2153,6 +2164,15 @@ impl<'a> State<'a> {
21532164

21542165
fn print_meta_item(&mut self, item: &ast::MetaItem) {
21552166
let ib = self.ibox(INDENT_UNIT);
2167+
2168+
match item.unsafety {
2169+
ast::Safety::Unsafe(_) => {
2170+
self.word("unsafe");
2171+
self.popen();
2172+
}
2173+
ast::Safety::Default | ast::Safety::Safe(_) => {}
2174+
}
2175+
21562176
match &item.kind {
21572177
ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
21582178
ast::MetaItemKind::NameValue(value) => {
@@ -2168,6 +2188,12 @@ impl<'a> State<'a> {
21682188
self.pclose();
21692189
}
21702190
}
2191+
2192+
match item.unsafety {
2193+
ast::Safety::Unsafe(_) => self.pclose(),
2194+
ast::Safety::Default | ast::Safety::Safe(_) => {}
2195+
}
2196+
21712197
self.end(ib);
21722198
}
21732199

compiler/rustc_ast_pretty/src/pprust/state/item.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use ast::StaticItem;
22
use itertools::{Itertools, Position};
3-
use rustc_ast::{self as ast, ModKind, TraitAlias};
3+
use rustc_ast::{self as ast, EiiImpl, ModKind, Safety, TraitAlias};
44
use rustc_span::Ident;
55

66
use crate::pp::BoxMarker;
@@ -675,10 +675,25 @@ impl<'a> State<'a> {
675675
}
676676

677677
fn print_fn_full(&mut self, vis: &ast::Visibility, attrs: &[ast::Attribute], func: &ast::Fn) {
678-
let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque } = func;
678+
let ast::Fn { defaultness, ident, generics, sig, contract, body, define_opaque, eii_impls } =
679+
func;
679680

680681
self.print_define_opaques(define_opaque.as_deref());
681682

683+
for EiiImpl { eii_macro_path, impl_safety, .. } in eii_impls {
684+
self.word("#[");
685+
if let Safety::Unsafe(..) = impl_safety {
686+
self.word("unsafe");
687+
self.popen();
688+
}
689+
self.print_path(eii_macro_path, false, 0);
690+
if let Safety::Unsafe(..) = impl_safety {
691+
self.pclose();
692+
}
693+
self.word("]");
694+
self.hardbreak();
695+
}
696+
682697
let body_cb_ib = body.as_ref().map(|body| (body, self.head("")));
683698

684699
self.print_visibility(vis);

compiler/rustc_builtin_macros/messages.ftl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,17 @@ builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept
154154
155155
builtin_macros_duplicate_macro_attribute = duplicated attribute
156156
157+
builtin_macros_eii_extern_target_expected_list = `#[eii_extern_target(...)]` expects a list of one or two elements
158+
builtin_macros_eii_extern_target_expected_macro = `#[eii_extern_target(...)]` is only valid on macros
159+
builtin_macros_eii_extern_target_expected_unsafe = expected this argument to be "unsafe"
160+
.note = the second argument is optional
161+
162+
builtin_macros_eii_only_once = `#[{$name}]` can only be specified once
163+
.note = specified again here
164+
165+
builtin_macros_eii_shared_macro_expected_function = `#[{$name}]` is only valid on functions
166+
builtin_macros_eii_shared_macro_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]`
167+
157168
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
158169
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
159170
.cargo_typo = there is a similar Cargo environment variable: `{$suggested_var}`

0 commit comments

Comments
 (0)