Code change:
<ins> // Documents that Rust currently does not permit the coercion &mut &mut T -> *mut *mut T // Making this compile was a feature request in rust-lang/rust#34117 but this is currently // "working as intended". Allowing "deep pointer coercion" seems footgun-prone, and would // require proceeding carefully. use std::ops::{Deref, DerefMut}; struct Foo(i32); struct SmartPtr<T>(*mut T); impl<T> SmartPtr<T> { fn get_addr(&mut self) -> &mut *mut T { &mut self.0 } } impl<T> Deref for SmartPtr<T> { type Target = T; fn deref(&self) -> &T { unsafe { &*self.0 } } } impl<T> DerefMut for SmartPtr<T> { fn deref_mut(&mut self) -> &mut T { unsafe { &mut *self.0 } } } /// Puts a Foo into the pointer provided by the caller fn make_foo(_: *mut *mut Foo) { unimplemented!() } fn main() { let mut result: SmartPtr<Foo> = SmartPtr(std::ptr::null_mut()); make_foo(&mut &mut *result); //~ mismatched types //~^ expected `*mut *mut Foo`, found `&mut &mut Foo` make_foo(out(&mut result)); // works, but makes one wonder why above coercion cannot happen } fn out<T>(ptr: &mut SmartPtr<T>) -> &mut *mut T { ptr.get_addr() } </ins>

Related discussion:
text: The title already says it, but as an illustrating example you can have a look at Since &mut T can be implicitly converted to *mut T, I wondered whether there's a reason that it doesn't work for &mut &mut T (besides "no one has implemented it" :smile: ). pointed out that this might be (in IRC). The example code also illustrates a somewhat unexpected failure of type inference, which might be worth filing as a separate issue.
Hmm... take the following: Rust will currently complain about mismatched types for the second coercion. It's not clear such a coercion should exist: it's like converting a to a .
Note that first coercing to instead of seems to work ().
Your testcase is constructing a , not a .
Ah, thanks for pointing that out.
In don't know if I understand your point, but if you argue that such a coercion should not exist because it might be unsafe, the line in my original example shows that this conversion is already possible in safe code.
Heh, C++ has special rules for multi-level pointer conversions exactly to prevent these kinds of type unsafeties: "More qualified" relations can be translated to Rust's // relations.
isn't doing the same thing: the outer is actually constructing a temporary, so you end up with an (as opposed to a ). Also, safety isn't really relevant; we allow arbitrary explicit pointer casts anyway.
Oh, wait, I see, you expect the original to interpreted as , and then converted from there to . That makes sense.
I think this would work if borrow expressions would take into account that they might get coerced later and pass down the from (where here), instead of only working for .
Triage: this still reproduces.
Closing this as the bug is fixed and playground link above works for all editions.
The playground link had the problematic line commented out: It still gives a compile error:
oops my bad then
This idea has been suggested. A T-compiler member has pointed out that other languages apply rules to restrain pointer coercion, specifically because multi-level pointer coercion is prone to being a bit of a footgun. Not quite "this is a bad idea", but despite the simplicity of the proposal, it deserves being treated with caution. There is no strong argument that this is a bug because it is consistent, if annoying.