Skip to content

Commit 747cb00

Browse files
authored
Remove converter hack around std::map::iterator (#523)
The old code special cased `std::map::iterator` (which is just a sugar for `std::pair<const K, V>`) to generate `i.first()` and `i.second()` instead of `i.0` and `i.1`. This PR removes the hack by saving a pair in `libcc2rs::MapIter` which can be accessed with `.0` and `.1`. It also fixes a translation bug: ```cpp for (auto i : m) { i.second = -1; assert(i.second == -1); } for (const auto &i : m) { assert(i.second != -1); } ```
1 parent e63c904 commit 747cb00

28 files changed

Lines changed: 1253 additions & 521 deletions

‎cpp2rust/converter/converter.cpp‎

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,12 +1498,8 @@ void Converter::ConvertLoopVariable(clang::VarDecl *decl,
14981498
}
14991499
}
15001500

1501-
void Converter::ConvertForRangeBody(clang::CXXForRangeStmt *stmt,
1502-
const clang::VarDecl *map_iter_decl) {
1501+
void Converter::ConvertForRangeBody(clang::CXXForRangeStmt *stmt) {
15031502
PushBreakTarget push(break_target_, BreakTarget::Loop);
1504-
std::optional<ScopedMapIterDecl> skip;
1505-
if (map_iter_decl)
1506-
skip.emplace(*this, map_iter_decl);
15071503
curr_for_inc_.emplace_back(nullptr);
15081504
ConvertBodyStmts(stmt->getBody());
15091505
curr_for_inc_.pop_back();
@@ -1529,18 +1525,19 @@ bool Converter::VisitCXXForRangeStmt(clang::CXXForRangeStmt *stmt) {
15291525
}
15301526

15311527
bool Converter::VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt) {
1532-
auto *loop_var = stmt->getLoopVariable();
1533-
auto loop_var_name = GetNamedDeclAsString(loop_var);
1528+
auto begin =
1529+
llvm::cast<clang::VarDecl>(stmt->getBeginStmt()->getSingleDecl());
15341530

15351531
StrCat("'loop_:");
15361532
auto map_type = Mapper::Map(*this, stmt->getRangeInit()->getType());
1537-
StrCat(keyword::kFor, loop_var_name, keyword::kIn,
1533+
StrCat(keyword::kFor, GetNamedDeclAsString(begin), keyword::kIn,
15381534
"UnsafeMapIterator::begin(&");
15391535
Convert(stmt->getRangeInit());
15401536
StrCat(std::format(" as *const {})", map_type));
15411537
{
15421538
PushBrace brace(*this);
1543-
ConvertForRangeBody(stmt, loop_var);
1539+
Convert(stmt->getLoopVarStmt());
1540+
ConvertForRangeBody(stmt);
15441541
}
15451542

15461543
return false;
@@ -3239,8 +3236,7 @@ void Converter::ConvertDeclRefValue(clang::Expr *expr, clang::ValueDecl *decl) {
32393236
auto str = ConvertDeclRef(expr, decl);
32403237
auto type = GetDeclRefType(curr_function_, expr, decl);
32413238

3242-
if (type->getAs<clang::ReferenceType>() && !isAddrOf() &&
3243-
!map_iter_decls_.contains(clang::dyn_cast<clang::VarDecl>(decl))) {
3239+
if (type->getAs<clang::ReferenceType>() && !isAddrOf()) {
32443240
EmitDeref(std::move(str), type.getNonReferenceType());
32453241
SetValueFreshness(expr->getType());
32463242
return;

‎cpp2rust/converter/converter.h‎

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
215215
bool VisitCXXForRangeStmtIndexBased(clang::CXXForRangeStmt *stmt,
216216
const char *len_suffix);
217217

218-
void ConvertForRangeBody(clang::CXXForRangeStmt *stmt,
219-
const clang::VarDecl *map_iter_decl = nullptr);
218+
void ConvertForRangeBody(clang::CXXForRangeStmt *stmt);
220219

221220
virtual bool VisitBreakStmt(clang::BreakStmt *stmt);
222221

@@ -902,8 +901,6 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
902901
Converter &c_;
903902
};
904903

905-
std::unordered_set<const clang::VarDecl *> map_iter_decls_;
906-
907904
// Local variables hoisted outside a goto_block so that all labels can see and
908905
// use the variables.
909906
std::unordered_set<const clang::VarDecl *> hoisted_decls_;
@@ -954,15 +951,6 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
954951
operator=(const HoistMaterializedTempBindings &) = delete;
955952
};
956953

957-
struct ScopedMapIterDecl {
958-
Converter &c;
959-
const clang::VarDecl *decl;
960-
ScopedMapIterDecl(Converter &c, const clang::VarDecl *decl)
961-
: c(c), decl(decl) {
962-
c.map_iter_decls_.insert(decl);
963-
}
964-
~ScopedMapIterDecl() { c.map_iter_decls_.erase(decl); }
965-
};
966954
static std::unordered_set<std::string> decl_ids_;
967955
static std::unordered_set<std::string> abstract_structs_;
968956

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,38 +1902,6 @@ GetStrongestIteratorCategory(clang::ASTContext &ctx, clang::QualType type) {
19021902
return std::nullopt;
19031903
}
19041904

1905-
const clang::CXXForRangeStmt *
1906-
GetParentForRange(clang::ASTContext &ctx, const clang::MemberExpr *member) {
1907-
auto base = member->getBase()->IgnoreParenImpCasts();
1908-
if (auto decl_ref = llvm::dyn_cast<clang::DeclRefExpr>(base)) {
1909-
if (auto var = llvm::dyn_cast<clang::VarDecl>(decl_ref->getDecl())) {
1910-
for (const auto &parent : ctx.getParents(*var)) {
1911-
if (auto decl_stmt = parent.get<clang::DeclStmt>()) {
1912-
for (const auto &grandparent : ctx.getParents(*decl_stmt)) {
1913-
if (auto for_range = grandparent.get<clang::CXXForRangeStmt>()) {
1914-
return for_range;
1915-
}
1916-
}
1917-
}
1918-
}
1919-
}
1920-
}
1921-
return nullptr;
1922-
}
1923-
1924-
clang::QualType
1925-
GetForRangeIteratorType(const clang::CXXForRangeStmt *for_range) {
1926-
if (auto begin_stmt = for_range->getBeginStmt()) {
1927-
if (auto begin_decl_stmt = llvm::dyn_cast<clang::DeclStmt>(begin_stmt)) {
1928-
if (auto begin_var = llvm::dyn_cast<clang::VarDecl>(
1929-
begin_decl_stmt->getSingleDecl())) {
1930-
return begin_var->getType();
1931-
}
1932-
}
1933-
}
1934-
return {};
1935-
}
1936-
19371905
std::string GetClassName(clang::QualType type) {
19381906
if (auto *record = type->getAsCXXRecordDecl())
19391907
return record->getQualifiedNameAsString();

‎cpp2rust/converter/converter_lib.h‎

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -323,12 +323,6 @@ clang::Expr *BuildInitExpr(clang::Sema &sema, clang::QualType type,
323323
llvm::ArrayRef<clang::Expr *> args,
324324
clang::SourceLocation loc);
325325

326-
const clang::CXXForRangeStmt *
327-
GetParentForRange(clang::ASTContext &ctx, const clang::MemberExpr *member);
328-
329-
clang::QualType
330-
GetForRangeIteratorType(const clang::CXXForRangeStmt *for_range);
331-
332326
std::string GetClassName(clang::QualType type);
333327

334328
bool IsVaListType(clang::QualType type);

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,12 +1044,6 @@ void ConverterRefCount::ConvertDeclRefValue(clang::Expr *expr,
10441044
}
10451045

10461046
if (auto *ref = decl_t->getAs<clang::ReferenceType>()) {
1047-
if (map_iter_decls_.contains(clang::dyn_cast<clang::VarDecl>(decl))) {
1048-
StrCat(str);
1049-
SetValueFreshness(expr->getType());
1050-
return;
1051-
}
1052-
10531047
if (auto pointee = ref->getPointeeType();
10541048
isObject() && WantsElementPtr() && IsBoxedType(ctx_, pointee)) {
10551049
StrCat(std::format("Ptr::<{}>::decay(&({}))", ToString(pointee),
@@ -2269,19 +2263,19 @@ void ConverterRefCount::EmitByValueShadow(const clang::VarDecl *loop_var,
22692263
}
22702264

22712265
bool ConverterRefCount::VisitCXXForRangeStmtMap(clang::CXXForRangeStmt *stmt) {
2272-
auto *loop_var = stmt->getLoopVariable();
2273-
auto loop_var_name = GetNamedDeclAsString(loop_var);
2266+
auto begin =
2267+
llvm::cast<clang::VarDecl>(stmt->getBeginStmt()->getSingleDecl());
2268+
auto begin_name = GetNamedDeclAsString(begin);
22742269

22752270
StrCat("'loop_:");
2276-
StrCat(keyword::kFor, loop_var_name, keyword::kIn, "RefcountMapIter::begin(",
2271+
StrCat(keyword::kFor, begin_name, keyword::kIn, "RefcountMapIter::begin(",
22772272
ConvertObject(stmt->getRangeInit()), ')');
22782273
PushBrace brace(*this);
22792274

2280-
EmitByValueShadow(
2281-
loop_var, std::string(loop_var_name),
2282-
"Value<" + Mapper::Map(*this, GetForRangeIteratorType(stmt)) + '>');
2275+
EmitByValueShadow(begin, std::string(begin_name));
2276+
Convert(stmt->getLoopVarStmt());
22832277

2284-
ConvertForRangeBody(stmt, loop_var);
2278+
ConvertForRangeBody(stmt);
22852279

22862280
return false;
22872281
}

‎cpp2rust/converter/printer.cpp‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -371,14 +371,6 @@ std::string ToString(clang::ASTContext &ctx, const clang::Expr *expr) {
371371
ToString(ctx, member_decl);
372372
}
373373
}
374-
} else if (auto for_range = GetParentForRange(ctx, ME)) {
375-
if (ToString(ctx, for_range->getRangeInit()->getType())
376-
.starts_with("std::map<")) {
377-
auto iter_type = GetForRangeIteratorType(for_range);
378-
if (!iter_type.isNull()) {
379-
return ToString(ctx, iter_type) + "->" + ToString(ctx, member_decl);
380-
}
381-
}
382374
}
383375
return ToString(ctx, member_decl);
384376
}

‎libcc2rs/src/iterators.rs‎

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
// Copyright (c) 2022-present INESC-ID.
22
// Distributed under the MIT license that can be found in the LICENSE file.
33

4-
use crate::{CChar, PostfixDec, PostfixInc, PrefixDec, PrefixInc, Ptr, Value};
5-
use std::cell::RefCell;
4+
use crate::{AsPointer, CChar, PostfixDec, PostfixInc, PrefixDec, PrefixInc, Ptr, Value};
65
use std::collections::BTreeMap;
76
use std::ops::Bound;
8-
use std::rc::Rc;
97

108
pub trait MapAccess: Clone + Default {
119
type Key: Ord + Clone;
@@ -45,8 +43,8 @@ pub struct MapIter<K, MapRef> {
4543
key: Option<K>,
4644
}
4745

48-
pub type RefcountMapIter<K, V> = MapIter<K, Ptr<BTreeMap<K, Value<V>>>>;
49-
pub type UnsafeMapIterator<K, V> = MapIter<K, *const BTreeMap<K, Box<V>>>;
46+
pub type RefcountMapIter<K, V> = MapIter<K, Ptr<BTreeMap<K, Value<(Value<K>, Value<V>)>>>>;
47+
pub type UnsafeMapIterator<K, V> = MapIter<K, *const BTreeMap<K, Box<(K, V)>>>;
5048

5149
impl<K: Clone, MapRef: Clone> Clone for MapIter<K, MapRef> {
5250
fn clone(&self) -> Self {
@@ -141,44 +139,31 @@ impl<K: Ord + Clone, MapRef: MapAccess<Key = K>> MapIter<K, MapRef> {
141139
}
142140

143141
pub trait MapIterator {
144-
type First;
145-
type Second;
146-
fn first(&self) -> Self::First;
147-
fn second(&self) -> Self::Second;
142+
type Entry;
143+
fn deref(&self) -> Self::Entry;
148144
}
149145

150146
impl<K: Ord + Clone + 'static, V: 'static> MapIterator for RefcountMapIter<K, V> {
151-
type First = Value<K>;
152-
type Second = Value<V>;
147+
type Entry = Ptr<(Value<K>, Value<V>)>;
153148

154-
fn first(&self) -> Value<K> {
155-
let key = self.key.as_ref().expect("ub: dereference of end iterator");
156-
Rc::new(RefCell::new(key.clone()))
157-
}
158-
159-
fn second(&self) -> Value<V> {
149+
fn deref(&self) -> Ptr<(Value<K>, Value<V>)> {
160150
let key = self.key.as_ref().expect("ub: dereference of end iterator");
161151
self.map
162-
.with(|m| m.get(key).expect("ub: key not found in map").clone())
152+
.with(|m| m.get(key).expect("ub: key not found in map").as_pointer())
163153
}
164154
}
165155

166156
impl<K: Ord + Clone, V> MapIterator for UnsafeMapIterator<K, V> {
167-
type First = *const K;
168-
type Second = *mut V;
169-
170-
fn first(&self) -> *const K {
171-
self.key.as_ref().expect("ub: dereference of end iterator") as *const K
172-
}
157+
type Entry = *mut (K, V);
173158

174-
fn second(&self) -> *mut V {
159+
fn deref(&self) -> *mut (K, V) {
175160
unsafe {
176-
let map_mut = self.map as *mut BTreeMap<K, Box<V>>;
161+
let map_mut = self.map as *mut BTreeMap<K, Box<(K, V)>>;
177162
let key = self.key.as_ref().expect("ub: dereference of end iterator");
178163
(*map_mut)
179164
.get_mut(key)
180165
.expect("ub: key not found in map")
181-
.as_mut() as *mut V
166+
.as_mut() as *mut (K, V)
182167
}
183168
}
184169
}

‎rules/map/src.cpp‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,14 @@ template <typename T1, typename T2>
134134
std::map<T1, T2> &f26(std::map<T1, T2> &dst, const std::map<T1, T2> &src) {
135135
return dst.operator=(src);
136136
}
137+
138+
template <typename T1, typename T2>
139+
std::pair<const T1, T2> &f27(typename std::map<T1, T2>::iterator it) {
140+
return it.operator*();
141+
}
142+
143+
template <typename T1, typename T2>
144+
const std::pair<const T1, T2> &
145+
f28(typename std::map<T1, T2>::const_iterator it) {
146+
return it.operator*();
147+
}

0 commit comments

Comments
 (0)