Rollup merge of #140094 - Kivooeo:raw-pointer-assignment-suggestion, r=compiler-errors
Improve diagnostics for pointer arithmetic += and -= (fixes #137391) **Description**: This PR improves the diagnostic message for cases where a binary assignment operation like `ptr += offset` or `ptr -= offset` is attempted on `*mut T`. These operations are not allowed, and the compiler previously suggested calling `.add()` or `.wrapping_add()`, which is misleading if not assigned. This PR updates the diagnostics to suggest assigning the result of `.wrapping_add()` or `.wrapping_sub()` back to the pointer, e.g.: **Examples** For this code ```rust let mut arr = [0u8; 10]; let mut ptr = arr.as_mut_ptr(); ptr += 2; ``` it will say: ```rust 10 | ptr += 2; | ---^^^^^ | | | cannot use `+=` on type `*mut u8` | help: consider replacing `ptr += offset` with `ptr = ptr.wrapping_add(offset)` or `ptr.add(offset)` | 10 - ptr += 2; 10 + ptr = ptr.wrapping_add(2); ``` **Related issue**: #137391 cc `@nabijaczleweli` for context (issue author)
This commit is contained in:
commit
8f42ac0043
4 changed files with 122 additions and 1 deletions
|
@ -234,7 +234,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// us do better coercions than we would be able to do otherwise,
|
||||
// particularly for things like `String + &String`.
|
||||
let rhs_ty_var = self.next_ty_var(rhs_expr.span);
|
||||
|
||||
let result = self.lookup_op_method(
|
||||
(lhs_expr, lhs_ty),
|
||||
Some((rhs_expr, rhs_ty_var)),
|
||||
|
@ -698,6 +697,57 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let lhs_name_str = match lhs_expr.kind {
|
||||
hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => {
|
||||
path.segments.last().map_or("_".to_string(), |s| s.ident.to_string())
|
||||
}
|
||||
_ => self
|
||||
.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(lhs_expr.span)
|
||||
.unwrap_or("_".to_string()),
|
||||
};
|
||||
|
||||
if op.span().can_be_used_for_suggestions() {
|
||||
match op {
|
||||
Op::AssignOp(Spanned { node: hir::AssignOpKind::AddAssign, .. })
|
||||
if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() =>
|
||||
{
|
||||
err.multipart_suggestion(
|
||||
"consider using `add` or `wrapping_add` to do pointer arithmetic",
|
||||
vec![
|
||||
(lhs_expr.span.shrink_to_lo(), format!("{} = ", lhs_name_str)),
|
||||
(
|
||||
lhs_expr.span.between(rhs_expr.span),
|
||||
".wrapping_add(".to_owned(),
|
||||
),
|
||||
(rhs_expr.span.shrink_to_hi(), ")".to_owned()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
Op::AssignOp(Spanned { node: hir::AssignOpKind::SubAssign, .. }) => {
|
||||
if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() {
|
||||
err.multipart_suggestion(
|
||||
"consider using `sub` or `wrapping_sub` to do pointer arithmetic",
|
||||
vec![
|
||||
(lhs_expr.span.shrink_to_lo(), format!("{} = ", lhs_name_str)),
|
||||
(
|
||||
lhs_expr.span.between(rhs_expr.span),
|
||||
".wrapping_sub(".to_owned(),
|
||||
|
||||
),
|
||||
(rhs_expr.span.shrink_to_hi(), ")".to_owned()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let reported = err.emit();
|
||||
Ty::new_error(self.tcx, reported)
|
||||
}
|
||||
|
|
20
tests/ui/typeck/pointer-arith-assign.fixed
Normal file
20
tests/ui/typeck/pointer-arith-assign.fixed
Normal file
|
@ -0,0 +1,20 @@
|
|||
//@ run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(unused_assignments)]
|
||||
|
||||
fn test_add_assign_raw_pointer() {
|
||||
let mut arr = [0u8; 10];
|
||||
let mut _ptr = arr.as_mut_ptr();
|
||||
|
||||
_ptr = _ptr.wrapping_add(2); //~ ERROR binary assignment operation `+=` cannot be applied to type `*mut u8` [E0368]
|
||||
}
|
||||
|
||||
fn test_sub_assign_raw_pointer() {
|
||||
let mut arr = [0u8; 10];
|
||||
let mut _ptr = arr.as_mut_ptr();
|
||||
|
||||
_ptr = _ptr.wrapping_sub(2); //~ ERROR binary assignment operation `-=` cannot be applied to type `*mut u8` [E0368]
|
||||
}
|
||||
|
||||
fn main() {}
|
20
tests/ui/typeck/pointer-arith-assign.rs
Normal file
20
tests/ui/typeck/pointer-arith-assign.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
//@ run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(unused_assignments)]
|
||||
|
||||
fn test_add_assign_raw_pointer() {
|
||||
let mut arr = [0u8; 10];
|
||||
let mut _ptr = arr.as_mut_ptr();
|
||||
|
||||
_ptr += 2; //~ ERROR binary assignment operation `+=` cannot be applied to type `*mut u8` [E0368]
|
||||
}
|
||||
|
||||
fn test_sub_assign_raw_pointer() {
|
||||
let mut arr = [0u8; 10];
|
||||
let mut _ptr = arr.as_mut_ptr();
|
||||
|
||||
_ptr -= 2; //~ ERROR binary assignment operation `-=` cannot be applied to type `*mut u8` [E0368]
|
||||
}
|
||||
|
||||
fn main() {}
|
31
tests/ui/typeck/pointer-arith-assign.stderr
Normal file
31
tests/ui/typeck/pointer-arith-assign.stderr
Normal file
|
@ -0,0 +1,31 @@
|
|||
error[E0368]: binary assignment operation `+=` cannot be applied to type `*mut u8`
|
||||
--> $DIR/pointer-arith-assign.rs:10:5
|
||||
|
|
||||
LL | _ptr += 2;
|
||||
| ----^^^^^
|
||||
| |
|
||||
| cannot use `+=` on type `*mut u8`
|
||||
|
|
||||
help: consider using `add` or `wrapping_add` to do pointer arithmetic
|
||||
|
|
||||
LL - _ptr += 2;
|
||||
LL + _ptr = _ptr.wrapping_add(2);
|
||||
|
|
||||
|
||||
error[E0368]: binary assignment operation `-=` cannot be applied to type `*mut u8`
|
||||
--> $DIR/pointer-arith-assign.rs:17:5
|
||||
|
|
||||
LL | _ptr -= 2;
|
||||
| ----^^^^^
|
||||
| |
|
||||
| cannot use `-=` on type `*mut u8`
|
||||
|
|
||||
help: consider using `sub` or `wrapping_sub` to do pointer arithmetic
|
||||
|
|
||||
LL - _ptr -= 2;
|
||||
LL + _ptr = _ptr.wrapping_sub(2);
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0368`.
|
Loading…
Add table
Add a link
Reference in a new issue