logo
#[turn_off_the_borrow_checker]
Expand description

You can’t “turn off the borrow checker” in Rust, and you shouldn’t want to. Rust’s references aren’t pointers, and the compiler is free to decimate code that tries to use references as though they are. If you need raw pointer behaviour in Rust, don’t use this, use Rust’s actual raw pointers, which don’t make the same aliasing guarantees to the compiler. However, if you would like to pretend the borrow checker doesn’t exist for educational purposes and never in production code, this macro that will suppress many (though not all) borrow checker errors in the code it’s applied to.

This shouldn’t break any otherwise-valid code; the borrow checker doesn’t affect compilation output, only verify input validity. However, it will allow unsound and unsafe nonsense that will fail unpredictably and dangerously. This is not safe to use.

Example

Without Macro
fn main() {
    let mut owned = vec![1, 32];

    let mut_1 = &mut owned[0];
    let mut_2 = &mut owned[1];
    //~^ ERROR cannot borrow `owned` as mutable more than once at a time

    drop(owned);
    //~^ ERROR cannot move out of `owned` because it is borrowed
    let undefined = *mut_1 + *mut_2;
    println!("{undefined}");
}
With Macro
#[you_can::turn_off_the_borrow_checker]
fn main() {
    let mut owned = vec![1, 32];

    let mut_1 = &mut owned[0];
    let mut_2 = &mut owned[1];
    //~^ WARNING the borrow checker is suppressed for these references.

    drop(owned);
    let undefined = *mut_1 + *mut_2;
    println!("{undefined}");
}

Explanation

The macro looks for references created in the code by use of the & or &mut operators or the ref and ref mut bindings, and wraps them with our borrow_unchecked() function to unbind their lifetimes, causing the borrow checker to effectively ignore them. If running on nightly, it adds new warning diagnostic messages for every reference it modifies.

Expanded
fn main() {
    let mut owned = vec![1, 32];

    let mut_1 = unsafe { ::you_can::borrow_unchecked(&mut owned[0]) };
    let mut_2 = unsafe { ::you_can::borrow_unchecked(&mut owned[1]) };

    drop(owned);
    let undefined = *mut_1 + *mut_2;
    println!("{undefined}");
}

This approached is limited. It can’t suppress errors resulting from the code illegally composing lifetimes created elsewhere, or references created implicitly. As a workaround, prefixing &* can sometimes be used to force an explicit reference where one is needed, such as as in the example below.

Example

#[you_can::turn_off_the_borrow_checker]
fn main() {
    let mut source = Some(1);
    let inner_mut = &*source.as_ref().unwrap();
    let mutable_alias = &mut source;

    source = None;
    *mutable_alias = Some(2);

    if let Some(ref mut inner_a) = source {
        match source {
            Some(ref mut inner_b) => {
                *inner_b = inner_mut + 1;
                *inner_a = inner_mut + 2;
            },
            None => {
                println!("none");
            },
        }
    }

    println!("{source:?}");
}
Expanded
fn main() {
    let mut source = Some(1);
    let inner_mut = unsafe { ::you_can::borrow_unchecked(&*source.as_ref().unwrap()) };
    let mutable_alias = unsafe { ::you_can::borrow_unchecked(&mut source) };

    source = None;
    *mutable_alias = Some(2);

    if let Some(ref mut inner_a) = source {
        let inner_a = unsafe { ::you_can::borrow_unchecked(inner_a) };

        match source {
            Some(ref mut inner_b) => {
                let inner_b = unsafe { ::you_can::borrow_unchecked(inner_b) };

                *inner_b = inner_mut + 1;
                *inner_a = inner_mut + 2;
            },
            None => {
                println!("none");
            },
        }
    }

    println!("{source:?}");
}

Discussions

Here are some related discussions, mostly about why you shouldn’t do this: