Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't coerce &mut &mut T to *mut *mut T #34117

Closed
Boddlnagg opened this issue Jun 6, 2016 · 14 comments · Fixed by #124692
Closed

Can't coerce &mut &mut T to *mut *mut T #34117

Boddlnagg opened this issue Jun 6, 2016 · 14 comments · Fixed by #124692
Labels
A-type-system Area: Type system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Boddlnagg
Copy link
Contributor

The title already says it, but as an illustrating example you can have a look at https://is.gd/4jWY3m.
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" 😄 ). @mbrubeck pointed out that this might be #18602 (in IRC).

The example code also illustrates a somewhat unexpected failure of type inference, which might be worth filing as a separate issue.

@eefriedman
Copy link
Contributor

Hmm... take the following:

    let mut result = SmartPtr(std::ptr::null_mut());
    let x : &mut &mut _ = &mut &mut *result;
    let x : *mut &mut _ = x;
    let x: *mut *mut _ = x;
    make_foo(x); 

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 *mut i8 to a *mut u8.

@TimNN
Copy link
Contributor

TimNN commented Jun 6, 2016

@eefriedman Note that first coercing to &mut *mut instead of *mut &mut seems to work (playpen).

@eefriedman
Copy link
Contributor

@TimNN Your testcase is constructing a SmartPtr<*mut Foo>, not a SmartPtr<Foo>.

@TimNN
Copy link
Contributor

TimNN commented Jun 6, 2016

Ah, thanks for pointing that out.

@Boddlnagg
Copy link
Contributor Author

@eefriedman 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 make_foo(&mut (&mut *result as *mut _)); in my original example shows that this conversion is already possible in safe code.

@petrochenkov
Copy link
Contributor

It's not clear such a coercion should exist: it's like converting a *mut i8 to a *mut u8.

Heh, C++ has special rules for multi-level pointer conversions exactly to prevent these kinds of type unsafeties: http://en.cppreference.com/w/cpp/language/implicit_conversion#Qualification_conversions
"More qualified" relations can be translated to Rust's &mut T -> *mut T/&T -> *const T/*mut T -> *const T relations.

@eefriedman
Copy link
Contributor

@Boddlnagg make_foo(&mut (&mut *result as *mut _)); isn't doing the same thing: the outer &mut is actually constructing a temporary, so you end up with an &mut *mut Foo (as opposed to a *mut &mut Foo).

Also, safety isn't really relevant; we allow arbitrary explicit pointer casts anyway.

@eefriedman
Copy link
Contributor

Oh, wait, I see, you expect the original make_foo(&mut &mut *result) to interpreted as &mut *mut Foo, and then converted from there to *mut *mut Foo. That makes sense.

@steveklabnik steveklabnik added the A-type-system Area: Type system label Jun 6, 2016
@eddyb
Copy link
Member

eddyb commented Jun 11, 2016

I think this would work if borrow expressions would take into account that they might get coerced later and pass down the T from *mut T (where T = *mut Foo here), instead of only working for &mut T.

@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 25, 2017
@steveklabnik
Copy link
Member

Triage: this still reproduces.

@Dylan-DPC
Copy link
Member

Closing this as the bug is fixed and playground link above works for all editions.

@Boddlnagg
Copy link
Contributor Author

The playground link had the problematic line commented out:

make_foo(&mut &mut *result); // mismatched types: expected `*mut *mut Foo`, found `&mut &mut _`

It still gives a compile error:

error[[E0308]](https://doc.rust-lang.org/nightly/error_codes/E0308.html): mismatched types
  --> src/main.rs:31:14
   |
31 |     make_foo(&mut &mut *result); // mismatched types: expected `*mut *mut Foo`, found `&mut &mut _`
   |     -------- ^^^^^^^^^^^^^^^^^ expected `*mut *mut Foo`, found `&mut &mut _`
   |     |
   |     arguments to this function are incorrect
   |
   = note:    expected raw pointer `*mut *mut Foo`
           found mutable reference `&mut &mut _`

@Dylan-DPC
Copy link
Member

oops my bad then

@Dylan-DPC Dylan-DPC reopened this Mar 15, 2023
@Noratrieb Noratrieb added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 5, 2023
@workingjubilee
Copy link
Member

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.

Legalizing this behavior with narrow cases seems permissible, but amounts to a new language feature design request. Transitive coercions, as part of the revised coercion rules, are closed as requiring new proposals.

Accordingly, I think this should also be closed... but not before documenting the current behavior in the form of a regression test.

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue May 4, 2024
…pointer-coercion-happens, r=compiler-errors

We do not coerce `&mut &mut T -> *mut mut T`

Resolves rust-lang#34117 by declaring it to be "working as intended" until someone RFCs it or whatever other lang proposal would be required. It seems a bit of a footgun, but perhaps there are strong reasons to allow it anyways. Seeing as how I often have to be mindful to not allow a pointer to coerce the wrong way in my FFI work, I am inclined to think not, but perhaps it's fine in some use-case and that's actually more common?
@bors bors closed this as completed in b0715b4 May 4, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this issue May 4, 2024
Rollup merge of rust-lang#124692 - workingjubilee:document-no-double-pointer-coercion-happens, r=compiler-errors

We do not coerce `&mut &mut T -> *mut mut T`

Resolves rust-lang#34117 by declaring it to be "working as intended" until someone RFCs it or whatever other lang proposal would be required. It seems a bit of a footgun, but perhaps there are strong reasons to allow it anyways. Seeing as how I often have to be mindful to not allow a pointer to coerce the wrong way in my FFI work, I am inclined to think not, but perhaps it's fine in some use-case and that's actually more common?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-type-system Area: Type system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants