Skip to content

Commit ae13b48

Browse files
authored
Use fresh rvalues for comma operands and materialized temporaries (#461)
Fixes miscompilations, rvalue comma operands should be cloned, not moved.
1 parent 86f03c3 commit ae13b48

5 files changed

Lines changed: 137 additions & 2 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2776,7 +2776,11 @@ void Converter::ConvertBinaryOperator(clang::BinaryOperator *expr) {
27762776
Convert(lhs);
27772777
}
27782778
StrCat(token::kSemiColon);
2779-
Convert(rhs);
2779+
if (isRValue()) {
2780+
StrCat(ConvertFreshRValue(rhs));
2781+
} else {
2782+
Convert(rhs);
2783+
}
27802784
} else if (IsUnsignedArithOp(expr)) {
27812785
if (expr->isCompoundAssignmentOp()) {
27822786
Convert(lhs);

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ ConverterRefCount::MaterializeTemp(const std::string &binding_name,
496496
clang::QualType param_type,
497497
clang::Expr *expr) {
498498
auto pointee = param_type.getNonReferenceType();
499-
auto value = ConvertRValue(expr, pointee);
499+
auto value = ConvertFreshRValue(expr, pointee);
500500
auto type_str = ToStringBase(pointee);
501501
const auto *decl = in_const_initializer_ ? keyword::kStatic : keyword::kLet;
502502

‎tests/unit/comma_operator.cpp‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
#include <cassert>
2+
#include <vector>
3+
4+
struct Pair {
5+
int first;
6+
int second;
7+
};
8+
9+
long twice(const long &v) { return v * 2; }
10+
11+
int sum(const Pair &p) { return p.first + p.second; }
212

313
int main() {
414
int x = 1;
@@ -20,5 +30,22 @@ int main() {
2030
assert(b == 2);
2131
}
2232

33+
std::vector<int> v1 = {1, 2};
34+
std::vector<int> v2 = (a = 5, v1);
35+
v2.push_back(3);
36+
assert(a == 5);
37+
assert(v1.size() == 2);
38+
assert(v2.size() == 3);
39+
40+
Pair p1{1, 2};
41+
Pair p2 = (b = 6, p1);
42+
p2.first = 10;
43+
assert(p1.first == 1);
44+
assert(p2.first == 10);
45+
46+
assert(twice(a) == 10);
47+
assert(sum((a = 7, p1)) == 3);
48+
assert(a == 7);
49+
2350
return 0;
2451
}

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,20 @@ use std::io::prelude::*;
66
use std::io::{Read, Seek, Write};
77
use std::os::fd::AsFd;
88
use std::rc::{Rc, Weak};
9+
#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)]
10+
#[byte_size(8)]
11+
pub struct Pair {
12+
#[offset(0)]
13+
pub first: i32,
14+
#[offset(4)]
15+
pub second: i32,
16+
}
17+
pub fn twice_0(v: Ptr<i64>) -> i64 {
18+
return ((v.read()) * 2_i64);
19+
}
20+
pub fn sum_1(p: Ptr<Pair>) -> i32 {
21+
return ({ p.with(|__s| __s.first) } + { p.with(|__s| __s.second) });
22+
}
923
pub fn main() {
1024
__cpp2rust_init_globals();
1125
std::process::exit(main_0());
@@ -48,6 +62,45 @@ fn main_0() -> i32 {
4862
assert!((a == 1));
4963
assert!((b == 2));
5064
}
65+
let v1: Value<Vec<i32>> = Rc::new(RefCell::new(vec![1, 2]));
66+
let mut v2: Vec<i32> = {
67+
a = 5;
68+
(*v1.borrow()).clone()
69+
}
70+
.clone();
71+
{
72+
let __a1 = 3;
73+
v2.push(__a1)
74+
};
75+
assert!((a == 5));
76+
assert!(((*v1.borrow()).len() == 2_usize));
77+
assert!((v2.len() == 3_usize));
78+
let p1: Value<Pair> = Rc::new(RefCell::new(Pair {
79+
first: 1,
80+
second: 2,
81+
}));
82+
let mut p2: Pair = {
83+
b = 6;
84+
(*p1.borrow()).clone()
85+
};
86+
p2.first = 10;
87+
assert!(({ (*p1.borrow()).first } == 1));
88+
assert!((p2.first == 10));
89+
assert!(
90+
(({
91+
let _v: Value<i64> = Rc::new(RefCell::new((a as i64)));
92+
twice_0(_v.as_pointer())
93+
}) == 10_i64)
94+
);
95+
assert!(
96+
(({
97+
sum_1({
98+
a = 7;
99+
p1.as_pointer()
100+
})
101+
}) == 3)
102+
);
103+
assert!((a == 7));
51104
return 0;
52105
}
53106
pub fn __cpp2rust_init_globals() {}

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@ use std::collections::BTreeMap;
66
use std::io::{Read, Seek, Write};
77
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
88
use std::rc::Rc;
9+
#[repr(C)]
10+
#[derive(Copy, Clone, VaArg, FnPtrArg, Default)]
11+
pub struct Pair {
12+
pub first: i32,
13+
pub second: i32,
14+
}
15+
pub unsafe fn twice_0(v: *const i64) -> i64 {
16+
return ((*v) * (2_i64));
17+
}
18+
pub unsafe fn sum_1(p: *const Pair) -> i32 {
19+
return (((*p).first) + ((*p).second));
20+
}
921
pub fn main() {
1022
unsafe {
1123
__cpp2rust_init_globals();
@@ -50,6 +62,45 @@ unsafe fn main_0() -> i32 {
5062
assert!(((a) == (1)));
5163
assert!(((b) == (2)));
5264
}
65+
let mut v1: Vec<i32> = vec![1, 2];
66+
let mut v2: Vec<i32> = {
67+
a = 5;
68+
(v1).clone()
69+
}
70+
.clone();
71+
{
72+
let __a1 = 3;
73+
v2.push(__a1)
74+
};
75+
assert!(((a) == (5)));
76+
assert!(((v1.len()) == (2_usize)));
77+
assert!(((v2.len()) == (3_usize)));
78+
let mut p1: Pair = Pair {
79+
first: 1,
80+
second: 2,
81+
};
82+
let mut p2: Pair = {
83+
b = 6;
84+
p1
85+
};
86+
p2.first = 10;
87+
assert!(((p1.first) == (1)));
88+
assert!(((p2.first) == (10)));
89+
assert!(
90+
((unsafe {
91+
let mut _v: i64 = (a as i64);
92+
twice_0(&mut _v)
93+
}) == (10_i64))
94+
);
95+
assert!(
96+
((unsafe {
97+
sum_1(&{
98+
a = 7;
99+
p1
100+
})
101+
}) == (3))
102+
);
103+
assert!(((a) == (7)));
53104
return 0;
54105
}
55106
pub unsafe fn __cpp2rust_init_globals() {}

0 commit comments

Comments
 (0)