Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion compiler/rustc_codegen_cranelift/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ impl<T: PointeeSized> Copy for *const T {}
impl<T: PointeeSized> Copy for *mut T {}
impl<T: Copy> Copy for Option<T> {}

#[lang = "sync"]
pub unsafe trait Sync {}

unsafe impl Sync for bool {}
Expand All @@ -104,6 +103,10 @@ unsafe impl Sync for f32 {}
unsafe impl<'a, T: PointeeSized> Sync for &'a T {}
unsafe impl<T: Sync, const N: usize> Sync for [T; N] {}

#[lang = "allow_shared_static"]
unsafe trait AllowSharedStatic {}
unsafe impl<T: PointeeSized + Sync> AllowSharedStatic for T {}

#[lang = "freeze"]
unsafe auto trait Freeze {}

Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_codegen_gcc/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ impl<'a, T: PointeeSized> Copy for &'a T {}
impl<T: PointeeSized> Copy for *const T {}
impl<T: PointeeSized> Copy for *mut T {}

#[lang = "sync"]
pub unsafe trait Sync {}

unsafe impl Sync for bool {}
Expand All @@ -111,6 +110,10 @@ unsafe impl Sync for char {}
unsafe impl<'a, T: PointeeSized> Sync for &'a T {}
unsafe impl Sync for [u8; 16] {}

#[lang = "allow_shared_static"]
unsafe trait AllowSharedStatic {}
unsafe impl<T: PointeeSized + Sync> AllowSharedStatic for T {}

#[lang = "freeze"]
unsafe auto trait Freeze {}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ language_item_table! {
CloneFn, sym::clone_fn, clone_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
UseCloned, sym::use_cloned, use_cloned_trait, Target::Trait, GenericRequirement::None;
TrivialClone, sym::trivial_clone, trivial_clone_trait, Target::Trait, GenericRequirement::None;
Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0);
DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None;
/// The associated item of the `DiscriminantKind` trait.
Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy, GenericRequirement::None;
Expand Down Expand Up @@ -231,6 +230,7 @@ language_item_table! {
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);

UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
AllowSharedStatic, sym::allow_shared_static, allow_shared_static_trait, Target::Trait, GenericRequirement::Exact(0);
UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None;

VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
check_static_linkage(tcx, def_id);
let ty = tcx.type_of(def_id).instantiate_identity();
res = res.and(wfcheck::check_static_item(
tcx, def_id, ty, /* should_check_for_sync */ true,
tcx, def_id, ty, /* should_check_allow_in_shared_static */ true,
));

// Only `Node::Item` and `Node::ForeignItem` still have HIR based
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1228,7 +1228,7 @@ pub(crate) fn check_static_item<'tcx>(
tcx: TyCtxt<'tcx>,
item_id: LocalDefId,
ty: Ty<'tcx>,
should_check_for_sync: bool,
should_check_allow_in_shared_static: bool,
) -> Result<(), ErrorGuaranteed> {
enter_wf_checking_ctxt(tcx, item_id, |wfcx| {
let span = tcx.ty_span(item_id);
Expand Down Expand Up @@ -1263,13 +1263,13 @@ pub(crate) fn check_static_item<'tcx>(
);
}

// Ensure that the end result is `Sync` in a non-thread local `static`.
let should_check_for_sync = should_check_for_sync
// Ensure that the end result is `Sync` or `UnsafeCell<T: Sync>` in a non-thread local `static`.
let should_check_allow_in_shared_static = should_check_allow_in_shared_static
&& !is_foreign_item
&& tcx.static_mutability(item_id.to_def_id()) == Some(hir::Mutability::Not)
&& !tcx.is_thread_local_static(item_id.to_def_id());

if should_check_for_sync {
if should_check_allow_in_shared_static {
wfcx.register_bound(
traits::ObligationCause::new(
span,
Expand All @@ -1278,7 +1278,7 @@ pub(crate) fn check_static_item<'tcx>(
),
wfcx.param_env,
item_ty,
tcx.require_lang_item(LangItem::Sync, span),
tcx.require_lang_item(LangItem::AllowSharedStatic, span),
);
}
Ok(())
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
// Verify that here to avoid ill-formed MIR.
// We skip the `Sync` check to avoid cycles for type-alias-impl-trait,
// relying on the fact that non-Sync statics don't ICE the rest of the compiler.
match check_static_item(tcx, def_id, ty, /* should_check_for_sync */ false) {
match check_static_item(
tcx, def_id, ty, /* should_check_allow_in_shared_static */ false,
) {
Ok(()) => ty,
Err(guar) => Ty::new_error(tcx, guar),
}
Expand Down Expand Up @@ -199,7 +201,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
// Verify that here to avoid ill-formed MIR.
// We skip the `Sync` check to avoid cycles for type-alias-impl-trait,
// relying on the fact that non-Sync statics don't ICE the rest of the compiler.
match check_static_item(tcx, def_id, ty, /* should_check_for_sync */ false) {
match check_static_item(
tcx, def_id, ty, /* should_check_allow_in_shared_static */ false,
) {
Ok(()) => ty,
Err(guar) => Ty::new_error(tcx, guar),
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1153,7 +1153,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Option<FxIndexMap<UpvarMigrationInfo, UnordSet<&'static str>>> {
let auto_traits_def_id = [
self.tcx.lang_items().clone_trait(),
self.tcx.lang_items().sync_trait(),
self.tcx.get_diagnostic_item(sym::Sync),
self.tcx.get_diagnostic_item(sym::Send),
self.tcx.lang_items().unpin_trait(),
self.tcx.get_diagnostic_item(sym::unwind_safe_trait),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ pub enum ObligationCauseCode<'tcx> {
/// Constant expressions must be sized.
SizedConstOrStatic,

/// `static` items must have `Sync` type.
/// `static` items must have `Sync` or `UnsafeCell<T: Sync>` type (`AllowSharedStatic`).
SharedStatic,

/// Derived obligation (i.e. theoretical `where` clause) on a built-in
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ symbols! {
allow_fail,
allow_internal_unsafe,
allow_internal_unstable,
allow_shared_static,
altivec,
alu32,
always,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3400,6 +3400,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
));
}
ObligationCauseCode::SharedStatic => {
// TODO: Add note about `UnsafeCell` here too?
err.note("shared static variables must have a type that implements `Sync`");
}
ObligationCauseCode::BuiltinDerived(ref data) => {
Expand Down
30 changes: 29 additions & 1 deletion library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,6 @@ pub trait BikeshedGuaranteedNoDrop {}
/// [nomicon-send-and-sync]: ../../nomicon/send-and-sync.html
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Sync"]
#[lang = "sync"]
#[rustc_on_unimplemented(
on(
Self = "core::cell::once::OnceCell<T>",
Expand Down Expand Up @@ -676,6 +675,35 @@ impl<T: PointeeSized> !Sync for *const T {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PointeeSized> !Sync for *mut T {}

/// Whether a type is usable in shared statics.
///
/// TODO.
#[lang = "allow_shared_static"]
#[unstable(feature = "allow_shared_static_trait", issue = "none")]
#[rustc_on_unimplemented(
message = "`{Self}` cannot be shared between threads safely",
label = "`{Self}` cannot be shared between threads safely"
)]
pub unsafe trait AllowSharedStatic {}

// SAFETY: All `T: Sync` types are usable in shared statics.
//
// NOTE: The `MetaSized` bound is mostly a lie, as only sized types can be
// used directly in statics. But this is already enforced by the compiler.
#[unstable(feature = "allow_shared_static_trait", issue = "none")]
unsafe impl<T: MetaSized + Sync> AllowSharedStatic for T {}

// SAFETY: `UnsafeCell<T: Sync>` could (and should) have been `Sync`, there
// is nothing inherent to `UnsafeCell` that forbids `Sync`.
//
// NOTE: Ideally, we'd have marked `UnsafeCell<T: Sync>: Sync`, but that is a
// breaking change, since users rely upon `UnsafeCell<u32>` making their type
// `!Sync`.
//
// See also TODO link.
#[unstable(feature = "allow_shared_static_trait", issue = "none")]
unsafe impl<T: MetaSized + Sync> AllowSharedStatic for UnsafeCell<T> {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this have a Sync bound on T? The argument for why this is sound (all accesses are unsafe) also work for arbitrary T.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intended for this PR to be the minimal first step. We can extend it to T: !Sync later (or during the unstable period).


/// Zero-sized type used to mark things that "act like" they own a `T`.
///
/// Adding a `PhantomData<T>` field to your type tells the compiler that your
Expand Down
5 changes: 3 additions & 2 deletions library/rtstartup/rsbegin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ pub trait MetaSized: PointeeSized {}
#[lang = "sized"]
pub trait Sized: MetaSized {}

#[lang = "sync"]
auto trait Sync {}
#[lang = "allow_shared_static"]
trait AllowSharedStatic {}
impl<T: PointeeSized> AllowSharedStatic for T {}
#[lang = "copy"]
trait Copy {}
#[lang = "freeze"]
Expand Down
6 changes: 3 additions & 3 deletions library/rtstartup/rsend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ pub trait MetaSized: PointeeSized {}
#[lang = "sized"]
pub trait Sized: MetaSized {}

#[lang = "sync"]
trait Sync {}
impl<T> Sync for T {}
#[lang = "allow_shared_static"]
trait AllowSharedStatic {}
impl<T: PointeeSized> AllowSharedStatic for T {}
#[lang = "copy"]
trait Copy {}
#[lang = "freeze"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
!matches!(arg.kind(), GenericArgKind::Type(ty) if matches!(ty.kind(), ty::Param(_)))
})
&& let Some(send) = cx.tcx.get_diagnostic_item(sym::Send)
&& let Some(sync) = cx.tcx.lang_items().sync_trait()
&& let Some(sync) = cx.tcx.get_diagnostic_item(sym::Sync)
&& let [is_send, is_sync] = [send, sync].map(|id| implements_trait(cx, arg_ty, id, &[]))
&& let reason = match (is_send, is_sync) {
(false, false) => "neither `Send` nor `Sync`",
Expand Down
4 changes: 2 additions & 2 deletions src/tools/clippy/clippy_lints/src/non_copy_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -725,10 +725,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
ident.span,
"named constant with interior mutability",
|diag| {
let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else {
let Some(sync) = cx.tcx.get_diagnostic_item(sym::Sync) else {
return;
};
if implements_trait(cx, ty, sync_trait, &[]) {
if implements_trait(cx, ty, sync, &[]) {
diag.help("did you mean to make this a `static` item");
} else {
diag.help("did you mean to make this a `thread_local!` item");
Expand Down
1 change: 0 additions & 1 deletion src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,6 @@ language_item_table! { LangItems =>
Copy, sym::copy, TraitId;
Clone, sym::clone, TraitId;
TrivialClone, sym::trivial_clone, TraitId;
Sync, sym::sync, TraitId;
DiscriminantKind, sym::discriminant_kind, TraitId;
/// The associated item of the `DiscriminantKind` trait.
Discriminant, sym::discriminant_type, TypeAliasId;
Expand Down
5 changes: 4 additions & 1 deletion tests/auxiliary/minicore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,6 @@ impl Neg for i8 {
}
}

#[lang = "sync"]
pub trait Sync {}
impl_marker_trait!(
Sync => [
Expand All @@ -229,6 +228,10 @@ impl_marker_trait!(
]
);

#[lang = "allow_shared_static"]
trait AllowSharedStatic {}
impl<T: PointeeSized + Sync> AllowSharedStatic for T {}

#[lang = "drop_in_place"]
fn drop_in_place<T>(_: *mut T) {}

Expand Down
6 changes: 3 additions & 3 deletions tests/run-make/arm64ec-import-export-static/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ pub trait PointeeSized {}
pub trait MetaSized: PointeeSized {}
#[lang = "sized"]
pub trait Sized: MetaSized {}
#[lang = "sync"]
trait Sync {}
impl Sync for i32 {}
#[lang = "allow_shared_static"]
trait AllowSharedStatic {}
impl AllowSharedStatic for i32 {}
#[lang = "copy"]
pub trait Copy {}
impl Copy for i32 {}
Expand Down
8 changes: 4 additions & 4 deletions tests/run-make/min-global-align/min_global_align.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ trait Freeze {}
// No `UnsafeCell`, so everything is `Freeze`.
impl<T: ?Sized> Freeze for T {}

#[lang = "sync"]
trait Sync {}
impl Sync for bool {}
impl Sync for &'static bool {}
#[lang = "allow_shared_static"]
trait AllowSharedStatic {}
impl AllowSharedStatic for bool {}
impl AllowSharedStatic for &'static bool {}

#[lang = "drop_in_place"]
pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {}
8 changes: 4 additions & 4 deletions tests/ui/lang-items/issue-87573.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ trait Sized: MetaSized {}
#[lang = "copy"]
trait Copy {}

#[lang = "sync"]
trait Sync {}
impl Sync for bool {}
#[lang = "allow_shared_static"]
trait AllowSharedStatic {}
impl AllowSharedStatic for bool {}

#[lang = "drop_in_place"]
//~^ ERROR: `drop_in_place` lang item must be applied to a function with at least 1 generic argument
Expand All @@ -31,4 +31,4 @@ fn drop_fn() {

#[lang = "start"]
//~^ ERROR: `start` lang item must be applied to a function with 1 generic argument
fn start(){}
fn start() {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ LL | static boxed: Box<RefCell<isize>> = Box::new(RefCell::new(0));
= note: required for `std::ptr::Unique<RefCell<isize>>` to implement `Sync`
note: required because it appears within the type `Box<RefCell<isize>>`
--> $SRC_DIR/alloc/src/boxed.rs:LL:COL
= note: required for `Box<RefCell<isize>>` to implement `AllowSharedStatic`
= note: shared static variables must have a type that implements `Sync`

error[E0015]: cannot call non-const associated function `Box::<RefCell<isize>>::new` in statics
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/static/static-requires-lang-item.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Test that creating statics requires the `AllowSharedStatic` language item.
#![feature(lang_items, no_core)]
#![no_core]
#![no_main]

#[lang = "pointee_sized"]
trait PointeeSized {}
#[lang = "meta_sized"]
trait MetaSized: PointeeSized {}
#[lang = "sized"]
pub trait Sized: MetaSized {}
#[lang = "copy"]
trait Copy {}

static FOO: () = ();
//~^ ERROR: requires `allow_shared_static` lang_item
8 changes: 8 additions & 0 deletions tests/ui/static/static-requires-lang-item.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: requires `allow_shared_static` lang_item
--> $DIR/static-requires-lang-item.rs:15:13
|
LL | static FOO: () = ();
| ^^

error: aborting due to 1 previous error

14 changes: 14 additions & 0 deletions tests/ui/static/unsafe-cell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Test `UnsafeCell` in `static`s.
use std::cell::UnsafeCell;

// Works even though it isn't `Sync`.
#[allow(dead_code)]
static FOO: UnsafeCell<i32> = UnsafeCell::new(42);

// Does not work, requires `unsafe impl Sync for Bar {}`.
struct Bar(UnsafeCell<i32>);
#[allow(dead_code)]
static BAR: Bar = Bar(UnsafeCell::new(42));
//~^ ERROR: `UnsafeCell<i32>` cannot be shared between threads safely

fn main() {}
18 changes: 18 additions & 0 deletions tests/ui/static/unsafe-cell.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error[E0277]: `UnsafeCell<i32>` cannot be shared between threads safely
--> $DIR/unsafe-cell.rs:11:13
|
LL | static BAR: Bar = Bar(UnsafeCell::new(42));
| ^^^ `UnsafeCell<i32>` cannot be shared between threads safely
|
= help: within `Bar`, the trait `Sync` is not implemented for `UnsafeCell<i32>`
note: required because it appears within the type `Bar`
--> $DIR/unsafe-cell.rs:9:8
|
LL | struct Bar(UnsafeCell<i32>);
| ^^^
= note: required for `Bar` to implement `AllowSharedStatic`
= note: shared static variables must have a type that implements `Sync`

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.
1 change: 1 addition & 0 deletions tests/ui/statics/issue-17718-static-sync.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ help: the trait `Sync` is not implemented for `Foo`
|
LL | struct Foo;
| ^^^^^^^^^^
= note: required for `Foo` to implement `AllowSharedStatic`
= note: shared static variables must have a type that implements `Sync`

error: aborting due to 1 previous error
Expand Down
Loading
Loading