Auto merge of #94695 - matthiaskrgr:rollup-5pi3acz, r=matthiaskrgr
Rollup of 4 pull requests Successful merges: - #94553 (add tests for #94502) - #94614 (Remove ordering traits from `rustc_span::hygiene::LocalExpnId`) - #94685 (interpret: move saturating_add/sub into (pub) helper method) - #94688 (Erase regions when checking for missing Copy predicates) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
d137c3a7bd
@ -448,8 +448,16 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
|
|||||||
self.mir_hir_id(),
|
self.mir_hir_id(),
|
||||||
rustc_infer::traits::ObligationCauseCode::MiscObligation,
|
rustc_infer::traits::ObligationCauseCode::MiscObligation,
|
||||||
);
|
);
|
||||||
fulfill_cx.register_bound(&infcx, self.param_env, ty, copy_did, cause);
|
fulfill_cx.register_bound(
|
||||||
let errors = fulfill_cx.select_where_possible(&infcx);
|
&infcx,
|
||||||
|
self.param_env,
|
||||||
|
// Erase any region vids from the type, which may not be resolved
|
||||||
|
infcx.tcx.erase_regions(ty),
|
||||||
|
copy_did,
|
||||||
|
cause,
|
||||||
|
);
|
||||||
|
// Select all, including ambiguous predicates
|
||||||
|
let errors = fulfill_cx.select_all_or_error(&infcx);
|
||||||
|
|
||||||
// Only emit suggestion if all required predicates are on generic
|
// Only emit suggestion if all required predicates are on generic
|
||||||
errors
|
errors
|
||||||
|
@ -219,48 +219,11 @@ pub fn emulate_intrinsic(
|
|||||||
sym::saturating_add | sym::saturating_sub => {
|
sym::saturating_add | sym::saturating_sub => {
|
||||||
let l = self.read_immediate(&args[0])?;
|
let l = self.read_immediate(&args[0])?;
|
||||||
let r = self.read_immediate(&args[1])?;
|
let r = self.read_immediate(&args[1])?;
|
||||||
let is_add = intrinsic_name == sym::saturating_add;
|
let val = self.saturating_arith(
|
||||||
let (val, overflowed, _ty) = self.overflowing_binary_op(
|
if intrinsic_name == sym::saturating_add { BinOp::Add } else { BinOp::Sub },
|
||||||
if is_add { BinOp::Add } else { BinOp::Sub },
|
|
||||||
&l,
|
&l,
|
||||||
&r,
|
&r,
|
||||||
)?;
|
)?;
|
||||||
let val = if overflowed {
|
|
||||||
let size = l.layout.size;
|
|
||||||
let num_bits = size.bits();
|
|
||||||
if l.layout.abi.is_signed() {
|
|
||||||
// For signed ints the saturated value depends on the sign of the first
|
|
||||||
// term since the sign of the second term can be inferred from this and
|
|
||||||
// the fact that the operation has overflowed (if either is 0 no
|
|
||||||
// overflow can occur)
|
|
||||||
let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
|
|
||||||
let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
|
|
||||||
if first_term_positive {
|
|
||||||
// Negative overflow not possible since the positive first term
|
|
||||||
// can only increase an (in range) negative term for addition
|
|
||||||
// or corresponding negated positive term for subtraction
|
|
||||||
Scalar::from_uint(
|
|
||||||
(1u128 << (num_bits - 1)) - 1, // max positive
|
|
||||||
Size::from_bits(num_bits),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// Positive overflow not possible for similar reason
|
|
||||||
// max negative
|
|
||||||
Scalar::from_uint(1u128 << (num_bits - 1), Size::from_bits(num_bits))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// unsigned
|
|
||||||
if is_add {
|
|
||||||
// max unsigned
|
|
||||||
Scalar::from_uint(size.unsigned_int_max(), Size::from_bits(num_bits))
|
|
||||||
} else {
|
|
||||||
// underflow to 0
|
|
||||||
Scalar::from_uint(0u128, Size::from_bits(num_bits))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val
|
|
||||||
};
|
|
||||||
self.write_scalar(val, dest)?;
|
self.write_scalar(val, dest)?;
|
||||||
}
|
}
|
||||||
sym::discriminant_value => {
|
sym::discriminant_value => {
|
||||||
@ -508,6 +471,49 @@ pub fn exact_div(
|
|||||||
self.binop_ignore_overflow(BinOp::Div, &a, &b, dest)
|
self.binop_ignore_overflow(BinOp::Div, &a, &b, dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn saturating_arith(
|
||||||
|
&self,
|
||||||
|
mir_op: BinOp,
|
||||||
|
l: &ImmTy<'tcx, M::PointerTag>,
|
||||||
|
r: &ImmTy<'tcx, M::PointerTag>,
|
||||||
|
) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
|
||||||
|
assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
|
||||||
|
let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?;
|
||||||
|
Ok(if overflowed {
|
||||||
|
let size = l.layout.size;
|
||||||
|
let num_bits = size.bits();
|
||||||
|
if l.layout.abi.is_signed() {
|
||||||
|
// For signed ints the saturated value depends on the sign of the first
|
||||||
|
// term since the sign of the second term can be inferred from this and
|
||||||
|
// the fact that the operation has overflowed (if either is 0 no
|
||||||
|
// overflow can occur)
|
||||||
|
let first_term: u128 = l.to_scalar()?.to_bits(l.layout.size)?;
|
||||||
|
let first_term_positive = first_term & (1 << (num_bits - 1)) == 0;
|
||||||
|
if first_term_positive {
|
||||||
|
// Negative overflow not possible since the positive first term
|
||||||
|
// can only increase an (in range) negative term for addition
|
||||||
|
// or corresponding negated positive term for subtraction
|
||||||
|
Scalar::from_int(size.signed_int_max(), size)
|
||||||
|
} else {
|
||||||
|
// Positive overflow not possible for similar reason
|
||||||
|
// max negative
|
||||||
|
Scalar::from_int(size.signed_int_min(), size)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// unsigned
|
||||||
|
if matches!(mir_op, BinOp::Add) {
|
||||||
|
// max unsigned
|
||||||
|
Scalar::from_uint(size.unsigned_int_max(), size)
|
||||||
|
} else {
|
||||||
|
// underflow to 0
|
||||||
|
Scalar::from_uint(0u128, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
|
/// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
|
||||||
/// allocation. For integer pointers, we consider each of them their own tiny allocation of size
|
/// allocation. For integer pointers, we consider each of them their own tiny allocation of size
|
||||||
/// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
|
/// 0, so offset-by-0 (and only 0) is okay -- except that null cannot be offset by _any_ value.
|
||||||
|
@ -85,10 +85,17 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|||||||
/// A unique ID associated with a macro invocation and expansion.
|
/// A unique ID associated with a macro invocation and expansion.
|
||||||
pub struct LocalExpnId {
|
pub struct LocalExpnId {
|
||||||
ENCODABLE = custom
|
ENCODABLE = custom
|
||||||
|
ORD_IMPL = custom
|
||||||
DEBUG_FORMAT = "expn{}"
|
DEBUG_FORMAT = "expn{}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To ensure correctness of incremental compilation,
|
||||||
|
// `LocalExpnId` must not implement `Ord` or `PartialOrd`.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/90317.
|
||||||
|
impl !Ord for LocalExpnId {}
|
||||||
|
impl !PartialOrd for LocalExpnId {}
|
||||||
|
|
||||||
/// Assert that the provided `HashStableContext` is configured with the 'default'
|
/// Assert that the provided `HashStableContext` is configured with the 'default'
|
||||||
/// `HashingControls`. We should always have bailed out before getting to here
|
/// `HashingControls`. We should always have bailed out before getting to here
|
||||||
/// with a non-default mode. With this check in place, we can avoid the need
|
/// with a non-default mode. With this check in place, we can avoid the need
|
||||||
|
17
src/test/ui/borrowck/copy-suggestion-region-vid.rs
Normal file
17
src/test/ui/borrowck/copy-suggestion-region-vid.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
pub struct DataStruct();
|
||||||
|
|
||||||
|
pub struct HelperStruct<'n> {
|
||||||
|
pub helpers: [Vec<&'n i64>; 2],
|
||||||
|
pub is_empty: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataStruct {
|
||||||
|
pub fn f(&self) -> HelperStruct {
|
||||||
|
let helpers = [vec![], vec![]];
|
||||||
|
|
||||||
|
HelperStruct { helpers, is_empty: helpers[0].is_empty() }
|
||||||
|
//~^ ERROR borrow of moved value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
14
src/test/ui/borrowck/copy-suggestion-region-vid.stderr
Normal file
14
src/test/ui/borrowck/copy-suggestion-region-vid.stderr
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
error[E0382]: borrow of moved value: `helpers`
|
||||||
|
--> $DIR/copy-suggestion-region-vid.rs:12:43
|
||||||
|
|
|
||||||
|
LL | let helpers = [vec![], vec![]];
|
||||||
|
| ------- move occurs because `helpers` has type `[Vec<&i64>; 2]`, which does not implement the `Copy` trait
|
||||||
|
LL |
|
||||||
|
LL | HelperStruct { helpers, is_empty: helpers[0].is_empty() }
|
||||||
|
| ------- ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
|
||||||
|
| |
|
||||||
|
| value moved here
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0382`.
|
28
src/test/ui/nll/lint-no-err.rs
Normal file
28
src/test/ui/nll/lint-no-err.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
// mir borrowck previously incorrectly set `tainted_by_errors`
|
||||||
|
// when buffering lints, which resulted in ICE later on,
|
||||||
|
// see #94502.
|
||||||
|
|
||||||
|
// Errors with `nll` which is already tested in enough other tests,
|
||||||
|
// so we ignore it here.
|
||||||
|
//
|
||||||
|
// ignore-compare-mode-nll
|
||||||
|
|
||||||
|
struct Repro;
|
||||||
|
impl Repro {
|
||||||
|
fn get(&self) -> &i32 {
|
||||||
|
&3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&mut self, _: i32) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = &0;
|
||||||
|
let mut conflict = Repro;
|
||||||
|
let prev = conflict.get();
|
||||||
|
conflict.insert(*prev + *x);
|
||||||
|
//~^ WARN cannot borrow `conflict` as mutable because it is also borrowed as immutable
|
||||||
|
//~| WARN this borrowing pattern was not meant to be accepted
|
||||||
|
}
|
17
src/test/ui/nll/lint-no-err.stderr
Normal file
17
src/test/ui/nll/lint-no-err.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
warning: cannot borrow `conflict` as mutable because it is also borrowed as immutable
|
||||||
|
--> $DIR/lint-no-err.rs:25:5
|
||||||
|
|
|
||||||
|
LL | let prev = conflict.get();
|
||||||
|
| -------------- immutable borrow occurs here
|
||||||
|
LL | conflict.insert(*prev + *x);
|
||||||
|
| ^^^^^^^^^^^^^^^^-----^^^^^^
|
||||||
|
| | |
|
||||||
|
| | immutable borrow later used here
|
||||||
|
| mutable borrow occurs here
|
||||||
|
|
|
||||||
|
= note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
|
||||||
|
= warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
|
||||||
|
= note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
Loading…
Reference in New Issue
Block a user