Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f98598c

Browse files
committedMar 29, 2023
Auto merge of #108089 - Zoxc:windows-tls, r=bjorn3
Support TLS access into dylibs on Windows This allows access to `#[thread_local]` in upstream dylibs on Windows by introducing a MIR shim to return the address of the thread local. Accesses that go into an upstream dylib will call the MIR shim to get the address of it. `convert_tls_rvalues` is introduced in `rustc_codegen_ssa` which rewrites MIR TLS accesses to dummy calls which are replaced with calls to the MIR shims when the dummy calls are lowered to backend calls. A new `dll_tls_export` target option enables this behavior with a `false` value which is set for Windows platforms. This fixes #84933.
2 parents 8679208 + d499bbb commit f98598c

File tree

28 files changed

+262
-95
lines changed

28 files changed

+262
-95
lines changed
 

‎compiler/rustc_codegen_cranelift/src/constant.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,22 @@ pub(crate) fn codegen_tls_ref<'tcx>(
5454
def_id: DefId,
5555
layout: TyAndLayout<'tcx>,
5656
) -> CValue<'tcx> {
57-
let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
58-
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
59-
if fx.clif_comments.enabled() {
60-
fx.add_comment(local_data_id, format!("tls {:?}", def_id));
61-
}
62-
let tls_ptr = fx.bcx.ins().tls_value(fx.pointer_type, local_data_id);
57+
let tls_ptr = if !def_id.is_local() && fx.tcx.needs_thread_local_shim(def_id) {
58+
let instance = ty::Instance {
59+
def: ty::InstanceDef::ThreadLocalShim(def_id),
60+
substs: ty::InternalSubsts::empty(),
61+
};
62+
let func_ref = fx.get_function_ref(instance);
63+
let call = fx.bcx.ins().call(func_ref, &[]);
64+
fx.bcx.func.dfg.first_result(call)
65+
} else {
66+
let data_id = data_id_for_static(fx.tcx, fx.module, def_id, false);
67+
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
68+
if fx.clif_comments.enabled() {
69+
fx.add_comment(local_data_id, format!("tls {:?}", def_id));
70+
}
71+
fx.bcx.ins().tls_value(fx.pointer_type, local_data_id)
72+
};
6373
CValue::by_val(tls_ptr, layout)
6474
}
6575

‎compiler/rustc_codegen_ssa/src/back/symbol_export.rs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,29 @@ fn exported_symbols_provider_local(
177177

178178
// FIXME: Sorting this is unnecessary since we are sorting later anyway.
179179
// Can we skip the later sorting?
180-
let mut symbols: Vec<_> = tcx.with_stable_hashing_context(|hcx| {
181-
tcx.reachable_non_generics(LOCAL_CRATE)
182-
.to_sorted(&hcx, true)
183-
.into_iter()
184-
.map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info))
185-
.collect()
180+
let sorted = tcx.with_stable_hashing_context(|hcx| {
181+
tcx.reachable_non_generics(LOCAL_CRATE).to_sorted(&hcx, true)
186182
});
187183

184+
let mut symbols: Vec<_> =
185+
sorted.iter().map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)).collect();
186+
187+
// Export TLS shims
188+
if !tcx.sess.target.dll_tls_export {
189+
symbols.extend(sorted.iter().filter_map(|(&def_id, &info)| {
190+
tcx.needs_thread_local_shim(def_id).then(|| {
191+
(
192+
ExportedSymbol::ThreadLocalShim(def_id),
193+
SymbolExportInfo {
194+
level: info.level,
195+
kind: SymbolExportKind::Text,
196+
used: info.used,
197+
},
198+
)
199+
})
200+
}))
201+
}
202+
188203
if tcx.entry_fn(()).is_some() {
189204
let exported_symbol =
190205
ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref()));
@@ -380,7 +395,9 @@ fn upstream_monomorphizations_provider(
380395
continue;
381396
}
382397
}
383-
ExportedSymbol::NonGeneric(..) | ExportedSymbol::NoDefId(..) => {
398+
ExportedSymbol::NonGeneric(..)
399+
| ExportedSymbol::ThreadLocalShim(..)
400+
| ExportedSymbol::NoDefId(..) => {
384401
// These are no monomorphizations
385402
continue;
386403
}
@@ -500,6 +517,16 @@ pub fn symbol_name_for_instance_in_crate<'tcx>(
500517
instantiating_crate,
501518
)
502519
}
520+
ExportedSymbol::ThreadLocalShim(def_id) => {
521+
rustc_symbol_mangling::symbol_name_for_instance_in_crate(
522+
tcx,
523+
ty::Instance {
524+
def: ty::InstanceDef::ThreadLocalShim(def_id),
525+
substs: ty::InternalSubsts::empty(),
526+
},
527+
instantiating_crate,
528+
)
529+
}
503530
ExportedSymbol::DropGlue(ty) => rustc_symbol_mangling::symbol_name_for_instance_in_crate(
504531
tcx,
505532
Instance::resolve_drop_in_place(tcx, ty),
@@ -548,6 +575,8 @@ pub fn linking_symbol_name_for_instance_in_crate<'tcx>(
548575
ExportedSymbol::DropGlue(..) => None,
549576
// NoDefId always follow the target's default symbol decoration scheme.
550577
ExportedSymbol::NoDefId(..) => None,
578+
// ThreadLocalShim always follow the target's default symbol decoration scheme.
579+
ExportedSymbol::ThreadLocalShim(..) => None,
551580
};
552581

553582
let (conv, args) = instance

‎compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
516516

517517
mir::Rvalue::ThreadLocalRef(def_id) => {
518518
assert!(bx.cx().tcx().is_static(def_id));
519-
let static_ = bx.get_static(def_id);
520519
let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id));
520+
let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id)
521+
{
522+
let instance = ty::Instance {
523+
def: ty::InstanceDef::ThreadLocalShim(def_id),
524+
substs: ty::InternalSubsts::empty(),
525+
};
526+
let fn_ptr = bx.get_fn_addr(instance);
527+
let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
528+
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
529+
bx.call(fn_ty, Some(fn_abi), fn_ptr, &[], None)
530+
} else {
531+
bx.get_static(def_id)
532+
};
521533
OperandRef { val: OperandValue::Immediate(static_), layout }
522534
}
523535
mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand),

‎compiler/rustc_const_eval/src/interpret/terminator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
383383
| ty::InstanceDef::DropGlue(..)
384384
| ty::InstanceDef::CloneShim(..)
385385
| ty::InstanceDef::FnPtrAddrShim(..)
386+
| ty::InstanceDef::ThreadLocalShim(..)
386387
| ty::InstanceDef::Item(_) => {
387388
// We need MIR for this fn
388389
let Some((body, instance)) =

‎compiler/rustc_middle/src/middle/exported_symbols.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub enum ExportedSymbol<'tcx> {
4343
NonGeneric(DefId),
4444
Generic(DefId, SubstsRef<'tcx>),
4545
DropGlue(Ty<'tcx>),
46+
ThreadLocalShim(DefId),
4647
NoDefId(ty::SymbolName<'tcx>),
4748
}
4849

@@ -58,6 +59,10 @@ impl<'tcx> ExportedSymbol<'tcx> {
5859
ExportedSymbol::DropGlue(ty) => {
5960
tcx.symbol_name(ty::Instance::resolve_drop_in_place(tcx, ty))
6061
}
62+
ExportedSymbol::ThreadLocalShim(def_id) => tcx.symbol_name(ty::Instance {
63+
def: ty::InstanceDef::ThreadLocalShim(def_id),
64+
substs: ty::InternalSubsts::empty(),
65+
}),
6166
ExportedSymbol::NoDefId(symbol_name) => symbol_name,
6267
}
6368
}

‎compiler/rustc_middle/src/mir/mono.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ impl<'tcx> CodegenUnit<'tcx> {
382382
| InstanceDef::ClosureOnceShim { .. }
383383
| InstanceDef::DropGlue(..)
384384
| InstanceDef::CloneShim(..)
385+
| InstanceDef::ThreadLocalShim(..)
385386
| InstanceDef::FnPtrAddrShim(..) => None,
386387
}
387388
}

‎compiler/rustc_middle/src/mir/tcx.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -164,17 +164,7 @@ impl<'tcx> Rvalue<'tcx> {
164164
Rvalue::Repeat(ref operand, count) => {
165165
tcx.mk_array_with_const_len(operand.ty(local_decls, tcx), count)
166166
}
167-
Rvalue::ThreadLocalRef(did) => {
168-
let static_ty = tcx.type_of(did).subst_identity();
169-
if tcx.is_mutable_static(did) {
170-
tcx.mk_mut_ptr(static_ty)
171-
} else if tcx.is_foreign_item(did) {
172-
tcx.mk_imm_ptr(static_ty)
173-
} else {
174-
// FIXME: These things don't *really* have 'static lifetime.
175-
tcx.mk_imm_ref(tcx.lifetimes.re_static, static_ty)
176-
}
177-
}
167+
Rvalue::ThreadLocalRef(did) => tcx.thread_local_ptr_ty(did),
178168
Rvalue::Ref(reg, bk, ref place) => {
179169
let place_ty = place.ty(local_decls, tcx).ty;
180170
tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, mutbl: bk.to_mutbl_lossy() })

‎compiler/rustc_middle/src/mir/visit.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ macro_rules! make_mir_visitor {
335335
ty::InstanceDef::VTableShim(_def_id) |
336336
ty::InstanceDef::ReifyShim(_def_id) |
337337
ty::InstanceDef::Virtual(_def_id, _) |
338+
ty::InstanceDef::ThreadLocalShim(_def_id) |
338339
ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
339340
ty::InstanceDef::DropGlue(_def_id, None) => {}
340341

‎compiler/rustc_middle/src/ty/instance.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ pub enum InstanceDef<'tcx> {
8282
/// The `DefId` is the ID of the `call_once` method in `FnOnce`.
8383
ClosureOnceShim { call_once: DefId, track_caller: bool },
8484

85+
/// Compiler-generated accessor for thread locals which returns a reference to the thread local
86+
/// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking
87+
/// native support.
88+
ThreadLocalShim(DefId),
89+
8590
/// `core::ptr::drop_in_place::<T>`.
8691
///
8792
/// The `DefId` is for `core::ptr::drop_in_place`.
@@ -156,6 +161,7 @@ impl<'tcx> InstanceDef<'tcx> {
156161
| InstanceDef::FnPtrShim(def_id, _)
157162
| InstanceDef::Virtual(def_id, _)
158163
| InstanceDef::Intrinsic(def_id)
164+
| InstanceDef::ThreadLocalShim(def_id)
159165
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
160166
| InstanceDef::DropGlue(def_id, _)
161167
| InstanceDef::CloneShim(def_id, _)
@@ -167,7 +173,9 @@ impl<'tcx> InstanceDef<'tcx> {
167173
pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
168174
match self {
169175
ty::InstanceDef::Item(def) => Some(def.did),
170-
ty::InstanceDef::DropGlue(def_id, Some(_)) => Some(def_id),
176+
ty::InstanceDef::DropGlue(def_id, Some(_)) | InstanceDef::ThreadLocalShim(def_id) => {
177+
Some(def_id)
178+
}
171179
InstanceDef::VTableShim(..)
172180
| InstanceDef::ReifyShim(..)
173181
| InstanceDef::FnPtrShim(..)
@@ -192,6 +200,7 @@ impl<'tcx> InstanceDef<'tcx> {
192200
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
193201
| InstanceDef::DropGlue(def_id, _)
194202
| InstanceDef::CloneShim(def_id, _)
203+
| InstanceDef::ThreadLocalShim(def_id)
195204
| InstanceDef::FnPtrAddrShim(def_id, _) => ty::WithOptConstParam::unknown(def_id),
196205
}
197206
}
@@ -215,6 +224,7 @@ impl<'tcx> InstanceDef<'tcx> {
215224
let def_id = match *self {
216225
ty::InstanceDef::Item(def) => def.did,
217226
ty::InstanceDef::DropGlue(_, Some(_)) => return false,
227+
ty::InstanceDef::ThreadLocalShim(_) => return false,
218228
_ => return true,
219229
};
220230
matches!(
@@ -255,6 +265,9 @@ impl<'tcx> InstanceDef<'tcx> {
255265
)
256266
});
257267
}
268+
if let ty::InstanceDef::ThreadLocalShim(..) = *self {
269+
return false;
270+
}
258271
tcx.codegen_fn_attrs(self.def_id()).requests_inline()
259272
}
260273

@@ -278,6 +291,7 @@ impl<'tcx> InstanceDef<'tcx> {
278291
pub fn has_polymorphic_mir_body(&self) -> bool {
279292
match *self {
280293
InstanceDef::CloneShim(..)
294+
| InstanceDef::ThreadLocalShim(..)
281295
| InstanceDef::FnPtrAddrShim(..)
282296
| InstanceDef::FnPtrShim(..)
283297
| InstanceDef::DropGlue(_, Some(_)) => false,
@@ -310,6 +324,7 @@ fn fmt_instance(
310324
InstanceDef::Item(_) => Ok(()),
311325
InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"),
312326
InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"),
327+
InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"),
313328
InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"),
314329
InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num),
315330
InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({})", ty),

‎compiler/rustc_middle/src/ty/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2386,6 +2386,7 @@ impl<'tcx> TyCtxt<'tcx> {
23862386
| ty::InstanceDef::ClosureOnceShim { .. }
23872387
| ty::InstanceDef::DropGlue(..)
23882388
| ty::InstanceDef::CloneShim(..)
2389+
| ty::InstanceDef::ThreadLocalShim(..)
23892390
| ty::InstanceDef::FnPtrAddrShim(..) => self.mir_shims(instance),
23902391
}
23912392
}

‎compiler/rustc_middle/src/ty/util.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,28 @@ impl<'tcx> TyCtxt<'tcx> {
597597
self.static_mutability(def_id) == Some(hir::Mutability::Mut)
598598
}
599599

600+
/// Returns `true` if the item pointed to by `def_id` is a thread local which needs a
601+
/// thread local shim generated.
602+
#[inline]
603+
pub fn needs_thread_local_shim(self, def_id: DefId) -> bool {
604+
!self.sess.target.dll_tls_export
605+
&& self.is_thread_local_static(def_id)
606+
&& !self.is_foreign_item(def_id)
607+
}
608+
609+
/// Returns the type a reference to the thread local takes in MIR.
610+
pub fn thread_local_ptr_ty(self, def_id: DefId) -> Ty<'tcx> {
611+
let static_ty = self.type_of(def_id).subst_identity();
612+
if self.is_mutable_static(def_id) {
613+
self.mk_mut_ptr(static_ty)
614+
} else if self.is_foreign_item(def_id) {
615+
self.mk_imm_ptr(static_ty)
616+
} else {
617+
// FIXME: These things don't *really* have 'static lifetime.
618+
self.mk_imm_ref(self.lifetimes.re_static, static_ty)
619+
}
620+
}
621+
600622
/// Get the type of the pointer to the static that we use in MIR.
601623
pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> {
602624
// Make sure that any constants in the static's type are evaluated.

‎compiler/rustc_mir_transform/src/inline.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ impl<'tcx> Inliner<'tcx> {
271271
| InstanceDef::ClosureOnceShim { .. }
272272
| InstanceDef::DropGlue(..)
273273
| InstanceDef::CloneShim(..)
274+
| InstanceDef::ThreadLocalShim(..)
274275
| InstanceDef::FnPtrAddrShim(..) => return Ok(()),
275276
}
276277

‎compiler/rustc_mir_transform/src/inline/cycle.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
8383
| InstanceDef::ReifyShim(_)
8484
| InstanceDef::FnPtrShim(..)
8585
| InstanceDef::ClosureOnceShim { .. }
86+
| InstanceDef::ThreadLocalShim { .. }
8687
| InstanceDef::CloneShim(..) => {}
8788

8889
// This shim does not call any other functions, thus there can be no recursion.

‎compiler/rustc_mir_transform/src/shim.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
7676

7777
build_drop_shim(tcx, def_id, ty)
7878
}
79+
ty::InstanceDef::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance),
7980
ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
8081
ty::InstanceDef::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty),
8182
ty::InstanceDef::Virtual(..) => {
@@ -322,6 +323,34 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
322323
}
323324
}
324325

326+
fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> {
327+
let def_id = instance.def_id();
328+
329+
let span = tcx.def_span(def_id);
330+
let source_info = SourceInfo::outermost(span);
331+
332+
let mut blocks = IndexVec::with_capacity(1);
333+
blocks.push(BasicBlockData {
334+
statements: vec![Statement {
335+
source_info,
336+
kind: StatementKind::Assign(Box::new((
337+
Place::return_place(),
338+
Rvalue::ThreadLocalRef(def_id),
339+
))),
340+
}],
341+
terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
342+
is_cleanup: false,
343+
});
344+
345+
new_body(
346+
MirSource::from_instance(instance),
347+
blocks,
348+
IndexVec::from_raw(vec![LocalDecl::new(tcx.thread_local_ptr_ty(def_id), span)]),
349+
0,
350+
span,
351+
)
352+
}
353+
325354
/// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
326355
fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
327356
debug!("build_clone_shim(def_id={:?})", def_id);

‎compiler/rustc_monomorphize/src/collector.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,8 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
190190
use rustc_middle::ty::query::TyCtxtAt;
191191
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
192192
use rustc_middle::ty::{
193-
self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, VtblEntry,
193+
self, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
194+
VtblEntry,
194195
};
195196
use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
196197
use rustc_session::config::EntryFnType;
@@ -462,6 +463,16 @@ fn collect_items_rec<'tcx>(
462463
collect_miri(tcx, id, &mut neighbors);
463464
}
464465
}
466+
467+
if tcx.needs_thread_local_shim(def_id) {
468+
neighbors.push(respan(
469+
starting_point.span,
470+
MonoItem::Fn(Instance {
471+
def: InstanceDef::ThreadLocalShim(def_id),
472+
substs: InternalSubsts::empty(),
473+
}),
474+
));
475+
}
465476
}
466477
MonoItem::Fn(instance) => {
467478
// Sanity check whether this ended up being collected accidentally
@@ -962,6 +973,9 @@ fn visit_instance_use<'tcx>(
962973
bug!("{:?} being reified", instance);
963974
}
964975
}
976+
ty::InstanceDef::ThreadLocalShim(..) => {
977+
bug!("{:?} being reified", instance);
978+
}
965979
ty::InstanceDef::DropGlue(_, None) => {
966980
// Don't need to emit noop drop glue if we are calling directly.
967981
if !is_direct_call {
@@ -1210,11 +1224,9 @@ impl<'v> RootCollector<'_, 'v> {
12101224
self.output.push(dummy_spanned(MonoItem::GlobalAsm(id)));
12111225
}
12121226
DefKind::Static(..) => {
1213-
debug!(
1214-
"RootCollector: ItemKind::Static({})",
1215-
self.tcx.def_path_str(id.owner_id.to_def_id())
1216-
);
1217-
self.output.push(dummy_spanned(MonoItem::Static(id.owner_id.to_def_id())));
1227+
let def_id = id.owner_id.to_def_id();
1228+
debug!("RootCollector: ItemKind::Static({})", self.tcx.def_path_str(def_id));
1229+
self.output.push(dummy_spanned(MonoItem::Static(def_id)));
12181230
}
12191231
DefKind::Const => {
12201232
// const items only generate mono items if they are

‎compiler/rustc_monomorphize/src/partitioning/default.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
279279
| ty::InstanceDef::DropGlue(..)
280280
| ty::InstanceDef::Virtual(..)
281281
| ty::InstanceDef::CloneShim(..)
282+
| ty::InstanceDef::ThreadLocalShim(..)
282283
| ty::InstanceDef::FnPtrAddrShim(..) => return None,
283284
};
284285

@@ -392,6 +393,19 @@ fn mono_item_linkage_and_visibility<'tcx>(
392393

393394
type CguNameCache = FxHashMap<(DefId, bool), Symbol>;
394395

396+
fn static_visibility<'tcx>(
397+
tcx: TyCtxt<'tcx>,
398+
can_be_internalized: &mut bool,
399+
def_id: DefId,
400+
) -> Visibility {
401+
if tcx.is_reachable_non_generic(def_id) {
402+
*can_be_internalized = false;
403+
default_visibility(tcx, def_id, false)
404+
} else {
405+
Visibility::Hidden
406+
}
407+
}
408+
395409
fn mono_item_visibility<'tcx>(
396410
tcx: TyCtxt<'tcx>,
397411
mono_item: &MonoItem<'tcx>,
@@ -403,28 +417,21 @@ fn mono_item_visibility<'tcx>(
403417
MonoItem::Fn(instance) => instance,
404418

405419
// Misc handling for generics and such, but otherwise:
406-
MonoItem::Static(def_id) => {
407-
return if tcx.is_reachable_non_generic(*def_id) {
408-
*can_be_internalized = false;
409-
default_visibility(tcx, *def_id, false)
410-
} else {
411-
Visibility::Hidden
412-
};
413-
}
420+
MonoItem::Static(def_id) => return static_visibility(tcx, can_be_internalized, *def_id),
414421
MonoItem::GlobalAsm(item_id) => {
415-
return if tcx.is_reachable_non_generic(item_id.owner_id) {
416-
*can_be_internalized = false;
417-
default_visibility(tcx, item_id.owner_id.to_def_id(), false)
418-
} else {
419-
Visibility::Hidden
420-
};
422+
return static_visibility(tcx, can_be_internalized, item_id.owner_id.to_def_id());
421423
}
422424
};
423425

424426
let def_id = match instance.def {
425427
InstanceDef::Item(def) => def.did,
426428
InstanceDef::DropGlue(def_id, Some(_)) => def_id,
427429

430+
// We match the visiblity of statics here
431+
InstanceDef::ThreadLocalShim(def_id) => {
432+
return static_visibility(tcx, can_be_internalized, def_id);
433+
}
434+
428435
// These are all compiler glue and such, never exported, always hidden.
429436
InstanceDef::VTableShim(..)
430437
| InstanceDef::ReifyShim(..)

‎compiler/rustc_symbol_mangling/src/legacy.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ pub(super) fn mangle<'tcx>(
6565
)
6666
.unwrap();
6767

68+
if let ty::InstanceDef::ThreadLocalShim(..) = instance.def {
69+
let _ = printer.write_str("{{tls-shim}}");
70+
}
71+
6872
if let ty::InstanceDef::VTableShim(..) = instance.def {
6973
let _ = printer.write_str("{{vtable-shim}}");
7074
}

‎compiler/rustc_symbol_mangling/src/v0.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub(super) fn mangle<'tcx>(
4242

4343
// Append `::{shim:...#0}` to shims that can coexist with a non-shim instance.
4444
let shim_kind = match instance.def {
45+
ty::InstanceDef::ThreadLocalShim(_) => Some("tls"),
4546
ty::InstanceDef::VTableShim(_) => Some("vtable"),
4647
ty::InstanceDef::ReifyShim(_) => Some("reify"),
4748

‎compiler/rustc_target/src/spec/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,8 @@ pub struct TargetOptions {
14711471
pub features: StaticCow<str>,
14721472
/// Whether dynamic linking is available on this target. Defaults to false.
14731473
pub dynamic_linking: bool,
1474+
/// Whether dynamic linking can export TLS globals. Defaults to true.
1475+
pub dll_tls_export: bool,
14741476
/// If dynamic linking is available, whether only cdylibs are supported.
14751477
pub only_cdylib: bool,
14761478
/// Whether executables are available on this target. Defaults to true.
@@ -1865,6 +1867,7 @@ impl Default for TargetOptions {
18651867
cpu: "generic".into(),
18661868
features: "".into(),
18671869
dynamic_linking: false,
1870+
dll_tls_export: true,
18681871
only_cdylib: false,
18691872
executables: true,
18701873
relocation_model: RelocModel::Pic,
@@ -2537,6 +2540,7 @@ impl Target {
25372540
key!(cpu);
25382541
key!(features);
25392542
key!(dynamic_linking, bool);
2543+
key!(dll_tls_export, bool);
25402544
key!(only_cdylib, bool);
25412545
key!(executables, bool);
25422546
key!(relocation_model, RelocModel)?;
@@ -2791,6 +2795,7 @@ impl ToJson for Target {
27912795
target_option_val!(cpu);
27922796
target_option_val!(features);
27932797
target_option_val!(dynamic_linking);
2798+
target_option_val!(dll_tls_export);
27942799
target_option_val!(only_cdylib);
27952800
target_option_val!(executables);
27962801
target_option_val!(relocation_model);

‎compiler/rustc_target/src/spec/msvc_base.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub fn opts() -> TargetOptions {
88

99
TargetOptions {
1010
linker_flavor: LinkerFlavor::Msvc(Lld::No),
11+
dll_tls_export: false,
1112
is_like_windows: true,
1213
is_like_msvc: true,
1314
pre_link_args,

‎compiler/rustc_target/src/spec/windows_gnu_base.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ pub fn opts() -> TargetOptions {
7878
function_sections: false,
7979
linker: Some("gcc".into()),
8080
dynamic_linking: true,
81+
dll_tls_export: false,
8182
dll_prefix: "".into(),
8283
dll_suffix: ".dll".into(),
8384
exe_suffix: ".exe".into(),

‎compiler/rustc_target/src/spec/windows_gnullvm_base.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub fn opts() -> TargetOptions {
2323
abi: "llvm".into(),
2424
linker: Some("clang".into()),
2525
dynamic_linking: true,
26+
dll_tls_export: false,
2627
dll_prefix: "".into(),
2728
dll_suffix: ".dll".into(),
2829
exe_suffix: ".exe".into(),

‎compiler/rustc_ty_utils/src/abi.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_hir::lang_items::LangItem;
33
use rustc_middle::ty::layout::{
44
fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout,
55
};
6-
use rustc_middle::ty::{self, Ty, TyCtxt};
6+
use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt};
77
use rustc_session::config::OptLevel;
88
use rustc_span::def_id::DefId;
99
use rustc_target::abi::call::{
@@ -29,6 +29,16 @@ fn fn_sig_for_fn_abi<'tcx>(
2929
instance: ty::Instance<'tcx>,
3030
param_env: ty::ParamEnv<'tcx>,
3131
) -> ty::PolyFnSig<'tcx> {
32+
if let InstanceDef::ThreadLocalShim(..) = instance.def {
33+
return ty::Binder::dummy(tcx.mk_fn_sig(
34+
[],
35+
tcx.thread_local_ptr_ty(instance.def_id()),
36+
false,
37+
hir::Unsafety::Normal,
38+
rustc_target::spec::abi::Abi::Unadjusted,
39+
));
40+
}
41+
3242
let ty = instance.ty(tcx, param_env);
3343
match *ty.kind() {
3444
ty::FnDef(..) => {

‎library/std/src/sys/common/thread_local/fast_local.rs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
macro_rules! __thread_local_inner {
1111
// used to generate the `LocalKey` value for const-initialized thread locals
1212
(@key $t:ty, const $init:expr) => {{
13-
#[cfg_attr(not(windows), inline)] // see comments below
13+
#[cfg_attr(not(bootstrap), inline)]
1414
#[deny(unsafe_op_in_unsafe_fn)]
1515
unsafe fn __getit(
1616
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
@@ -77,29 +77,7 @@ macro_rules! __thread_local_inner {
7777
#[inline]
7878
fn __init() -> $t { $init }
7979

80-
// When reading this function you might ask "why is this inlined
81-
// everywhere other than Windows?", and that's a very reasonable
82-
// question to ask. The short story is that it segfaults rustc if
83-
// this function is inlined. The longer story is that Windows looks
84-
// to not support `extern` references to thread locals across DLL
85-
// boundaries. This appears to at least not be supported in the ABI
86-
// that LLVM implements.
87-
//
88-
// Because of this we never inline on Windows, but we do inline on
89-
// other platforms (where external references to thread locals
90-
// across DLLs are supported). A better fix for this would be to
91-
// inline this function on Windows, but only for "statically linked"
92-
// components. For example if two separately compiled rlibs end up
93-
// getting linked into a DLL then it's fine to inline this function
94-
// across that boundary. It's only not fine to inline this function
95-
// across a DLL boundary. Unfortunately rustc doesn't currently
96-
// have this sort of logic available in an attribute, and it's not
97-
// clear that rustc is even equipped to answer this (it's more of a
98-
// Cargo question kinda). This means that, unfortunately, Windows
99-
// gets the pessimistic path for now where it's never inlined.
100-
//
101-
// The issue of "should enable on Windows sometimes" is #84933
102-
#[cfg_attr(not(windows), inline)]
80+
#[cfg_attr(not(bootstrap), inline)]
10381
unsafe fn __getit(
10482
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
10583
) -> $crate::option::Option<&'static $t> {

‎library/std/src/sys/common/thread_local/os_local.rs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
macro_rules! __thread_local_inner {
1111
// used to generate the `LocalKey` value for const-initialized thread locals
1212
(@key $t:ty, const $init:expr) => {{
13-
#[cfg_attr(not(windows), inline)] // see comments below
13+
#[cfg_attr(not(bootstrap), inline)]
1414
#[deny(unsafe_op_in_unsafe_fn)]
1515
unsafe fn __getit(
1616
_init: $crate::option::Option<&mut $crate::option::Option<$t>>,
@@ -49,29 +49,7 @@ macro_rules! __thread_local_inner {
4949
#[inline]
5050
fn __init() -> $t { $init }
5151

52-
// When reading this function you might ask "why is this inlined
53-
// everywhere other than Windows?", and that's a very reasonable
54-
// question to ask. The short story is that it segfaults rustc if
55-
// this function is inlined. The longer story is that Windows looks
56-
// to not support `extern` references to thread locals across DLL
57-
// boundaries. This appears to at least not be supported in the ABI
58-
// that LLVM implements.
59-
//
60-
// Because of this we never inline on Windows, but we do inline on
61-
// other platforms (where external references to thread locals
62-
// across DLLs are supported). A better fix for this would be to
63-
// inline this function on Windows, but only for "statically linked"
64-
// components. For example if two separately compiled rlibs end up
65-
// getting linked into a DLL then it's fine to inline this function
66-
// across that boundary. It's only not fine to inline this function
67-
// across a DLL boundary. Unfortunately rustc doesn't currently
68-
// have this sort of logic available in an attribute, and it's not
69-
// clear that rustc is even equipped to answer this (it's more of a
70-
// Cargo question kinda). This means that, unfortunately, Windows
71-
// gets the pessimistic path for now where it's never inlined.
72-
//
73-
// The issue of "should enable on Windows sometimes" is #84933
74-
#[cfg_attr(not(windows), inline)]
52+
#[cfg_attr(not(bootstrap), inline)]
7553
unsafe fn __getit(
7654
init: $crate::option::Option<&mut $crate::option::Option<$t>>,
7755
) -> $crate::option::Option<&'static $t> {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#![crate_type = "dylib"]
2+
#![feature(thread_local)]
3+
#![feature(cfg_target_thread_local)]
4+
5+
extern crate tls_rlib;
6+
7+
pub use tls_rlib::*;
8+
9+
#[cfg(target_thread_local)]
10+
#[thread_local]
11+
pub static FOO: bool = true;
12+
13+
#[cfg(target_thread_local)]
14+
#[inline(never)]
15+
pub fn foo_addr() -> usize {
16+
&FOO as *const bool as usize
17+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// no-prefer-dynamic
2+
3+
#![crate_type = "rlib"]
4+
#![feature(thread_local)]
5+
#![feature(cfg_target_thread_local)]
6+
7+
#[cfg(target_thread_local)]
8+
#[thread_local]
9+
pub static BAR: bool = true;
10+
11+
#[cfg(target_thread_local)]
12+
#[inline(never)]
13+
pub fn bar_addr() -> usize {
14+
&BAR as *const bool as usize
15+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// aux-build: tls-rlib.rs
2+
// aux-build: tls-export.rs
3+
// run-pass
4+
5+
#![feature(cfg_target_thread_local)]
6+
7+
#[cfg(target_thread_local)]
8+
extern crate tls_export;
9+
10+
fn main() {
11+
#[cfg(target_thread_local)]
12+
{
13+
// Check that we get the real address of the `FOO` TLS in the dylib
14+
assert_eq!(&tls_export::FOO as *const bool as usize, tls_export::foo_addr());
15+
16+
// Check that we get the real address of the `BAR` TLS in the rlib linked into the dylib
17+
assert_eq!(&tls_export::BAR as *const bool as usize, tls_export::bar_addr());
18+
}
19+
}

0 commit comments

Comments
 (0)
Please sign in to comment.