Skip to content

Commit 4a942cd

Browse files
committed
Auto merge of #146348 - jdonszelmann:eiiv3, r=lcnr,oli-obk
Externally implementable items Supersedes #140010 Tracking issue: #125418 Getting started: ```rust #![feature(eii)] #[eii(eii1)] pub fn decl1(x: u64) // body optional (it's the default) { println!("default {x}"); } // in another crate, maybe #[eii1] pub fn decl2(x: u64) { println!("explicit {x}"); } fn main() { decl1(4); } ``` - tiny perf regression, underlying issue makes multiple things in the compiler slow, not just EII, planning to solve those separately. - No codegen_gcc support, they don't have bindings for weak symbols yet but could - No windows support yet for weak definitions This PR merges the implementation of EII for just llvm + not windows, doesn't yet contain like a new panic handler implementation or alloc handler. With this implementation, it would support implementing the panic handler in terms of EII already since it requires no default implementation so no weak symbols The PR has been open in various forms for about a year now, but I feel that having some implementation merged to build upon
2 parents 3391c01 + e7b729c commit 4a942cd

File tree

140 files changed

+3428
-65
lines changed

Some content is hidden

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

140 files changed

+3428
-65
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2109,6 +2109,19 @@ pub struct MacroDef {
21092109
pub body: Box<DelimArgs>,
21102110
/// `true` if macro was defined with `macro_rules`.
21112111
pub macro_rules: bool,
2112+
2113+
/// If this is a macro used for externally implementable items,
2114+
/// it refers to an extern item which is its "target". This requires
2115+
/// name resolution so can't just be an attribute, so we store it in this field.
2116+
pub eii_extern_target: Option<EiiExternTarget>,
2117+
}
2118+
2119+
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
2120+
pub struct EiiExternTarget {
2121+
/// path to the extern item we're targetting
2122+
pub extern_item_path: Path,
2123+
pub impl_unsafe: bool,
2124+
pub span: Span,
21122125
}
21132126

21142127
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
@@ -3748,6 +3761,21 @@ pub struct Fn {
37483761
pub contract: Option<Box<FnContract>>,
37493762
pub define_opaque: Option<ThinVec<(NodeId, Path)>>,
37503763
pub body: Option<Box<Block>>,
3764+
3765+
/// This function is an implementation of an externally implementable item (EII).
3766+
/// This means, there was an EII declared somewhere and this function is the
3767+
/// implementation that should be run when the declaration is called.
3768+
pub eii_impls: ThinVec<EiiImpl>,
3769+
}
3770+
3771+
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
3772+
pub struct EiiImpl {
3773+
pub node_id: NodeId,
3774+
pub eii_macro_path: Path,
3775+
pub impl_safety: Safety,
3776+
pub span: Span,
3777+
pub inner_span: Span,
3778+
pub is_default: bool,
37513779
}
37523780

37533781
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
@@ -4114,7 +4142,7 @@ mod size_asserts {
41144142
static_assert_size!(Block, 32);
41154143
static_assert_size!(Expr, 72);
41164144
static_assert_size!(ExprKind, 40);
4117-
static_assert_size!(Fn, 184);
4145+
static_assert_size!(Fn, 192);
41184146
static_assert_size!(ForeignItem, 80);
41194147
static_assert_size!(ForeignItemKind, 16);
41204148
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
}
@@ -435,7 +522,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
435522
);
436523
hir::ItemKind::TraitAlias(constness, ident, generics, bounds)
437524
}
438-
ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => {
525+
ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_extern_target: _ }) => {
439526
let ident = self.lower_ident(*ident);
440527
let body = Box::new(self.lower_delim_args(body));
441528
let def_id = self.local_def_id(id);
@@ -446,7 +533,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
446533
def_kind.descr(def_id.to_def_id())
447534
);
448535
};
449-
let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
536+
let macro_def = self.arena.alloc(ast::MacroDef {
537+
body,
538+
macro_rules: *macro_rules,
539+
eii_extern_target: None,
540+
});
450541
hir::ItemKind::Macro(ident, macro_def, macro_kinds)
451542
}
452543
ItemKind::Delegation(box delegation) => {
@@ -465,6 +556,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
465556
}
466557
}
467558

559+
fn lower_path_simple_eii(&mut self, id: NodeId, path: &Path) -> Option<DefId> {
560+
let res = self.resolver.get_partial_res(id)?;
561+
let Some(did) = res.expect_full_res().opt_def_id() else {
562+
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
563+
return None;
564+
};
565+
566+
Some(did)
567+
}
568+
468569
#[instrument(level = "debug", skip(self))]
469570
fn lower_use_tree(
470571
&mut self,
@@ -573,6 +674,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
573674
vis_span,
574675
span: this.lower_span(use_tree.span),
575676
has_delayed_lints: !this.delayed_lints.is_empty(),
677+
eii: find_attr!(
678+
attrs,
679+
AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..)
680+
),
576681
};
577682
hir::OwnerNode::Item(this.arena.alloc(item))
578683
});

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -971,11 +971,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
971971
target_span: Span,
972972
target: Target,
973973
) -> &'hir [hir::Attribute] {
974-
if attrs.is_empty() {
974+
self.lower_attrs_with_extra(id, attrs, target_span, target, &[])
975+
}
976+
977+
fn lower_attrs_with_extra(
978+
&mut self,
979+
id: HirId,
980+
attrs: &[Attribute],
981+
target_span: Span,
982+
target: Target,
983+
extra_hir_attributes: &[hir::Attribute],
984+
) -> &'hir [hir::Attribute] {
985+
if attrs.is_empty() && extra_hir_attributes.is_empty() {
975986
&[]
976987
} else {
977-
let lowered_attrs =
988+
let mut lowered_attrs =
978989
self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target);
990+
lowered_attrs.extend(extra_hir_attributes.iter().cloned());
979991

980992
assert_eq!(id.owner, self.current_hir_id_owner);
981993
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
@@ -1179,11 +1179,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11791179
contract: _,
11801180
body,
11811181
define_opaque: _,
1182+
eii_impls,
11821183
},
11831184
) => {
11841185
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
11851186
self.check_defaultness(item.span, *defaultness);
11861187

1188+
for EiiImpl { eii_macro_path, .. } in eii_impls {
1189+
self.visit_path(eii_macro_path);
1190+
}
1191+
11871192
let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
11881193
if body.is_none() && !is_intrinsic && !self.is_sdylib_interface {
11891194
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
@@ -865,6 +865,17 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
865865
sp: Span,
866866
print_visibility: impl FnOnce(&mut Self),
867867
) {
868+
if let Some(eii_extern_target) = &macro_def.eii_extern_target {
869+
self.word("#[eii_extern_target(");
870+
self.print_path(&eii_extern_target.extern_item_path, false, 0);
871+
if eii_extern_target.impl_unsafe {
872+
self.word(",");
873+
self.space();
874+
self.word("unsafe");
875+
}
876+
self.word(")]");
877+
self.hardbreak();
878+
}
868879
let (kw, has_bang) = if macro_def.macro_rules {
869880
("macro_rules", true)
870881
} else {
@@ -2162,6 +2173,15 @@ impl<'a> State<'a> {
21622173

21632174
fn print_meta_item(&mut self, item: &ast::MetaItem) {
21642175
let ib = self.ibox(INDENT_UNIT);
2176+
2177+
match item.unsafety {
2178+
ast::Safety::Unsafe(_) => {
2179+
self.word("unsafe");
2180+
self.popen();
2181+
}
2182+
ast::Safety::Default | ast::Safety::Safe(_) => {}
2183+
}
2184+
21652185
match &item.kind {
21662186
ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
21672187
ast::MetaItemKind::NameValue(value) => {
@@ -2177,6 +2197,12 @@ impl<'a> State<'a> {
21772197
self.pclose();
21782198
}
21792199
}
2200+
2201+
match item.unsafety {
2202+
ast::Safety::Unsafe(_) => self.pclose(),
2203+
ast::Safety::Default | ast::Safety::Safe(_) => {}
2204+
}
2205+
21802206
self.end(ib);
21812207
}
21822208

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;
@@ -671,10 +671,25 @@ impl<'a> State<'a> {
671671
}
672672

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

676677
self.print_define_opaques(define_opaque.as_deref());
677678

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

680695
self.print_visibility(vis);

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,3 +699,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisPa
699699
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
700700
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
701701
}
702+
703+
pub(crate) struct EiiExternItemParser;
704+
705+
impl<S: Stage> NoArgsAttributeParser<S> for EiiExternItemParser {
706+
const PATH: &[Symbol] = &[sym::rustc_eii_extern_item];
707+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
708+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
709+
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiExternItem;
710+
}

0 commit comments

Comments
 (0)