Skip to content

Commit 77eb95f

Browse files
Copilotnunoplopes
andauthored
Preserve first-element semantics in max_element translations (#479)
`std::max_element` returns the first iterator when multiple elements share the maximum, but the Rust translations selected the last. This affected vector rules f42/f94 and algorithm rule f8. - Fixes #454 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Nuno Lopes <nuno.lopes@tecnico.ulisboa.pt>
1 parent 7ffaf61 commit 77eb95f

7 files changed

Lines changed: 59 additions & 6 deletions

File tree

‎rules/algorithm/tgt_refcount.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ fn f8<T1: PartialOrd + Clone + ByteRepr>(a0: Ptr<T1>, a1: Ptr<T1>) -> Ptr<T1> {
4747
let count = a1.get_offset() - a0.get_offset();
4848
let max_index = PtrValueIter::new(&a0, count)
4949
.enumerate()
50-
.max_by(|(_, val_a), (_, val_b)| {
50+
.max_by(|(idx_a, val_a), (idx_b, val_b)| {
5151
val_a
5252
.partial_cmp(val_b)
5353
.unwrap_or(std::cmp::Ordering::Equal)
54+
.then_with(|| idx_b.cmp(idx_a))
5455
})
5556
.map(|(idx, _)| idx)
5657
.unwrap_or(0);

‎rules/algorithm/tgt_unsafe.rs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ unsafe fn f8<T1: PartialOrd>(a0: *mut T1, a1: *mut T1) -> *mut T1 {
4949
std::slice::from_raw_parts(a0, count)
5050
.iter()
5151
.enumerate()
52-
.max_by(|(_, x), (_, y)| x.partial_cmp(y).unwrap_or(std::cmp::Ordering::Equal))
52+
.max_by(|(idx_a, x), (idx_b, y)| {
53+
x.partial_cmp(y)
54+
.unwrap_or(std::cmp::Ordering::Equal)
55+
.then_with(|| idx_b.cmp(idx_a))
56+
})
5357
.map(|(i, _)| a0.add(i))
5458
.unwrap_or(a0)
5559
}

‎rules/vector/tgt_refcount.rs‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ fn f42(a0: Ptr<u8>, a1: Ptr<u8>) -> Ptr<u8> {
152152
let __count = a1.get_offset() - a0.get_offset();
153153
let max_index = PtrValueIter::new(&a0, __count)
154154
.enumerate()
155-
.max_by_key(|&(_, val)| val)
155+
.max_by(|&(idx_a, val_a), &(idx_b, val_b)| {
156+
val_a.cmp(&val_b).then_with(|| idx_b.cmp(&idx_a))
157+
})
156158
.map(|(idx, _)| idx)
157159
.unwrap_or(0);
158160

@@ -312,7 +314,9 @@ fn f94(a0: Ptr<u8>, a1: Ptr<u8>) -> Ptr<u8> {
312314
let __count = a1.get_offset() - a0.get_offset();
313315
let max_index = PtrValueIter::new(&a0, __count)
314316
.enumerate()
315-
.max_by_key(|&(_, val)| val)
317+
.max_by(|&(idx_a, val_a), &(idx_b, val_b)| {
318+
val_a.cmp(&val_b).then_with(|| idx_b.cmp(&idx_a))
319+
})
316320
.map(|(idx, _)| idx)
317321
.unwrap_or(0);
318322

‎rules/vector/tgt_unsafe.rs‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,9 @@ unsafe fn f41<T1>(a0: &mut Vec<T1>) -> *const T1 {
184184
unsafe fn f42<T1: Ord>(a0: *const T1, a1: *const T1) -> *const T1 {
185185
core::slice::from_raw_parts(a0, (a1).offset_from(a0) as usize)
186186
.iter()
187-
.max()
187+
.enumerate()
188+
.max_by(|(idx_a, val_a), (idx_b, val_b)| val_a.cmp(val_b).then_with(|| idx_b.cmp(idx_a)))
189+
.map(|(_, value)| value)
188190
.unwrap()
189191
}
190192

@@ -407,7 +409,9 @@ unsafe fn f93<T1>(a0: &mut Vec<T1>) -> *const T1 {
407409
unsafe fn f94<T1: Ord>(a0: *const T1, a1: *const T1) -> *const T1 {
408410
core::slice::from_raw_parts(a0, (a1).offset_from(a0) as usize)
409411
.iter()
410-
.max()
412+
.enumerate()
413+
.max_by(|(idx_a, val_a), (idx_b, val_b)| val_a.cmp(val_b).then_with(|| idx_b.cmp(idx_a)))
414+
.map(|(_, value)| value)
411415
.unwrap()
412416
}
413417

‎tests/unit/max.cpp‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,8 @@ int main() {
1010
int r4 = std::min(*p2, x3);
1111
int r5 = std::max(30, 40);
1212
assert(r1 + r2 + r3 + r4 + r5 == 56);
13+
int values[] = {1, 7, 7, 3};
14+
int *max = std::max_element(values, values + 4);
15+
assert(max == values + 1);
1316
return 0;
1417
}

‎tests/unit/out/refcount/max.rs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,25 @@ fn main_0() -> i32 {
5252
.read())
5353
};
5454
assert!((((((r1 + r2) + r3) + r4) + r5) == 56));
55+
let values: Value<Box<[i32]>> = Rc::new(RefCell::new(Box::new([1, 7, 7, 3])));
56+
let mut max: Ptr<i32> = {
57+
let count = (values.as_pointer() as Ptr<i32>)
58+
.offset((4) as isize)
59+
.get_offset()
60+
- (values.as_pointer() as Ptr<i32>).get_offset();
61+
let max_index = PtrValueIter::new(&(values.as_pointer() as Ptr<i32>), count)
62+
.enumerate()
63+
.max_by(|(idx_a, val_a), (idx_b, val_b)| {
64+
val_a
65+
.partial_cmp(val_b)
66+
.unwrap_or(std::cmp::Ordering::Equal)
67+
.then_with(|| idx_b.cmp(idx_a))
68+
})
69+
.map(|(idx, _)| idx)
70+
.unwrap_or(0);
71+
(values.as_pointer() as Ptr<i32>) + max_index
72+
};
73+
assert!(({ (max).clone() } == { (values.as_pointer() as Ptr::<i32>).offset((1) as isize) }));
5574
return 0;
5675
}
5776
pub fn __cpp2rust_init_globals() {}

‎tests/unit/out/unsafe/max.rs‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,24 @@ unsafe fn main_0() -> i32 {
4949
})
5050
};
5151
assert!(((((((r1) + (r2)) + (r3)) + (r4)) + (r5)) == (56)));
52+
let mut values: [i32; 4] = [1, 7, 7, 3];
53+
let mut max: *mut i32 = {
54+
let count = values
55+
.as_mut_ptr()
56+
.offset((4) as isize)
57+
.offset_from(values.as_mut_ptr()) as usize;
58+
std::slice::from_raw_parts(values.as_mut_ptr(), count)
59+
.iter()
60+
.enumerate()
61+
.max_by(|(idx_a, x), (idx_b, y)| {
62+
x.partial_cmp(y)
63+
.unwrap_or(std::cmp::Ordering::Equal)
64+
.then_with(|| idx_b.cmp(idx_a))
65+
})
66+
.map(|(i, _)| values.as_mut_ptr().add(i))
67+
.unwrap_or(values.as_mut_ptr())
68+
};
69+
assert!(((max) == (values.as_mut_ptr().offset((1) as isize))));
5270
return 0;
5371
}
5472
pub unsafe fn __cpp2rust_init_globals() {}

0 commit comments

Comments
 (0)