diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 205625573a6d9..6bf23af81bf6b 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -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 diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index a90582fc33820..48c90e1881a9a 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -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, diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index e897e89982c0d..84bdb8eece654 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -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); - - 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 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)?; + 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(_)) => 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)?; + + 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), }) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0f8c0e1b8cff8..c62ebb271f4b0 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -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 { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index feb4f82ce8ddc..3e1afdfa9a5c6 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -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", ) diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 13b8c059e37ae..18ea6a2141377 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -863,7 +863,7 @@ fn test_splitator_inclusive() { assert_eq!(xs.split_inclusive(|_| true).collect::>(), splits); let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.split_inclusive(|x| *x == 5).collect::>(), splits); } @@ -883,7 +883,7 @@ fn test_splitator_inclusive_reverse() { assert_eq!(xs.split_inclusive(|_| true).rev().collect::>(), splits); let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::>(), splits); } @@ -903,7 +903,7 @@ fn test_splitator_mut_inclusive() { assert_eq!(xs.split_inclusive_mut(|_| true).collect::>(), splits); let xs: &mut [i32] = &mut []; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::>(), splits); } @@ -923,7 +923,7 @@ fn test_splitator_mut_inclusive_reverse() { assert_eq!(xs.split_inclusive_mut(|_| true).rev().collect::>(), splits); let xs: &mut [i32] = &mut []; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); } diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index ad1d6b8b846a0..11a57558f67d7 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -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 } } } diff --git a/src/test/ui/binop/binary-op-on-fn-ptr-eq.rs b/src/test/ui/binop/binary-op-on-fn-ptr-eq.rs new file mode 100644 index 0000000000000..8e20640b58d94 --- /dev/null +++ b/src/test/ui/binop/binary-op-on-fn-ptr-eq.rs @@ -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; +} diff --git a/src/test/ui/issues/issue-87490.rs b/src/test/ui/issues/issue-87490.rs new file mode 100644 index 0000000000000..998f61a6bd32d --- /dev/null +++ b/src/test/ui/issues/issue-87490.rs @@ -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 +} diff --git a/src/test/ui/issues/issue-87490.stderr b/src/test/ui/issues/issue-87490.stderr new file mode 100644 index 0000000000000..f359dd638ad93 --- /dev/null +++ b/src/test/ui/issues/issue-87490.stderr @@ -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`. diff --git a/src/test/ui/mir/mir_const_prop_identity.rs b/src/test/ui/mir/mir_const_prop_identity.rs new file mode 100644 index 0000000000000..25d2202b909d9 --- /dev/null +++ b/src/test/ui/mir/mir_const_prop_identity.rs @@ -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); +} diff --git a/src/test/ui/operator-recovery/less-than-greater-than.rs b/src/test/ui/operator-recovery/less-than-greater-than.rs new file mode 100644 index 0000000000000..2beed528ff1c1 --- /dev/null +++ b/src/test/ui/operator-recovery/less-than-greater-than.rs @@ -0,0 +1,4 @@ +fn main() { + println!("{}", 1 <> 2); + //~^ERROR invalid comparison operator `<>` +} diff --git a/src/test/ui/operator-recovery/less-than-greater-than.stderr b/src/test/ui/operator-recovery/less-than-greater-than.stderr new file mode 100644 index 0000000000000..80c921535bd08 --- /dev/null +++ b/src/test/ui/operator-recovery/less-than-greater-than.stderr @@ -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 + diff --git a/src/test/ui/operator-recovery/spaceship.rs b/src/test/ui/operator-recovery/spaceship.rs new file mode 100644 index 0000000000000..a65f9389625fc --- /dev/null +++ b/src/test/ui/operator-recovery/spaceship.rs @@ -0,0 +1,4 @@ +fn main() { + println!("{}", 1 <=> 2); + //~^ERROR invalid comparison operator `<=>` +} diff --git a/src/test/ui/operator-recovery/spaceship.stderr b/src/test/ui/operator-recovery/spaceship.stderr new file mode 100644 index 0000000000000..ed6bd74c9b92e --- /dev/null +++ b/src/test/ui/operator-recovery/spaceship.stderr @@ -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 + diff --git a/src/test/ui/suggestions/suggest-add-self.rs b/src/test/ui/suggestions/suggest-add-self.rs new file mode 100644 index 0000000000000..40692c8df2053 --- /dev/null +++ b/src/test/ui/suggestions/suggest-add-self.rs @@ -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() {} diff --git a/src/test/ui/suggestions/suggest-add-self.stderr b/src/test/ui/suggestions/suggest-add-self.stderr new file mode 100644 index 0000000000000..a5e8f93deb64a --- /dev/null +++ b/src/test/ui/suggestions/suggest-add-self.stderr @@ -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`.