mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Auto merge of #91933 - matthiaskrgr:rollup-cw9qolb, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #89825 (Make split_inclusive() on an empty slice yield an empty output) - #91239 (regression test for issue 87490) - #91597 (Recover on invalid operators `<>` and `<=>`) - #91774 (Fix typo for MutVisitor) - #91786 (Return an error when `eval_rvalue_with_identities` fails) - #91798 (Avoid suggest adding `self` in visibility spec) - #91856 (Looser check for overflowing_binary_op) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
d594910a2d
@ -1,5 +1,5 @@
|
||||
//! A `MutVisitor` represents an AST modification; it accepts an AST piece and
|
||||
//! and mutates it in place. So, for instance, macro expansion is a `MutVisitor`
|
||||
//! mutates it in place. So, for instance, macro expansion is a `MutVisitor`
|
||||
//! that walks over an AST and modifies it.
|
||||
//!
|
||||
//! Note: using a `MutVisitor` (other than the `MacroExpander` `MutVisitor`) on
|
||||
|
@ -328,9 +328,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.binary_int_op(bin_op, l, left.layout, r, right.layout)
|
||||
}
|
||||
_ if left.layout.ty.is_any_ptr() => {
|
||||
// The RHS type must be the same *or an integer type* (for `Offset`).
|
||||
// The RHS type must be a `pointer` *or an integer type* (for `Offset`).
|
||||
// (Even when both sides are pointers, their type might differ, see issue #91636)
|
||||
assert!(
|
||||
right.layout.ty == left.layout.ty || right.layout.ty.is_integral(),
|
||||
right.layout.ty.is_any_ptr() || right.layout.ty.is_integral(),
|
||||
"Unexpected types for BinOp: {:?} {:?} {:?}",
|
||||
left.layout.ty,
|
||||
bin_op,
|
||||
|
@ -752,62 +752,44 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||
rvalue: &Rvalue<'tcx>,
|
||||
place: Place<'tcx>,
|
||||
) -> Option<()> {
|
||||
self.use_ecx(|this| {
|
||||
match rvalue {
|
||||
Rvalue::BinaryOp(op, box (left, right))
|
||||
| Rvalue::CheckedBinaryOp(op, box (left, right)) => {
|
||||
let l = this.ecx.eval_operand(left, None);
|
||||
let r = this.ecx.eval_operand(right, None);
|
||||
self.use_ecx(|this| match rvalue {
|
||||
Rvalue::BinaryOp(op, box (left, right))
|
||||
| Rvalue::CheckedBinaryOp(op, box (left, right)) => {
|
||||
let l = this.ecx.eval_operand(left, None);
|
||||
let r = this.ecx.eval_operand(right, None);
|
||||
|
||||
let const_arg = match (l, r) {
|
||||
(Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
|
||||
(Err(e), Err(_)) => return Err(e),
|
||||
(Ok(_), Ok(_)) => {
|
||||
this.ecx.eval_rvalue_into_place(rvalue, place)?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let const_arg = match (l, r) {
|
||||
(Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
|
||||
(Err(e), Err(_)) => return Err(e),
|
||||
(Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place),
|
||||
};
|
||||
|
||||
let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?;
|
||||
let dest = this.ecx.eval_place(place)?;
|
||||
let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?;
|
||||
let dest = this.ecx.eval_place(place)?;
|
||||
|
||||
match op {
|
||||
BinOp::BitAnd => {
|
||||
if arg_value == 0 {
|
||||
this.ecx.write_immediate(*const_arg, &dest)?;
|
||||
}
|
||||
}
|
||||
BinOp::BitOr => {
|
||||
if arg_value == const_arg.layout.size.truncate(u128::MAX)
|
||||
|| (const_arg.layout.ty.is_bool() && arg_value == 1)
|
||||
{
|
||||
this.ecx.write_immediate(*const_arg, &dest)?;
|
||||
}
|
||||
}
|
||||
BinOp::Mul => {
|
||||
if const_arg.layout.ty.is_integral() && arg_value == 0 {
|
||||
if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
|
||||
let val = Immediate::ScalarPair(
|
||||
const_arg.to_scalar()?.into(),
|
||||
Scalar::from_bool(false).into(),
|
||||
);
|
||||
this.ecx.write_immediate(val, &dest)?;
|
||||
} else {
|
||||
this.ecx.write_immediate(*const_arg, &dest)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
this.ecx.eval_rvalue_into_place(rvalue, place)?;
|
||||
match op {
|
||||
BinOp::BitAnd if arg_value == 0 => this.ecx.write_immediate(*const_arg, &dest),
|
||||
BinOp::BitOr
|
||||
if arg_value == const_arg.layout.size.truncate(u128::MAX)
|
||||
|| (const_arg.layout.ty.is_bool() && arg_value == 1) =>
|
||||
{
|
||||
this.ecx.write_immediate(*const_arg, &dest)
|
||||
}
|
||||
BinOp::Mul if const_arg.layout.ty.is_integral() && arg_value == 0 => {
|
||||
if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
|
||||
let val = Immediate::ScalarPair(
|
||||
const_arg.to_scalar()?.into(),
|
||||
Scalar::from_bool(false).into(),
|
||||
);
|
||||
this.ecx.write_immediate(val, &dest)
|
||||
} else {
|
||||
this.ecx.write_immediate(*const_arg, &dest)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
this.ecx.eval_rvalue_into_place(rvalue, place)?;
|
||||
_ => this.ecx.eval_rvalue_into_place(rvalue, place),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
_ => this.ecx.eval_rvalue_into_place(rvalue, place),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -213,11 +213,11 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// Look for JS' `===` and `!==` and recover
|
||||
if (op.node == AssocOp::Equal || op.node == AssocOp::NotEqual)
|
||||
&& self.token.kind == token::Eq
|
||||
&& self.prev_token.span.hi() == self.token.span.lo()
|
||||
{
|
||||
// Look for JS' `===` and `!==` and recover 😇
|
||||
let sp = op.span.to(self.token.span);
|
||||
let sugg = match op.node {
|
||||
AssocOp::Equal => "==",
|
||||
@ -235,6 +235,38 @@ impl<'a> Parser<'a> {
|
||||
self.bump();
|
||||
}
|
||||
|
||||
// Look for PHP's `<>` and recover
|
||||
if op.node == AssocOp::Less
|
||||
&& self.token.kind == token::Gt
|
||||
&& self.prev_token.span.hi() == self.token.span.lo()
|
||||
{
|
||||
let sp = op.span.to(self.token.span);
|
||||
self.struct_span_err(sp, "invalid comparison operator `<>`")
|
||||
.span_suggestion_short(
|
||||
sp,
|
||||
"`<>` is not a valid comparison operator, use `!=`",
|
||||
"!=".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
)
|
||||
.emit();
|
||||
self.bump();
|
||||
}
|
||||
|
||||
// Look for C++'s `<=>` and recover
|
||||
if op.node == AssocOp::LessEqual
|
||||
&& self.token.kind == token::Gt
|
||||
&& self.prev_token.span.hi() == self.token.span.lo()
|
||||
{
|
||||
let sp = op.span.to(self.token.span);
|
||||
self.struct_span_err(sp, "invalid comparison operator `<=>`")
|
||||
.span_label(
|
||||
sp,
|
||||
"`<=>` is not a valid comparison operator, use `std::cmp::Ordering`",
|
||||
)
|
||||
.emit();
|
||||
self.bump();
|
||||
}
|
||||
|
||||
let op = op.node;
|
||||
// Special cases:
|
||||
if op == AssocOp::As {
|
||||
|
@ -298,11 +298,16 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
||||
.get(0)
|
||||
.map(|p| (p.span.shrink_to_lo(), "&self, "))
|
||||
.unwrap_or_else(|| {
|
||||
// Try to look for the "(" after the function name, if possible.
|
||||
// This avoids placing the suggestion into the visibility specifier.
|
||||
let span = fn_kind
|
||||
.ident()
|
||||
.map_or(*span, |ident| span.with_lo(ident.span.hi()));
|
||||
(
|
||||
self.r
|
||||
.session
|
||||
.source_map()
|
||||
.span_through_char(*span, '(')
|
||||
.span_through_char(span, '(')
|
||||
.shrink_to_hi(),
|
||||
"&self",
|
||||
)
|
||||
|
@ -863,7 +863,7 @@ fn test_splitator_inclusive() {
|
||||
assert_eq!(xs.split_inclusive(|_| true).collect::<Vec<&[i32]>>(), splits);
|
||||
|
||||
let xs: &[i32] = &[];
|
||||
let splits: &[&[i32]] = &[&[]];
|
||||
let splits: &[&[i32]] = &[];
|
||||
assert_eq!(xs.split_inclusive(|x| *x == 5).collect::<Vec<&[i32]>>(), splits);
|
||||
}
|
||||
|
||||
@ -883,7 +883,7 @@ fn test_splitator_inclusive_reverse() {
|
||||
assert_eq!(xs.split_inclusive(|_| true).rev().collect::<Vec<_>>(), splits);
|
||||
|
||||
let xs: &[i32] = &[];
|
||||
let splits: &[&[i32]] = &[&[]];
|
||||
let splits: &[&[i32]] = &[];
|
||||
assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
|
||||
}
|
||||
|
||||
@ -903,7 +903,7 @@ fn test_splitator_mut_inclusive() {
|
||||
assert_eq!(xs.split_inclusive_mut(|_| true).collect::<Vec<_>>(), splits);
|
||||
|
||||
let xs: &mut [i32] = &mut [];
|
||||
let splits: &[&[i32]] = &[&[]];
|
||||
let splits: &[&[i32]] = &[];
|
||||
assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
|
||||
}
|
||||
|
||||
@ -923,7 +923,7 @@ fn test_splitator_mut_inclusive_reverse() {
|
||||
assert_eq!(xs.split_inclusive_mut(|_| true).rev().collect::<Vec<_>>(), splits);
|
||||
|
||||
let xs: &mut [i32] = &mut [];
|
||||
let splits: &[&[i32]] = &[&[]];
|
||||
let splits: &[&[i32]] = &[];
|
||||
assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
|
||||
}
|
||||
|
||||
|
@ -481,7 +481,8 @@ where
|
||||
impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusive<'a, T, P> {
|
||||
#[inline]
|
||||
pub(super) fn new(slice: &'a [T], pred: P) -> Self {
|
||||
Self { v: slice, pred, finished: false }
|
||||
let finished = slice.is_empty();
|
||||
Self { v: slice, pred, finished }
|
||||
}
|
||||
}
|
||||
|
||||
@ -729,7 +730,8 @@ where
|
||||
impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusiveMut<'a, T, P> {
|
||||
#[inline]
|
||||
pub(super) fn new(slice: &'a mut [T], pred: P) -> Self {
|
||||
Self { v: slice, pred, finished: false }
|
||||
let finished = slice.is_empty();
|
||||
Self { v: slice, pred, finished }
|
||||
}
|
||||
}
|
||||
|
||||
|
9
src/test/ui/binop/binary-op-on-fn-ptr-eq.rs
Normal file
9
src/test/ui/binop/binary-op-on-fn-ptr-eq.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// run-pass
|
||||
// Tests equality between supertype and subtype of a function
|
||||
// See the issue #91636
|
||||
fn foo(_a: &str) {}
|
||||
|
||||
fn main() {
|
||||
let x = foo as fn(&'static str);
|
||||
let _ = x == foo;
|
||||
}
|
10
src/test/ui/issues/issue-87490.rs
Normal file
10
src/test/ui/issues/issue-87490.rs
Normal file
@ -0,0 +1,10 @@
|
||||
fn main() {}
|
||||
trait StreamOnce {
|
||||
type Position;
|
||||
}
|
||||
impl StreamOnce for &str {
|
||||
type Position = usize;
|
||||
}
|
||||
fn follow(_: &str) -> <&str as StreamOnce>::Position {
|
||||
String::new //~ ERROR mismatched types
|
||||
}
|
14
src/test/ui/issues/issue-87490.stderr
Normal file
14
src/test/ui/issues/issue-87490.stderr
Normal file
@ -0,0 +1,14 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-87490.rs:9:5
|
||||
|
|
||||
LL | fn follow(_: &str) -> <&str as StreamOnce>::Position {
|
||||
| ------------------------------ expected `usize` because of return type
|
||||
LL | String::new
|
||||
| ^^^^^^^^^^^ expected `usize`, found fn item
|
||||
|
|
||||
= note: expected type `usize`
|
||||
found fn item `fn() -> String {String::new}`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
12
src/test/ui/mir/mir_const_prop_identity.rs
Normal file
12
src/test/ui/mir/mir_const_prop_identity.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// Regression test for issue #91725.
|
||||
//
|
||||
// run-pass
|
||||
// compile-flags: -Zmir-opt-level=4
|
||||
|
||||
fn main() {
|
||||
let a = true;
|
||||
let _ = &a;
|
||||
let mut b = false;
|
||||
b |= a;
|
||||
assert!(b);
|
||||
}
|
4
src/test/ui/operator-recovery/less-than-greater-than.rs
Normal file
4
src/test/ui/operator-recovery/less-than-greater-than.rs
Normal file
@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
println!("{}", 1 <> 2);
|
||||
//~^ERROR invalid comparison operator `<>`
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
error: invalid comparison operator `<>`
|
||||
--> $DIR/less-than-greater-than.rs:2:22
|
||||
|
|
||||
LL | println!("{}", 1 <> 2);
|
||||
| ^^ help: `<>` is not a valid comparison operator, use `!=`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
4
src/test/ui/operator-recovery/spaceship.rs
Normal file
4
src/test/ui/operator-recovery/spaceship.rs
Normal file
@ -0,0 +1,4 @@
|
||||
fn main() {
|
||||
println!("{}", 1 <=> 2);
|
||||
//~^ERROR invalid comparison operator `<=>`
|
||||
}
|
8
src/test/ui/operator-recovery/spaceship.stderr
Normal file
8
src/test/ui/operator-recovery/spaceship.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: invalid comparison operator `<=>`
|
||||
--> $DIR/spaceship.rs:2:22
|
||||
|
|
||||
LL | println!("{}", 1 <=> 2);
|
||||
| ^^^ `<=>` is not a valid comparison operator, use `std::cmp::Ordering`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
15
src/test/ui/suggestions/suggest-add-self.rs
Normal file
15
src/test/ui/suggestions/suggest-add-self.rs
Normal file
@ -0,0 +1,15 @@
|
||||
struct X(i32);
|
||||
|
||||
impl X {
|
||||
pub(crate) fn f() {
|
||||
self.0
|
||||
//~^ ERROR expected value, found module `self`
|
||||
}
|
||||
|
||||
pub fn g() {
|
||||
self.0
|
||||
//~^ ERROR expected value, found module `self`
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
29
src/test/ui/suggestions/suggest-add-self.stderr
Normal file
29
src/test/ui/suggestions/suggest-add-self.stderr
Normal file
@ -0,0 +1,29 @@
|
||||
error[E0424]: expected value, found module `self`
|
||||
--> $DIR/suggest-add-self.rs:5:9
|
||||
|
|
||||
LL | pub(crate) fn f() {
|
||||
| - this function doesn't have a `self` parameter
|
||||
LL | self.0
|
||||
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
||||
|
|
||||
help: add a `self` receiver parameter to make the associated `fn` a method
|
||||
|
|
||||
LL | pub(crate) fn f(&self) {
|
||||
| +++++
|
||||
|
||||
error[E0424]: expected value, found module `self`
|
||||
--> $DIR/suggest-add-self.rs:10:9
|
||||
|
|
||||
LL | pub fn g() {
|
||||
| - this function doesn't have a `self` parameter
|
||||
LL | self.0
|
||||
| ^^^^ `self` value is a keyword only available in methods with a `self` parameter
|
||||
|
|
||||
help: add a `self` receiver parameter to make the associated `fn` a method
|
||||
|
|
||||
LL | pub fn g(&self) {
|
||||
| +++++
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0424`.
|
Loading…
Reference in New Issue
Block a user