Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

gccrs#4767: Improve box

Link: Rust-GCC/gccrs#4767

Note

This is important

Objective

This PR introduces full DST support for Box, allowing it to correctly handle unsized types like trait objects and slices. Crucially, it also implements the compiler-level auto-deref mechanism for Box.

Changes Made

Wired up the compiler’s auto-dereference logic to recognize Box<T> similarly to how it recognizes standard references (&T). This ensures that method dispatch, array indexing, and tuple field accesses are transparently forwarded to the underlying data pointer inside the box.

Why is this needed for alloc?

While Box<T> is defined as a standard struct in the alloc crate, it requires compiler magic to be ergonomic. When a developer writes my_box.method() or my_box[0], the compiler must automatically dereference the pointer.

Test Case

Box dispatch from dyn:

trait Animal {
    fn get_age(self: Box<Self>) -> i32;
}

struct Dog {
    age: i32,
}

impl Animal for Dog {
    fn get_age(self: Box<Self>) -> i32 {
        self.age
    }
}

fn foo () -> i32 {
    let dog = Dog { age: 42 };
    let _ = dog.age;

    let coerced_box: Box<dyn Animal> = Box::new(dog);

    let result = coerced_box.get_age();
    //           ^^^^^^^^^^^^^^^^^^^^^ auto-deref for method call

    if result == 42 {
        0
    } else {
        1
    }
}

fn main() {
    if foo() == 0 {
        println!("ok.");
    }
}

Box dispatch:

struct X { data: i32 }

trait A {
    fn a(&self) -> i32;
}

impl A for X {
    fn a(&self) -> i32 {
        self.data
    }
}
fn foo() -> i32 {
    let x = X { data: 44 };
    let y = X { data: 22 };
    let z : [i32; 3] = [1, 2, 3];
    let w : (i32, i32) = (10, 20);

    let a : Box<dyn A> = Box::new(x);
    let b : Box<X> = Box::new(y);
    let c : Box<[i32; 3]> = Box::new(z);
    let d : Box<(i32, i32)> = Box::new(w);
    let e : Box<[i32]> = Box::new(z);

    a.a() - 2 * b.data // 44 - 2 * 22
//  ^^^^^       ^^^^^^ ─> field access
//    └─> method dispatch(dyn)
    +
    c[0] + c[1] - c[2] // 1 + 2 - 3
//  ^^^^ ─ ^^^^ ─ ^^^^ ─> array index access
    +
    2 * d.0 - d.1 // 2 * 10 - 20
//      ^^^ ─ ^^^ ─> tuple field access
    +
    e[0] + e[1] - e[2] // 1 + 2 - 3
//  ^^^^ ─ ^^^^ ─ ^^^^ ─> slice index access with trait Index
}

fn main() {
    if foo() == 0 {
        println!("ok.");
    }
}