Skip to content

Commit e2c21d4

Browse files
committed
Auto merge of #3970 - RalfJung:rustup, r=RalfJung
Rustup
2 parents 49b53d4 + aeed2b2 commit e2c21d4

File tree

9 files changed

+157
-8
lines changed

9 files changed

+157
-8
lines changed

rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
7067e4aee45c18cfa1c6af3bf79bd097684fb294
1+
17a19e684cdf3ca088af8b4da6a6209d128913f4

src/diagnostics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -473,14 +473,14 @@ pub fn report_leaks<'tcx>(
473473
leaks: Vec<(AllocId, MemoryKind, Allocation<Provenance, AllocExtra<'tcx>, MiriAllocBytes>)>,
474474
) {
475475
let mut any_pruned = false;
476-
for (id, kind, mut alloc) in leaks {
476+
for (id, kind, alloc) in leaks {
477477
let mut title = format!(
478478
"memory leaked: {id:?} ({}, size: {:?}, align: {:?})",
479479
kind,
480480
alloc.size().bytes(),
481481
alloc.align.bytes()
482482
);
483-
let Some(backtrace) = alloc.extra.backtrace.take() else {
483+
let Some(backtrace) = alloc.extra.backtrace else {
484484
ecx.tcx.dcx().err(title);
485485
continue;
486486
};

src/eval.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ pub fn eval_entry<'tcx>(
473473
}
474474
// Check for memory leaks.
475475
info!("Additional static roots: {:?}", ecx.machine.static_roots);
476-
let leaks = ecx.find_leaked_allocations(&ecx.machine.static_roots);
476+
let leaks = ecx.take_leaked_allocations(|ecx| &ecx.machine.static_roots);
477477
if !leaks.is_empty() {
478478
report_leaks(&ecx, leaks);
479479
tcx.dcx().note("set `MIRIFLAGS=-Zmiri-ignore-leaks` to disable this check");

src/intrinsics/mod.rs

+33
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,39 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
295295
this.write_scalar(res, dest)?;
296296
}
297297

298+
"fmuladdf32" => {
299+
let [a, b, c] = check_arg_count(args)?;
300+
let a = this.read_scalar(a)?.to_f32()?;
301+
let b = this.read_scalar(b)?.to_f32()?;
302+
let c = this.read_scalar(c)?.to_f32()?;
303+
let fuse: bool = this.machine.rng.get_mut().gen();
304+
#[allow(clippy::arithmetic_side_effects)] // float ops don't overflow
305+
let res = if fuse {
306+
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
307+
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
308+
} else {
309+
((a * b).value + c).value
310+
};
311+
let res = this.adjust_nan(res, &[a, b, c]);
312+
this.write_scalar(res, dest)?;
313+
}
314+
"fmuladdf64" => {
315+
let [a, b, c] = check_arg_count(args)?;
316+
let a = this.read_scalar(a)?.to_f64()?;
317+
let b = this.read_scalar(b)?.to_f64()?;
318+
let c = this.read_scalar(c)?.to_f64()?;
319+
let fuse: bool = this.machine.rng.get_mut().gen();
320+
#[allow(clippy::arithmetic_side_effects)] // float ops don't overflow
321+
let res = if fuse {
322+
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
323+
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
324+
} else {
325+
((a * b).value + c).value
326+
};
327+
let res = this.adjust_nan(res, &[a, b, c]);
328+
this.write_scalar(res, dest)?;
329+
}
330+
298331
"powf32" => {
299332
let [f1, f2] = check_arg_count(args)?;
300333
let f1 = this.read_scalar(f1)?.to_f32()?;

src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#![feature(rustc_private)]
22
#![feature(cell_update)]
3-
#![feature(const_option)]
43
#![feature(float_gamma)]
54
#![feature(map_try_insert)]
65
#![feature(never_type)]

src/machine.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ impl ProvenanceExtra {
321321
}
322322

323323
/// Extra per-allocation data
324-
#[derive(Debug, Clone)]
324+
#[derive(Debug)]
325325
pub struct AllocExtra<'tcx> {
326326
/// Global state of the borrow tracker, if enabled.
327327
pub borrow_tracker: Option<borrow_tracker::AllocState>,
@@ -338,6 +338,14 @@ pub struct AllocExtra<'tcx> {
338338
pub backtrace: Option<Vec<FrameInfo<'tcx>>>,
339339
}
340340

341+
// We need a `Clone` impl because the machine passes `Allocation` through `Cow`...
342+
// but that should never end up actually cloning our `AllocExtra`.
343+
impl<'tcx> Clone for AllocExtra<'tcx> {
344+
fn clone(&self) -> Self {
345+
panic!("our allocations should never be cloned");
346+
}
347+
}
348+
341349
impl VisitProvenance for AllocExtra<'_> {
342350
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
343351
let AllocExtra { borrow_tracker, data_race, weak_memory, backtrace: _ } = self;

tests/pass/float.rs

+18
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ fn main() {
3030
libm();
3131
test_fast();
3232
test_algebraic();
33+
test_fmuladd();
3334
}
3435

3536
trait Float: Copy + PartialEq + Debug {
@@ -1041,3 +1042,20 @@ fn test_algebraic() {
10411042
test_operations_f32(11., 2.);
10421043
test_operations_f32(10., 15.);
10431044
}
1045+
1046+
fn test_fmuladd() {
1047+
use std::intrinsics::{fmuladdf32, fmuladdf64};
1048+
1049+
#[inline(never)]
1050+
pub fn test_operations_f32(a: f32, b: f32, c: f32) {
1051+
assert_approx_eq!(unsafe { fmuladdf32(a, b, c) }, a * b + c);
1052+
}
1053+
1054+
#[inline(never)]
1055+
pub fn test_operations_f64(a: f64, b: f64, c: f64) {
1056+
assert_approx_eq!(unsafe { fmuladdf64(a, b, c) }, a * b + c);
1057+
}
1058+
1059+
test_operations_f32(0.1, 0.2, 0.3);
1060+
test_operations_f64(1.1, 1.2, 1.3);
1061+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#![feature(core_intrinsics)]
2+
use std::intrinsics::{fmuladdf32, fmuladdf64};
3+
4+
fn main() {
5+
let mut saw_zero = false;
6+
let mut saw_nonzero = false;
7+
for _ in 0..50 {
8+
let a = std::hint::black_box(0.1_f64);
9+
let b = std::hint::black_box(0.2);
10+
let c = std::hint::black_box(-a * b);
11+
// It is unspecified whether the following operation is fused or not. The
12+
// following evaluates to 0.0 if unfused, and nonzero (-1.66e-18) if fused.
13+
let x = unsafe { fmuladdf64(a, b, c) };
14+
if x == 0.0 {
15+
saw_zero = true;
16+
} else {
17+
saw_nonzero = true;
18+
}
19+
}
20+
assert!(
21+
saw_zero && saw_nonzero,
22+
"`fmuladdf64` failed to be evaluated as both fused and unfused"
23+
);
24+
25+
let mut saw_zero = false;
26+
let mut saw_nonzero = false;
27+
for _ in 0..50 {
28+
let a = std::hint::black_box(0.1_f32);
29+
let b = std::hint::black_box(0.2);
30+
let c = std::hint::black_box(-a * b);
31+
// It is unspecified whether the following operation is fused or not. The
32+
// following evaluates to 0.0 if unfused, and nonzero (-8.1956386e-10) if fused.
33+
let x = unsafe { fmuladdf32(a, b, c) };
34+
if x == 0.0 {
35+
saw_zero = true;
36+
} else {
37+
saw_nonzero = true;
38+
}
39+
}
40+
assert!(
41+
saw_zero && saw_nonzero,
42+
"`fmuladdf32` failed to be evaluated as both fused and unfused"
43+
);
44+
}

tests/pass/underscore_pattern.rs

+49-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// Various tests ensuring that underscore patterns really just construct the place, but don't check its contents.
22
#![feature(strict_provenance)]
3+
#![feature(never_type)]
4+
35
use std::ptr;
46

57
fn main() {
@@ -9,6 +11,7 @@ fn main() {
911
invalid_let();
1012
dangling_let_type_annotation();
1113
invalid_let_type_annotation();
14+
never();
1215
}
1316

1417
fn dangling_match() {
@@ -34,13 +37,25 @@ fn invalid_match() {
3437
_ => {}
3538
}
3639
}
40+
41+
unsafe {
42+
let x: Uninit<!> = Uninit { uninit: () };
43+
match x.value {
44+
_ => {}
45+
}
46+
}
3747
}
3848

3949
fn dangling_let() {
4050
unsafe {
4151
let ptr = ptr::without_provenance::<bool>(0x40);
4252
let _ = *ptr;
4353
}
54+
55+
unsafe {
56+
let ptr = ptr::without_provenance::<!>(0x40);
57+
let _ = *ptr;
58+
}
4459
}
4560

4661
fn invalid_let() {
@@ -49,6 +64,12 @@ fn invalid_let() {
4964
let ptr = ptr::addr_of!(val).cast::<bool>();
5065
let _ = *ptr;
5166
}
67+
68+
unsafe {
69+
let val = 3u8;
70+
let ptr = ptr::addr_of!(val).cast::<!>();
71+
let _ = *ptr;
72+
}
5273
}
5374

5475
// Adding a type annotation used to change how MIR is generated, make sure we cover both cases.
@@ -57,6 +78,11 @@ fn dangling_let_type_annotation() {
5778
let ptr = ptr::without_provenance::<bool>(0x40);
5879
let _: bool = *ptr;
5980
}
81+
82+
unsafe {
83+
let ptr = ptr::without_provenance::<!>(0x40);
84+
let _: ! = *ptr;
85+
}
6086
}
6187

6288
fn invalid_let_type_annotation() {
@@ -65,7 +91,28 @@ fn invalid_let_type_annotation() {
6591
let ptr = ptr::addr_of!(val).cast::<bool>();
6692
let _: bool = *ptr;
6793
}
94+
95+
unsafe {
96+
let val = 3u8;
97+
let ptr = ptr::addr_of!(val).cast::<!>();
98+
let _: ! = *ptr;
99+
}
68100
}
69101

70-
// FIXME: we should also test `!`, not just `bool` -- but that s currently buggy:
71-
// https://github.com/rust-lang/rust/issues/117288
102+
// Regression test from <https://github.com/rust-lang/rust/issues/117288>.
103+
fn never() {
104+
unsafe {
105+
let x = 3u8;
106+
let x: *const ! = &x as *const u8 as *const _;
107+
let _: ! = *x;
108+
}
109+
110+
// Without a type annotation, make sure we don't implicitly coerce `!` to `()`
111+
// when we do the noop `*x` (as that would require a `!` *value*, creating
112+
// which is UB).
113+
unsafe {
114+
let x = 3u8;
115+
let x: *const ! = &x as *const u8 as *const _;
116+
let _ = *x;
117+
}
118+
}

0 commit comments

Comments
 (0)