[WIP] Forbid object lifetime changing pointer casts by BoxyUwU · Pull Request #136776 · rust-lang/rust (original) (raw)
@tmandry: I guess I was a bit misled when I said we only recently started to allow this behavior. What I should have said is that we only recently made this behavior more relaxed beginning with #113262.
That PR made casts where nothing but the lifetime was changing work, i.e. expr as *const dyn Tr + '_ as *const dyn Tr + 'static
even if expr
's type doesn't outlive 'static
. That's why most of the regressions are from ~1 year ago or so.
But there are rare cases where this behavior coincidentally worked when there were more than 1 casts chained together and between the two casts more than the lifetime changed in the casted type. That old diesel one is an example. Boxy and I worked out a few examples where this was allowed even pre 1.75 which is when that linked PR landed.
This is the moral equivalent of the diesel example:
trait Tr {}
struct Foo {
ptr: dyn Tr + 'static
}
fn foo<T: Tr>(x: &dyn Tr) -> *const Foo {
let x = x as *const dyn Tr as *const Foo;
x
}
And this is the moral equivalent of the brainfuck one:
trait Tr {}
fn foo<T: Tr>(x: &dyn Tr) -> *mut (dyn Tr + 'static) {
x as *const dyn Tr as *mut dyn Tr
}
Both of these examples worked before 1.75 because they were emitting something that was a non-trivial pointer cast. But they still are definitely violations of the vtable validity here.
I will note that we're still really funny with what we allow when doing raw pointer casts of wide pointers. For example, this errors today:
trait Tr {}
fn foo<T: Tr>(x: &dyn Tr) -> *const (dyn Tr + 'static) {
x as *const dyn Tr
}
i.e. it was not fixed by #113262. You could argue that @BoxyUwU's PR here is making the language more consistent by always enforcing the correct lifetimes in wide pointers along these lines :)