about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJacob Pratt <jacob@jhpratt.dev>2025-08-22 22:00:55 -0400
committerGitHub <noreply@github.com>2025-08-22 22:00:55 -0400
commit566c13c88e790b96997c689ce9a0f067b9f0d6cf (patch)
tree61c36c978127b9b3ca4c5ec1149314339dede5db
parent0cd557b096bfba07a82213d0e3135d7f609f748d (diff)
parentfd44708aa33e92fb165b35916bb120033bce9f23 (diff)
downloadrust-566c13c88e790b96997c689ce9a0f067b9f0d6cf.tar.gz
rust-566c13c88e790b96997c689ce9a0f067b9f0d6cf.zip
Rollup merge of #145726 - aapoalas:reborrow-lang-experiment, r=petrochenkov
Experiment: Reborrow trait

Tracking issue: rust-lang/rust#145612

Starting off really small here: just introduce the unstable feature and the feature gate, and one of the two traits that the Reborrow experiment deals with.

### Cliff-notes explanation

The `Reborrow` trait is conceptually a close cousin of `Copy` with the exception that it disables the source (`self`) for the lifetime of the target / result of the reborrow action. It can be viewed as a method of `fn reborrow(self: Self<'a>) -> Self<'a>` with the compiler adding tracking of the resulting `Self<'a>` (or any value derived from it that retains the `'a` lifetime) to keep the `self` disabled for reads and writes.

No method is planned to be surfaced to the user, however, as reborrowing cannot be seen in code (except for method calls [`a.foo()` reborrows `a`] and explicit reborrows [`&*a`]) and thus triggering user-code in it could be viewed as "spooky action at a distance". Furthermore, the added compiler tracking cannot be seen on the method itself, violating the Golden Rule. Note that the userland "reborrow" method is not True Reborrowing, but rather a form of a "Fancy Deref":
```rust
fn reborrow(&'short self: Self<'long>) -> Self<'short>;
```
The lifetime shortening is the issue here: a reborrowed `Self` or any value derived from it is bound to the method that called `reborrow`, since `&'short` is effectively a local variable. True Reborrowing does not shorten the lifetime of the result.

To avoid having to introduce new kinds of references, new kinds of lifetime annotations, or a blessed trait method, no method will be introduced at all. Instead, the `Reborrow` trait is intended to be a derived trait that effectively reborrows each field individually; `Copy` fields end up just copying, while fields that themselves `Reborrow` get disabled in the source, usually leading to the source itself being disabled (some differences may appear with structs that contain multiple reborrowable fields). The goal of the experiment is to determine how the actual implementation here will shape out, and what the "bottom case" for the recursive / deriving `Reborrow` is.

`Reborrow` has a friend trait, `CoerceShared`, which is equivalent to a `&'a mut T -> &'a T` conversion. This is needed as a different trait and different operation due to the different semantics it enforces on the source: a `CoerceShared` operation only disables the source for writes / exclusive access for the lifetime of the result. That trait is not yet introduced in this PR, though there is no particular reason why it could not be introduced.
-rw-r--r--compiler/rustc_feature/src/unstable.rs1
-rw-r--r--compiler/rustc_hir/src/lang_items.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/marker.rs8
-rw-r--r--tests/ui/feature-gates/feature-gate-reborrow.rs3
-rw-r--r--tests/ui/feature-gates/feature-gate-reborrow.stderr13
7 files changed, 30 insertions, 0 deletions
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 705d5db4595..92b435b4b01 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -616,6 +616,7 @@ declare_features! (
     (unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
     /// Allows the use of raw-dylibs on ELF platforms
     (incomplete, raw_dylib_elf, "1.87.0", Some(135694)),
+    (unstable, reborrow, "CURRENT_RUSTC_VERSION", Some(145612)),
     /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
     (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)),
     /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 905b84a8cbe..0464665b41f 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -437,6 +437,9 @@ language_item_table! {
     DefaultTrait1,           sym::default_trait1,      default_trait1_trait,       Target::Trait,          GenericRequirement::None;
 
     ContractCheckEnsures,     sym::contract_check_ensures,      contract_check_ensures_fn,      Target::Fn, GenericRequirement::None;
+
+    // Reborrowing related lang-items
+    Reborrow,                sym::reborrow,            reborrow,                   Target::Trait,          GenericRequirement::Exact(0);
 }
 
 /// The requirement imposed on the generics of a lang item
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index e4cb9b39b82..5d140cc6117 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1756,6 +1756,7 @@ symbols! {
         readonly,
         realloc,
         reason,
+        reborrow,
         receiver,
         receiver_target,
         recursion_limit,
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 71abd707374..f69d6a98592 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -172,6 +172,7 @@
 #![feature(no_core)]
 #![feature(optimize_attribute)]
 #![feature(prelude_import)]
+#![feature(reborrow)]
 #![feature(repr_simd)]
 #![feature(rustc_allow_const_fn_unstable)]
 #![feature(rustc_attrs)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index ba00ee17b65..8ad58599c68 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -1365,3 +1365,11 @@ pub macro CoercePointee($item:item) {
 pub trait CoercePointeeValidated {
     /* compiler built-in */
 }
+
+/// Allows value to be reborrowed as exclusive, creating a copy of the value
+/// that disables the source for reads and writes for the lifetime of the copy.
+#[lang = "reborrow"]
+#[unstable(feature = "reborrow", issue = "145612")]
+pub trait Reborrow {
+    // Empty.
+}
diff --git a/tests/ui/feature-gates/feature-gate-reborrow.rs b/tests/ui/feature-gates/feature-gate-reborrow.rs
new file mode 100644
index 00000000000..f016f6c6bfa
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-reborrow.rs
@@ -0,0 +1,3 @@
+use std::marker::Reborrow; //~ ERROR  use of unstable library feature `reborrow`
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-reborrow.stderr b/tests/ui/feature-gates/feature-gate-reborrow.stderr
new file mode 100644
index 00000000000..5e3033f3bf1
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-reborrow.stderr
@@ -0,0 +1,13 @@
+error[E0658]: use of unstable library feature `reborrow`
+  --> $DIR/feature-gate-reborrow.rs:1:5
+   |
+LL | use std::marker::Reborrow;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #145612 <https://github.com/rust-lang/rust/issues/145612> for more information
+   = help: add `#![feature(reborrow)]` 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 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.