Skip to content

Commit ee37726

Browse files
Add and use cfg(target_has_threads) to enforce no_thread impl usage
The standard library has fallback code for targets without threads (e.g., using a Cell-based Mutex and similar). Today there's no enforcement in std that those targets truly don't have threads which makes that code potentially unsound. This will let us add a static assertion that the target spec agrees that the target is non-threaded.
1 parent c397dae commit ee37726

37 files changed

Lines changed: 142 additions & 58 deletions

compiler/rustc_codegen_llvm/src/back/write.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_fs_util::{link_or_copy, path_to_c_string};
2222
use rustc_middle::ty::TyCtxt;
2323
use rustc_session::Session;
2424
use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
25-
use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext, sym};
25+
use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext};
2626
use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
2727
use tracing::{debug, trace};
2828

@@ -209,14 +209,8 @@ pub(crate) fn target_machine_factory(
209209

210210
let code_model = to_llvm_code_model(sess.code_model());
211211

212-
let mut singlethread = sess.target.singlethread;
213-
214-
// On the wasm target once the `atomics` feature is enabled that means that
215-
// we're no longer single-threaded, or otherwise we don't want LLVM to
216-
// lower atomic operations to single-threaded operations.
217-
if singlethread && sess.target.is_like_wasm && sess.target_features.contains(&sym::atomics) {
218-
singlethread = false;
219-
}
212+
// This is used to set cfg_has_threads, so all logic must be in this method.
213+
let singlethread = sess.target.singlethread(&sess.target_features);
220214

221215
let triple = SmallCStr::new(&versioned_llvm_target(sess));
222216
let cpu = SmallCStr::new(llvm_util::target_cpu(sess));

compiler/rustc_feature/src/builtin_attrs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const GATED_CFGS: &[GatedCfg] = &[
5050
sym::cfg_target_has_reliable_f16_f128,
5151
Features::cfg_target_has_reliable_f16_f128,
5252
),
53+
(sym::target_has_threads, sym::cfg_target_has_threads, Features::cfg_target_has_threads),
5354
(sym::target_object_format, sym::cfg_target_object_format, Features::cfg_target_object_format),
5455
];
5556

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ declare_features! (
254254
(unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None),
255255
/// Allows checking whether or not the backend correctly supports unstable float types.
256256
(internal, cfg_target_has_reliable_f16_f128, "1.88.0", None),
257+
/// Allows checking whether or not the target might have thread support.
258+
(internal, cfg_target_has_threads, "CURRENT_RUSTC_VERSION", None),
257259
/// Allows identifying the `compiler_builtins` crate.
258260
(internal, compiler_builtins, "1.13.0", None),
259261
/// Allows skipping `ConstParamTy_` trait implementation checks

compiler/rustc_session/src/config/cfg.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
149149
| (sym::target_pointer_width, Some(_))
150150
| (sym::target_vendor, None | Some(_))
151151
| (sym::target_has_atomic, Some(_))
152+
| (sym::target_has_threads, None | Some(_))
152153
| (sym::target_has_atomic_primitive_alignment, Some(_))
153154
| (sym::target_has_atomic_load_store, Some(_))
154155
| (sym::target_has_reliable_f16, None | Some(_))
@@ -303,6 +304,10 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg {
303304
}
304305
}
305306

307+
if !sess.target.singlethread(&sess.target_features) {
308+
ins_none!(sym::target_has_threads);
309+
}
310+
306311
ins_sym!(sym::target_os, sess.target.os.desc_symbol());
307312
ins_sym!(sym::target_pointer_width, sym::integer(sess.target.pointer_width));
308313

@@ -485,6 +490,7 @@ impl CheckCfg {
485490
ins!(sym::target_has_atomic_primitive_alignment, empty_values).extend(atomic_values);
486491

487492
ins!(sym::target_thread_local, no_values);
493+
ins!(sym::target_has_threads, no_values);
488494

489495
ins!(sym::ub_checks, no_values);
490496
ins!(sym::contract_checks, no_values);

compiler/rustc_span/src/symbol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,7 @@ symbols! {
598598
cfg_target_has_atomic,
599599
cfg_target_has_atomic_equal_alignment,
600600
cfg_target_has_reliable_f16_f128,
601+
cfg_target_has_threads,
601602
cfg_target_object_format,
602603
cfg_target_thread_local,
603604
cfg_target_vendor,
@@ -2084,6 +2085,7 @@ symbols! {
20842085
target_has_reliable_f16_math,
20852086
target_has_reliable_f128,
20862087
target_has_reliable_f128_math,
2088+
target_has_threads,
20872089
target_object_format,
20882090
target_os,
20892091
target_pointer_width,

compiler/rustc_target/src/spec/mod.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2255,6 +2255,26 @@ impl Target {
22552255
}
22562256
}
22572257
}
2258+
2259+
/// Is this target single-threaded?
2260+
///
2261+
/// This affects both optimizations (e.g., atomics can be lowered to regular operations) and
2262+
/// is also exposed as cfg(target_has_threads).
2263+
pub fn singlethread(&self, target_features: &FxIndexSet<Symbol>) -> bool {
2264+
// On the wasm target once the `atomics` feature is enabled that means that
2265+
// we're no longer single-threaded, or otherwise we don't want LLVM to
2266+
// lower atomic operations to single-threaded operations.
2267+
//
2268+
// FIXME: This (probably?) implies that atomics should be a target modifier, at which point
2269+
// it probably makes sense to be a separate target to ship precompiled artifacts for it?
2270+
//
2271+
// cc #77839 (tracking issue for wasm atomics)
2272+
if self.singlethread && self.is_like_wasm && target_features.contains(&sym::atomics) {
2273+
return false;
2274+
}
2275+
2276+
self.singlethread
2277+
}
22582278
}
22592279

22602280
pub trait HasTargetSpec {
@@ -2570,7 +2590,8 @@ pub struct TargetOptions {
25702590
pub requires_lto: bool,
25712591

25722592
/// This target has no support for threads.
2573-
pub singlethread: bool,
2593+
// This is private because wasm changes this depending on target features.
2594+
singlethread: bool,
25742595

25752596
/// Whether library functions call lowering/optimization is disabled in LLVM
25762597
/// for this target unconditionally.

library/std/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@
276276
#![feature(asm_experimental_arch)]
277277
#![feature(autodiff)]
278278
#![feature(cfg_sanitizer_cfi)]
279+
#![feature(cfg_target_has_threads)]
279280
#![feature(cfg_target_thread_local)]
280281
#![feature(cfi_encoding)]
281282
#![feature(const_trait_impl)]

library/std/src/sys/sync/condvar/no_threads.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ use crate::sys::sync::Mutex;
22
use crate::thread::sleep;
33
use crate::time::Duration;
44

5+
#[cfg(target_has_threads)]
6+
compile_error!("Using no_threads implementation on a target with threads");
7+
58
pub struct Condvar {}
69

710
impl Condvar {

library/std/src/sys/sync/mutex/no_threads.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use crate::cell::Cell;
22

3+
#[cfg(target_has_threads)]
4+
compile_error!("Using no_threads implementation on a target with threads");
5+
36
pub struct Mutex {
47
// This platform has no threads, so we can use a Cell here.
58
locked: Cell<bool>,

library/std/src/sys/sync/once/no_threads.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ use crate::cell::Cell;
22
use crate::sync as public;
33
use crate::sync::once::OnceExclusiveState;
44

5+
#[cfg(target_has_threads)]
6+
compile_error!("Using no_threads implementation on a target with threads");
7+
58
pub struct Once {
69
state: Cell<State>,
710
}

0 commit comments

Comments
 (0)