Why can't rustc
separately compile const functions without restrictions in function body?
I thought all the examples below would be compiled. I thought there were requirements for the function arguments and the return type to implement Sized
and Copy
, in the first example UB is called, but not in the second and third. But it doesn't compile, it's not available in rust.
While technically possible, the Rust team decided against it. The primary reason being semantic versioning issues. Changing the body of a function, without changing the signature, could make that function no longer const-compatible and break uses in a const-context. const fn is a contract, and breaking that contract is an explicit breaking change.
Why did the rust team refuse this? Are there any links to this discussion and decision?
I have a view for the third example that rustc
can separately, as a library, compile the do_something
function, call it separately in some rust-sandbox and substitute the result into a constant SOMETHING
.
It seems to me that marking all const
is terrible and unnecessary. It is necessary to simply reduce the restrictions that const
imposes.
Example 1:
const fn do_something(count: isize) -> isize {
struct Something {
x: isize,
y: isize,
}
let mut something = Box::new(Something { x: 1, y: 1 });
for i in 0..count {
something.x += i;
something.y -= i;
}
let Something { x, y } = *something;
x * x + y * y
}
const SOMETHING: isize = do_something(10);
fn main() {
println!("{SOMETHING}"); // SAFETY: OK
}
Example 2:
#[derive(Clone, Copy)]
pub struct Foo {
ptr: usize,
}
impl Foo {
fn new() -> Self {
let data = Box::leak(Box::new(1i32)) as *mut i32;
Self { ptr: data as usize }
}
/// do action
///
/// # Safety
///
/// The caller must ensure that the context in which Foo was created was non-const (runtime)
fn do_action(self) {
// SAFETY: ptr is leak from Box<i32> from runtime
let data = unsafe { Box::from_raw(self.ptr as *mut i32) };
println!("{}", data);
}
}
const fn do_something() -> Foo {
Foo::new()
}
const FOO: Foo = do_something();
fn main() {
let foo = Foo::new();
foo.do_action(); // SAFETY: OK
FOO.do_action(); // NOT SAFETY: UB
}
Example 3:
const fn do_something(count: isize) -> isize {
struct Something {
x: isize,
y: isize,
}
let mut something = Box::new(Something { x: 1, y: 1 });
for i in 0..count {
something.x += i;
something.y -= i;
}
let Something { x, y } = *something;
x * x + y * y
}
const SOMETHING: isize = do_something(10);
fn main() {
println!("{SOMETHING}"); // SAFETY: OK
}