Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 41ad4d9

Browse files
committed
Auto merge of rust-lang#98936 - matthiaskrgr:rollup-dvr0ucm, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - rust-lang#98860 (adjust dangling-int-ptr error message) - rust-lang#98888 (interpret: fix CheckedBinOp behavior when overflow checking is disabled) - rust-lang#98889 (Add regression test for rust-lang#79467) - rust-lang#98895 (bootstrap.py: Always use `.exe` for Windows) - rust-lang#98920 (adapt issue-37945 codegen test to accept any order of ops) - rust-lang#98921 (Refactor: remove a redundant mutable variable) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents efb171e + 720eb12 commit 41ad4d9

27 files changed

+116
-57
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
217217
sym::mul_with_overflow => BinOp::Mul,
218218
_ => bug!(),
219219
};
220-
self.binop_with_overflow(bin_op, &lhs, &rhs, dest)?;
220+
self.binop_with_overflow(
221+
bin_op, /*force_overflow_checks*/ true, &lhs, &rhs, dest,
222+
)?;
221223
}
222224
sym::saturating_add | sym::saturating_sub => {
223225
let l = self.read_immediate(&args[0])?;

compiler/rustc_const_eval/src/interpret/machine.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ pub trait Machine<'mir, 'tcx>: Sized {
144144
true
145145
}
146146

147+
/// Whether CheckedBinOp MIR statements should actually check for overflow.
148+
fn check_binop_checks_overflow(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
149+
147150
/// Entry point for obtaining the MIR of anything that should get evaluated.
148151
/// So not just functions and shims, but also const/static initializers, anonymous
149152
/// constants, ...
@@ -468,6 +471,11 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
468471
true
469472
}
470473

474+
#[inline(always)]
475+
fn check_binop_checks_overflow(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
476+
true
477+
}
478+
471479
#[inline(always)]
472480
fn call_extra_fn(
473481
_ecx: &mut InterpCx<$mir, $tcx, Self>,
@@ -513,7 +521,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
513521
_ecx: &InterpCx<$mir, $tcx, Self>,
514522
addr: u64,
515523
) -> Pointer<Option<AllocId>> {
516-
Pointer::new(None, Size::from_bytes(addr))
524+
Pointer::from_addr(addr)
517525
}
518526

519527
#[inline(always)]
@@ -523,7 +531,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
523531
) -> InterpResult<$tcx, Pointer<Option<AllocId>>> {
524532
// Allow these casts, but make the pointer not dereferenceable.
525533
// (I.e., they behave like transmutation.)
526-
Ok(Pointer::new(None, Size::from_bytes(addr)))
534+
Ok(Pointer::from_addr(addr))
527535
}
528536

529537
#[inline(always)]

compiler/rustc_const_eval/src/interpret/operator.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@ use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy};
1212
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1313
/// Applies the binary operation `op` to the two operands and writes a tuple of the result
1414
/// and a boolean signifying the potential overflow to the destination.
15+
///
16+
/// `force_overflow_checks` indicates whether overflow checks should be done even when
17+
/// `tcx.sess.overflow_checks()` is `false`.
1518
pub fn binop_with_overflow(
1619
&mut self,
1720
op: mir::BinOp,
21+
force_overflow_checks: bool,
1822
left: &ImmTy<'tcx, M::PointerTag>,
1923
right: &ImmTy<'tcx, M::PointerTag>,
2024
dest: &PlaceTy<'tcx, M::PointerTag>,
@@ -26,6 +30,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
2630
"type mismatch for result of {:?}",
2731
op,
2832
);
33+
// As per https://github.com/rust-lang/rust/pull/98738, we always return `false` in the 2nd
34+
// component when overflow checking is disabled.
35+
let overflowed =
36+
overflowed && (force_overflow_checks || M::check_binop_checks_overflow(self));
37+
// Write the result to `dest`.
2938
if let Abi::ScalarPair(..) = dest.layout.abi {
3039
// We can use the optimized path and avoid `place_field` (which might do
3140
// `force_allocation`).

compiler/rustc_const_eval/src/interpret/place.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ impl<'tcx, Tag: Provenance> MPlaceTy<'tcx, Tag> {
188188
#[inline]
189189
pub fn dangling(layout: TyAndLayout<'tcx>) -> Self {
190190
let align = layout.align.abi;
191-
let ptr = Pointer::new(None, Size::from_bytes(align.bytes())); // no provenance, absolute address
191+
let ptr = Pointer::from_addr(align.bytes()); // no provenance, absolute address
192192
// `Poison` this to make sure that the pointer value `ptr` is never observable by the program.
193193
MPlaceTy { mplace: MemPlace { ptr, meta: MemPlaceMeta::Poison }, layout, align }
194194
}

compiler/rustc_const_eval/src/interpret/step.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
185185
let left = self.read_immediate(&self.eval_operand(left, None)?)?;
186186
let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
187187
let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
188-
self.binop_with_overflow(bin_op, &left, &right, &dest)?;
188+
self.binop_with_overflow(
189+
bin_op, /*force_overflow_checks*/ false, &left, &right, &dest,
190+
)?;
189191
}
190192

191193
UnaryOp(un_op, ref operand) => {

compiler/rustc_middle/src/mir/interpret/error.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -186,17 +186,17 @@ pub enum CheckInAllocMsg {
186186

187187
impl fmt::Display for CheckInAllocMsg {
188188
/// When this is printed as an error the context looks like this:
189-
/// "{msg}0x01 is not a valid pointer".
189+
/// "{msg}{pointer} is a dangling pointer".
190190
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191191
write!(
192192
f,
193193
"{}",
194194
match *self {
195195
CheckInAllocMsg::DerefTest => "dereferencing pointer failed: ",
196196
CheckInAllocMsg::MemoryAccessTest => "memory access failed: ",
197-
CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic failed: ",
197+
CheckInAllocMsg::PointerArithmeticTest => "out-of-bounds pointer arithmetic: ",
198198
CheckInAllocMsg::OffsetFromTest => "out-of-bounds offset_from: ",
199-
CheckInAllocMsg::InboundsTest => "",
199+
CheckInAllocMsg::InboundsTest => "out-of-bounds pointer use: ",
200200
}
201201
)
202202
}
@@ -350,14 +350,12 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
350350
ptr_size = ptr_size.bytes(),
351351
ptr_size_p = pluralize!(ptr_size.bytes()),
352352
),
353-
DanglingIntPointer(0, CheckInAllocMsg::InboundsTest) => {
354-
write!(f, "null pointer is not a valid pointer for this operation")
355-
}
356-
DanglingIntPointer(0, msg) => {
357-
write!(f, "{msg}null pointer is not a valid pointer")
358-
}
359353
DanglingIntPointer(i, msg) => {
360-
write!(f, "{msg}{i:#x} is not a valid pointer")
354+
write!(
355+
f,
356+
"{msg}{pointer} is a dangling pointer (it has no provenance)",
357+
pointer = Pointer::<Option<AllocId>>::from_addr(*i),
358+
)
361359
}
362360
AlignmentCheckFailed { required, has } => write!(
363361
f,

compiler/rustc_middle/src/mir/interpret/pointer.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,17 @@ impl<Tag: Provenance> fmt::Debug for Pointer<Option<Tag>> {
181181
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182182
match self.provenance {
183183
Some(tag) => Provenance::fmt(&Pointer::new(tag, self.offset), f),
184-
None => write!(f, "{:#x}", self.offset.bytes()),
184+
None => write!(f, "{:#x}[noalloc]", self.offset.bytes()),
185+
}
186+
}
187+
}
188+
189+
impl<Tag: Provenance> fmt::Display for Pointer<Option<Tag>> {
190+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191+
if self.provenance.is_none() && self.offset.bytes() == 0 {
192+
write!(f, "null pointer")
193+
} else {
194+
fmt::Debug::fmt(self, f)
185195
}
186196
}
187197
}
@@ -226,9 +236,14 @@ impl<Tag> Pointer<Option<Tag>> {
226236
}
227237

228238
impl<Tag> Pointer<Option<Tag>> {
239+
#[inline(always)]
240+
pub fn from_addr(addr: u64) -> Self {
241+
Pointer { provenance: None, offset: Size::from_bytes(addr) }
242+
}
243+
229244
#[inline(always)]
230245
pub fn null() -> Self {
231-
Pointer { provenance: None, offset: Size::ZERO }
246+
Pointer::from_addr(0)
232247
}
233248
}
234249

compiler/rustc_middle/src/mir/syntax.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -993,8 +993,9 @@ pub enum Rvalue<'tcx> {
993993

994994
/// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
995995
///
996-
/// When overflow checking is disabled, the error condition is false. Otherwise, the error
997-
/// condition is determined as described below.
996+
/// When overflow checking is disabled and we are generating run-time code, the error condition
997+
/// is false. Otherwise, and always during CTFE, the error condition is determined as described
998+
/// below.
998999
///
9991000
/// For addition, subtraction, and multiplication on integers the error condition is set when
10001001
/// the infinite precision result would be unequal to the actual result.

compiler/rustc_trait_selection/src/traits/fulfill.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,6 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
131131
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
132132
let _enter = span.enter();
133133

134-
let mut errors = Vec::new();
135-
136134
// Process pending obligations.
137135
let outcome: Outcome<_, _> = self.predicates.process_obligations(&mut FulfillProcessor {
138136
selcx,
@@ -142,7 +140,8 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
142140
// FIXME: if we kept the original cache key, we could mark projection
143141
// obligations as complete for the projection cache here.
144142

145-
errors.extend(outcome.errors.into_iter().map(to_fulfillment_error));
143+
let errors: Vec<FulfillmentError<'tcx>> =
144+
outcome.errors.into_iter().map(to_fulfillment_error).collect();
146145

147146
debug!(
148147
"select({} predicates remaining, {} errors) done",
@@ -728,7 +727,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
728727
}
729728
return ProcessResult::Changed(vec![]);
730729
} else {
731-
tracing::debug!("Does NOT hold: {:?}", obligation);
730+
debug!("Does NOT hold: {:?}", obligation);
732731
}
733732
}
734733

src/bootstrap/bootstrap.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs):
152152
if verbose:
153153
print("running: " + ' '.join(args))
154154
sys.stdout.flush()
155+
# Ensure that the .exe is used on Windows just in case a Linux ELF has been
156+
# compiled in the same directory.
157+
if os.name == 'nt' and not args[0].endswith('.exe'):
158+
args[0] += '.exe'
155159
# Use Popen here instead of call() as it apparently allows powershell on
156160
# Windows to not lock up waiting for input presumably.
157161
ret = subprocess.Popen(args, **kwargs)

0 commit comments

Comments
 (0)