Skip to content

Rollup of 4 pull requests #94695

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 7, 2022
12 changes: 10 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
self.mir_hir_id(),
rustc_infer::traits::ObligationCauseCode::MiscObligation,
);
fulfill_cx.register_bound(&infcx, self.param_env, ty, copy_did, cause);
let errors = fulfill_cx.select_where_possible(&infcx);
fulfill_cx.register_bound(
&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
errors
Expand Down
84 changes: 45 additions & 39 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,48 +219,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::saturating_add | sym::saturating_sub => {
let l = self.read_immediate(&args[0])?;
let r = self.read_immediate(&args[1])?;
let is_add = intrinsic_name == sym::saturating_add;
let (val, overflowed, _ty) = self.overflowing_binary_op(
if is_add { BinOp::Add } else { BinOp::Sub },
let val = self.saturating_arith(
if intrinsic_name == sym::saturating_add { BinOp::Add } else { BinOp::Sub },
&l,
&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)?;
}
sym::discriminant_value => {
Expand Down Expand Up @@ -508,6 +471,49 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
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
/// 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.
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_span/src/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,17 @@ rustc_index::newtype_index! {
/// A unique ID associated with a macro invocation and expansion.
pub struct LocalExpnId {
ENCODABLE = custom
ORD_IMPL = custom
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'
/// `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
Expand Down
17 changes: 17 additions & 0 deletions src/test/ui/borrowck/copy-suggestion-region-vid.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions src/test/ui/borrowck/copy-suggestion-region-vid.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 28 additions & 0 deletions src/test/ui/nll/lint-no-err.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions src/test/ui/nll/lint-no-err.stderr
Original file line number Diff line number Diff line change
@@ -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