Skip to content

Commit

Permalink
Rollup merge of #121840 - oli-obk:freeze, r=dtolnay
Browse files Browse the repository at this point in the history
Expose the Freeze trait again (unstably) and forbid implementing it manually

non-emoji version of #121501

cc #60715

This trait is useful for generic constants (associated consts of generic traits). See the test (`tests/ui/associated-consts/freeze.rs`) added in this PR for a usage example. The builtin `Freeze` trait is the only way to do it, users cannot work around this issue.

It's also a useful trait for building some very specific abstrations, as shown by the usage by the `zerocopy` crate: google/zerocopy#941

cc ```@RalfJung```

T-lang signed off on reexposing this unstably: #121501 (comment)
  • Loading branch information
jhpratt authored Mar 11, 2024
2 parents 1a989e0 + 7849230 commit 05f22c3
Show file tree
Hide file tree
Showing 15 changed files with 89 additions and 11 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_codegen_cranelift/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
rustc_attrs,
transparent_unions,
auto_traits,
freeze_impls,
thread_local
)]
#![no_core]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/example/mini_core.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![feature(
no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types,
decl_macro, rustc_attrs, transparent_unions, auto_traits,
decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls,
thread_local
)]
#![no_core]
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,8 @@ declare_features! (
(unstable, fn_align, "1.53.0", Some(82232)),
/// Support delegating implementation of functions to other already implemented functions.
(incomplete, fn_delegation, "1.76.0", Some(118212)),
/// Allows impls for the Freeze trait.
(internal, freeze_impls, "CURRENT_RUSTC_VERSION", Some(121675)),
/// Allows defining gen blocks and `gen fn`.
(unstable, gen_blocks, "1.75.0", Some(117078)),
/// Infer generic args for both consts and types.
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_hir_analysis/src/coherence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use rustc_errors::{codes::*, struct_span_code_err};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_session::parse::feature_err;
use rustc_span::{sym, ErrorGuaranteed};
use rustc_trait_selection::traits;

Expand Down Expand Up @@ -49,6 +50,19 @@ fn enforce_trait_manually_implementable(
) -> Result<(), ErrorGuaranteed> {
let impl_header_span = tcx.def_span(impl_def_id);

if tcx.lang_items().freeze_trait() == Some(trait_def_id) {
if !tcx.features().freeze_impls {
feature_err(
&tcx.sess,
sym::freeze_impls,
impl_header_span,
"explicit impls for the `Freeze` trait are not permitted",
)
.with_span_label(impl_header_span, format!("impl of `Freeze` not allowed"))
.emit();
}
}

// Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]`
if trait_def.deny_explicit_impl {
let trait_name = tcx.item_name(trait_def_id);
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 @@ -864,6 +864,7 @@ symbols! {
format_placeholder,
format_unsafe_arg,
freeze,
freeze_impls,
freg,
frem_algebraic,
frem_fast,
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(diagnostic_namespace))]
#![cfg_attr(bootstrap, feature(platform_intrinsics))]
#![cfg_attr(not(bootstrap), feature(freeze_impls))]
#![feature(abi_unadjusted)]
#![feature(adt_const_params)]
#![feature(allow_internal_unsafe)]
Expand Down
10 changes: 8 additions & 2 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -810,15 +810,21 @@ pub trait DiscriminantKind {
type Discriminant: Clone + Copy + Debug + Eq + PartialEq + Hash + Send + Sync + Unpin;
}

/// Compiler-internal trait used to determine whether a type contains
/// Used to determine whether a type contains
/// any `UnsafeCell` internally, but not through an indirection.
/// This affects, for example, whether a `static` of that type is
/// placed in read-only static memory or writable static memory.
/// This can be used to declare that a constant with a generic type
/// will not contain interior mutability, and subsequently allow
/// placing the constant behind references.
#[lang = "freeze"]
pub(crate) unsafe auto trait Freeze {}
#[unstable(feature = "freeze", issue = "121675")]
pub unsafe auto trait Freeze {}

#[unstable(feature = "freeze", issue = "121675")]
impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
marker_impls! {
#[unstable(feature = "freeze", issue = "121675")]
unsafe Freeze for
{T: ?Sized} PhantomData<T>,
{T: ?Sized} *const T,
Expand Down
2 changes: 1 addition & 1 deletion tests/run-make/min-global-align/min_global_align.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![feature(no_core, lang_items)]
#![feature(no_core, lang_items, freeze_impls)]
#![crate_type = "rlib"]
#![no_core]

Expand Down
9 changes: 6 additions & 3 deletions tests/rustdoc/auto-trait-bounds-by-associated-type-50159.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// https://github.com/rust-lang/rust/issues/50159
#![crate_name="foo"]
#![crate_name = "foo"]

pub trait Signal {
type Item;
Expand All @@ -9,15 +9,18 @@ pub trait Signal2 {
type Item2;
}

impl<B, C> Signal2 for B where B: Signal<Item = C> {
impl<B, C> Signal2 for B
where
B: Signal<Item = C>,
{
type Item2 = C;
}

// @has foo/struct.Switch.html
// @has - '//h3[@class="code-header"]' 'impl<B> Send for Switch<B>where <B as Signal>::Item: Send'
// @has - '//h3[@class="code-header"]' 'impl<B> Sync for Switch<B>where <B as Signal>::Item: Sync'
// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 6
pub struct Switch<B: Signal> {
pub inner: <B as Signal2>::Item2,
}
4 changes: 2 additions & 2 deletions tests/rustdoc/empty-section.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#![crate_name = "foo"]

#![feature(negative_impls)]
#![feature(negative_impls, freeze_impls, freeze)]

pub struct Foo;

// @has foo/struct.Foo.html
// @!hasraw - 'Auto Trait Implementations'
impl !Send for Foo {}
impl !Sync for Foo {}
impl !std::marker::Freeze for Foo {}
impl !std::marker::Unpin for Foo {}
impl !std::panic::RefUnwindSafe for Foo {}
impl !std::panic::UnwindSafe for Foo {}
2 changes: 1 addition & 1 deletion tests/rustdoc/synthetic_auto/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// @has - '//h3[@class="code-header"]' 'impl<T> Send for Foo<T>where T: Send'
// @has - '//h3[@class="code-header"]' 'impl<T> Sync for Foo<T>where T: Sync'
// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 6
pub struct Foo<T> {
field: T,
}
2 changes: 1 addition & 1 deletion tests/rustdoc/synthetic_auto/manual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// 'impl<T> Send for Foo<T>'
//
// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4
// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
pub struct Foo<T> {
field: T,
}
Expand Down
12 changes: 12 additions & 0 deletions tests/ui/associated-consts/freeze.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#![feature(freeze)]

//@ check-pass

use std::marker::Freeze;

trait Trait<T: Freeze + 'static> {
const VALUE: T;
const VALUE_REF: &'static T = &Self::VALUE;
}

fn main() {}
15 changes: 15 additions & 0 deletions tests/ui/feature-gates/feature-gate-freeze-impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![feature(freeze, negative_impls)]

use std::marker::Freeze;

struct Foo;

unsafe impl Freeze for Foo {}
//~^ explicit impls for the `Freeze` trait are not permitted

struct Bar;

impl !Freeze for Bar {}
//~^ explicit impls for the `Freeze` trait are not permitted

fn main() {}
23 changes: 23 additions & 0 deletions tests/ui/feature-gates/feature-gate-freeze-impls.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
error[E0658]: explicit impls for the `Freeze` trait are not permitted
--> $DIR/feature-gate-freeze-impls.rs:7:1
|
LL | unsafe impl Freeze for Foo {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `Freeze` not allowed
|
= note: see issue #121675 <https://github.com/rust-lang/rust/issues/121675> for more information
= help: add `#![feature(freeze_impls)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error[E0658]: explicit impls for the `Freeze` trait are not permitted
--> $DIR/feature-gate-freeze-impls.rs:12:1
|
LL | impl !Freeze for Bar {}
| ^^^^^^^^^^^^^^^^^^^^ impl of `Freeze` not allowed
|
= note: see issue #121675 <https://github.com/rust-lang/rust/issues/121675> for more information
= help: add `#![feature(freeze_impls)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.

0 comments on commit 05f22c3

Please sign in to comment.