Skip to content

Commit

Permalink
Fix overloaded deref unused mut false positive
Browse files Browse the repository at this point in the history
  • Loading branch information
HKalbasi committed Mar 4, 2023
1 parent ac42343 commit f517b1e
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 6 deletions.
12 changes: 7 additions & 5 deletions crates/hir-ty/src/mir/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,14 @@ impl Evaluator<'_> {
for proj in &p.projection {
match proj {
ProjectionElem::Deref => {
match &ty.data(Interner).kind {
TyKind::Ref(_, _, inner) => {
ty = inner.clone();
ty = match &ty.data(Interner).kind {
TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(),
_ => {
return Err(MirEvalError::TypeError(
"Overloaded deref in MIR is disallowed",
))
}
_ => not_supported!("dereferencing smart pointers"),
}
};
let x = from_bytes!(usize, self.read_memory(addr, self.ptr_size())?);
addr = Address::from_usize(x);
}
Expand Down
11 changes: 10 additions & 1 deletion crates/hir-ty/src/mir/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ impl MirLowerCtx<'_> {
}
Expr::UnaryOp { expr, op } => match op {
hir_def::expr::UnaryOp::Deref => {
if !matches!(
self.expr_ty(*expr).kind(Interner),
TyKind::Ref(..) | TyKind::Raw(..)
) {
return None;
}
let mut r = self.lower_expr_as_place(*expr)?;
r.projection.push(ProjectionElem::Deref);
Some(r)
Expand Down Expand Up @@ -210,7 +216,7 @@ impl MirLowerCtx<'_> {
Adjust::Deref(None) => {
r.projection.push(ProjectionElem::Deref);
}
Adjust::Deref(Some(_)) => not_supported!("overloaded dereference"),
Adjust::Deref(Some(_)) => not_supported!("implicit overloaded dereference"),
Adjust::Borrow(AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m)) => {
let tmp = self.temp(adjustment.target.clone())?;
self.push_assignment(
Expand Down Expand Up @@ -757,6 +763,9 @@ impl MirLowerCtx<'_> {
Expr::Box { .. } => not_supported!("box expression"),
Expr::UnaryOp { expr, op } => match op {
hir_def::expr::UnaryOp::Deref => {
if !matches!(self.expr_ty(*expr).kind(Interner), TyKind::Ref(..) | TyKind::Raw(..)) {
not_supported!("explicit overloaded deref");
}
let (mut tmp, Some(current)) = self.lower_expr_to_some_place(*expr, current)? else {
return Ok(None);
};
Expand Down
28 changes: 28 additions & 0 deletions crates/ide-diagnostics/src/handlers/mutability_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,34 @@ fn f(x: [(i32, u8); 10]) {
//^^^^^ 💡 error: cannot mutate immutable variable `a`
}
}
"#,
);
}

#[test]
fn overloaded_deref() {
check_diagnostics(
r#"
//- minicore: deref_mut
use core::ops::{Deref, DerefMut};
struct Foo;
impl Deref for Foo {
type Target = i32;
fn deref(&self) -> &i32 {
&5
}
}
impl DerefMut for Foo {
fn deref_mut(&mut self) -> &mut i32 {
&mut 5
}
}
fn f() {
// FIXME: remove this mut and detect error
let mut x = Foo;
let y = &mut *x;
}
"#,
);
}
Expand Down

0 comments on commit f517b1e

Please sign in to comment.