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

Unhelpful compiler suggestion when trying to dereference a pointer that is not Copy #126863

Closed
cyrgani opened this issue Jun 23, 2024 · 5 comments · Fixed by #127114
Closed

Unhelpful compiler suggestion when trying to dereference a pointer that is not Copy #126863

cyrgani opened this issue Jun 23, 2024 · 5 comments · Fixed by #127114
Assignees
Labels
A-diagnostics Area: Messages for errors, warnings, and lints D-papercut Diagnostics: An error or lint that needs small tweaks. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@cyrgani
Copy link
Contributor

cyrgani commented Jun 23, 2024

Code

fn main() {
    let val = String::from("test");
    let p = std::ptr::addr_of!(val);
    unsafe {
        let inner: String = *p;
        dbg!(inner);
        std::mem::forget(val);
    }
}

Current output

error[E0507]: cannot move out of `*p` which is behind a raw pointer
 --> src/main.rs:5:29
  |
5 |         let inner: String = *p;
  |                             ^^ move occurs because `*p` has type `String`, which does not implement the `Copy` trait
  |
help: consider removing the dereference here
  |
5 -         let inner: String = *p;
5 +         let inner: String = p;
  |
help: consider cloning the value if the performance cost is acceptable
  |
5 -         let inner: String = *p;
5 +         let inner: String = p.clone();
  |

For more information about this error, try `rustc --explain E0507`.

Desired output

error[E0507]: cannot move out of `*p` which is behind a raw pointer
 --> src/main.rs:5:29
  |
5 |         let inner: String = *p;
  |                             ^^ move occurs because `*p` has type `String`, which does not implement the `Copy` trait
  |
help: consider using `ptr::read` to get the value the pointer refers to
  |
5 -         let inner: String = *p;
5 +         let inner: String = p.read();  
  |

For more information about this error, try `rustc --explain E0507`.

Rationale and extra context

Cloning the pointer doesn't make sense in that situation and would cause a type mismatch error. I'm not sure whether any of the two current suggestions should be kept or removed in this case.

Other cases

No response

Rust Version

rustc 1.79.0 (129f3b996 2024-06-10)
binary: rustc
commit-hash: 129f3b9964af4d4a709d1383930ade12dfe7c081
commit-date: 2024-06-10
host: x86_64-unknown-linux-gnu
release: 1.79.0
LLVM version: 18.1.7

Anything else?

No response

@cyrgani cyrgani added A-diagnostics Area: Messages for errors, warnings, and lints T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 23, 2024
@workingjubilee
Copy link
Member

Note that this works:

        let inner: String = (*p).clone();

It works because (*p) is a place expression and then we attach .clone() to that, which then reborrows the String.

I don't think we should suggest .read(), which may have undesirable or unexpected effects in the case of things like types that handle backing buffers, instead of issuing a safe .clone() which will recreate the backing allocation correctly.

@cyrgani
Copy link
Contributor Author

cyrgani commented Jun 23, 2024

I didn't know that was possible, thanks for letting me know. I guess that the best approach would then be to change the .clone() suggestion accordingly as below?

help: consider cloning the value if the performance cost is acceptable
  |
5 -         let inner: String = *p;
5 +         let inner: String = (*p).clone();
  |

@workingjubilee
Copy link
Member

workingjubilee commented Jun 23, 2024

Correct.

Also, we could mention read in the error for pointers, but we shouldn't recommend it. It's unsafe code, we should strive to preserve the "you break it, you buy it" / "do your own research" experience for that.

@workingjubilee
Copy link
Member

The relevant section of diagnostic code is here

// Remove uses of `&` and `*` when suggesting `.clone()`.
while let hir::ExprKind::AddrOf(.., inner) | hir::ExprKind::Unary(hir::UnOp::Deref, inner) =
&inner_expr.kind
{
if let hir::ExprKind::AddrOf(_, hir::Mutability::Mut, _) = inner_expr.kind {
// We assume that `&mut` refs are desired for their side-effects, so cloning the
// value wouldn't do what the user wanted.
return false;
}
inner_expr = inner;
}
if inner_expr.span.lo() != expr.span.lo() {
sugg.push((expr.span.with_hi(inner_expr.span.lo()), String::new()));
}
let span = if inner_expr.span.hi() != expr.span.hi() {
// Account for `(*x)` to suggest `x.clone()`.
expr.span.with_lo(inner_expr.span.hi())
} else {
expr.span.shrink_to_hi()
};
sugg.push((span, suggestion));
let msg = if let ty::Adt(def, _) = ty.kind()
&& [tcx.get_diagnostic_item(sym::Arc), tcx.get_diagnostic_item(sym::Rc)]
.contains(&Some(def.did()))
{
"clone the value to increment its reference count"
} else {
"consider cloning the value if the performance cost is acceptable"
};
but it will require some restructuring to account for the fact that the ty::RawPtr suggestion will not be doing things like stripping parentheses, but suggesting adding them if they don't exist.

@workingjubilee workingjubilee added the D-papercut Diagnostics: An error or lint that needs small tweaks. label Jun 25, 2024
@linyihai
Copy link
Contributor

@rustbot claim
It looks good for me to make a try.

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jun 29, 2024
fix: prefer `(*p).clone` to `p.clone` if the `p` is a raw pointer

Fixes rust-lang#126863

I wonder if there is a better way to solve the regression problem of this test case:
`tests/ui/borrowck/issue-20801.rs`.
It's okay to drop the dereference symbol in this scenario.

But it's not correct in rust-lang#126863

```
help: consider removing the dereference here
  |
5 -         let inner: String = *p;
5 +         let inner: String = p;
```

I haven't found out how to tell if clone pointer is allowed, i.e. no type mismatch occurs
@bors bors closed this as completed in 9879b46 Jun 30, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Jun 30, 2024
Rollup merge of rust-lang#127114 - linyihai:issue-126863, r=Nadrieril

fix: prefer `(*p).clone` to `p.clone` if the `p` is a raw pointer

Fixes rust-lang#126863

I wonder if there is a better way to solve the regression problem of this test case:
`tests/ui/borrowck/issue-20801.rs`.
It's okay to drop the dereference symbol in this scenario.

But it's not correct in rust-lang#126863

```
help: consider removing the dereference here
  |
5 -         let inner: String = *p;
5 +         let inner: String = p;
```

I haven't found out how to tell if clone pointer is allowed, i.e. no type mismatch occurs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints D-papercut Diagnostics: An error or lint that needs small tweaks. 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.

3 participants