Is double dereference Box<T> to get `&T` the compiler magic?

#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
impl<T: ?Sized, A: Allocator> const Deref for Box<T, A> {
    type Target = T;

    fn deref(&self) -> &T {
        &**self   // multiple times of the dereference
    }
}
    let d = Box::new(10);
    let c = d.deref();  // get a reference to i32

As a contrast

struct Wrapper(i32);

impl Deref for Wrapper{
    type Target = i32;

    fn deref(&self) -> &Self::Target {  // Compiler warns that "recursive call site"
        &**self
    }
}

Is &**self in the implementation of Deref for Box the compiler magic?

Not sure why Google-foo failed you because for me search for why rust box is special sends me to both previous thread on the topic and the appropriate blog post.

2 Likes

It is not. This deref isn't even used. Box is a built-in, and you can't make a Box-like type in user code, unfortunately.

1 Like

These impls are actually used when referencing them through generics. For example

use core::ops::Deref;

fn foo(a: &impl Deref<Target = u32>) -> &u32 {
    &**a // don't know the concrete type of a, so has to refer to Deref::deref
}

pub fn bar() {
    foo(&Box::new(0));
}
; <alloc::boxed::Box<T,A> as core::ops::deref::Deref>::deref
; Function Attrs: nonlazybind uwtable
define align 4 i32* @"_ZN74_$LT$alloc..boxed..Box$LT$T$C$A$GT$$u20$as$u20$core..ops..deref..Deref$GT$5deref17h94e506c0f5dd2922E"(i32** align 8 %self) unnamed_addr #1 !dbg !763 {
start:
  %self.dbg.spill = alloca i32**, align 8
  store i32** %self, i32*** %self.dbg.spill, align 8
  call void @llvm.dbg.declare(metadata i32*** %self.dbg.spill, metadata !771, metadata !DIExpression()), !dbg !772
  %_2 = load i32*, i32** %self, align 8, !dbg !773, !nonnull !98, !align !774, !noundef !98
  ret i32* %_2, !dbg !775
}

; playground::foo
; Function Attrs: nonlazybind uwtable
define internal align 4 i32* @_ZN10playground3foo17h7fae4ae4a9075a9fE(i32** align 8 %a) unnamed_addr #1 !dbg !816 {
start:
  %a.dbg.spill = alloca i32**, align 8
  store i32** %a, i32*** %a.dbg.spill, align 8
  call void @llvm.dbg.declare(metadata i32*** %a.dbg.spill, metadata !820, metadata !DIExpression()), !dbg !823
; call <alloc::boxed::Box<T,A> as core::ops::deref::Deref>::deref
  %_2 = call align 4 i32* @"_ZN74_$LT$alloc..boxed..Box$LT$T$C$A$GT$$u20$as$u20$core..ops..deref..Deref$GT$5deref17h94e506c0f5dd2922E"(i32** align 8 %a), !dbg !824
  br label %bb1, !dbg !824

bb1:                                              ; preds = %start
  ret i32* %_2, !dbg !825
}

What basically happens is that if the type is know to be a Box, it replaces the deref with a compiler builtin deref operation and if not inserts a real Deref::deref call. Inside the Deref impl for Box, it knows that it is a Box and as such does replace it with a builtin deref operation. The same happens for other operations with builtin impls, like math on integers and floats.