Introduction

This is the unfair Rust quiz, a collection of extremely hard and sometimes even unfair questions about Rust, made by the gayest people you know.

This quiz is split into multiple sections where each section covers a different topic or style of question. Each section has its own introduction page that describes what the section is about, how to go about answering questions in it.

Currently there are four sections:

  • Unsafe
  • Miscellaneous
  • Trait Solver
  • Borrow Checker

The canonical URL of this quiz is https://this.quiz.is.fckn.gay

You can find the repo at https://github.com/BoxyUwU/rust-quiz

The code examples were tested with nightly-2026-01-04, but it is intended that they work on any future Rust version too.

unsafe code questions

For each code example on each page, when Miri is run with Stacked Borrows enabled does the example invoke UB or not.

When the example has UB, explain which operation is UB and why.

Null Pointer Derefs @WaffleLapkin @BoxyUwU @m-ou-se @Victoronz

fn main() {
    // 1. UB?
    unsafe {
        _ = *std::ptr::null::<u32>();
    }
}
fn main() {
    // 2. UB?
    unsafe {
        _ = (*std::ptr::null::<u32>());
    }
}
fn main() {
    // 3. UB?
    unsafe {
        _ = (*std::ptr::null::<u32>(),);
    }
}
fn main() {
    // 4. UB?
    unsafe {
        _ = { *std::ptr::null::<u32>() };
    }
}
fn main() {
    // 5. UB?
    _ = unsafe { *std::ptr::null::<u32>() };
}
Solution

Examples 1 and 2 are fine, while 3, 4 and 5 are UB:

error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got null pointer
 --> examples/unsafe_1_3.rs:7:14
  |
7 |         _ = (*std::ptr::null::<u32>(),);
  |              ^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
  = note: BACKTRACE:
  = note: inside `main` at examples/unsafe_1_3.rs:7:14: 7:38

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got null pointer
 --> examples/unsafe_1_4.rs:7:15
  |
7 |         _ = { *std::ptr::null::<u32>() };
  |               ^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
  = note: BACKTRACE:
  = note: inside `main` at examples/unsafe_1_4.rs:7:15: 7:39

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got null pointer
 --> examples/unsafe_1_5.rs:6:18
  |
6 |     _ = unsafe { *std::ptr::null::<u32>() };
  |                  ^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
  = note: BACKTRACE:
  = note: inside `main` at examples/unsafe_1_5.rs:6:18: 6:42

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

Loading a value from a null pointer is undefined behavior in Rust. However, dereferencing a pointer does not always cause a load, it only creates a place that can then be implicitly coerced to a value.

In examples 1 and 2 the dereference produces a place which is immediately discarded by the assignment to _ (note that parenthesis do not affect anything other than precedence of operators).

In example 3 the place created by the dereference is coerced to a value because (...,) creates a single element tuple (note the ,!).

In examples 4 and 5 the place created by the dereference is coerced to a value, because it is returned from a block (note that normal and unsafe blocks behave the same) which causes UB.

To learn more about differences between places and values read an article by Ralf Jung, "What is a place expression?".

Random Number Generator @WaffleLapkin @BoxyUwU

use std::mem::MaybeUninit;

fn main() {
    // Safety: all bitpatterns are valid for u8
    let random_number: u8 = unsafe { MaybeUninit::uninit().assume_init() };

    let very_random_number = if random_number <= 100 {
        unsafe {
            // Safety: all bitpatterns are valid for u32
            let rng_array: [u32; 100] = MaybeUninit::uninit().assume_init();
            // Safety: The `random_number` is in bounds
            *rng_array.get_unchecked(random_number as usize)
        }
    } else {
        // chosen by a fair dice roll
        4
    };

    dbg!(very_random_number);
}
Solution
warning: the type `u8` does not permit being left uninitialized
 --> examples/unsafe_2.rs:5:38
  |
5 |     let random_number: u8 = unsafe { MaybeUninit::uninit().assume_init() };
  |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |                                      |
  |                                      this code causes undefined behavior when executed
  |                                      help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
  |
  = note: integers must be initialized
  = note: `#[warn(invalid_value)]` on by default

warning: the type `[u32; 100]` does not permit being left uninitialized
  --> examples/unsafe_2.rs:10:41
   |
10 |             let rng_array: [u32; 100] = MaybeUninit::uninit().assume_init();
   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                                         |
   |                                         this code causes undefined behavior when executed
   |                                         help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
   |
   = note: integers must be initialized

error: Undefined Behavior: reading memory at alloc133[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory
 --> examples/unsafe_2.rs:5:38
  |
5 |     let random_number: u8 = unsafe { MaybeUninit::uninit().assume_init() };
  |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
  |
  = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
  = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
  = note: BACKTRACE:
  = note: inside `main` at examples/unsafe_2.rs:5:38: 5:73

Uninitialized memory occurred at alloc133[0x0..0x1], in this allocation:
alloc133 (stack variable, size: 1, align: 1) {
    __                                              │ ░
}

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error; 2 warnings emitted

Even though all initialized bitpatterns are valid for integer types, creating an integer value from uninitialized memory is still undefined behavior. More details can be found in the MaybeUninit documentation.

Careful readers may also have noticed that there is an index out of bounds error from checking random_number <= 100 instead of random_number < 100. While this is logically incorrect, it does not result in any UB as the previous line when creating random_number is UB and thus all future lines are not executed.

Pointer Writes to a Vec @orlp @Noratrieb

fn main() {
    let mut v = vec![0_u8; 10];

    // SAFETY: The vec has 10 elements, so 1 and 2 are in bounds.
    //         The two elements are distinct, so we are not overlapping.
    unsafe {
        let r1: *mut u8 = v.as_mut_ptr().add(1);
        let r2: *mut u8 = v.as_mut_ptr().add(2);
        *r1 = 10;
        *r2 = 10;
    }
}
fn main() {
    let mut v = vec![0_u8; 10];

    // SAFETY: The vec has 10 elements, so 1 and 2 are in bounds.
    //         The two elements are distinct, so we are not overlapping.
    unsafe {
        let r1: *mut u8 = v.get_unchecked_mut(1);
        let r2: *mut u8 = v.get_unchecked_mut(2);
        *r1 = 10;
        *r2 = 10;
    }
}
Solution

Example 1 is sound, example 2 is UB.

error: Undefined Behavior: attempting a write access using <415> at alloc230[0x1], but that tag does not exist in the borrow stack for this location
 --> examples/unsafe_3_2.rs:9:9
  |
9 |         *r1 = 10;
  |         ^^^^^^^^ this error occurs as part of an access at alloc230[0x1..0x2]
  |
  = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
  = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <415> was created by a SharedReadWrite retag at offsets [0x1..0x2]
 --> examples/unsafe_3_2.rs:7:27
  |
7 |         let r1: *mut u8 = v.get_unchecked_mut(1);
  |                           ^^^^^^^^^^^^^^^^^^^^^^
help: <415> was later invalidated at offsets [0x0..0xa] by a Unique retag
 --> examples/unsafe_3_2.rs:8:27
  |
8 |         let r2: *mut u8 = v.get_unchecked_mut(2);
  |                           ^^^^^^^^^^^^^^^^^^^^^^
  = note: BACKTRACE (of the first span):
  = note: inside `main` at examples/unsafe_3_2.rs:9:9: 9:17

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to 1 previous error

v.as_mut_ptr() refers to Vec::as_mut_ptr(v), which only creates a &mut reference to the vec itself.

v.get_unchecked_mut() comes from an implicit dereference to a slice, referring to <[T]>::get_unchecked_mut(Vec::deref(v)), creating a &mut to all slice elements. When doing the deref for creating r2, this full &mut invalidates r1.

Miscellaneous

For each code example on each page, when running cargo run what does the example output. This may be a compiler error, a runtime panic, some kind of runtime logging, etc.

When the example is a compiler error, explain which operation errors and why.

When the example is a runtime panic, explain which part panics and why.

When the example runs successfully, explain why it does so and what it outputs.

Array Transmutery @WaffleLapkin @BoxyUwU

pub unsafe const fn my_zeroed<T>() -> T {
    assert!(std::mem::size_of::<T>() <= 256);

    unsafe {
        std::mem::transmute_copy(&[0u8; 256])
    }
}

fn main() {
    unsafe {
        my_zeroed::<[*mut u32; 64]>();
    }
}
Solution
error: expected one of `extern` or `fn`, found keyword `const`
 --> examples/misc_1.rs:1:12
  |
1 | pub unsafe const fn my_zeroed<T>() -> T {
  |     -------^^^^^
  |     |      |
  |     |      expected one of `extern` or `fn`
  |     help: `const` must come before `unsafe`: `const unsafe`
  |
  = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`

error: could not compile `code` (example "misc_1") due to 1 previous error

As the error says, there is a given order function qualifiers must go in.

Careful readers may also have noticed that the size of [*mut u32; 64] is not necessarily equal to [u8; 256]. On 64bit platforms the array of pointers would be 512 bytes large, 8 bytes * 64 elements = 256 bytes. While this is a logical error and would result in a panic at runtime, the code can never be executed due to the compilation error.

Boxy Fake Bones @WaffleLapkin @BoxyUwU

struct Data {
    name: String,
    bones: Vec<String>,
}

impl std::fmt::Debug for Data {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", &self.name)?;
        for bone in &self.bones {
            write!(f, " {}", bone)?;
        }
        writeln!(f, "")
    }
}

fn main() {
    let data = Data {
        name: "Boxy".into(),
        bones: vec!["fakebone1".into(), "fakebone2".into()],
    };
    dbg!(data)
}
Solution
error[E0308]: mismatched types
  --> examples/misc_2.rs:21:5
   |
16 | fn main() {
   |          - expected `()` because of default return type
...
21 |     dbg!(data)
   |     ^^^^^^^^^^ expected `()`, found `Data`
   |
   = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0308`.
error: could not compile `code` (example "misc_2") due to 1 previous error

There is a lot of fluff, the mistake is on the second to last line. dbg! returns its argument after printing to the stderr, which means that you need to use ; after it in cases like this.

Printing Time @WaffleLapkin @BoxyUwU

struct Foo {
    func: fn(),
}

fn bar(foo: Foo) {
    foo.func();
}
Solution
error[E0599]: no method named `func` found for struct `Foo` in the current scope
 --> examples/misc_3.rs:7:9
  |
2 | struct Foo {
  | ---------- method `func` not found for this struct
...
7 |     foo.func();
  |         ^^^^ field, not a method
  |
help: to call the function pointer stored in `func`, surround the field access with parentheses
  |
7 |     (foo.func)();
  |     +        +

For more information about this error, try `rustc --explain E0599`.
error: could not compile `code` (example "misc_3") due to 1 previous error

There is a syntactic difference between a method call and a normal call. expr.identifier() is always a method call and Foo does not have a method called func. To call the function stored in a field you need to add parenthesis:

fn bar(foo: Foo) {
    (foo.func)();
}

Note that the same problem does not apply to tuples and tuple structs, because you can't name a method with an integer identifier. The following example compiles and prints "ferrisUwu" when run:

struct Foo(fn());

fn print_heheh() {
    println!("ferrisUwu")
}

fn main() {
    let foo = Foo(print_heheh);
    foo.0();
}

The Dastardly Hashmap @BoxyUwU

fn main() {
    let mut map = HashMap::new();
    map.insert(1, 2);
    assert_eq!(map.get_mut(&1), Some(&mut 2));
}
Solution
error[E0433]: failed to resolve: use of undeclared type `HashMap`
 --> examples/misc_4.rs:2:19
  |
2 |     let mut map = HashMap::new();
  |                   ^^^^^^^ use of undeclared type `HashMap`
  |
help: consider importing this struct
  |
1 + use std::collections::HashMap;
  |

For more information about this error, try `rustc --explain E0433`.
error: could not compile `code` (example "misc_4") due to 1 previous error

Dastardly...

HashMap is not included in the prelude and so must be imported explicitly.

Super Trait Ultra Associated Item @WaffleLapkin @BoxyUwU

trait Super {
    fn assoc() -> Self;
}

trait Sub: Super {}

fn f<T: Sub>() -> T {
    Sub::assoc()
}

fn main() {}
Solution
error[E0782]: expected a type, found a trait
 --> examples/misc_5.rs:8:5
  |
8 |     Sub::assoc()
  |     ^^^
  |
help: you can add the `dyn` keyword if you want a trait object
  |
8 |     <dyn Sub>::assoc()
  |     ++++    +

For more information about this error, try `rustc --explain E0782`.
error: could not compile `code` (example "misc_5") due to 1 previous error

This diagnostic is fairly confusing. The diagnostic assumes that you meant to use Sub as a type, not a trait, which requires the dyn keyword. Though, in this specific case this assumption doesn't make sense as Sub is not dyn compatible.

The compilation error is caused by being unable to refer to items from super traits through sub traits. Even though Sub has a super trait Super, you can't use Sub::assoc().

You can use Super::assoc() though, for example this compiles just fine:

trait Super {
    fn assoc() -> Self;
}

trait Sub: Super {}

fn f<T: Sub>() -> T {
    Super::assoc()
}

Trait::assoc is a shorter version of <_ as Trait>::assoc (aka fully qualified path).

Temporary Name @orlp @Noratrieb @BoxyUwU

#![allow(unreachable_code)]

struct PrintOnDrop(&'static str);
impl Drop for PrintOnDrop {
    fn drop(&mut self) {
        eprint!("{}", self.0);
    }
}

fn main() {
    owo();
    uwu();
}

fn owo() {
    (
        (PrintOnDrop("1"), PrintOnDrop("2"), PrintOnDrop("3")),
        return,
    );
}

fn uwu() {
    (PrintOnDrop("1"), PrintOnDrop("2"), PrintOnDrop("3"), return);
}
Solution
123321

When structs/tuples/arrays are dropped, they drop their constituent parts (e.g. fields, tuple elements, array elements) from first to last.

On the other hand, when exiting a scope in a function body, locals and temporaries are dropped in reverse definition order. In other words, temporaries/locals are dropped in order of youngest to oldest.

In fn owo there is a fully constructed value of type (PrintOnDrop, PrintOnDrop, PrintOnDrop). When exiting the function the tuple is dropped as a whole, dropping its first element, then second, and finally its third.

In fn uwu there is never a fully constructed tuple type, instead there are three temporaries of type PrintOnDrop on the stack. When exiting the function the temporaries on the stack are dropped in reverse definition order, starting from the most recently created, PrintOnDrop("3"), to oldest created, PrintOnDrop("1").

Quantum Captures @Kivooeo

macro_rules! capture {
    ($e:expr) => {
        transform!($e)
    };
}

macro_rules! transform {
    ($a:tt + $b:tt) => {
        $a * $b
    };
    ($other:expr) => {
        $other
    };
}

fn main() {
    let x = capture!(2 + 3);
    eprintln!("{}", x);
}
Solution
5

Once a token is captured as an expression (:expr), it becomes opaque to macro pattern matching and cannot be destructured into its component tokens.

When capture!(2 + 3) is invoked, the $e:expr matcher captures 2 + 3 as a single expression token tree. This captured expression is then passed to transform!($e), which attempts to match it against the pattern $a:tt + $b:tt.

However, because $e was already captured as an :expr, it cannot be pattern-matched as separate tokens anymore. The first arm $a:tt + $b:tt fails to match, so the second arm $other:expr matches instead, and the expression 2 + 3 is returned as-is, evaluating to 5.

We're in Spaaaaace @adotinthevoid @BoxyUwU

struct bar {}
fn bar() {}

const foo: usize = 1;
fn foo() {}
Solution
error[E0428]: the name `foo` is defined multiple times
 --> examples/misc_8.rs:8:1
  |
7 | const foo: usize = 1;
  | --------------------- previous definition of the value `foo` here
8 | fn foo() {}
  | ^^^^^^^^ `foo` redefined here
  |
  = note: `foo` must be defined only once in the value namespace of this module

For more information about this error, try `rustc --explain E0428`.
error: could not compile `code` (example "misc_8") due to 1 previous error

Types and values live in separate namespaces as it is usually possible to syntactically determine whether an identifier should be for a value or type.

This means that struct bar {} is part of the type namespace, whereas fn bar is part of the value namespace (as functions in Rust are first class values). This allows for both of these declarations to co-exist.

However, const foo and fn foo are both part of the value namespace, causing a compiler error.

Construction Site @adotinthevoid @jdonszelmann @Victoronz @GoldsteinE @WaffleLapkin @BoxyUwU

// 1.
struct Struct {}
struct Tuple(u32);
struct Unit;

fn main() {
    Struct;
    Tuple;
    Unit;
}
// 2.
struct Struct {}
struct Tuple(u32);
struct Unit;

fn main() {
    Struct {};
    Tuple { 0: 1_u32 };
    Unit {};
}
Solution

There are 3 kinds of structs in Rust:

  1. Plain structs (eg struct Foo { bar: i32 })
  2. Tuple structs (eg struct Bar(i32);)
  3. Unit structs (eg struct Baz;)

The name of a plain struct refers to the type of the struct.

The name of a tuple struct either refers to the type of the struct or the implicit function used to construct it:

struct Tuple(u32);

// conceptually desugars to...
struct Tuple { 0: u32 }
fn Tuple(0: u32) -> Tuple { /* not important */ }

The name of a unit struct either refers to the type of the struct or the implicit constant representing its only value.

struct Tuple;

// conceptually desugars to...
struct Tuple { }
const Tuple: Tuple = /* not important */;

// 1.
error[E0423]: expected value, found struct `Struct`
 --> examples/misc_9_1.rs:9:5
  |
4 | struct Struct {}
  | ---------------- `Struct` defined here
...
9 |     Struct;
  |     ^^^^^^ help: use struct literal syntax instead: `Struct {}`

For more information about this error, try `rustc --explain E0423`.
error: could not compile `code` (example "misc_9_1") due to 1 previous error

In the first example both Unit and Tuple are valid expressions, evaluating to either the only value of the Unit type or the function item for the constructor of Tuple.

Struct however is not a valid expression as it simply refers to the type of the struct.

// 2.

In the second example, perhaps surprisingly, all of Unit {}, Tuple { 0: 1_u32 } and Struct {} are valid. Both tuple and unit structs both support Struct {} syntax as it is useful for macros.


Another interesting example would be the interactions between Unit's constant and destructuring assignment:

// 3.
struct Struct {}
struct Tuple();
struct Unit;

fn main() {
    Struct = loop {};
    Tuple = loop {};
    Unit = loop {};
}

error[E0423]: expected value, found struct `Struct`
 --> examples/misc_9_3.rs:9:5
  |
4 | struct Struct {}
  | ---------------- `Struct` defined here
...
9 |     Struct = loop {};
  |     ^^^^^^ help: use struct literal syntax instead: `Struct {}`

error[E0070]: invalid left-hand side of assignment
  --> examples/misc_9_3.rs:10:11
   |
10 |     Tuple = loop {};
   |     ----- ^
   |     |
   |     cannot assign to this expression

Some errors have detailed explanations: E0070, E0423.
For more information about an error, try `rustc --explain E0070`.
error: could not compile `code` (example "misc_9_3") due to 2 previous errors

Unit is a valid pattern as it actually refers to the constant representing the only value of the unit struct.

Tuple and Struct however are not valid patterns as they are a path to a function and a path to a type.

Threadsafe Pointer!? @jdonszelmann

use std::future::Future;

struct ThreadSafePtr<T>(pub *const T);
unsafe impl<T> Send for ThreadSafePtr<T> {}

fn requires_send(_f: impl Future + Send) {}

fn main() {
    let x = 10;
    let y = ThreadSafePtr(&raw const x);

    requires_send(async move {
        println!("{}", unsafe{*y.0})
    })
}
Solution
error[E0277]: `*const i32` cannot be sent between threads safely
  --> examples/misc_10.rs:12:5
   |
12 |       requires_send(async move {
   |       ^             ---------- within this `{async block@examples/misc_10.rs:12:19: 12:29}`
   |  _____|
   | |
13 | |         println!("{}", unsafe{*y.0})
14 | |     })
   | |______^ `*const i32` cannot be sent between threads safely
   |
   = help: within `{async block@examples/misc_10.rs:12:19: 12:29}`, the trait `Send` is not implemented for `*const i32`
note: required because it's used within this `async` block
  --> examples/misc_10.rs:12:19
   |
12 |     requires_send(async move {
   |                   ^^^^^^^^^^
note: required by a bound in `requires_send`
  --> examples/misc_10.rs:6:36
   |
 6 | fn requires_send(_f: impl Future + Send) {}
   |                                    ^^^^ required by this bound in `requires_send`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `code` (example "misc_10") due to 1 previous error

Despite the closure being move, not the whole ThreadSafePtr is moved into the async block. Rust allows us to move different fields of a struct into different closures or async blocks. Since we only access y.0, it only moves that field, which is a *const T, which is not Send, which means this code doesn't compile.

A slightly comical way to fix it is like this:


use std::future::Future;

struct ThreadSafePtr<T>(pub *const T);
unsafe impl<T> Send for ThreadSafePtr<T> {}

fn requires_send(_f: impl Future + Send) {}

fn main() {
    let x = 10;
    let y = ThreadSafePtr(&raw const x);

    requires_send(async move {
        let y = y; // <-- ADD THIS
        println!("{}", unsafe{*y.0})
    })
}

Note, before edition 2021, this kind of splitting was not possible and y would be moved into the closure as a whole.

Trait Solver

For each code example on each page, when running cargo run what does the example output. This may be a compiler error, a runtime panic, some kind of runtime logging, etc.

When the example is a compiler error, explain which operation errors and why.

When the example is a runtime panic, explain which part panics and why.

When the example runs successfully, explain why it does so and what it outputs.

Uhm... @BoxyUwU @WaffleLapkin

trait Trait {}

impl Trait for for<'a> fn(&'a u32) {}

fn f()
where
    for<'a> fn(&'a u32): Trait,
{
}

fn main() {
    f();
}
Solution
error: implementation of `Trait` is not general enough
  --> examples/trait_solver_1.rs:12:5
   |
12 |     f();
   |     ^^^ implementation of `Trait` is not general enough
   |
   = note: `for<'a> fn(&'a u32)` must implement `Trait`, for any lifetime `'0`...
   = note: ...but `Trait` is actually implemented for the type `for<'a> fn(&'a u32)`

error: could not compile `code` (example "trait_solver_1") due to 1 previous error

The trait implementation is for a higher ranked function pointer (for<'a> fn). But the where clause is different, there the for<'a> is parsed as part of the bound, so the bound is on a not higher-ranked function pointer.

impl:

type: for<'a> fn(&'a u32)
trait: Trait

bound:

type: fn(&'a u32)
trait: Trait

Only higher-ranked function pointers implement the trait, so it fails to compile.

In a sense this is really a parser question. Parenthesis can be used to disambiguate this as a higher ranked function pointer and get a successful compilation:

trait Trait {}

impl Trait for for<'a> fn(&'a u32) {}

fn f()
where
    (for<'a> fn(&'a u32)): Trait,
{
}

fn main() {
    f();
}

Type System 2 @BoxyUwU @WaffleLapkin

struct A;
struct B;
struct C;

trait Trait<'a, T> {
    type Assoc;
}

trait Bound {}

impl Bound for B {}
impl Bound for C {}

impl<'a> Trait<'a, B> for A {
    type Assoc = B;
}

impl<'a> Trait<'a, C> for A {
    type Assoc = C;
}

fn f<T>(_: T)
where
    for<'a> A: Trait<'a, T>,
    for<'a> <A as Trait<'a, T>>::Assoc: Bound,
{
}

fn main() {
    f(B);
}
Solution
error[E0277]: the trait bound `for<'a> <A as Trait<'a, _>>::Assoc: Bound` is not satisfied
  --> examples/trait_solver_2.rs:30:7
   |
30 |     f(B);
   |     - ^ the trait `for<'a> Bound` is not implemented for `<A as Trait<'a, _>>::Assoc`
   |     |
   |     required by a bound introduced by this call
   |
help: the following other types implement trait `Bound`
  --> examples/trait_solver_2.rs:11:1
   |
11 | impl Bound for B {}
   | ^^^^^^^^^^^^^^^^ `B`
12 | impl Bound for C {}
   | ^^^^^^^^^^^^^^^^ `C`
note: this is a known limitation of the trait solver that will be lifted in the future
  --> examples/trait_solver_2.rs:30:7
   |
30 |     f(B);
   |     --^-
   |     | |
   |     | the trait solver is unable to infer the generic types that should be inferred from this argument
   |     add turbofish arguments to this call to specify the types manually, even if it's redundant
note: required by a bound in `f`
  --> examples/trait_solver_2.rs:25:41
   |
22 | fn f<T>(_: T)
   |    - required by a bound in this function
...
25 |     for<'a> <A as Trait<'a, T>>::Assoc: Bound,
   |                                         ^^^^^ required by this bound in `f`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `code` (example "trait_solver_2") due to 1 previous error

As the error message states this is actually a compiler bug! The trait bound for<'a> <A as Trait<'a, B>>::Assoc: Bound does actually hold.

Let's step through the process of type checking fn main to see where the compiler goes wrong.

Firstly, f(B); desugars to f::<_>(B). Let's give the inferred type argument of _ the name ?x for future reference.

Note that while as humans we can trivially tell that ?x should be inferred to B, the compiler has to actually figure this out which happens at a later step than where the bug in the compiler is.

When typechecking a function call, the compiler is responsible for checking all the where clauses of the function hold. This looks something like:

  1. Iterate over all the where clauses on the function
  2. For each where clause replace any generic parameters with the corresponding generic arguments provided by the caller
  3. Iterate over the list of where clauses with generic parameters replaced
  4. For each where clause have the trait solver try and prove the trait bound

In this question we have the function call f::<?x>(B), going through the above steps would look something like:

  1. Iterate over the where clauses
    • for<'a> A: Trait<'a, T>
    • for<'a> <A as Trait<'a, T>>::Assoc: Bound
  2. Replace the generic parameters with the generic arguments provided by the caller, in this case T should be replaced with ?x
    • for<'a> A: Trait<'a, ?x>
    • for<'a> <A as Trait<'a, ?x>>::Assoc: Bound
  3. Iterate over the where clauses with replaced generic parameters
    • See above list
  4. Have the trait solver check these trait bounds
    • for<'a> A: Trait<'a, ?x>. The trait solver handles this correct and returns ambiguity, meaning it doesn't yet know whether the trait bound holds or not.
    • for<'a> <A as Trait<'a, ?x>>::Assoc: Bound. The trait solver handles this incorrectly, and returns an error, meaning it thinks the trait bound doesn't hold.

The trait solver considers for<'a> <A as Trait<'a, ?x>>::Assoc: Bound to not hold due to a bug in how associated types are handled.

Let's start with going over a bit of context about how associated types are handled.

Currently the trait solver expects that all associated types have either been replaced with the aliased type, or the associated type is too generic and will never be possible to figure out what the aliased type is.

fn replaced_with_aliased_type() -> <std::vec::Iter<'_, u8> as Iterator>::Item {
    /* not important */
}

fn too_generic<I: Iterator>(i: I) -> <I as Iterator>::Item { 
    /* not important */
}

In this example we have two associated types:

  1. <std::vec::Iter<'_, u8> as Iterator>::Item
  2. <I as Iterator>::Item

The first associated type can be replaced with the aliased type, u8, by looking at the implementation of Iterator for std::vec::Iter and looking at the definition of the Item associated type.

The second associated type can't be replaced with the aliased type as there is no implementation corresponding to I: Iterator- only a trait bound.

Now, stepping back, if you remember the example trait bound that the trait solver doesn't handle correctly: for<'a> <A as Trait<'a, ?x>>::Assoc: Bound.

Part of this trait bound is the associated type <A as Trait<'a, ?x>>::Assoc. This associated type doesn't fit into either of the options we just discussed.

The compiler can't replace it with the aliased type because we dont't know which implementation to look at- it could be either Trait<'a, B> for A or Trait<'a, C> for A!

It's also not "too generic", there's no trait bound on main corresponding to A: Trait<'a, ?x>. This associated type should be able to be replaced with the aliased type, the compiler just can't do so yet at this point during type inference.

This associated type violates the expectation that all associated types fit neatly into one of these two categories.

When attempting to check the for<'a> <A as Trait<'a, ?x>>::Assoc: Bound trait bound holds, the trait solver assumes the associated type is this "too generic" kind of associated type.

Due to this assumption, it considers the types B and C to not be equal to <A as Trait<'a, ?x>>::Assoc. This in turn means that the impl's Bound for B and Bound for C are considered to not apply, as in order for these impls to be useable, the associated type must be equal to B or C (depending on which impl we're talking about).

Finally, as there are no impls that apply when trying to check the for<'a> <A as Trait<'a, ?x>>::Assoc: Bound trait bound, the trait solver considers the trait bound to not hold.

Note: This bug is fixed by the next-gen trait solver! Running this question's example with the unstable -Znext-solver flag results in compilation succeeding.

Slices are Sized Right? @BoxyUwU @WaffleLapkin

Note: The T: Sized bound made explicit on trait TraitB is unnecessary. It is present solely to draw attention to the (implicit) bound.

trait TraitA {}
trait TraitB<T: Sized> {}

impl TraitA for &dyn TraitB<[u8]> {}

trait MyDefault {
    fn default() -> Self;
}

impl<T: TraitA> MyDefault for T {
    fn default() -> T {
        todo!("not important for the example")
    }
}

fn main() {
    <&dyn TraitB<[u8]> as MyDefault>::default();
}
Solution

thread 'main' (???) panicked at examples/trait_solver_3.rs:12:9:
not yet implemented: not important for the example
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

When the compiler checks that a type is well formed (i.e. all of its where clauses hold), it skips checking the where clauses of the Trait of a trait object.

This means that when checking dyn Trait<T> is well formed, we don't require any of the bounds involving T hold. For example T: Sized in this question's TraitB trait object.

However, note that the compiler still enforces the generic arguments are themselves well formed. For example dyn TraitB<Vec<[u8]>> would be rejected by the compiler.

This questions's example compiling successfully is certainly a bug in the compiler, however it is likely not a soundness bug. The trait bounds on the trait of a trait object are actually upheld when coercing a value to a trait object, rather than when naming the trait object type.

Higher Ranked APIT bounds @BoxyUwU @WaffleLapkin

trait A<'a> {
   type Assoc;
}

trait B {}

fn f(_: impl for<'a> A<'a, Assoc = impl B + 'a>) {}

impl<'a> A<'a> for () {
   type Assoc = &'a u8;
}

impl B for &u8 {}

fn main() {
   f(());
}
Solution
error: `impl Trait` can only mention lifetimes from an fn or impl
 --> examples/trait_solver_4.rs:7:45
  |
7 | fn f(_: impl for<'a> A<'a, Assoc = impl B + 'a>) {}
  |                  -- lifetime declared here  ^^

error: could not compile `code` (example "trait_solver_4") due to 1 previous error

The impls are turned into generic parameters on the function (O for the outer impl A, I for the inner impl B).

fn f<O, I>(_: O)
where
    O: for<'a> A<'a, Assoc = I>,
    I: B + 'a,
{}

When looked at like this, it can be seen that the 'a in I: B + 'a doesn't actually exist. It is supposed to come from the O: for<'a> bound, but that's a separate bound. So the I bound cannot name 'a, which is why this does not compile.

This is why nested argument-position-impl-trait can sometimes inhibit confusing behavior.

To make this example compile, you can use associated type bounds instead of an impl Trait:

fn f(_: impl for<'a> A<'a, Assoc: B + 'a>) {}

As the Assoc: B + 'a is part of the bound on the generic parameter, it can name the higher-ranked region 'a.

Supertraits and Coherence @BoxyUwU @WaffleLapkin @lcnr

pub trait Super {}
pub trait Sub<T>: Super {}

pub trait Overlap<T> {}
impl<T, U: Sub<T>> Overlap<T> for U {}
impl<T> Overlap<T> for () {}
Solution

Coherence is responsible for checking whether the two impls of Overlap overlap, and if so emitting an error.

In order for these two impls to overlap there must be some type T for which () implements Sub<T>. The Sub trait is public so downstream crate could exist which implement (): Sub<Local>.

In theory this should mean that these impls overlap, however, the supertrait Super can't be implement for the type () by any downstream crates as impl Super for () { would not pass the orphan check in downstream crates. This logic allows for coherence to consider these impls to not overlap.

If we were to introduce an impl of (): Super to this example then coherence would (rightly) forbid this code.

Note: This example previously did not compile. Coherence was too conservative and rejected this on the basis that (): Sub<Local> may be implementable by downstream crates. This improvement to coherence occurred when coherence started using the next-gen trait solver on stable.

Function Rights @WaffleLapkin @BoxyUwU

fn func(a: &u32) {
    dbg!(a);
}

fn accepts_func(b: fn(&u32), c: &u32) {
    b(c);
}

fn main() {
    accepts_func(func as fn(_), &23);
}
Solution
error[E0308]: mismatched types
  --> examples/trait_solver_6.rs:10:18
   |
10 |     accepts_func(func as fn(_), &23);
   |     ------------ ^^^^^^^^^^^^^ one type is more general than the other
   |     |
   |     arguments to this function are incorrect
   |
   = note: expected fn pointer `for<'a> fn(&'a u32)`
              found fn pointer `fn(_)`
note: function defined here
  --> examples/trait_solver_6.rs:5:4
   |
 5 | fn accepts_func(b: fn(&u32), c: &u32) {
   |    ^^^^^^^^^^^^ -----------

For more information about this error, try `rustc --explain E0308`.
error: could not compile `code` (example "trait_solver_6") due to 1 previous error

Let's first explicitly annotate all elided lifetimes:

fn func<'a>(a: &'a u32) {
    dbg!(a);
}

fn accepts_func<'a>(b: for<'b> fn(&'b u32), c: &'a u32) {
    b(c);
}

fn main() {
    accepts_func(func as fn(_), &23);
}

func is a higher-ranked function of type for<'a> fn(&'a u32). This means it can accept any lifetime. accepts_func's first parameter b is also a higher ranked function of the same type, so it needs a function that can accept any lifetime.

But in main, we cast the higher-ranked function type to fn(_). fn(_) is inferred to not be a higher-ranked function pointer type (inferring a specific lifetime for the argument), so it is no longer valid to pass to accepts_func.

If we instead specify it as as fn(&_) it gets inferred as a higher-ranked function pointer type again and the program compiles. Specifying an inferred type as &_ is sometimes done in real programs for closure arguments to make sure the closure type is inferred to be higher-ranked.

Schrödinger's Borrows @Noratrieb

trait Cat {}

// meow!
impl<T> Cat for T {}

fn main() {
    let r = &0;
    require_box(Box::new(r));

    let local = 0;
    let r = &local;
    require_box(Box::new(r));
}

// Cats love boxes.
fn require_box(_a: Box<dyn Cat>) {}
Solution
error[E0597]: `local` does not live long enough
  --> examples/trait_solver_7.rs:11:13
   |
10 |     let local = 0;
   |         ----- binding `local` declared here
11 |     let r = &local;
   |             ^^^^^^ borrowed value does not live long enough
12 |     require_box(Box::new(r));
   |                 ----------- coercion requires that `local` is borrowed for `'static`
13 | }
   | - `local` dropped here while still borrowed
   |
   = note: due to object lifetime defaults, `Box<dyn Cat>` actually means `Box<(dyn Cat + 'static)>`

For more information about this error, try `rustc --explain E0597`.
error: could not compile `code` (example "trait_solver_7") due to 1 previous error

Box<dyn Cat> means Box<dyn Cat + 'static>, and the local variable is not 'static. &0 does produce a &'static i32 though, because it is implicitly static-promoted.

Borrow Checker

For each code example on each page, when running cargo run what does the example output. This may be a compiler error, a runtime panic, some kind of runtime logging, etc.

When the example is a compiler error, explain which operation errors and why.

When the example is a runtime panic, explain which part panics and why.

When the example runs successfully, explain why it does so and what it outputs.

Top to Bottom @WaffleLapkin @BoxyUwU

fn func(a: &'static u32) {
    dbg!(a);
}

fn accepts_func(f: for<'a> fn(&'a u32), data: &u32) {
    f(data);
}

fn main() {
    let local = 274;
    //  &'static u32 can be shortened to any
    // lifetime borrow so func should be fine
    accepts_func(func, &local);
}
Solution
error[E0308]: mismatched types
  --> examples/borrowck_1.rs:13:18
   |
13 |     accepts_func(func, &local);
   |     ------------ ^^^^ one type is more general than the other
   |     |
   |     arguments to this function are incorrect
   |
   = note: expected fn pointer `for<'a> fn(&'a _)`
                 found fn item `fn(&'static _) {func}`
note: function defined here
  --> examples/borrowck_1.rs:5:4
   |
 5 | fn accepts_func(f: for<'a> fn(&'a u32), data: &u32) {
   |    ^^^^^^^^^^^^ ----------------------

For more information about this error, try `rustc --explain E0308`.
error: could not compile `code` (example "borrowck_1") due to 1 previous error

The accepts_func function requires a function that can be called with a reference with any lifetime. Notably func can't be called with any lifetime — it can only be called with 'static.

In most situations the lifetime of a reference can be shortened, allowing &'static u32 to turn into a reference of any lifetime. However, argument types of function pointers work the opposite way; instead of lifetimes shrinking they can only be extended. We can turn a function pointer fn(&'a u32) into fn(&'static u32), even when 'a doesn't outlive 'static.

This can be thought of as the function pointer performing the subtyping that the caller could have done themselves:

fn foo<'a>(fnptr: fn(&'a u32), borrow: &'static u32) {
    // As the caller we can shrink the lifetime of `borrow` before
    // passing it to `fnptr` which expects a borrow of lifetime `'a`
    let borrow: &'a u32 = borrow;
    fnptr(borrow);

    // Alternatively we can have the function pointer itself do
    // this for all of its callers!
    let fnptr: fn(&'static u32) = borrow;
    fnptr(borrow);

    // It may also be helpful to realise we can *explicitly* perform
    // this implicit subtyping by writing it as a closure
    let closure = |borrow: &'static u32| {
        let borrow: &'a u32 = borrow;
        fnptr(borrow);
    };
    closure(borrow);
}

Argument types of function pointers having special subtyping rules is more commonly referred to contravariance, opposed to the normal covariance that allows for shrinking lifetimes. More information on variance can be found in the Subtyping and Variance chapter of the Rustonomicon.

A Whole Wide Universe @WaffleLapkin @BoxyUwU

fn identity(x: &u32) -> &u32 { x }

fn consume_fn<R, F: for<'a> FnOnce(&'a u32) -> R>(_: F) {}

fn main() {
    let fnptr: for<'b> fn(&'b u32) -> &'b u32 = identity;
    consume_fn(fnptr);
}
Solution
error[E0308]: mismatched types
 --> examples/borrowck_2.rs:7:5
  |
7 |     consume_fn(fnptr);
  |     ^^^^^^^^^^^^^^^^^ one type is more general than the other
  |
  = note: expected reference `&'a _`
             found reference `&_`
note: the lifetime requirement is introduced here
 --> examples/borrowck_2.rs:3:48
  |
3 | fn consume_fn<R, F: for<'a> FnOnce(&'a u32) -> R>(_: F) {}
  |                                                ^

For more information about this error, try `rustc --explain E0308`.
error: could not compile `code` (example "borrowck_2") due to 1 previous error

In order for this code to compile the type parameter R on consume_fn must be able to be given a type argument of &'b u32 by the caller in main.

The type &'b u32 mentions a higher-ranked lifetime 'b from the for-all for<'b>. Only types inside of the for-all can name lifetimes introduced by the for-all.

If the compiler allowed this we would wind up with a function call that looks something like: consume_fn::<&'b u32, for<'b> fn(&'b u32) -> &'b u32>(...).

This would be quite incoherent as the lifetime 'b can be chosen to be a different lifetime by every caller of fnptr. There's no way to know what &'b u32 actually means outside of the for<'b>.

This concept is very closely related to existential and universal quantifiers in formal logic. exists<T> forall<U> T == U cannot be proven, however forall<U> exists<T> T == U can.

In Rust terms this roughly corresponds to inferences variables being existential quantifiers, and for<...> in types as being universal quantifiers. Though, it's worth noting that in some cases for<...> in types is actually treated as an existential quantifier.

Close Encounters of the Net Kind @BoxyUwU

fn foo(a: &mut u32) -> u32 {
    let mut b = || &mut *a;

    *b() = 12;
    *b() = 73;
    *a
}

fn main() {
    foo(&mut 292);
}
Solution
error: captured variable cannot escape `FnMut` closure body
 --> examples/borrowck_3.rs:2:20
  |
1 | fn foo(a: &mut u32) -> u32 {
  |        - variable defined here
2 |     let mut b = || &mut *a;
  |                  - ^^^^^^-
  |                  | |     |
  |                  | |     variable captured here
  |                  | returns a reference to a captured variable which escapes the closure body
  |                  inferred to be a `FnMut` closure
  |
  = note: `FnMut` closures only have access to their captured variables while they are executing...
  = note: ...therefore, they cannot allow references to captured variables to escape

error: could not compile `code` (example "borrowck_3") due to 1 previous error

The closure assigned to b can only return a reference with one specific lifetime (because it has no lifetimes in arguments). So both calls to b return a unique (mutable) reference with the same lifetime, which is an error, because all unique references must be disjoint.

If you inline calls to b it would work though:

fn foo(a: &mut u32) -> u32 {
    *(&mut *a) = 12;
    *(&mut *a) = 73;
    *a
}

This is fine as reborrows can have different lifetimes, allowing them to be disjoint.

Irrecoverably Scarred @BoxyUwU @WaffleLapkin

#[derive(Debug)]
struct Foo<'a>(&'a mut u32);

fn main() {
    let mut data = 10;
    let mut foo = Foo(&mut data);
    mutate(&mut foo);
    dbg!(foo);
}

fn mutate<'a>(f: &'a mut Foo<'a>) {
    *f.0 += 1;
}
Solution
error[E0505]: cannot move out of `foo` because it is borrowed
 --> examples/borrowck_4.rs:8:5
  |
6 |     let mut foo = Foo(&mut data);
  |         ------- binding `foo` declared here
7 |     mutate(&mut foo);
  |            -------- borrow of `foo` occurs here
8 |     dbg!(foo);
  |     ^^^^^^^^^
  |     |
  |     move out of `foo` occurs here
  |     borrow later used here
  |
note: if `Foo<'_>` implemented `Clone`, you could clone the value
 --> examples/borrowck_4.rs:2:1
  |
2 | struct Foo<'a>(&'a mut u32);
  | ^^^^^^^^^^^^^^ consider implementing `Clone` for this type
...
7 |     mutate(&mut foo);
  |                 --- you could clone this value
  = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0505`.
error: could not compile `code` (example "borrowck_4") due to 1 previous error

mutate forces the lifetime of the reference to be the same as the lifetime of the foo itself, so you effectively can't use it ever again — any reference will overlap with the one passed to mutate.

To fix this you need to detach the lifetime of the reference from Foo's lifetime:

fn mutate<'a, 'b>(f: &'a mut Foo<'b>) { ... }

Alternatively you can elide both lifetimes:

fn mutate(f: &mut Foo<'_>) { ... }

Much Ado About Nothing @WaffleLapkin @BoxyUwU

use std::collections::HashMap;

fn get_or_insert_1234(map: &mut HashMap<u32, u64>) -> &mut u64 {
    if let Some(v) = map.get_mut(&0) {
        return v;
    }

    map.insert(0, 1234);
    map.get_mut(&0).unwrap()
}

fn main() {}
Solution
error[E0499]: cannot borrow `*map` as mutable more than once at a time
 --> examples/borrowck_5.rs:8:5
  |
3 | fn get_or_insert_1234(map: &mut HashMap<u32, u64>) -> &mut u64 {
  |                            - let's call the lifetime of this reference `'1`
4 |     if let Some(v) = map.get_mut(&0) {
  |                      --- first mutable borrow occurs here
5 |         return v;
  |                - returning this value requires that `*map` is borrowed for `'1`
...
8 |     map.insert(0, 1234);
  |     ^^^ second mutable borrow occurs here

error[E0499]: cannot borrow `*map` as mutable more than once at a time
 --> examples/borrowck_5.rs:9:5
  |
3 | fn get_or_insert_1234(map: &mut HashMap<u32, u64>) -> &mut u64 {
  |                            - let's call the lifetime of this reference `'1`
4 |     if let Some(v) = map.get_mut(&0) {
  |                      --- first mutable borrow occurs here
5 |         return v;
  |                - returning this value requires that `*map` is borrowed for `'1`
...
9 |     map.get_mut(&0).unwrap()
  |     ^^^ second mutable borrow occurs here

For more information about this error, try `rustc --explain E0499`.
error: could not compile `code` (example "borrowck_5") due to 2 previous errors

This error is the limitation of the current borrow checker. Because v is returned from the function, the lifetime of the reference returned from the first get_mut is inferred to be "until the end of the function". The current borrow checker does not understand that the None variant does not contain the lifetime, so after the if the reference does not need to be kept alive (there is no reference).

This is a very famous example which is fixed by the next implementation of the borrow checker, polonius.

Loansharks @adotinthevoid @Noratrieb

type R1<'a> = &'a mut i32;
struct R2<'a>(&'a mut i32);

fn r1_once(_: R1){}
fn r2_once(_: R2){}

pub fn r1_twice(x: R1) {
    r1_once(x);
    r1_once(x);
}

pub fn r2_twice(x: R2) {
    r2_once(x);
    r2_once(x);
}

fn main() {
    r1_twice(&mut 0);
    r2_twice(R2(&mut 0));
}
Solution
error[E0382]: use of moved value: `x`
  --> examples/borrowck_6.rs:14:13
   |
12 | pub fn r2_twice(x: R2) {
   |                 - move occurs because `x` has type `R2<'_>`, which does not implement the `Copy` trait
13 |     r2_once(x);
   |             - value moved here
14 |     r2_once(x);
   |             ^ value used here after move
   |
note: consider changing this parameter type in function `r2_once` to borrow instead if owning the value isn't necessary
  --> examples/borrowck_6.rs:5:15
   |
 5 | fn r2_once(_: R2){}
   |    -------    ^^ this parameter takes ownership of the value
   |    |
   |    in this function
note: if `R2<'_>` implemented `Clone`, you could clone the value
  --> examples/borrowck_6.rs:2:1
   |
 2 | struct R2<'a>(&'a mut i32);
   | ^^^^^^^^^^^^^ consider implementing `Clone` for this type
...
13 |     r2_once(x);
   |             - you could clone this value

For more information about this error, try `rustc --explain E0382`.
error: could not compile `code` (example "borrowck_6") due to 1 previous error

r2_twice does not compile because R2 does not implement Copy, and is moved twice. However, r1_twice does compile even though &mut i32 does not implement Copy!

This is because, for R1, the reference is not moved into r1_once, instead it's reborrowed. Reborrows are a special operation on references that the borrow checker understands and behave like &mut *x. So there is a new reference passed to r1_once, with the original borrow having been preserved.