Skip to content

Commit 6a075ae

Browse files
committed
make linkage be external more often
1 parent 9d4d1e5 commit 6a075ae

File tree

20 files changed

+168
-114
lines changed

20 files changed

+168
-114
lines changed

compiler/rustc_error_codes/src/error_codes/E0264.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#### this error code is no longer emitted by the compiler.
2+
13
An unknown external lang item was used.
24

35
Erroneous code example:

compiler/rustc_hir/src/lang_items.rs

+4
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,10 @@ language_item_table! {
293293
PanicMisalignedPointerDereference, sym::panic_misaligned_pointer_dereference, panic_misaligned_pointer_dereference_fn, Target::Fn, GenericRequirement::Exact(0);
294294
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
295295
PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
296+
/// Note: used to mark an extern item but now marks an externally implementable item. This means
297+
/// that the PanicImpl used to be marked to be specially treated in the compiler, while it now
298+
/// is only marked so we can check if it exists. There's no other reason for this lang item
299+
/// anymore.
296300
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
297301
PanicCannotUnwind, sym::panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0);
298302
PanicInCleanup, sym::panic_in_cleanup, panic_in_cleanup, Target::Fn, GenericRequirement::Exact(0);

compiler/rustc_middle/src/middle/eii.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable};
77
pub struct EiiMapping {
88
pub extern_item: DefId,
99
pub chosen_impl: DefId,
10+
pub weak_linkage: bool,
1011
}
1112

1213
pub type EiiMap = FxIndexMap<LocalDefId, EiiMapping>;

compiler/rustc_middle/src/mir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1672,7 +1672,7 @@ mod size_asserts {
16721672
// tidy-alphabetical-start
16731673
static_assert_size!(BasicBlockData<'_>, 128);
16741674
static_assert_size!(LocalDecl<'_>, 40);
1675-
static_assert_size!(SourceScopeData<'_>, 64);
1675+
static_assert_size!(SourceScopeData<'_>, 72);
16761676
static_assert_size!(Statement<'_>, 32);
16771677
static_assert_size!(Terminator<'_>, 96);
16781678
static_assert_size!(VarDebugInfo<'_>, 88);

compiler/rustc_middle/src/mir/mono.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ pub struct MonoItemData {
382382
/// Specifies the linkage type for a `MonoItem`.
383383
///
384384
/// See <https://llvm.org/docs/LangRef.html#linkage-types> for more details about these variants.
385-
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
385+
#[derive(Copy, Clone, PartialEq, Debug, TyEncodable, TyDecodable, HashStable, Eq, Hash)]
386386
pub enum Linkage {
387387
External,
388388
AvailableExternally,

compiler/rustc_middle/src/mir/terminator.rs

+8
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ impl<O> AssertKind<O> {
215215
}
216216
}
217217

218+
/// Generally do not use this and use `panic_function` instead.
219+
/// Gives the lang item that is required to exist for this assertion
220+
/// to be emitted. This sometimes causes the assertion not to be emitted
221+
/// if a lang item isn't there.
222+
pub fn required_lang_item(&self) {
223+
224+
}
225+
218226
/// Format the message arguments for the `assert(cond, msg..)` terminator in MIR printing.
219227
///
220228
/// Needs to be kept in sync with the run-time behavior (which is defined by

compiler/rustc_middle/src/mir/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ macro_rules! make_mir_visitor {
355355
}
356356
| ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, None)
357357
| ty::InstanceKind::DropGlue(_def_id, None)
358-
| ty::InstanceKind::EiiShim { def_id: _def_id, extern_item: _, chosen_impl: _ } => {}
358+
| ty::InstanceKind::EiiShim { def_id: _def_id, extern_item: _, chosen_impl: _, weak_linkage: _ } => {}
359359

360360
ty::InstanceKind::FnPtrShim(_def_id, ty)
361361
| ty::InstanceKind::DropGlue(_def_id, Some(ty))

compiler/rustc_middle/src/ty/instance.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ pub enum InstanceKind<'tcx> {
178178
/// Generated by externally implementable items. This function adds indirection so we can choose
179179
/// in the final crate whether to call an explicit implementation or, if none are given, call the
180180
/// default.
181-
EiiShim { def_id: DefId, extern_item: DefId, chosen_impl: DefId },
181+
EiiShim { def_id: DefId, extern_item: DefId, chosen_impl: DefId, weak_linkage: bool },
182182
}
183183

184184
impl<'tcx> Instance<'tcx> {
@@ -416,7 +416,10 @@ pub fn fmt_instance(
416416
InstanceKind::FnPtrAddrShim(_, ty) => write!(f, " - shim({ty})"),
417417
InstanceKind::AsyncDropGlueCtorShim(_, None) => write!(f, " - shim(None)"),
418418
InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)) => write!(f, " - shim(Some({ty}))"),
419-
InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl } => {
419+
InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl, weak_linkage: true} => {
420+
write!(f, " - shim(eii: {extern_item:?} -> {chosen_impl:?} [weak]")
421+
}
422+
InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl, weak_linkage: false} => {
420423
write!(f, " - shim(eii: {extern_item:?} -> {chosen_impl:?})")
421424
}
422425
}

compiler/rustc_mir_transform/src/shim.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
7878
receiver_by_ref,
7979
} => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref),
8080

81-
e @ ty::InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl } => {
81+
e @ ty::InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl, weak_linkage: _ } => {
8282
let source = MirSource::from_instance(e);
8383

8484
// get the signature for the new function this shim is creating

compiler/rustc_monomorphize/src/collector.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1592,7 +1592,7 @@ impl<'v> RootCollector<'_, 'v> {
15921592
/// For each externally implementable item, we should generate an alias MonoItem that
15931593
/// determines what implementation is called. This could be a default implementation.
15941594
fn push_extra_eii_roots(&mut self) {
1595-
for (shim_did, &EiiMapping { extern_item, chosen_impl, .. }) in
1595+
for (shim_did, &EiiMapping { extern_item, chosen_impl, weak_linkage, .. }) in
15961596
self.tcx.get_externally_implementable_item_impls(())
15971597
{
15981598
self.output.push(create_fn_mono_item(
@@ -1602,6 +1602,7 @@ impl<'v> RootCollector<'_, 'v> {
16021602
def_id: (*shim_did).into(),
16031603
extern_item,
16041604
chosen_impl,
1605+
weak_linkage,
16051606
},
16061607
args: ty::GenericArgs::empty(),
16071608
},

compiler/rustc_monomorphize/src/partitioning.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
634634
ty::InstanceKind::Item(def) => def,
635635
// EII shims have a characteristic defid.
636636
// But it's not their own, its the one of the extern item it is implementing.
637-
ty::InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl: _ } => extern_item,
637+
ty::InstanceKind::EiiShim { def_id: _, extern_item, chosen_impl: _, weak_linkage: _ } => extern_item,
638638
ty::InstanceKind::VTableShim(..)
639639
| ty::InstanceKind::ReifyShim(..)
640640
| ty::InstanceKind::FnPtrShim(..)
@@ -767,8 +767,12 @@ fn mono_item_linkage_and_visibility<'tcx>(
767767
// together anyway. LLVM ensures the last one is the one that's chosen
768768
// TODO: this isn't the problem if they both decided to choose either the default or the
769769
// same explicit impl but if their view on it differs it is a problem!
770-
if let MonoItem::Fn(Instance { def: InstanceKind::EiiShim { .. }, .. }) = mono_item {
771-
(Linkage::WeakAny, vis)
770+
if let MonoItem::Fn(Instance { def: InstanceKind::EiiShim { weak_linkage, .. }, .. }) = mono_item {
771+
if *weak_linkage {
772+
(Linkage::WeakAny, vis)
773+
} else {
774+
(Linkage::External, vis)
775+
}
772776
} else {
773777
(Linkage::External, vis)
774778
}

compiler/rustc_passes/messages.ftl

-3
Original file line numberDiff line numberDiff line change
@@ -760,9 +760,6 @@ passes_transparent_incompatible =
760760
passes_undefined_naked_function_abi =
761761
Rust ABI is unsupported in naked functions
762762
763-
passes_unknown_external_lang_item =
764-
unknown external lang item: `{$lang_item}`
765-
766763
passes_unknown_feature =
767764
unknown feature `{$feature}`
768765

compiler/rustc_passes/src/eii.rs

+124-68
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_attr_parsing::{EIIDecl, EIIImpl};
66
use rustc_data_structures::fx::FxIndexMap;
77
use rustc_hir::def::DefKind;
88
use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId};
9+
use rustc_middle::bug;
910
use rustc_middle::middle::eii::EiiMapping;
1011
use rustc_middle::ty::TyCtxt;
1112
use rustc_session::config::CrateType;
@@ -21,39 +22,59 @@ pub(crate) fn get_externally_implementable_item_impls<'tcx>(
2122
tcx: TyCtxt<'tcx>,
2223
(): (),
2324
) -> &'tcx FxIndexMap<LocalDefId, EiiMapping> {
24-
// We only need to check whether there are duplicate or missing EIIs if we're
25-
// emitting something that's not an rlib.
26-
let needs_check = tcx.crate_types().iter().any(|kind| match *kind {
27-
// Executables are leafs of the crate graph and need all EIIs to be satisfied,
28-
// either with defaults or explicit implementations. So they check their crate
29-
// graph to make sure this is the case.
30-
CrateType::Executable => true,
31-
// Proc macros are leafs of their crate graph and will be run,
32-
// and so need to check the EIIs of their dependencies.
33-
CrateType::ProcMacro => true,
34-
35-
// These are a litte difficult. We don't know whether things depending on these
36-
// will perform checks to see if EIIs are implemented, or duplicated, or any other
37-
// of the checks performed in this function. So we must do the checks. However,
38-
// this can later lead to duplicate symbols when linking them together.
39-
// For this reason, we later mark EII symbols as "globally shared" and "may conflict".
40-
// In other words, if two shared libraries both provide an implementation for an EII,
41-
// that's fine! Just choose one... And because their mangled symbol names are the same
42-
// (that's exactly the conflict we're having) we hopefully have the same exact implementation.
43-
CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => true,
44-
45-
// Rlibs are just a step in the crate graph.
46-
// Later on we'll link it together into an executable and over there we can check for EIIs
47-
CrateType::Rlib => false,
48-
});
49-
if !needs_check {
50-
// In this case we could only have called it when checking,
51-
// and not when we were actually codegenning functions so we don't need to return any real data
52-
return &*tcx.arena.alloc(FxIndexMap::default());
25+
#[derive(Copy, Clone)]
26+
enum Case {
27+
/// We need to generate all EII shims because we are generating some final target like an
28+
/// executable or library (not rlib)
29+
AlwaysEmit,
30+
/// We need to generate all EII shims because one of our crate types is a final target like
31+
/// an executable. However, we're also generating an rlib. So. If we see explicit
32+
/// definitions of EIIs we can generate them with external linkage. However, if we find
33+
/// defaults, they must also be emitted because some of our crate types are final targets.
34+
/// And unfortunately the rlib will also contain these definitions. However, because rlibs
35+
/// will later be used in final targets, which will use `AlwaysEmit`, these symbols that were
36+
/// spuriously generated in rlibs will be redefined and then flagged by the linker as
37+
/// duplicate definitions. So, we have to emit EII shims which are default impls (not
38+
/// explicit ones) as weak symbols.
39+
EmitMaybeWeak,
40+
/// We don't always need to emit EIIs because we're generating an Rlib. However, if we see
41+
/// an explicit implementation, we can! Because it cannot be overwritten anymore.
42+
EmitExternalIfExplicit,
43+
}
44+
45+
let has_rlib = tcx.crate_types().iter().any(|i| matches!(i, CrateType::Rlib));
46+
let has_target = tcx.crate_types().iter().any(|i| !matches!(i, CrateType::Rlib));
47+
48+
let case = match (has_rlib, has_target) {
49+
(true, true) => {
50+
Case::EmitMaybeWeak
51+
},
52+
(true, false) => {
53+
Case::EmitExternalIfExplicit
54+
},
55+
(false, true) => {
56+
Case::AlwaysEmit
57+
},
58+
(false, false) => {
59+
bug!("no targets but somehow we are running the compiler")
60+
},
61+
};
62+
63+
#[derive(Debug)]
64+
struct FoundImpl {
65+
imp: EIIImpl,
66+
impl_crate: CrateNum
67+
}
68+
69+
#[derive(Debug)]
70+
struct FoundEii {
71+
decl: EIIDecl,
72+
decl_crate: CrateNum,
73+
impls: FxIndexMap<DefId, FoundImpl>
5374
}
5475

5576
let mut eiis =
56-
FxIndexMap::<DefId, (EIIDecl, CrateNum, FxIndexMap<DefId, (EIIImpl, CrateNum)>)>::default();
77+
FxIndexMap::<DefId, FoundEii>::default();
5778

5879
// println!("current crate: {}", tcx.crate_name(LOCAL_CRATE));
5980

@@ -66,28 +87,28 @@ pub(crate) fn get_externally_implementable_item_impls<'tcx>(
6687
// update or insert the corresponding entries
6788
for (did, (decl, impls)) in crate_eiis {
6889
eiis.entry(*did)
69-
.or_insert_with(|| (*decl, cnum, Default::default()))
70-
.2
71-
.extend(impls.into_iter().map(|(did, i)| (*did, (*i, cnum))));
90+
.or_insert_with(|| FoundEii {decl: *decl, decl_crate: cnum, impls: Default::default()})
91+
.impls
92+
.extend(impls.into_iter().map(|(did, i)| (*did, FoundImpl{ imp: *i, impl_crate: cnum})));
7293
}
7394
}
7495

7596
let mut final_impls = FxIndexMap::default();
7697

7798
// now we have all eiis! For each of them, choose one we want to actually generate.
7899

79-
for (decl_did, (decl, decl_crate, impls)) in eiis {
100+
for (decl_did, FoundEii { decl, decl_crate, impls } ) in eiis {
80101
// println!("for decl: {decl_did:?}: {decl:?}");
81102
let mut default_impls = Vec::new();
82103
let mut explicit_impls = Vec::new();
83104

84-
for (impl_did, (impl_metadata, cnum)) in impls {
85-
if impl_metadata.is_default {
105+
for (impl_did, FoundImpl { imp, impl_crate }) in impls {
106+
if imp.is_default {
86107
// println!("found default impl in {}", tcx.crate_name(cnum));
87-
default_impls.push((impl_did, cnum));
108+
default_impls.push((impl_did, impl_crate));
88109
} else {
89110
// println!("found impl in {}", tcx.crate_name(cnum));
90-
explicit_impls.push((impl_did, cnum));
111+
explicit_impls.push((impl_did, impl_crate));
91112
}
92113
}
93114

@@ -115,43 +136,78 @@ pub(crate) fn get_externally_implementable_item_impls<'tcx>(
115136
panic!("multiple not supported right now, but this is easily possible");
116137
}
117138

118-
// println!("impls: {explicit_impls:?}");
119-
// println!("default impls: {default_impls:?}");
120139

121-
if let Some((chosen_impl, _)) = explicit_impls.first().or(default_impls.first()) {
122-
let feed = tcx.create_def(
123-
CRATE_DEF_ID,
124-
Some(Symbol::intern(&format!("EII shim for {decl_did:?}"))),
125-
DefKind::Fn,
126-
);
140+
let (chosen_impl, weak_linkage) = match (case, explicit_impls.first(), default_impls.first()) {
141+
(Case::EmitExternalIfExplicit, Some((explicit, impl_crate)), _) => {
142+
if impl_crate != &LOCAL_CRATE {
143+
continue;
144+
}
145+
(explicit, false)
146+
}
147+
// we don't care in this case if we find no implementation yet. Another can come
148+
// downstream.
149+
(Case::EmitExternalIfExplicit, None, _) => {
150+
continue;
151+
}
152+
153+
(Case::AlwaysEmit, Some((explicit, impl_crate)), _) => {
154+
if impl_crate != &LOCAL_CRATE {
155+
continue;
156+
}
157+
158+
(explicit, false)
159+
}
160+
(Case::AlwaysEmit, _, Some((deflt, _))) => (deflt, false),
161+
162+
(Case::EmitMaybeWeak, Some((explicit, impl_crate)), _) => {
163+
if impl_crate != &LOCAL_CRATE {
164+
continue;
165+
}
127166

128-
let extern_item_did = decl.eii_extern_item;
167+
(explicit, false)
168+
}
169+
// IMPORTANT! weak linkage because the symbol will also end up in the rlib and may need
170+
// to be overwritten :(
171+
(Case::EmitMaybeWeak, _, Some((deflt, _))) => (deflt, true),
172+
173+
// We have a target to generate, but no impl to put in it. error!
174+
(Case::EmitMaybeWeak | Case::AlwaysEmit, None, None) => {
175+
tcx.dcx().emit_err(EiiWithoutImpl {
176+
current_crate_name: tcx.crate_name(LOCAL_CRATE),
177+
decl_crate_name: tcx.crate_name(decl_crate),
178+
name: tcx.item_name(decl_did),
179+
span: decl.span,
180+
help: (),
181+
});
182+
183+
continue;
184+
}
185+
};
129186

130-
feed.generics_of(tcx.generics_of(extern_item_did).clone());
131-
feed.type_of(tcx.type_of(extern_item_did).clone());
132-
feed.def_span(tcx.def_span(chosen_impl));
133-
feed.visibility(tcx.visibility(chosen_impl));
134-
feed.feed_hir();
187+
let feed = tcx.create_def(
188+
CRATE_DEF_ID,
189+
Some(Symbol::intern(&format!("EII shim for {decl_did:?}"))),
190+
DefKind::Fn,
191+
);
135192

136-
// println!("generating {extern_item_did:?} for impl {chosen_impl:?} in crate {} with did {decl_did:?}", tcx.crate_name(LOCAL_CRATE));
193+
let extern_item_did = decl.eii_extern_item;
137194

138-
let shim_did = feed.def_id();
195+
feed.generics_of(tcx.generics_of(extern_item_did).clone());
196+
feed.type_of(tcx.type_of(extern_item_did).clone());
197+
feed.def_span(tcx.def_span(chosen_impl));
198+
feed.visibility(tcx.visibility(chosen_impl));
199+
feed.feed_hir();
139200

140-
// println!("shim: {shim_did:?}");
201+
// println!("generating {extern_item_did:?} for impl {chosen_impl:?} in crate {} with did {decl_did:?}", tcx.crate_name(LOCAL_CRATE));
141202

142-
final_impls.insert(
143-
shim_did,
144-
EiiMapping { extern_item: extern_item_did, chosen_impl: *chosen_impl },
145-
);
146-
} else {
147-
tcx.dcx().emit_err(EiiWithoutImpl {
148-
current_crate_name: tcx.crate_name(LOCAL_CRATE),
149-
decl_crate_name: tcx.crate_name(decl_crate),
150-
name: tcx.item_name(decl_did),
151-
span: decl.span,
152-
help: (),
153-
});
154-
}
203+
let shim_did = feed.def_id();
204+
205+
// println!("shim: {shim_did:?}");
206+
207+
final_impls.insert(
208+
shim_did,
209+
EiiMapping { extern_item: extern_item_did, chosen_impl: *chosen_impl, weak_linkage },
210+
);
155211
}
156212

157213
tcx.arena.alloc(final_impls)

0 commit comments

Comments
 (0)