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:
bors 2021-12-15 00:23:44 +00:00
commit d594910a2d
17 changed files with 195 additions and 60 deletions

View File

@ -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

View File

@ -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,

View File

@ -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),
})
}

View File

@ -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 {

View File

@ -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",
)

View File

@ -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);
}

View File

@ -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 }
}
}

View 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;
}

View 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
}

View 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`.

View 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);
}

View File

@ -0,0 +1,4 @@
fn main() {
println!("{}", 1 <> 2);
//~^ERROR invalid comparison operator `<>`
}

View File

@ -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

View File

@ -0,0 +1,4 @@
fn main() {
println!("{}", 1 <=> 2);
//~^ERROR invalid comparison operator `<=>`
}

View 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

View 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() {}

View 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`.