Skip to content

Commit e421df0

Browse files
committed
Remove more hand-written temporaries from rules
1 parent 3ec3713 commit e421df0

235 files changed

Lines changed: 2350 additions & 1853 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎cpp2rust/converter/converter.cpp‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5018,7 +5018,9 @@ std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg,
50185018
[this, arg](clang::QualType type) {
50195019
return MaterializeTemp(NewTempName(), type, arg);
50205020
});
5021+
// The temporary is initialized in a statement, which ends its borrows.
50215022
if (!materialized.empty()) {
5023+
borrows_ = false;
50225024
return materialized;
50235025
}
50245026
}
@@ -5246,7 +5248,17 @@ std::string Converter::ConvertIRFragment(
52465248
RuleRegistry::ParamIsPointer(ctx_, expr, arg_idx),
52475249
.is_index_base = ph->is_index_base,
52485250
};
5249-
result += ConvertPlaceholder(expr, arg, ph_ctx);
5251+
// A value is read in a block, which ends its borrows before the rule
5252+
// accesses what they borrow, unless it may point to a temporary, which
5253+
// would end too.
5254+
auto outer_borrows = std::exchange(borrows_, false);
5255+
auto value = ConvertPlaceholder(expr, arg, ph_ctx);
5256+
if (borrows_ && isFresh() && !CreatesTemporary(arg)) {
5257+
value = std::format("({{ {} }})", value);
5258+
borrows_ = false;
5259+
}
5260+
borrows_ |= outer_borrows;
5261+
result += value;
52505262
} else if (std::get_if<TranslationRule::VaArgsFragment>(&frag)) {
52515263
assert(expr && "variadic arguments outside an expression rule");
52525264
result += ConvertVariadicTail(expr, all_args);

‎cpp2rust/converter/converter.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,10 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
874874
// closure parameter of its with_mut.
875875
std::vector<std::pair<std::string, std::string>> mut_borrows_;
876876

877+
// Whether the expression being converted borrows a value in a temporary,
878+
// e.g., a guard of a RefCell, which lives until the end of the statement.
879+
bool borrows_ = false;
880+
877881
// The variables that arguments of rules are bound to by value, whose
878882
// address is not taken.
879883
std::unordered_set<const clang::VarDecl *> bound_values_;

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,6 +2010,12 @@ bool ReadsMemory(const clang::Stmt *stmt) {
20102010
});
20112011
}
20122012

2013+
bool CreatesTemporary(const clang::Stmt *stmt) {
2014+
return AnyStmt(stmt, [](const clang::Stmt *s) {
2015+
return clang::isa<clang::MaterializeTemporaryExpr>(s);
2016+
});
2017+
}
2018+
20132019
bool ReferencesThis(const clang::Stmt *stmt) {
20142020
return AnyStmt(stmt, [](const clang::Stmt *s) {
20152021
return clang::isa<clang::CXXThisExpr>(s);

‎cpp2rust/converter/converter_lib.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,9 @@ bool ReferencesThis(const clang::Stmt *stmt);
325325
// Whether evaluating `stmt` reads a value from memory, e.g., a pointer.
326326
bool ReadsMemory(const clang::Stmt *stmt);
327327

328+
// Whether stmt materializes a temporary, which a value may point to.
329+
bool CreatesTemporary(const clang::Stmt *stmt);
330+
328331
bool MayCauseBorrowMutError(const clang::Expr *lhs, const clang::Expr *rhs);
329332

330333
bool ArgsMayAlias(const clang::Expr *a, const clang::Expr *b);

‎cpp2rust/converter/models/boxed_vars.cpp‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,10 @@ class AddressTakenVisitor
228228

229229
private:
230230
// The arguments of a call translated by a rule are passed by value or
231-
// borrowed, unless the rule takes a pointer to them, or they are bound to
232-
// references. A pointer parameter receives the value of an argument that is
233-
// itself translated to a pointer.
231+
// borrowed, unless the rule takes a pointer to them, other than to a
232+
// temporary copy of them, or they are bound to references. A pointer
233+
// parameter receives the value of an argument that is itself translated to a
234+
// pointer.
234235
void AddRuleArgs(clang::Expr *expr, clang::Expr **args, unsigned num_args) {
235236
auto *rule = RuleRegistry::GetExprRule(ctx_, expr);
236237
if (!rule) {
@@ -248,7 +249,8 @@ class AddressTakenVisitor
248249
TraverseStmt(init);
249250
continue;
250251
}
251-
if (!rule->takesAddress(ctx_, i, arg)) {
252+
if (!rule->takesAddress(ctx_, i, arg) ||
253+
rule->takesTemporaryAddress(ctx_, expr, i, arg)) {
252254
AddValueUse(arg);
253255
}
254256
}

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1018,17 +1018,20 @@ void ConverterRefCount::ConvertDeclRefValue(clang::Expr *expr,
10181018
if (is_global_value && TypeIsCopyable(decl_t)) {
10191019
StrCat(str, ".with(|rc| *rc.borrow())");
10201020
} else if (is_global_value) {
1021+
borrows_ = true;
10211022
// Borrow the global in place, like a local. Cloning it would be
10221023
// expensive for arrays, and writes through its fields would be lost.
10231024
StrCat(std::format("(*{}.with(Value::clone).borrow())", std::move(str)));
10241025
} else {
10251026
StrCat(std::format("(*{}.borrow())", std::move(str)));
1027+
borrows_ = true;
10261028
}
10271029
} else {
10281030
if (is_global_value) {
10291031
str += ".with(Value::clone)";
10301032
}
10311033
StrCat(std::format("(*{}.borrow_mut())", std::move(str)));
1034+
borrows_ = true;
10321035
}
10331036

10341037
// A copied global is read into a new value.
@@ -1827,6 +1830,7 @@ bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) {
18271830
} else {
18281831
StrCat(std::format("(*{}.borrow_mut())", std::move(str)));
18291832
}
1833+
borrows_ = true;
18301834
SetValueFreshness(expr->getType());
18311835
return false;
18321836
}
@@ -2895,7 +2899,11 @@ bool ConverterRefCount::DerefReadsValue(clang::QualType pointee_type) {
28952899

28962900
const char *
28972901
ConverterRefCount::GetPointerDerefSuffix(clang::QualType pointee_type) {
2898-
return DerefReadsValue(pointee_type) ? ".read()" : ".upgrade().deref()";
2902+
if (DerefReadsValue(pointee_type)) {
2903+
return ".read()";
2904+
}
2905+
borrows_ = true;
2906+
return ".upgrade().deref()";
28992907
}
29002908

29012909
void ConverterRefCount::EmitPointee(std::string ptr,

‎cpp2rust/converter/translation_rule.cpp‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,6 @@ ExprRule::argsToBind(clang::ASTContext &ctx, const clang::Expr *expr,
277277
// The right operand of an assignment is evaluated before the left one.
278278
auto *op = clang::dyn_cast<clang::CXXOperatorCallExpr>(expr);
279279
bool right_to_left = op && op->isAssignmentOp();
280-
auto *call = clang::dyn_cast<clang::CallExpr>(expr);
281-
unsigned first_arg = clang::isa<clang::CXXMemberCallExpr>(expr);
282280
std::vector<bool> bind(args.size());
283281
bool bind_rest = false;
284282
unsigned next_first = position;
@@ -293,10 +291,7 @@ ExprRule::argsToBind(clang::ASTContext &ctx, const clang::Expr *expr,
293291
if (arg->HasSideEffects(ctx)) {
294292
// A temporary that a reference parameter is bound to would be
295293
// materialized before the call, out of order.
296-
bool materialized =
297-
call && i >= first_arg && takesAddress(ctx, i, arg) &&
298-
GetRefBindingTempType(ctx, call, i - first_arg).has_value();
299-
bind_rest |= uses[i] > 1 || materialized ||
294+
bind_rest |= uses[i] > 1 || takesTemporaryAddress(ctx, expr, i, arg) ||
300295
(uses[i] == 1 && first[i] > next_first);
301296
bind[i] = bind_rest;
302297
if (uses[i] == 1) {
@@ -318,6 +313,15 @@ bool ExprRule::takesAddress(clang::ASTContext &ctx, unsigned i,
318313
!RuleRegistry::MapsToPointer(ctx, arg->getType());
319314
}
320315

316+
bool ExprRule::takesTemporaryAddress(clang::ASTContext &ctx,
317+
const clang::Expr *expr, unsigned i,
318+
const clang::Expr *arg) const {
319+
auto *call = clang::dyn_cast<clang::CallExpr>(expr);
320+
unsigned first_arg = clang::isa<clang::CXXMemberCallExpr>(expr);
321+
return call && i >= first_arg && takesAddress(ctx, i, arg) &&
322+
GetRefBindingTempType(ctx, call, i - first_arg).has_value();
323+
}
324+
321325
void RefExprFragment::dump() const {
322326
log() << " ref_expr: " << prefix << '\n';
323327
for (auto &frag : inner) {

‎cpp2rust/converter/translation_rule.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ struct ExprRule {
130130
// pointer.
131131
bool takesAddress(clang::ASTContext &ctx, unsigned i,
132132
const clang::Expr *arg) const;
133+
134+
// Whether the body takes a pointer to a temporary copy of arg, argument i
135+
// of expr, that a reference parameter is bound to.
136+
bool takesTemporaryAddress(clang::ASTContext &ctx, const clang::Expr *expr,
137+
unsigned i, const clang::Expr *arg) const;
133138
};
134139

135140
struct TypeRule {

‎rules/map/tgt_refcount.rs‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ fn f3<T1: CppLess + 'static, T2: 'static>(
2424
a0: Ptr<Map<T1, (Value<T1>, Value<T2>)>>,
2525
a1: BidirectionalIterator<(Value<T1>, Value<T2>)>,
2626
) -> BidirectionalIterator<(Value<T1>, Value<T2>)> {
27-
// The block ends the borrow of the iterator, e.g., in it = m.erase(it).
28-
let __it = a1;
29-
Map::erase(a0, &__it)
27+
Map::erase(a0, &a1)
3028
}
3129

3230
fn f5<T1, T2>() -> Map<T1, (Value<T1>, Value<T2>)> {
@@ -89,9 +87,7 @@ fn f27<T1: CppLess + 'static, T2: 'static>(
8987
a0: Ptr<Map<T1, (Value<T1>, Value<T2>)>>,
9088
a1: BidirectionalIterator<(Value<T1>, Value<T2>)>,
9189
) -> BidirectionalIterator<(Value<T1>, Value<T2>)> {
92-
// The block ends the borrow of the iterator, e.g., in it = m.erase(it).
93-
let __it = a1;
94-
Map::erase(a0, &__it)
90+
Map::erase(a0, &a1)
9591
}
9692

9793
fn f28<T1: CppLess + 'static, T2: 'static>(a0: Ptr<Map<T1, (Value<T1>, Value<T2>)>>, a1: Ptr<T1>) -> usize {

‎rules/pwd/tgt_refcount.rs‎

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@ fn t1() -> libcc2rs::Passwd {
88
}
99

1010
fn f2(a0: u32, a1: Ptr<Passwd>, a2: Ptr<i8>, a3: usize, a4: Ptr<Ptr<Passwd>>) -> i32 {
11-
// Computing the arguments first ends their borrows of what the call writes.
12-
let __pwbuf = a1;
13-
let __buf = a2;
14-
let __buflen = a3;
15-
let __out = a4;
1611
match nix::unistd::User::from_uid(nix::unistd::Uid::from_raw(a0)) {
1712
Ok(Some(__u)) => {
1813
let __strs: [Vec<u8>; 5] = [
@@ -23,30 +18,30 @@ fn f2(a0: u32, a1: Ptr<Passwd>, a2: Ptr<i8>, a3: usize, a4: Ptr<Ptr<Passwd>>) ->
2318
__u.shell.as_os_str().as_encoded_bytes().to_vec(),
2419
];
2520
let __needed: usize = __strs.iter().map(|__s| __s.len() + 1).sum();
26-
if __needed > __buflen {
27-
__out.write(Ptr::null());
21+
if __needed > a3 {
22+
a4.write(Ptr::null());
2823
::libc::ERANGE
2924
} else {
3025
let mut __ptrs: Vec<Ptr<i8>> = Vec::new();
3126
let mut __off: usize = 0;
3227
for __s in &__strs {
33-
__ptrs.push(__buf.offset(__off));
28+
__ptrs.push(a2.offset(__off));
3429
let __end = __s.len();
35-
__buf.offset(__off).write_c_bytes(__s);
36-
elem!(__buf, __off + __end).write(0);
30+
a2.offset(__off).write_c_bytes(__s);
31+
elem!(a2, __off + __end).write(0);
3732
__off += __end + 1;
3833
}
39-
__pwbuf.with_mut(|__pw| *__pw = Passwd::from_user_in(&__u, &__ptrs));
40-
__out.write(__pwbuf.clone());
34+
a1.with_mut(|__pw| *__pw = Passwd::from_user_in(&__u, &__ptrs));
35+
a4.write(a1.clone());
4136
0
4237
}
4338
}
4439
Ok(None) => {
45-
__out.write(Ptr::null());
40+
a4.write(Ptr::null());
4641
0
4742
}
4843
Err(__e) => {
49-
__out.write(Ptr::null());
44+
a4.write(Ptr::null());
5045
__e as i32
5146
}
5247
}

0 commit comments

Comments
 (0)